feat: finish generator

This commit is contained in:
samsonium
2026-11-05 00:04:12 +03:00
parent 181458ecda
commit bd8272abc7
11 changed files with 744 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
#include <compiler/fzl_gen.h>
#include <compiler/fzl_parser.h>
#include <compiler/internals/gen.h>
#include <string.h>
// Assignment to declaration
gen_res_t assign_declaration(fzl_gen_t *gen, fzl_node_t *node)
{
gen_res_t rres = gen_common(gen, node->binary_op.right);
if (rres.error)
return gen_error;
gen_res_t lres = gen_common(gen, node->binary_op.left);
if (lres.error)
return gen_error;
if (!gen_is_types_compatible(rres.type, lres.type, rres.classname,
lres.classname))
return gen_error;
gen_op(gen, FZL_OPCODE_WRITE);
return (gen_res_t){
.error = false, .type = rres.type, .classname = rres.classname};
}
// Assignment to identifier
gen_res_t assign_id(fzl_gen_t *gen, fzl_node_t *node)
{
gen_res_t rres = gen_common(gen, node->binary_op.right);
if (rres.error)
return gen_error;
char *name = (char *)node->binary_op.left->token->value;
fzl_sym_t sym;
bool found = false;
ssize_t i = gen->syms_top - 1;
for (; i >= 0; i--)
if ((found = fzl_symt_get(gen->syms[i], name, &sym)))
break;
if (!found)
return gen_error;
if (!gen_is_types_compatible(sym.type, rres.type, sym.classname,
rres.classname))
return gen_error;
if (!sym.slot_set)
return gen_error;
size_t depth = gen->syms_top - 1 - i;
gen_op(gen, FZL_OPCODE_STORE_LOCAL);
gen_word(gen, depth);
gen_word(gen, sym.slot);
return (gen_res_t){
.error = false, .type = rres.type, .classname = rres.classname};
}
// Assignment to field
gen_res_t assign_field(fzl_gen_t *gen, fzl_node_t *node)
{
gen_res_t rres = gen_common(gen, node->binary_op.right);
if (rres.error)
return gen_error;
fzl_node_t *field_node = node->binary_op.left;
gen_res_t obj_res = gen_common(gen, field_node->memb.parent);
if (obj_res.error)
return gen_error;
fzl_ctable_t *ct = NULL;
for (size_t i = 0; i < gen->classes_count; i++)
{
if (strcmp(obj_res.classname, gen->classes[i]->name) == 0)
{
ct = gen->classes[i];
break;
}
}
if (!ct)
return gen_error;
fzl_ctable_field_t *ctf = NULL;
for (size_t i = 0; i < ct->fields_count; i++)
{
if (strcmp(field_node->memb.field->token->value, ct->fields[i].name) == 0)
{
ctf = &ct->fields[i];
break;
}
}
if (!ctf)
return gen_error;
gen_op(gen, FZL_OPCODE_SET_FIELD);
gen_word(gen, ctf->slot_index);
return (gen_res_t){
.error = false, .type = rres.type, .classname = rres.classname};
}
// Assignment
gen_res_t gen_assign(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
if (node->binary_op.left->type == FZL_NODETYPE_DECLARATION)
return assign_declaration(gen, node);
if (node->binary_op.left->type == FZL_NODETYPE_IDENTIFIER)
return assign_id(gen, node);
if (node->binary_op.left->type == FZL_NODETYPE_FIELD)
return assign_field(gen, node);
return gen_error;
}
+27
View File
@@ -0,0 +1,27 @@
#include <compiler/fzl_gen.h>
#include <compiler/internals/gen.h>
// Block definition
gen_res_t gen_block(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
fzl_gen_ctx_t *ctx = gen_ctx(gen, FZL_GEN_CTX_TYPE_UNECCESSARY, node);
if (!ctx)
return gen_error;
gen_op(gen, FZL_OPCODE_MK_ENVTABLE);
if (node->list.entry_count > 0)
for (size_t i = 0; i < node->list.entry_count; i++)
if (gen_common(gen, node->list.entries[i]).error)
return gen_error;
ctx = gen_fin_ctx(gen);
if (!ctx)
return gen_error;
gen_op(gen, FZL_OPCODE_RM_ENVTABLE);
return gen_ok_null;
}
+231
View File
@@ -0,0 +1,231 @@
#include <common/fzl_builtins.h>
#include <common/fzl_extern.h>
#include <common/fzl_opcodes.h>
#include <common/fzl_types.h>
#include <compiler/fzl_parser.h>
#include <compiler/internals/gen.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
// Call definition
// NOTE: split by call type (builtin/declared/extern)
gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
// `printline(x)` builtin function
if (strcmp(node->token->value, "printline") == 0)
{
if (node->call.args_count > 0)
for (size_t i = 0; i < node->call.args_count; i++)
if (gen_common(gen, node->call.args[i]).error)
return gen_error;
gen_op(gen, FZL_OPCODE_CALL_BUILTIN);
gen_word(gen, FZL_BUILTIN_PRINTLINE);
if (node->call.args_count < 1)
return gen_error;
return gen_ok_null;
}
// `exit(x?)` builtin function
if (strcmp(node->token->value, "exit") == 0)
{
if (node->call.args_count > 0)
{
for (size_t i = 0; i < node->call.args_count; i++)
if (gen_common(gen, node->call.args[i]).error)
return gen_error;
gen_op(gen, FZL_OPCODE_CALL_BUILTIN);
gen_word(gen, FZL_BUILTIN_EXIT);
if (node->call.args_count < 1)
return gen_error;
}
return gen_ok_null;
}
if (node->call.callee->type == FZL_NODETYPE_IDENTIFIER)
{
if (node->call.args_count > 0)
for (size_t i = 0; i < node->call.args_count; i++)
if (gen_common(gen, node->call.args[i]).error)
return gen_error;
char *name = (char *)node->token->value;
fzl_sym_t sym;
bool found = gen_resolve_name(gen, name, &sym);
if (!found)
return gen_error;
gen_res_t result;
if (sym.node->type == FZL_NODETYPE_EXTERN_FN)
{
size_t fn_n = 0;
fzl_extern_fn_t *fn = NULL;
for (size_t i = 0; i < gen->extern_fns_count; i++)
{
if (strcmp(gen->extern_fns[i].used_name, name) == 0)
{
fn = &gen->extern_fns[i];
fn_n = i;
break;
}
}
if (!fn)
return gen_error;
fzl_type_t rettype;
char *rettypecn = NULL;
if (!fn->has_return)
{
rettype = FZL_TYPE_NULL;
}
else if (fn->ret_type.is_primitive)
{
rettype = fn->ret_type.primitive;
}
else
{
fzl_extern_type_t *type = &gen->extern_types[fn->ret_type.type_slot];
switch (type->kind)
{
case FZL_EXTERN_KIND_REF:
rettype = FZL_TYPE_HANDLE;
rettypecn = type->name;
break;
case FZL_EXTERN_KIND_STRUCT:
rettype = FZL_TYPE_STRUCT;
rettypecn = type->name;
break;
case FZL_EXTERN_KIND_HANDLE:
rettype = FZL_TYPE_HANDLE;
rettypecn = type->name;
break;
case FZL_EXTERN_KIND_ALIAS:
if (type->alias_target.is_primitive)
{
rettype = type->alias_target.primitive;
}
else
{
fzl_extern_type_t *aliased =
&gen->extern_types[type->alias_target.type_slot];
switch (aliased->kind)
{
case FZL_EXTERN_KIND_ALIAS:
return gen_error;
case FZL_EXTERN_KIND_HANDLE:
rettype = FZL_TYPE_HANDLE;
rettypecn = aliased->name;
break;
case FZL_EXTERN_KIND_STRUCT:
rettype = FZL_TYPE_STRUCT;
rettypecn = aliased->name;
break;
case FZL_EXTERN_KIND_REF:
rettype = FZL_TYPE_HANDLE;
rettypecn = aliased->name;
break;
default:
return gen_error;
}
}
break;
}
}
gen_op(gen, FZL_OPCODE_CALL_EXTERN);
gen_word(gen, fn_n);
return (gen_res_t){
.error = false, .type = rettype, .classname = rettypecn};
}
else
{
if (!sym.ip)
return gen_error;
gen_op(gen, FZL_OPCODE_CALL);
gen_word(gen, sym.ip);
return (gen_res_t){
.error = false, .type = sym.type, .classname = sym.classname};
}
return result;
}
if (node->call.callee->type == FZL_NODETYPE_FIELD)
{
fzl_node_t *parent_node = node->call.callee->memb.parent;
fzl_node_t *method_node = node->call.callee->memb.field;
gen_res_t parent_res = gen_common(gen, parent_node);
if (parent_res.error)
return gen_error;
if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname)
return gen_error;
char *classname = parent_res.classname;
bool class_exists = false;
for (size_t i = 0; i < gen->classes_count; i++)
{
if (strcmp(classname, gen->classes[i]->name) == 0)
{
class_exists = true;
break;
}
}
if (!class_exists)
return gen_error;
size_t classlen = strlen(classname);
size_t fnlen = strlen(method_node->token->value);
char *methodname = malloc(classlen + fnlen + 2);
strcpy(methodname, classname);
strcpy((methodname + classlen + 1), node->call.callee->token->value);
methodname[classlen] = '_';
methodname[classlen + fnlen + 1] = 0;
fzl_sym_t fn_sym;
bool found_method = false;
for (ssize_t i = gen->syms_top - 1; i >= 0; i--)
if ((found_method = fzl_symt_get(gen->syms[i], methodname, &fn_sym)))
break;
if (!found_method)
return gen_error;
free(methodname);
if (node->call.args_count > 0)
for (size_t i = 0; i < node->call.args_count; i++)
if (gen_common(gen, node->call.args[i]).error)
return gen_error;
gen_op(gen, FZL_OPCODE_CALL);
gen_word(gen, fn_sym.ip);
return (gen_res_t){
.error = false, .type = fn_sym.type, .classname = fn_sym.classname};
}
return gen_error;
}
+83
View File
@@ -0,0 +1,83 @@
#include <common/fzl_types.h>
#include <compiler/internals/gen.h>
#include <stdio.h>
// Comparison operations
gen_res_t gen_compare(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
gen_res_t left = gen_common(gen, node->binary_op.left);
if (left.error)
return left;
gen_res_t right = gen_common(gen, node->binary_op.right);
if (right.error)
return right;
if (!gen_is_types_compatible(left.type, right.type, left.classname,
right.classname))
return gen_error;
if (left.type == FZL_TYPE_STRING && right.type == FZL_TYPE_STRING)
{
switch (node->type)
{
case FZL_NODETYPE_EQUAL:
gen_op(gen, FZL_OPCODE_CMP_EQ_STR);
break;
case FZL_NODETYPE_NEQUAL:
gen_op(gen, FZL_OPCODE_CMP_NEQ_STR);
break;
default:
return gen_error;
}
}
else if (left.type == FZL_TYPE_OBJECT && right.type == FZL_TYPE_OBJECT)
{
switch (node->type)
{
case FZL_NODETYPE_EQUAL:
gen_op(gen, FZL_OPCODE_CMP_EQ_OBJ);
break;
case FZL_NODETYPE_NEQUAL:
gen_op(gen, FZL_OPCODE_CMP_NEQ_OBJ);
break;
default:
return gen_error;
}
}
else
{
switch (node->type)
{
case FZL_NODETYPE_EQUAL:
gen_op(gen, FZL_OPCODE_CMP_EQ);
break;
case FZL_NODETYPE_NEQUAL:
gen_op(gen, FZL_OPCODE_CMP_NEQ);
break;
case FZL_NODETYPE_LESS:
gen_op(gen, FZL_OPCODE_CMP_LT);
break;
case FZL_NODETYPE_LESS_EQUAL:
gen_op(gen, FZL_OPCODE_CMP_LTEQ);
break;
case FZL_NODETYPE_GREATER:
gen_op(gen, FZL_OPCODE_CMP_GT);
break;
case FZL_NODETYPE_GREATER_EQUAL:
gen_op(gen, FZL_OPCODE_CMP_GTEQ);
break;
default:
break;
}
}
return (gen_res_t){.error = false, .type = FZL_TYPE_BOOL, .classname = NULL};
}
+37
View File
@@ -0,0 +1,37 @@
#include <compiler/internals/gen.h>
// Conditional operation
gen_res_t gen_condition(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
gen_res_t cres = gen_common(gen, node->cond.condition);
if (cres.error)
return gen_error;
gen_op(gen, FZL_OPCODE_JZ);
size_t jz_if = gen->ops_count;
gen_word(gen, (uint64_t)0);
gen_res_t tblock_res = gen_common(gen, node->cond.true_block);
if (tblock_res.error)
return gen_error;
gen_op(gen, FZL_OPCODE_JMP);
size_t jmp_else = gen->ops_count;
gen_word(gen, (uint64_t)0);
gen->ops[jz_if] = gen->ops_count;
if (node->cond.else_block)
{
gen_res_t fblock_res = gen_common(gen, node->cond.else_block);
if (fblock_res.error)
return gen_error;
}
gen->ops[jmp_else] = gen->ops_count;
return gen_ok_null;
}
+60
View File
@@ -0,0 +1,60 @@
#include <common/fzl_types.h>
#include <compiler/internals/gen.h>
#include <stdbool.h>
#include <string.h>
// Variable (or argument) declaration
gen_res_t gen_declaration(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
char *name = (char *)node->var.identifier->token->value;
fzl_type_t type;
char typecn[256];
memset(typecn, 0, sizeof(typecn));
bool resolved = gen_resolve_type(gen, node->var.type, &type, typecn);
if (!resolved)
return gen_error;
fzl_ctable_t *ct = NULL;
if (type == FZL_TYPE_OBJECT)
{
for (size_t i = 0; i < gen->classes_count; i++)
{
if (strcmp(node->var.type->value, gen->classes[i]->name) == 0)
{
ct = gen->classes[i];
break;
}
}
}
fzl_symtable_res_t res =
fzl_symt_put(gen->syms[gen->syms_top - 1], node, name, type, 0);
if (ct)
fzl_symt_setobjclass(gen->syms[gen->syms_top - 1], name, ct->name);
if (res != FZL_SYMTABLE_RESULT_OK)
return gen_error;
if (fzl_symt_setslot(gen->syms[gen->syms_top - 1], name) < 0)
return gen_error;
fzl_token_t *id_tok = node->var.identifier->token;
size_t const_n =
gen_add_const(gen, (fzl_const_t){.type = FZL_CONSTTYPE_STRING,
.as.string.chars = id_tok->value,
.as.string.length = id_tok->value_sz});
gen_op(gen, FZL_OPCODE_LOADCONST);
gen_word(gen, const_n);
gen_op(gen, FZL_OPCODE_STORE);
gen_op(gen, FZL_OPCODE_LOADCONST);
gen_word(gen, const_n);
return (gen_res_t){.error = false, .type = type, .classname = typecn};
}
+29
View File
@@ -0,0 +1,29 @@
#include <compiler/internals/gen.h>
// Identifier lookup
gen_res_t gen_identifier(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
fzl_sym_t sym;
bool exists = false;
ssize_t i = gen->syms_top - 1;
for (; i >= 0; i--)
if ((exists = fzl_symt_get(gen->syms[i], node->token->value, &sym)))
break;
if (!exists)
return gen_error;
if (!sym.slot_set)
return gen_error;
size_t depth = gen->syms_top - 1 - i;
gen_op(gen, FZL_OPCODE_LOAD_LOCAL);
gen_word(gen, depth);
gen_word(gen, sym.slot);
return (gen_res_t){
.error = false, .type = sym.type, .classname = sym.classname};
}
+59
View File
@@ -0,0 +1,59 @@
#include <common/fzl_types.h>
#include <compiler/internals/gen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
gen_res_t gen_literal(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
if (node->token->type == FZL_TOKTYPE_STR_LITERAL)
{
size_t n = gen_add_const(
gen, (fzl_const_t){.type = FZL_CONSTTYPE_STRING,
.as.string.chars = node->token->value,
.as.string.length = node->token->value_sz});
gen_op(gen, FZL_OPCODE_LOADCONST);
gen_word(gen, n);
return (gen_res_t){
.error = false, .type = FZL_TYPE_STRING, .classname = NULL};
}
if (node->token->type == FZL_TOKTYPE_NUM_LITERAL)
{
gen_op(gen, FZL_OPCODE_PUSHNUM);
uint64_t num = strtol(node->token->value, NULL, 10);
gen_word(gen, num);
return (gen_res_t){.error = false, .type = FZL_TYPE_INT, .classname = NULL};
}
if (node->token->type == FZL_TOKTYPE_BOOL_LITERAL)
{
fzl_token_t *tok = node->token;
uint64_t val = strcmp(tok->value, "true") == 0 ? 1 : 0;
gen_op(gen, FZL_OPCODE_PUSHBOOL);
gen_word(gen, val);
return (gen_res_t){
.error = false, .type = FZL_TYPE_BOOL, .classname = NULL};
}
if (node->token->type == FZL_TOKTYPE_NULL_LITERAL)
{
gen_op(gen, FZL_OPCODE_PUSHNUM);
gen_word(gen, 0);
gen_op(gen, FZL_OPCODE_DEREFERENCE);
return (gen_res_t){
.error = false, .type = FZL_TYPE_OBJECT, .classname = null_name};
}
return gen_error;
}
+29
View File
@@ -0,0 +1,29 @@
#include <common/fzl_types.h>
#include <compiler/internals/gen.h>
#include <stdio.h>
// Binary logical operations (and / or)
gen_res_t gen_logical(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
gen_res_t left = gen_common(gen, node->binary_op.left);
if (left.error)
return left;
gen_res_t right = gen_common(gen, node->binary_op.right);
if (right.error)
return right;
if (!gen_is_types_compatible(left.type, right.type, left.classname,
right.classname))
return gen_error;
if (node->type == FZL_NODETYPE_AND)
gen_op(gen, FZL_OPCODE_AND);
else
gen_op(gen, FZL_OPCODE_OR);
return (gen_res_t){.error = false, .type = FZL_TYPE_BOOL, .classname = NULL};
}
+47
View File
@@ -0,0 +1,47 @@
#include <common/fzl_types.h>
#include <compiler/internals/gen.h>
#include <stdio.h>
// Binary math operations
gen_res_t gen_math(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
gen_res_t lres = gen_common(gen, node->binary_op.left);
if (lres.error)
return lres;
gen_res_t rres = gen_common(gen, node->binary_op.right);
if (rres.error)
return rres;
if (lres.type < FZL_TYPE_INT8 || rres.type < FZL_TYPE_INT8)
return gen_error;
switch (node->type)
{
case FZL_NODETYPE_ADD:
gen_op(gen, FZL_OPCODE_ADD);
break;
case FZL_NODETYPE_SUB:
gen_op(gen, FZL_OPCODE_SUB);
break;
case FZL_NODETYPE_MUL:
gen_op(gen, FZL_OPCODE_MUL);
break;
case FZL_NODETYPE_DIV:
gen_op(gen, FZL_OPCODE_DIV);
break;
case FZL_NODETYPE_POW:
gen_op(gen, FZL_OPCODE_POW);
break;
case FZL_NODETYPE_MOD:
gen_op(gen, FZL_OPCODE_MOD);
break;
default:
return gen_error;
}
return (gen_res_t){.error = false, .type = lres.type, .classname = NULL};
}
+20
View File
@@ -0,0 +1,20 @@
#include <common/fzl_opcodes.h>
#include <compiler/fzl_parser.h>
#include <compiler/internals/gen.h>
#include <stdio.h>
// Unary math operations
gen_res_t gen_unary_math(fzl_gen_t *gen, fzl_node_t *node)
{
if (!gen || !node)
return gen_error;
gen_res_t res = gen_common(gen, node->unary_op.operand);
if (res.error)
return gen_error;
if (node->type == FZL_NODETYPE_UNARY_MINUS)
gen_op(gen, FZL_OPCODE_NEG);
return (gen_res_t){.error = false, .type = res.type, .classname = NULL};
}