diff --git a/CMakeLists.txt b/CMakeLists.txt index 56c4072..d9ae82c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,38 @@ if (NOT FZL_SKIP_C) src/compiler/analyzer/an_typedef.c src/compiler/analyzer/an_unarycond.c src/compiler/analyzer/an_unarymath.c + src/compiler/generator/context.c + src/compiler/generator/op.c + src/compiler/generator/utility.c + src/compiler/generator/gen_alias.c + src/compiler/generator/gen_assign.c + src/compiler/generator/gen_block.c + src/compiler/generator/gen_break.c + src/compiler/generator/gen_call.c + src/compiler/generator/gen_class.c + src/compiler/generator/gen_common.c + src/compiler/generator/gen_compare.c + src/compiler/generator/gen_condition.c + src/compiler/generator/gen_construct.c + src/compiler/generator/gen_declaration.c + src/compiler/generator/gen_extern.c + src/compiler/generator/gen_externfn.c + src/compiler/generator/gen_field.c + src/compiler/generator/gen_fmtstr.c + src/compiler/generator/gen_fn.c + src/compiler/generator/gen_handle.c + src/compiler/generator/gen_identifier.c + src/compiler/generator/gen_literal.c + src/compiler/generator/gen_logical.c + src/compiler/generator/gen_loop.c + src/compiler/generator/gen_math.c + src/compiler/generator/gen_reference.c + src/compiler/generator/gen_return.c + src/compiler/generator/gen_struct.c + src/compiler/generator/gen_typedef.c + src/compiler/generator/gen_unary_logical.c + src/compiler/generator/gen_unary_math.c + src/compiler/parser/utility.c src/compiler/parser/pa_and.c src/compiler/parser/pa_assignment.c src/compiler/parser/pa_block.c @@ -91,7 +123,6 @@ if (NOT FZL_SKIP_C) src/compiler/parser/pa_typedef.c src/compiler/parser/pa_unary.c src/compiler/parser/pa_while.c - src/compiler/parser/utility.c src/compiler/reader/rd_fmtstr.c src/compiler/reader/rd_name.c src/compiler/reader/rd_number.c @@ -99,10 +130,10 @@ if (NOT FZL_SKIP_C) src/compiler/reader/utility.c src/compiler/fzl_analyzer.c src/compiler/fzl_debug.c + src/compiler/fzl_gen.c src/compiler/fzl_parser.c src/compiler/fzl_reader.c src/compiler/fzl_token.c - src/compiler/fzl_walker.c src/compiler/fzl_writer.c src/compiler/main.c) endif () diff --git a/include/compiler/fzl_walker.h b/include/compiler/fzl_walker.h deleted file mode 100644 index e8aca6d..0000000 --- a/include/compiler/fzl_walker.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef FZL_WALKER_H -#define FZL_WALKER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Type of context -typedef enum -{ - FZL_WALK_CTX_TYPE_GLOBAL, - FZL_WALK_CTX_TYPE_FN, - FZL_WALK_CTX_TYPE_CLASS, - FZL_WALK_CTX_TYPE_ASSIGN, - FZL_WALK_CTX_TYPE_LOOP, -} fzl_walk_ctx_type_t; - -// Internal walk function result -typedef struct -{ - fzl_type_t type; - - char *error_msg; - bool error; - - char *classname; -} fzl_walk_res_t; - -// Function context descriptor -typedef struct fzl_walk_ctx -{ - fzl_walk_ctx_type_t type; - struct fzl_walk_ctx *parent; - - size_t initial_env_lvl; - union - { - // function info - struct - { - fzl_node_t *fn; - }; - - // loops `break`s writeback addrs - struct - { - size_t *breaks; - size_t breaks_count; - size_t breaks_remainder; - }; - }; -} fzl_walk_ctx_t; - -// Walker descriptor -typedef struct -{ - fzl_node_t *root; - fzl_const_hash_pool_t *consts; - - uint64_t *ops; - size_t op_count; - size_t op_remainder; - - fzl_symtable_t *syms[64]; - size_t sym_top; - - fzl_walk_ctx_t *ctx; - - fzl_ctable_t *classes[64]; - size_t classes_count; - - fzl_extern_lib_t extern_libs[64]; - size_t extern_libs_count; - - fzl_extern_type_t extern_types[256]; - size_t extern_types_count; - - fzl_extern_fn_t extern_fns[256]; - size_t extern_fns_count; -} fzl_walker_t; - -// Allocate new walker -fzl_walker_t *fzl_mkwalker(fzl_node_t *root); - -// Walk throught the entire AST and build: -// 1. Constants table -// 2. Operations -int fzl_walk(fzl_walker_t *walker); - -// Get last error message -char *fzl_walker_geterror(); - -// Free walker -void fzl_freewalker(fzl_walker_t *walker); - -#endif // FZL_WALKER_H diff --git a/include/compiler/fzl_writer.h b/include/compiler/fzl_writer.h index f8184fd..58cdc28 100644 --- a/include/compiler/fzl_writer.h +++ b/include/compiler/fzl_writer.h @@ -1,7 +1,7 @@ #ifndef FZL_WRITER_H #define FZL_WRITER_H -#include +#include #include // File writer descriptor @@ -14,7 +14,7 @@ typedef struct fzl_writer_t *fzl_mkwriter(const char *filepath); // Write out a file -int fzl_write(fzl_writer_t *writer, fzl_walker_t *walker); +int fzl_write(fzl_writer_t *writer, fzl_gen_t *gen); // Get last writer error message char *fzl_writer_geterror(); diff --git a/src/compiler/fzl_gen.c b/src/compiler/fzl_gen.c index 9479f52..98c9ac9 100644 --- a/src/compiler/fzl_gen.c +++ b/src/compiler/fzl_gen.c @@ -1,9 +1,10 @@ -#include "compiler/fzl_parser.h" -#include "compiler/utils/fzl_ctable.h" -#include "compiler/utils/fzl_symtable.h" +#include #include +#include #include #include +#include +#include #include #include #include @@ -36,6 +37,7 @@ fzl_gen_t *fzl_mkgen(fzl_node_t *root) if (!gen->ctx) { fzl_consts_pool_free(gen->consts); + free(gen->ops); free(gen); return NULL; } @@ -48,10 +50,12 @@ bool fzl_gen_run(fzl_gen_t *gen) if (!gen) return false; + gen_op(gen, FZL_OPCODE_MK_ENVTABLE); + fzl_node_t *current = gen->root; while (current != NULL) { - if (!gen_common(gen, current)) + if (gen_common(gen, current).error) return false; current = current->next; @@ -71,6 +75,9 @@ void fzl_freegen(fzl_gen_t *gen) if (gen->ops) free(gen->ops); + while (gen->ctx != NULL) + gen_fin_ctx(gen); + if (gen->syms_top > 0) for (ssize_t i = gen->syms_top - 1; i >= 0; i--) fzl_freesymt(gen->syms[i]); @@ -79,5 +86,20 @@ void fzl_freegen(fzl_gen_t *gen) for (ssize_t i = gen->classes_count - 1; i >= 0; i--) fzl_freectable(gen->classes[i]); + for (size_t i = 0; i < gen->extern_types_count; i++) + { + fzl_extern_type_t *type = &gen->extern_types[i]; + if (type->kind == FZL_EXTERN_KIND_STRUCT) + if (type->structure.fields) + free(type->structure.fields); + } + + for (size_t i = 0; i < gen->extern_fns_count; i++) + { + fzl_extern_fn_t *fn = &gen->extern_fns[i]; + if (fn->args) + free(fn->args); + } + free(gen); } diff --git a/src/compiler/fzl_token.c b/src/compiler/fzl_token.c index 04ffe32..862616e 100644 --- a/src/compiler/fzl_token.c +++ b/src/compiler/fzl_token.c @@ -33,7 +33,7 @@ void fzl_freetoken(fzl_token_t *tok) if (!tok) return; - if (tok->store_value) + if (tok->store_value && tok->value) free(tok->value); free(tok); diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c deleted file mode 100644 index a998272..0000000 --- a/src/compiler/fzl_walker.c +++ /dev/null @@ -1,1504 +0,0 @@ -#include "common/fzl_extern.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char *null_name = ""; -char wlast_err[256]; - -fzl_walker_t *fzl_mkwalker(fzl_node_t *root) -{ - if (!root) - { - snprintf(wlast_err, sizeof(wlast_err), "root node is null"); - return NULL; - } - - fzl_walker_t *walker = malloc(sizeof(fzl_walker_t)); - if (!walker) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to allocated walker"); - return NULL; - } - - fzl_const_hash_pool_t *pool = fzl_mkconstpool(); - if (!pool) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to create constants pool"); - return NULL; - } - - walker->root = root; - walker->consts = pool; - - walker->op_count = 0; - walker->op_remainder = 2; - walker->ops = malloc(walker->op_remainder * sizeof(uint64_t)); - - walker->sym_top = 0; - walker->syms[walker->sym_top++] = fzl_mksymt(); - if (!walker->syms[walker->sym_top - 1]) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to create global symtable"); - return NULL; - } - - walker->ctx = NULL; - walker->classes_count = 0; - memset(walker->classes, 0, sizeof(walker->classes)); - - walker->extern_libs_count = 0; - walker->extern_types_count = 0; - walker->extern_fns_count = 0; - - memset(walker->extern_libs, 0, sizeof(walker->extern_libs)); - memset(walker->extern_types, 0, sizeof(walker->extern_types)); - memset(walker->extern_fns, 0, sizeof(walker->extern_fns)); - - return walker; -} - -// --- Walking zone --- - -// Convert type token to `fzl_type_t` -fzl_type_t tok_to_type(fzl_token_t *tok) -{ - if (tok->type == FZL_TOKTYPE_NAME) - return FZL_TYPE_OBJECT; - - if (strcmp((char *)tok->value, "i8") == 0) - return FZL_TYPE_INT8; - if (strcmp((char *)tok->value, "i16") == 0) - return FZL_TYPE_INT16; - if (strcmp((char *)tok->value, "i32") == 0) - return FZL_TYPE_INT32; - if (strcmp((char *)tok->value, "i64") == 0) - return FZL_TYPE_INT64; - - if (strcmp((char *)tok->value, "u8") == 0) - return FZL_TYPE_UINT8; - if (strcmp((char *)tok->value, "u16") == 0) - return FZL_TYPE_UINT16; - if (strcmp((char *)tok->value, "u32") == 0) - return FZL_TYPE_UINT32; - if (strcmp((char *)tok->value, "u64") == 0) - return FZL_TYPE_UINT64; - - if (strcmp((char *)tok->value, "int") == 0) - return FZL_TYPE_INT; - if (strcmp((char *)tok->value, "uint") == 0) - return FZL_TYPE_UINT; - - if (strcmp((char *)tok->value, "bool") == 0) - return FZL_TYPE_BOOL; - if (strcmp((char *)tok->value, "str") == 0) - return FZL_TYPE_STRING; - if (strcmp((char *)tok->value, "char") == 0) - return FZL_TYPE_CHAR; - - return FZL_TYPE_NULL; -} - -static bool is_compatible(fzl_type_t t1, fzl_type_t t2, char *c1, char *c2) -{ - if (t1 == FZL_TYPE_OBJECT || t2 == FZL_TYPE_OBJECT) - { - bool classes_compatible = strcmp(c1, c2) == 0 || - strcmp(c1, null_name) == 0 || - strcmp(c2, null_name) == 0; - - return t1 == FZL_TYPE_OBJECT && t2 == FZL_TYPE_OBJECT && classes_compatible; - } - - if (t1 == t2) - return true; - - return t1 >= FZL_TYPE_INT8 && t2 >= FZL_TYPE_INT8; -} - -// Add one layer of ctx -fzl_walk_ctx_t *nest_ctx(fzl_walker_t *walker, fzl_walk_ctx_type_t type) -{ - if (!walker) - return NULL; - - fzl_walk_ctx_t *newctx = malloc(sizeof(fzl_walk_ctx_t)); - if (!newctx) - return NULL; - - newctx->type = type; - newctx->parent = walker->ctx; - walker->ctx = newctx; - - return walker->ctx; -} - -// Go outside current ctx and then clean it -fzl_walk_ctx_t *fin_ctx(fzl_walker_t *walker) -{ - if (!walker) - return NULL; - - fzl_walk_ctx_t *curr = walker->ctx; - walker->ctx = walker->ctx->parent; - - free(curr); - return walker->ctx; -} - -// Add const to consts table -size_t add_const(fzl_walker_t *walker, fzl_const_t c) -{ - if (!walker) - return false; - return fzl_consts_pool_add(walker->consts, c); -} - -// Resize ops if size is equals to capacity -void ops_resize_if_needed(fzl_walker_t *walker) -{ - if (!walker) - return; - - if (walker->op_count >= walker->op_remainder) - { - walker->op_remainder *= 2; - walker->ops = realloc(walker->ops, walker->op_remainder * sizeof(uint64_t)); - } -} - -// Push opcode to operations array -void push_op(fzl_walker_t *walker, fzl_opcode_t opcode) -{ - if (!walker) - return; - - ops_resize_if_needed(walker); - walker->ops[walker->op_count++] = (uint64_t)opcode; -} - -// Push 64-bit integer to operations array -void push_word(fzl_walker_t *walker, uint64_t word) -{ - if (!walker) - return; - - ops_resize_if_needed(walker); - walker->ops[walker->op_count++] = word; -} - -fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) -{ - if (!walker || !node) - return (fzl_walk_res_t){.error = true, .error_msg = "walker is null"}; - - fzl_walk_res_t current_res; - while (node != NULL) - { - switch (node->type) - { - case FZL_NODETYPE_EXTERN: - walker->extern_libs[walker->extern_libs_count++] = - (fzl_extern_lib_t){.name = node->ext.libname}; - - for (size_t i = 0; i < node->ext.typedefs_count; i++) - { - fzl_walk_res_t res = walk(walker, node->ext.typedefs[i]); - if (res.error) - return res; - } - - for (size_t i = 0; i < node->ext.fns_count; i++) - { - fzl_walk_res_t res = walk(walker, node->ext.fns[i]); - if (res.error) - return res; - } - - current_res = (fzl_walk_res_t){ - .error = false, .type = FZL_TYPE_NULL, .classname = NULL}; - break; - - case FZL_NODETYPE_EXTERN_FN: - { - fzl_extern_fn_t *fn = &walker->extern_fns[walker->extern_fns_count++]; - fn->has_return = tok_to_type(node->ext_fn.type) != FZL_TYPE_NULL; - - for (size_t i = 0; i < node->ext_fn.args_count; i++) - { - // - } - - fn->args_count = node->ext_fn.args_count; - break; - } - - case FZL_NODETYPE_REFERENCE: // TODO: write to meta - case FZL_NODETYPE_STRUCT: // TODO: write to meta - case FZL_NODETYPE_ALIAS: // TODO: write to meta - case FZL_NODETYPE_HANDLE: // TODO: write to meta - case FZL_NODETYPE_TYPEDEF: // TODO: write to meta - break; - - case FZL_NODETYPE_FMT_STRING: - { - for (size_t i = 0; i < node->list.entry_count; i++) - { - fzl_walk_res_t res = walk(walker, node->list.entries[i]); - if (res.error) - return res; - } - - push_op(walker, FZL_OPCODE_BUILD_STR); - push_word(walker, node->list.entry_count); - break; - } - - case FZL_NODETYPE_BREAK: - { - fzl_walk_ctx_t *ctx = walker->ctx; - while (ctx) - { - if (ctx->type == FZL_WALK_CTX_TYPE_LOOP) - break; - - ctx = ctx->parent; - } - - if (!ctx || ctx->type != FZL_WALK_CTX_TYPE_LOOP) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': usage of 'break' outsude the loop at %ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - for (size_t i = walker->sym_top - 1; i > ctx->initial_env_lvl + 1; i--) - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - - if (ctx->breaks_remainder <= ctx->breaks_count) - { - ctx->breaks_remainder *= 2; - ctx->breaks = - realloc(ctx->breaks, ctx->breaks_remainder * sizeof(size_t)); - } - - push_op(walker, FZL_OPCODE_JMP); - ctx->breaks[ctx->breaks_count++] = walker->op_count; - push_word(walker, 0); - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - break; - } - - // NOTE: add new levels for infinite loop check: - // 1. Step direction (f.e. `for (; i > 5; i = i - 1)`) - case FZL_NODETYPE_LOOP: - { - fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_LOOP); - if (!newctx) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to nest context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - newctx->initial_env_lvl = walker->sym_top - 1; - newctx->breaks_count = 0; - newctx->breaks_remainder = 2; - newctx->breaks = malloc(newctx->breaks_remainder * sizeof(size_t)); - - push_op(walker, FZL_OPCODE_MK_ENVTABLE); - walker->syms[walker->sym_top++] = fzl_mksymt(); - // size_t loop_begin_ip = walker->op_count; - - if (node->loop.init) - { - fzl_walk_res_t res = walk(walker, node->loop.init); - if (res.error) - { - free(newctx->breaks); - return res; - } - } - - size_t start_ip = walker->op_count; - if (node->loop.cond) - { - fzl_walk_res_t res = walk(walker, node->loop.cond); - if (res.error) - { - free(newctx->breaks); - return res; - } - } - else - { - push_op(walker, FZL_OPCODE_PUSHNUM); - push_word(walker, 1); - } - - push_op(walker, FZL_OPCODE_JZ); - newctx->breaks[newctx->breaks_count++] = walker->op_count; - push_word(walker, 0); - - fzl_walk_res_t loop_body_res = walk(walker, node->loop.body); - if (loop_body_res.error) - { - free(newctx->breaks); - return loop_body_res; - } - - if (node->loop.step) - { - fzl_walk_res_t res = walk(walker, node->loop.step); - if (res.error) - { - free(newctx->breaks); - return res; - } - } - - push_op(walker, FZL_OPCODE_JMP); - push_word(walker, start_ip); - - // backpatch `break`s - for (size_t i = 0; i < newctx->breaks_count; i++) - walker->ops[newctx->breaks[i]] = walker->op_count; - - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - - // bool is_infinite = - // is_infinite_loop(walker, node, loop_begin_ip, walker->op_count - - // 2); - // if (is_infinite) - // { - // free(newctx->breaks); - // snprintf(wlast_err, sizeof(wlast_err), - // "'%s': infinite loop detected at %ld:%ld", - // node->token->filename, node->token->ln, node->token->cn); - // return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - // } - - for (size_t i = walker->sym_top - 1; i > newctx->initial_env_lvl; i--) - fzl_freesymt(walker->syms[--walker->sym_top]); - - free(newctx->breaks); - if (!fin_ctx(walker)) - { - snprintf(wlast_err, sizeof(wlast_err), - "failed to finish loop context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - break; - } - - case FZL_NODETYPE_CLASS: - { - fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_CLASS); - if (!newctx) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to nest context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - newctx->fn = node; - newctx->initial_env_lvl = walker->sym_top; - - walker->classes[walker->classes_count] = - fzl_mkctable(node->class.name->value); - fzl_ctable_t *class = walker->classes[walker->classes_count++]; - class->name = node->class.name->value; - - for (size_t i = 0; i < node->class.fields_count; i++) - { - if (class->fields_remainder <= class->fields_count) - { - class->fields_remainder *= 2; - class->fields = - realloc(class->fields, - class->fields_remainder * sizeof(fzl_ctable_field_t)); - } - - class->fields[class->fields_count] = (fzl_ctable_field_t){ - .name = node->class.fields[i]->var.identifier->token->value, - .type = tok_to_type(node->class.fields[i]->var.type), - .slot_index = class->fields_count++}; - } - - for (size_t i = 0; i < node->class.methods_count; i++) - { - fzl_node_t *fn = node->class.methods[i]; - - size_t classname_len = strlen(class->name); - size_t fnname_len = strlen(fn->fn.name->value); - char *method_name = malloc(classname_len + fnname_len + 2); - - strcpy(method_name, class->name); - method_name[classname_len] = '_'; - strcpy((method_name + classname_len + 1), fn->fn.name->value); - method_name[classname_len + fnname_len + 1] = 0; - - if (fn->fn.name->value) - free(fn->fn.name->value); - - fn->fn.name->value = method_name; - fzl_walk_res_t fnres = walk(walker, fn); - if (fnres.error) - return fnres; - } - - if (!fin_ctx(walker)) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to clean context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - break; - } - - case FZL_NODETYPE_CONSTRUCT: - { - fzl_node_t *classname = node->construct.name; - fzl_ctable_t *ct = NULL; - for (size_t i = 0; i < walker->classes_count; i++) - { - if (strcmp((char *)classname->token->value, - walker->classes[i]->name) == 0) - { - ct = walker->classes[i]; - break; - } - } - if (!ct) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': class '%s' not found (at %ld:%ld)", - classname->token->filename, (char *)classname->token->value, - classname->token->ln, classname->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - push_op(walker, FZL_OPCODE_ALLOC_OBJECT); - push_word(walker, ct->fields_count); - - current_res = (fzl_walk_res_t){ - .type = FZL_TYPE_OBJECT, .error = false, .classname = ct->name}; - break; - } - - case FZL_NODETYPE_FIELD: - { - fzl_walk_res_t parent_res = walk(walker, node->memb.parent); - if (parent_res.error) - return parent_res; - - if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname) - { - fzl_token_t *tok = node->memb.parent->token; - snprintf( - wlast_err, sizeof(wlast_err), - "'%s': cannot access field '%s' on non-object type at %ld:%ld", - tok->filename, (char *)node->memb.field->token->value, tok->ln, - tok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - fzl_ctable_t *ct = NULL; - for (size_t i = 0; i < walker->classes_count; i++) - { - if (strcmp(parent_res.classname, walker->classes[i]->name) == 0) - { - ct = walker->classes[i]; - break; - } - } - - if (!ct) - { - fzl_token_t *tok = node->memb.parent->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': access to unknown class '%s' at %ld:%ld", - tok->filename, (char *)tok->value, tok->ln, tok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - fzl_token_t *ftok = node->memb.field->token; - fzl_ctable_field_t ctf; - bool field_exists = false; - for (size_t i = 0; i < ct->fields_count; i++) - { - if (strcmp(ftok->value, ct->fields[i].name) == 0) - { - field_exists = true; - ctf = ct->fields[i]; - break; - } - } - - if (!field_exists) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot find field '%s' in class '%s' at %ld:%ld", - ftok->filename, (char *)ftok->value, parent_res.classname, - ftok->ln, ftok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - push_op(walker, FZL_OPCODE_GET_FIELD); - push_word(walker, ctf.slot_index); - - current_res = (fzl_walk_res_t){.type = ctf.type, - .error = false, - .classname = parent_res.classname}; - break; - } - - case FZL_NODETYPE_FUNCTION: - { - push_op(walker, FZL_OPCODE_JMP); - size_t skip_ip = walker->op_count; - push_word(walker, (uint64_t)0); - - fzl_type_t fntype = tok_to_type(node->fn.type); - fzl_symtable_res_t putres = - fzl_symt_put(walker->syms[walker->sym_top - 1], node, - node->fn.name->value, fntype, walker->op_count); - - if (putres != FZL_SYMTABLE_RESULT_OK) - { - if (putres == FZL_SYMTABLE_RESULT_EXISTS) - snprintf( - wlast_err, sizeof(wlast_err), - "'%s': cannot define already declared name '%s' at %ld:%ld", - node->token->filename, (char *)node->fn.name->value, - node->token->ln, node->token->cn); - else - snprintf(wlast_err, sizeof(wlast_err), - "'%s': failed to store name '%s'", node->fn.name->filename, - (char *)node->fn.name->value); - - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (fntype == FZL_TYPE_OBJECT) - { - fzl_symtable_res_t updres = - fzl_symt_setobjclass(walker->syms[walker->sym_top - 1], - node->fn.name->value, node->fn.type->value); - if (updres != FZL_SYMTABLE_RESULT_OK) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': failed to assign object type to function return " - "type at %ld:%ld", - node->fn.type->filename, node->fn.type->ln, - node->fn.type->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - } - - // NOTE: add sym_top limit check - ssize_t lvl = walker->sym_top; - walker->syms[walker->sym_top++] = fzl_mksymt(); - - fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_FN); - if (!newctx) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to nest context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - newctx->type = FZL_WALK_CTX_TYPE_FN; - newctx->fn = node; - newctx->initial_env_lvl = lvl; - - push_op(walker, FZL_OPCODE_MK_ENVTABLE); - - for (ssize_t i = node->fn.args_count - 1; i >= 0; i--) - { - fzl_walk_res_t res = walk(walker, node->fn.args[i]); - if (res.error) - return res; - push_op(walker, FZL_OPCODE_WRITE); - } - - fzl_walk_res_t bodyres = walk(walker, node->fn.body); - if (bodyres.error) - return bodyres; - - // NOTE: ghost walk (w/o opcodes write) for arg check should be there in - // near future - - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - push_op(walker, FZL_OPCODE_RET); - walker->ops[skip_ip] = walker->op_count; - - if (!fin_ctx(walker)) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to clean context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - for (ssize_t i = walker->sym_top - 1; i >= lvl; i--) - fzl_freesymt(walker->syms[--walker->sym_top]); - - char *retclass = NULL; - if (fntype == FZL_TYPE_OBJECT && node->fn.type) - retclass = node->fn.type->value; - - current_res = (fzl_walk_res_t){ - .type = fntype, .error = false, .classname = retclass}; - break; - } - - case FZL_NODETYPE_RETURN: - { - fzl_walk_ctx_t *ctx = walker->ctx; - while (ctx) - { - if (ctx && ctx->type == FZL_WALK_CTX_TYPE_FN) - break; - - ctx = ctx->parent; - } - - if (!ctx || ctx->type != FZL_WALK_CTX_TYPE_FN) - { - snprintf( - wlast_err, sizeof(wlast_err), - "'%s': return cannot be used outside of functions (at %ld:%ld)", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - bool returning_object = false; - if (node->ret.value) - { - fzl_walk_res_t retres = walk(walker, node->ret.value); - if (retres.error) - return retres; - - fzl_node_t *fn_node = walker->ctx->fn; - if (!is_compatible(retres.type, tok_to_type(fn_node->fn.type), - retres.classname, walker->ctx->fn->fn.type->value)) - { - snprintf( - wlast_err, sizeof(wlast_err), - "'%s': incompatible types between return and function type at " - "%ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (retres.type == FZL_TYPE_OBJECT) - returning_object = true; - - current_res = (fzl_walk_res_t){.type = retres.type, - .error = false, - .classname = retres.classname}; - } - else - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - - for (size_t i = 0; i < (walker->sym_top - walker->ctx->initial_env_lvl); - i++) - { - if (returning_object) - push_op(walker, FZL_OPCODE_ESCAPE_OBJECT); - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - } - push_op(walker, FZL_OPCODE_RET); - break; - } - - case FZL_NODETYPE_NOT: - { - fzl_walk_res_t res = walk(walker, node->unary_op.operand); - if (res.error) - return res; - - push_op(walker, FZL_OPCODE_NOT); - current_res = (fzl_walk_res_t){.type = FZL_TYPE_BOOL, .error = false}; - break; - } - - case FZL_NODETYPE_EQUAL: - case FZL_NODETYPE_NEQUAL: - case FZL_NODETYPE_LESS: - case FZL_NODETYPE_LESS_EQUAL: - case FZL_NODETYPE_GREATER: - case FZL_NODETYPE_GREATER_EQUAL: - { - fzl_walk_res_t left = walk(walker, node->binary_op.left); - if (left.error) - return left; - - fzl_walk_res_t right = walk(walker, node->binary_op.right); - if (right.error) - return right; - - if (!is_compatible(left.type, right.type, left.classname, - right.classname)) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': incompatible types at %ld:%ld", node->token->filename, - node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (left.type == FZL_TYPE_STRING && right.type == FZL_TYPE_STRING) - { - switch (node->type) - { - case FZL_NODETYPE_EQUAL: - push_op(walker, FZL_OPCODE_CMP_EQ_STR); - break; - - case FZL_NODETYPE_NEQUAL: - push_op(walker, FZL_OPCODE_CMP_NEQ_STR); - break; - - default: - snprintf(wlast_err, sizeof(wlast_err), - "'%s': unsupported strings operation at %ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - } - else if (left.type == FZL_TYPE_OBJECT && right.type == FZL_TYPE_OBJECT) - { - switch (node->type) - { - case FZL_NODETYPE_EQUAL: - push_op(walker, FZL_OPCODE_CMP_EQ_OBJ); - break; - - case FZL_NODETYPE_NEQUAL: - push_op(walker, FZL_OPCODE_CMP_NEQ_OBJ); - break; - - default: - snprintf(wlast_err, sizeof(wlast_err), - "'%s': unsupported object operation at %ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - } - else - { - switch (node->type) - { - case FZL_NODETYPE_EQUAL: - push_op(walker, FZL_OPCODE_CMP_EQ); - break; - case FZL_NODETYPE_NEQUAL: - push_op(walker, FZL_OPCODE_CMP_NEQ); - break; - case FZL_NODETYPE_LESS: - push_op(walker, FZL_OPCODE_CMP_LT); - break; - case FZL_NODETYPE_LESS_EQUAL: - push_op(walker, FZL_OPCODE_CMP_LTEQ); - break; - case FZL_NODETYPE_GREATER: - push_op(walker, FZL_OPCODE_CMP_GT); - break; - case FZL_NODETYPE_GREATER_EQUAL: - push_op(walker, FZL_OPCODE_CMP_GTEQ); - break; - default: - break; - } - } - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_BOOL, .error = false}; - break; - } - - case FZL_NODETYPE_OR: - case FZL_NODETYPE_AND: - { - fzl_walk_res_t left = walk(walker, node->binary_op.left); - if (left.error) - return left; - - fzl_walk_res_t right = walk(walker, node->binary_op.right); - if (right.error) - return right; - - if (!is_compatible(left.type, right.type, left.classname, - right.classname)) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': incompatible types at %ld:%ld", node->token->filename, - node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (node->type == FZL_NODETYPE_AND) - push_op(walker, FZL_OPCODE_AND); - else - push_op(walker, FZL_OPCODE_OR); - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_BOOL, .error = false}; - break; - } - - case FZL_NODETYPE_CONDITIONAL: - { - fzl_walk_res_t cres = walk(walker, node->cond.condition); - if (cres.error) - return cres; - - push_op(walker, FZL_OPCODE_JZ); - - size_t jz_if = walker->op_count; - push_word(walker, (uint64_t)0); - - fzl_walk_res_t tblock_res = walk(walker, node->cond.true_block); - if (tblock_res.error) - return tblock_res; - - push_op(walker, FZL_OPCODE_JMP); - size_t jmp_else = walker->op_count; - push_word(walker, (uint64_t)0); - - walker->ops[jz_if] = walker->op_count; - - if (node->cond.else_block) - { - fzl_walk_res_t fblock_res = walk(walker, node->cond.else_block); - if (fblock_res.error) - return fblock_res; - } - - walker->ops[jmp_else] = walker->op_count; - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - break; - } - - case FZL_NODETYPE_UNARY_PLUS: - { - fzl_walk_res_t res = walk(walker, node->unary_op.operand); - if (res.error) - return res; - - current_res = res; - break; - } - - case FZL_NODETYPE_IDENTIFIER: - { - fzl_sym_t sym; - bool exists = false; - ssize_t i = walker->sym_top - 1; - for (; i >= 0; i--) - if ((exists = - fzl_symt_get(walker->syms[i], node->token->value, &sym))) - break; - - if (!exists) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot find symbol '%s' at %ld:%ld", - node->token->filename, (char *)node->token->value, - node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (!sym.slot_set) - { - snprintf(wlast_err, sizeof(wlast_err), - "internal error: local '%s' has no slot", sym.name); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - size_t depth = walker->sym_top - 1 - i; - push_op(walker, FZL_OPCODE_LOAD_LOCAL); - push_word(walker, depth); - push_word(walker, sym.slot); - - current_res = (fzl_walk_res_t){ - .type = sym.type, .error = false, .classname = sym.classname}; - break; - } - - case FZL_NODETYPE_BLOCK: - walker->syms[walker->sym_top++] = fzl_mksymt(); - push_op(walker, FZL_OPCODE_MK_ENVTABLE); - if (node->list.entry_count > 0) - for (size_t i = 0; i < node->list.entry_count; i++) - { - fzl_walk_res_t res = walk(walker, node->list.entries[i]); - if (res.error) - return res; - } - fzl_freesymt(walker->syms[--walker->sym_top]); - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - break; - - case FZL_NODETYPE_CALL: - if (strcmp(node->token->value, "printline") == 0) - { - if (node->call.args_count > 0) - { - for (size_t i = 0; i < node->call.args_count; i++) - { - fzl_walk_res_t res = walk(walker, node->call.args[i]); - if (res.error) - return res; - } - } - - push_op(walker, FZL_OPCODE_CALL_BUILTIN); - push_word(walker, FZL_BUILTIN_PRINTLINE); - if (node->call.args_count < 1) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': 'printline' call with zero arguments at %ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - } - else if (strcmp(node->token->value, "exit") == 0) - { - if (node->call.args_count > 0) - { - for (size_t i = 0; i < node->call.args_count; i++) - { - fzl_walk_res_t res = walk(walker, node->call.args[i]); - if (res.error) - return res; - } - - push_op(walker, FZL_OPCODE_CALL_BUILTIN); - push_word(walker, FZL_BUILTIN_EXIT); - if (node->call.args_count < 1) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': 'exit' call with zero arguments at %ld:%ld", - node->token->filename, node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - current_res = - (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; - } - } - else - { - 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++) - { - fzl_walk_res_t res = walk(walker, node->call.args[i]); - if (res.error) - return res; - } - } - - fzl_sym_t res; - bool found = false; - for (ssize_t i = walker->sym_top - 1; i >= 0; i--) - if ((found = - fzl_symt_get(walker->syms[i], node->token->value, &res))) - break; - - if (!found) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': call to unknown function '%s' at %ld:%ld", - node->token->filename, (char *)node->token->value, - node->token->ln, node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (!res.ip) - { - snprintf(wlast_err, sizeof(wlast_err), - "cannot jump to address 0x0"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - push_op(walker, FZL_OPCODE_CALL); - push_word(walker, res.ip); - - current_res = (fzl_walk_res_t){ - .type = res.type, .error = false, .classname = res.classname}; - } - else 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; - - fzl_walk_res_t parent_res = walk(walker, parent_node); - if (parent_res.error) - return parent_res; - - if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot call method on non-object type at %ld:%ld", - parent_node->token->filename, parent_node->token->ln, - parent_node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - char *classname = parent_res.classname; - bool class_exists = false; - for (size_t i = 0; i < walker->classes_count; i++) - { - if (strcmp(classname, walker->classes[i]->name) == 0) - { - class_exists = true; - break; - } - } - - if (!class_exists) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': class '%s' not found (at %ld:%ld)", - parent_node->token->filename, classname, - parent_node->token->ln, parent_node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - 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 = walker->sym_top - 1; i >= 0; i--) - if ((found_method = - fzl_symt_get(walker->syms[i], methodname, &fn_sym))) - break; - - if (!found_method) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': class '%s' has no method '%s' at %ld:%ld", - node->token->filename, classname, - (char *)node->call.callee->token->value, node->token->ln, - node->token->cn); - free(methodname); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - free(methodname); - - if (node->call.args_count > 0) - { - for (size_t i = 0; i < node->call.args_count; i++) - { - fzl_walk_res_t res = walk(walker, node->call.args[i]); - if (res.error) - return res; - } - } - - push_op(walker, FZL_OPCODE_CALL); - push_word(walker, fn_sym.ip); - - current_res = (fzl_walk_res_t){.type = fn_sym.type, - .error = false, - .classname = fn_sym.classname}; - } - } - break; - - case FZL_NODETYPE_LITERAL: - if (node->token->type == FZL_TOKTYPE_STR_LITERAL) - { - size_t n = add_const( - walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING, - .as.string.chars = node->token->value, - .as.string.length = node->token->value_sz}); - - push_op(walker, FZL_OPCODE_LOADCONST); - push_word(walker, n); - current_res = - (fzl_walk_res_t){.type = FZL_TYPE_STRING, .error = false}; - } - else if (node->token->type == FZL_TOKTYPE_NUM_LITERAL) - { - push_op(walker, FZL_OPCODE_PUSHNUM); - - uint64_t num = strtol(node->token->value, NULL, 10); - push_word(walker, num); - current_res = (fzl_walk_res_t){.type = FZL_TYPE_INT, .error = false}; - } - else if (node->token->type == FZL_TOKTYPE_BOOL_LITERAL) - { - fzl_token_t *tok = node->token; - uint64_t val = strcmp(tok->value, "true") == 0 ? 1 : 0; - - push_op(walker, FZL_OPCODE_PUSHBOOL); - push_word(walker, val); - current_res = (fzl_walk_res_t){.type = FZL_TYPE_BOOL, .error = false}; - } - else if (node->token->type == FZL_TOKTYPE_NULL_LITERAL) - { - push_op(walker, FZL_OPCODE_PUSHNUM); - push_word(walker, 0); - push_op(walker, FZL_OPCODE_DEREFERENCE); - current_res = (fzl_walk_res_t){ - .type = FZL_TYPE_OBJECT, .error = false, .classname = null_name}; - } - break; - - case FZL_NODETYPE_ADD: - case FZL_NODETYPE_SUB: - case FZL_NODETYPE_MUL: - case FZL_NODETYPE_DIV: - case FZL_NODETYPE_POW: - case FZL_NODETYPE_MOD: - { - fzl_walk_res_t lres = walk(walker, node->binary_op.left); - if (lres.error) - return lres; - - fzl_walk_res_t rres = walk(walker, node->binary_op.right); - if (rres.error) - return rres; - - if (lres.type < FZL_TYPE_INT8) - { - fzl_token_t *ltok = node->binary_op.left->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': left operand at %ld:%ld is not compatible to integer " - "types", - ltok->filename, ltok->ln, ltok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (rres.type < FZL_TYPE_INT8) - { - fzl_token_t *rtok = node->binary_op.right->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': right operand at %ld:%ld is not compatible to " - "integer types", - rtok->filename, rtok->ln, rtok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - switch (node->type) - { - case FZL_NODETYPE_ADD: - push_op(walker, FZL_OPCODE_ADD); - break; - case FZL_NODETYPE_SUB: - push_op(walker, FZL_OPCODE_SUB); - break; - case FZL_NODETYPE_MUL: - push_op(walker, FZL_OPCODE_MUL); - break; - case FZL_NODETYPE_DIV: - push_op(walker, FZL_OPCODE_DIV); - break; - case FZL_NODETYPE_POW: - push_op(walker, FZL_OPCODE_POW); - break; - case FZL_NODETYPE_MOD: - push_op(walker, FZL_OPCODE_MOD); - break; - default: - break; - } - current_res = (fzl_walk_res_t){.type = lres.type, .error = false}; - break; - } - - case FZL_NODETYPE_UNARY_MINUS: - { - fzl_walk_res_t res = walk(walker, node->unary_op.operand); - if (res.error) - return res; - - if (res.type < FZL_TYPE_INT8) - { - fzl_token_t *tok = node->unary_op.operand->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': incompatible with unary operator type at %ld:%ld", - tok->filename, tok->ln, tok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - push_op(walker, FZL_OPCODE_NEG); - current_res = (fzl_walk_res_t){.type = res.type, .error = false}; - break; - } - - case FZL_NODETYPE_DECLARATION: - { - fzl_ctable_t *ct = NULL; - for (size_t i = 0; i < walker->classes_count; i++) - { - if (strcmp(node->var.type->value, walker->classes[i]->name) == 0) - { - ct = walker->classes[i]; - break; - } - } - - fzl_symtable_res_t res = fzl_symt_put( - walker->syms[walker->sym_top - 1], node, - node->var.identifier->token->value, - ct != NULL ? FZL_TYPE_OBJECT : tok_to_type(node->var.type), 0); - - if (ct) - fzl_symt_setobjclass(walker->syms[walker->sym_top - 1], - node->var.identifier->token->value, ct->name); - - if (res != FZL_SYMTABLE_RESULT_OK) - { - fzl_token_t *tok = node->var.identifier->token; - if (res == FZL_SYMTABLE_RESULT_EXISTS) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot redefine '%s' at %ld:%ld", tok->filename, - (char *)tok->value, tok->ln, tok->cn); - } - else - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot store '%s' at %ld:%ld", tok->filename, - (char *)tok->value, tok->ln, tok->cn); - } - - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (fzl_symt_setslot(walker->syms[walker->sym_top - 1], - node->var.identifier->token->value) < 0) - { - snprintf(wlast_err, sizeof(wlast_err), - "failed to assign a local slot to '%s'", - (char *)node->var.identifier->token->value); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - fzl_token_t *id_tok = node->var.identifier->token; - size_t const_n = add_const( - walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING, - .as.string.chars = id_tok->value, - .as.string.length = id_tok->value_sz}); - - push_op(walker, FZL_OPCODE_LOADCONST); - push_word(walker, const_n); - - push_op(walker, FZL_OPCODE_STORE); - push_op(walker, FZL_OPCODE_LOADCONST); - push_word(walker, const_n); - - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, - .error = false, - .classname = node->var.type->value}; - break; - } - - case FZL_NODETYPE_ASSIGN: - { - fzl_walk_res_t rres = walk(walker, node->binary_op.right); - if (rres.error) - return rres; - - fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_ASSIGN); - if (!newctx) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to nest context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (node->binary_op.left->type == FZL_NODETYPE_DECLARATION) - { - fzl_walk_res_t lres = walk(walker, node->binary_op.left); - if (lres.error) - return lres; - - push_op(walker, FZL_OPCODE_WRITE); - } - else if (node->binary_op.left->type == FZL_NODETYPE_IDENTIFIER) - { - fzl_sym_t sym; - bool found = false; - ssize_t i = walker->sym_top - 1; - for (; i >= 0; i--) - if ((found = - fzl_symt_get(walker->syms[i], - node->binary_op.left->token->value, &sym))) - break; - - if (!found) - { - fzl_token_t *tok = node->binary_op.left->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': name '%s' is not exists at %ld:%ld", tok->filename, - (char *)tok->value, tok->ln, tok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (!is_compatible(sym.type, rres.type, sym.classname, - rres.classname)) - { - fzl_token_t *tok = node->binary_op.right->token; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': R-Value is not compatible with L-Value at %ld:%ld", - tok->filename, tok->ln, tok->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - if (!sym.slot_set) - { - snprintf(wlast_err, sizeof(wlast_err), - "internal error: local '%s' has no slot", sym.name); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - size_t depth = walker->sym_top - 1 - i; - push_op(walker, FZL_OPCODE_STORE_LOCAL); - push_word(walker, depth); - push_word(walker, sym.slot); - } - else if (node->binary_op.left->type == FZL_NODETYPE_FIELD) - { - fzl_node_t *field_node = node->binary_op.left; - fzl_walk_res_t obj_res = walk(walker, field_node->memb.parent); - if (obj_res.error) - return obj_res; - - fzl_ctable_t *ct = NULL; - for (size_t i = 0; i < walker->classes_count; i++) - { - if (strcmp(obj_res.classname, walker->classes[i]->name) == 0) - { - ct = walker->classes[i]; - break; - } - } - - if (!ct) - { - snprintf(wlast_err, sizeof(wlast_err), - "'%s': cannot find class '%s' at %ld:%ld", - field_node->token->filename, obj_res.classname, - field_node->token->ln, field_node->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - 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) - { - fzl_node_t *fn = field_node->memb.field; - snprintf(wlast_err, sizeof(wlast_err), - "'%s': class '%s' has no field '%s' at %ld:%ld", - fn->token->filename, obj_res.classname, - (char *)fn->token->value, fn->token->ln, fn->token->cn); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - push_op(walker, FZL_OPCODE_SET_FIELD); - push_word(walker, ctf->slot_index); - } - - if (!fin_ctx(walker)) - { - snprintf(wlast_err, sizeof(wlast_err), "failed to clean context"); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; - } - - current_res = (fzl_walk_res_t){ - .type = rres.type, .error = false, .classname = rres.classname}; - break; - } - } - - node = node->next; - } - - return current_res; -} - -// Walk entire AST recursevily -int fzl_walk(fzl_walker_t *walker) -{ - if (!walker) - { - snprintf(wlast_err, sizeof(wlast_err), "walker is null"); - return -1; - } - - nest_ctx(walker, FZL_WALK_CTX_TYPE_GLOBAL); - - push_op(walker, FZL_OPCODE_MK_ENVTABLE); - fzl_walk_res_t result = walk(walker, walker->root); - push_op(walker, FZL_OPCODE_RM_ENVTABLE); - - fin_ctx(walker); - if (walker->ctx) - { - while (walker->ctx) - fin_ctx(walker); - } - - if (result.error && !wlast_err[0]) - snprintf(wlast_err, sizeof(wlast_err), "%s", result.error_msg); - - return result.error ? -1 : 0; -} - -// --- Walking zone end --- - -char *fzl_walker_geterror() { return wlast_err; } - -void fzl_freewalker(fzl_walker_t *walker) -{ - if (!walker) - return; - - fzl_consts_pool_free(walker->consts); - - if (walker->ops) - free(walker->ops); - - while (walker->sym_top > 0) - fzl_freesymt(walker->syms[--walker->sym_top]); - - for (size_t i = 0; i < walker->classes_count; i++) - fzl_freectable(walker->classes[i]); - - free(walker); -} diff --git a/src/compiler/fzl_writer.c b/src/compiler/fzl_writer.c index 22ec471..5c0a4af 100644 --- a/src/compiler/fzl_writer.c +++ b/src/compiler/fzl_writer.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -22,9 +23,9 @@ fzl_writer_t *fzl_mkwriter(const char *filepath) return writer; } -int fzl_write(fzl_writer_t *writer, fzl_walker_t *walker) +int fzl_write(fzl_writer_t *writer, fzl_gen_t *gen) { - if (!writer || !walker) + if (!writer || !gen) return -1; FILE *fp = fopen(writer->filepath, "wb"); @@ -37,12 +38,12 @@ int fzl_write(fzl_writer_t *writer, fzl_walker_t *walker) const char hdr[5] = {'F', 'Z', 'L', 0x0, 0x1}; fwrite(hdr, sizeof(char), 5, fp); - fwrite(&walker->consts->size, sizeof(size_t), 1, fp); - fwrite(&walker->op_count, sizeof(size_t), 1, fp); + fwrite(&gen->consts->size, sizeof(size_t), 1, fp); + fwrite(&gen->ops_count, sizeof(size_t), 1, fp); - for (size_t i = 0; i < walker->consts->size; i++) + for (size_t i = 0; i < gen->consts->size; i++) { - fzl_const_t c = walker->consts->array[i]; + fzl_const_t c = gen->consts->array[i]; fwrite(&c.type, sizeof(fzl_consttype_t), 1, fp); if (c.type == FZL_CONSTTYPE_STRING) @@ -53,8 +54,8 @@ int fzl_write(fzl_writer_t *writer, fzl_walker_t *walker) } } - if (walker->op_count > 0) - fwrite(walker->ops, sizeof(uint64_t), walker->op_count, fp); + if (gen->ops_count > 0) + fwrite(gen->ops, sizeof(uint64_t), gen->ops_count, fp); fclose(fp); diff --git a/src/compiler/generator/context.c b/src/compiler/generator/context.c index 3c3a32d..aad5c5f 100644 --- a/src/compiler/generator/context.c +++ b/src/compiler/generator/context.c @@ -10,7 +10,7 @@ fzl_gen_ctx_t *gen_ctx(fzl_gen_t *gen, fzl_gen_ctx_type_t type, fzl_node_t *node) { - if (!gen || !type) + if (!gen) return NULL; fzl_gen_ctx_t *ctx = malloc(sizeof(fzl_gen_ctx_t)); @@ -18,15 +18,19 @@ fzl_gen_ctx_t *gen_ctx(fzl_gen_t *gen, fzl_gen_ctx_type_t type, return NULL; memset(ctx, 0, sizeof(fzl_gen_ctx_t)); + ctx->type = type; - fzl_symtable_t *symt = fzl_mksymt(); - if (!symt) + if (ctx->type != FZL_GEN_CTX_TYPE_CLASS) { - free(ctx); - return NULL; - } + fzl_symtable_t *symt = fzl_mksymt(); + if (!symt) + { + free(ctx); + return NULL; + } - gen->syms[gen->syms_top++] = symt; + gen->syms[gen->syms_top++] = symt; + } size_t level = 0; fzl_gen_ctx_t *parent = gen->ctx; @@ -36,17 +40,17 @@ fzl_gen_ctx_t *gen_ctx(fzl_gen_t *gen, fzl_gen_ctx_type_t type, parent = parent->parent; } - ctx->type = type; ctx->level = level; ctx->parent = gen->ctx; if (type == FZL_GEN_CTX_TYPE_FUNCTION) { - if (node->type == FZL_NODETYPE_FUNCTION) + if (node->type == FZL_NODETYPE_FUNCTION || + node->type == FZL_NODETYPE_EXTERN_FN) ctx->function = node; else { - fzl_freesymt(symt); + fzl_freesymt(gen->syms[--gen->syms_top]); free(ctx); return NULL; } @@ -66,9 +70,12 @@ fzl_gen_ctx_t *gen_fin_ctx(fzl_gen_t *gen) if (!ctx) return NULL; - fzl_symtable_t *sym = gen->syms[--gen->syms_top]; - if (sym) - fzl_freesymt(sym); + if (ctx->type != FZL_GEN_CTX_TYPE_CLASS) + { + fzl_symtable_t *sym = gen->syms[--gen->syms_top]; + if (sym) + fzl_freesymt(sym); + } gen->ctx = ctx->parent; free(ctx); diff --git a/src/compiler/generator/gen_alias.c b/src/compiler/generator/gen_alias.c index 9c01294..1f3d2d4 100644 --- a/src/compiler/generator/gen_alias.c +++ b/src/compiler/generator/gen_alias.c @@ -4,6 +4,8 @@ #include #include +char alias_typecn[256]; + // Type aliasing gen_res_t gen_alias(fzl_gen_t *gen, fzl_node_t *node) { @@ -11,14 +13,13 @@ gen_res_t gen_alias(fzl_gen_t *gen, fzl_node_t *node) return gen_error; fzl_type_t type; - char typecn[256]; - memset(typecn, 0, sizeof(typecn)); + memset(alias_typecn, 0, sizeof(alias_typecn)); - bool resolved = gen_resolve_type(gen, node->token, &type, typecn); + bool resolved = gen_resolve_type(gen, node->token, &type, alias_typecn); if (!resolved) return gen_error; - ssize_t slot = gen_resolve_extern_type(gen, typecn); + ssize_t slot = gen_resolve_extern_type(gen, alias_typecn); if (slot == -1) type_buf.alias_target = (fzl_extern_type_ref_t){.is_primitive = true, .primitive = type}; diff --git a/src/compiler/generator/gen_call.c b/src/compiler/generator/gen_call.c index 155d62d..26a9ed1 100644 --- a/src/compiler/generator/gen_call.c +++ b/src/compiler/generator/gen_call.c @@ -63,7 +63,6 @@ gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) if (!found) return gen_error; - gen_res_t result; if (sym.node->type == FZL_NODETYPE_EXTERN_FN) { size_t fn_n = 0; @@ -146,6 +145,9 @@ gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) } } break; + + default: + return gen_error; } } @@ -166,8 +168,6 @@ gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) return (gen_res_t){ .error = false, .type = sym.type, .classname = sym.classname}; } - - return result; } if (node->call.callee->type == FZL_NODETYPE_FIELD) @@ -200,7 +200,7 @@ gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) 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); + strcpy((methodname + classlen + 1), method_node->token->value); methodname[classlen] = '_'; methodname[classlen + fnlen + 1] = 0; @@ -210,11 +210,10 @@ gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) if ((found_method = fzl_symt_get(gen->syms[i], methodname, &fn_sym))) break; + free(methodname); 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) diff --git a/src/compiler/generator/gen_class.c b/src/compiler/generator/gen_class.c index 96dbf25..d066152 100644 --- a/src/compiler/generator/gen_class.c +++ b/src/compiler/generator/gen_class.c @@ -1,10 +1,14 @@ #include #include #include +#include #include +#include #include #include +char class_typecn[256]; + // Class definition gen_res_t gen_class(fzl_gen_t *gen, fzl_node_t *node) { @@ -17,7 +21,7 @@ gen_res_t gen_class(fzl_gen_t *gen, fzl_node_t *node) gen->classes[gen->classes_count] = fzl_mkctable(node->class.name->value); fzl_ctable_t *class = gen->classes[gen->classes_count++]; - class->name = node->class.name->value; + class->name = (char *)node->class.name->value; for (size_t i = 0; i < node->class.fields_count; i++) { @@ -29,16 +33,12 @@ gen_res_t gen_class(fzl_gen_t *gen, fzl_node_t *node) } fzl_type_t type; - char typecn[256]; - memset(typecn, 0, sizeof(typecn)); + memset(class_typecn, 0, sizeof(class_typecn)); - bool resolved = - gen_resolve_type(gen, node->class.fields[i]->var.type, &type, typecn); + bool resolved = gen_resolve_type(gen, node->class.fields[i]->var.type, + &type, class_typecn); if (!resolved) - { - free(class->fields); return gen_error; - } class->fields[class->fields_count] = (fzl_ctable_field_t){ .name = node->class.fields[i]->var.identifier->token->value, @@ -65,17 +65,15 @@ gen_res_t gen_class(fzl_gen_t *gen, fzl_node_t *node) fn->fn.name->value = method_name; if (gen_common(gen, fn).error) { - free(class->fields); + free(method_name); + fn->fn.name->value = NULL; return gen_error; } } ctx = gen_fin_ctx(gen); if (!ctx) - { - free(class->fields); return gen_error; - } return gen_ok_null; } diff --git a/src/compiler/generator/gen_common.c b/src/compiler/generator/gen_common.c index 2b28519..2fa4ac9 100644 --- a/src/compiler/generator/gen_common.c +++ b/src/compiler/generator/gen_common.c @@ -7,6 +7,8 @@ typedef gen_res_t (*gen_handle_fn)(fzl_gen_t *, fzl_node_t *); +char *null_name = ""; + gen_res_t gen_error = (gen_res_t){.error = true}; gen_res_t gen_ok_null = (gen_res_t){.error = false, .type = FZL_TYPE_NULL, .classname = NULL}; @@ -142,7 +144,11 @@ gen_res_t gen_common(fzl_gen_t *gen, fzl_node_t *node) } if (!res) + { + printf("Bruh, you, suka, go fix the generator blyat (%s:%d)\n", __FILE__, + __LINE__); return gen_error; + } return res(gen, node); } diff --git a/src/compiler/generator/gen_declaration.c b/src/compiler/generator/gen_declaration.c index 6307ba4..b68db0d 100644 --- a/src/compiler/generator/gen_declaration.c +++ b/src/compiler/generator/gen_declaration.c @@ -3,6 +3,8 @@ #include #include +char dec_typecn[256]; + // Variable (or argument) declaration gen_res_t gen_declaration(fzl_gen_t *gen, fzl_node_t *node) { @@ -11,10 +13,9 @@ gen_res_t gen_declaration(fzl_gen_t *gen, fzl_node_t *node) char *name = (char *)node->var.identifier->token->value; fzl_type_t type; - char typecn[256]; - memset(typecn, 0, sizeof(typecn)); + memset(dec_typecn, 0, sizeof(dec_typecn)); - bool resolved = gen_resolve_type(gen, node->var.type, &type, typecn); + bool resolved = gen_resolve_type(gen, node->var.type, &type, dec_typecn); if (!resolved) return gen_error; @@ -56,5 +57,5 @@ gen_res_t gen_declaration(fzl_gen_t *gen, fzl_node_t *node) gen_op(gen, FZL_OPCODE_LOADCONST); gen_word(gen, const_n); - return (gen_res_t){.error = false, .type = type, .classname = typecn}; + return (gen_res_t){.error = false, .type = type, .classname = dec_typecn}; } diff --git a/src/compiler/generator/gen_externfn.c b/src/compiler/generator/gen_externfn.c index ae3049e..97f1e8b 100644 --- a/src/compiler/generator/gen_externfn.c +++ b/src/compiler/generator/gen_externfn.c @@ -10,6 +10,9 @@ #include #include +char ex_argcn[256]; +char ex_retcn[256]; + // External function definition gen_res_t gen_externfn(fzl_gen_t *gen, fzl_node_t *node) { @@ -29,7 +32,7 @@ gen_res_t gen_externfn(fzl_gen_t *gen, fzl_node_t *node) for (size_t i = 0; i < node->ext_fn.args_count; i++) { fzl_node_t *argnode = node->ext_fn.args[i]; - if (!gen_common(gen, argnode)) + if (gen_common(gen, argnode).error) return gen_error; if (args_count >= args_remainder) @@ -55,17 +58,17 @@ gen_res_t gen_externfn(fzl_gen_t *gen, fzl_node_t *node) fzl_extern_arg_t *arg = &args[args_count++]; fzl_type_t argtype; - char argcn[256]; - memset(argcn, 0, sizeof(argcn)); + memset(ex_argcn, 0, sizeof(ex_argcn)); - bool resolved = gen_resolve_type(gen, argnode->var.type, &argtype, argcn); + bool resolved = + gen_resolve_type(gen, argnode->var.type, &argtype, ex_argcn); if (!resolved) { free(args); return gen_error; } - ssize_t slot = gen_resolve_extern_type(gen, argcn); + ssize_t slot = gen_resolve_extern_type(gen, ex_argcn); if (slot == -1) arg->type = (fzl_extern_type_ref_t){.is_primitive = true, .primitive = argtype}; @@ -85,10 +88,9 @@ gen_res_t gen_externfn(fzl_gen_t *gen, fzl_node_t *node) } fzl_type_t ret; - char retname[256]; - memset(retname, 0, sizeof(retname)); + memset(ex_retcn, 0, sizeof(ex_retcn)); - bool resolved = gen_resolve_type(gen, node->ext_fn.type, &ret, retname); + bool resolved = gen_resolve_type(gen, node->ext_fn.type, &ret, ex_retcn); if (!resolved) { free(args); @@ -103,16 +105,19 @@ gen_res_t gen_externfn(fzl_gen_t *gen, fzl_node_t *node) return gen_error; } - res = fzl_symt_setobjclass(gen->syms[0], node->ext_fn.name, retname); - if (res != FZL_SYMTABLE_RESULT_OK) + if (ret != FZL_TYPE_NULL) { - free(args); - return gen_error; + res = fzl_symt_setobjclass(gen->syms[0], node->ext_fn.name, ex_retcn); + if (res != FZL_SYMTABLE_RESULT_OK) + { + free(args); + return gen_error; + } } fzl_extern_fn_t *result = &gen->extern_fns[gen->extern_fns_count++]; - ssize_t slot = gen_resolve_extern_type(gen, retname); + ssize_t slot = gen_resolve_extern_type(gen, ex_retcn); if (slot == -1) result->ret_type = (fzl_extern_type_ref_t){.is_primitive = true, .primitive = ret}; diff --git a/src/compiler/generator/gen_fn.c b/src/compiler/generator/gen_fn.c index 5b17f36..040da21 100644 --- a/src/compiler/generator/gen_fn.c +++ b/src/compiler/generator/gen_fn.c @@ -4,6 +4,8 @@ #include #include +char fn_typecn[256]; + // Function definition gen_res_t gen_fn(fzl_gen_t *gen, fzl_node_t *node) { @@ -15,10 +17,9 @@ gen_res_t gen_fn(fzl_gen_t *gen, fzl_node_t *node) gen_word(gen, (uint64_t)0); fzl_type_t fntype; - char fntypcn[256]; - memset(fntypcn, 0, sizeof(fntypcn)); + memset(fn_typecn, 0, sizeof(fn_typecn)); - bool resolved = gen_resolve_type(gen, node->fn.type, &fntype, fntypcn); + bool resolved = gen_resolve_type(gen, node->fn.type, &fntype, fn_typecn); if (!resolved) return gen_error; @@ -32,7 +33,7 @@ gen_res_t gen_fn(fzl_gen_t *gen, fzl_node_t *node) if (fntype == FZL_TYPE_OBJECT) { fzl_symtable_res_t updres = fzl_symt_setobjclass( - gen->syms[gen->syms_top - 1], node->fn.name->value, fntypcn); + gen->syms[gen->syms_top - 1], node->fn.name->value, fn_typecn); if (updres != FZL_SYMTABLE_RESULT_OK) return gen_error; } @@ -62,5 +63,5 @@ gen_res_t gen_fn(fzl_gen_t *gen, fzl_node_t *node) if (!ctx) return gen_error; - return (gen_res_t){.error = false, .type = fntype, .classname = fntypcn}; + return (gen_res_t){.error = false, .type = fntype, .classname = fn_typecn}; } diff --git a/src/compiler/generator/gen_loop.c b/src/compiler/generator/gen_loop.c index cc24cbf..7ea0f75 100644 --- a/src/compiler/generator/gen_loop.c +++ b/src/compiler/generator/gen_loop.c @@ -52,7 +52,7 @@ gen_res_t gen_loop(fzl_gen_t *gen, fzl_node_t *node) gen_op(gen, FZL_OPCODE_RM_ENVTABLE); - for (size_t i = gen->syms_top - 1; i > ctx->level; i--) + for (size_t i = gen->syms_top - 1; i > ctx->level + 1; i--) fzl_freesymt(gen->syms[--gen->syms_top]); ctx = gen_fin_ctx(gen); diff --git a/src/compiler/generator/gen_return.c b/src/compiler/generator/gen_return.c index 394d514..4379fe6 100644 --- a/src/compiler/generator/gen_return.c +++ b/src/compiler/generator/gen_return.c @@ -2,9 +2,12 @@ #include #include #include +#include #include #include +char ret_typecn[256]; + // Return keyword gen_res_t gen_return(fzl_gen_t *gen, fzl_node_t *node) { @@ -31,17 +34,17 @@ gen_res_t gen_return(fzl_gen_t *gen, fzl_node_t *node) if (retres.error) return gen_error; - fzl_node_t *fn_node = gen->ctx->function; + fzl_node_t *fn_node = ctx->function; fzl_type_t fntype; - char fntypecn[256]; - memset(fntypecn, 0, sizeof(fntypecn)); + memset(ret_typecn, 0, sizeof(ret_typecn)); - bool resolved = gen_resolve_type(gen, fn_node->fn.type, &fntype, fntypecn); + bool resolved = + gen_resolve_type(gen, fn_node->fn.type, &fntype, ret_typecn); if (!resolved) return gen_error; if (!gen_is_types_compatible(retres.type, fntype, retres.classname, - fntypecn)) + ret_typecn)) return gen_error; if (retres.type == FZL_TYPE_OBJECT) @@ -52,7 +55,21 @@ gen_res_t gen_return(fzl_gen_t *gen, fzl_node_t *node) else result = gen_ok_null; - for (size_t i = 0; i < (gen->syms_top - gen->ctx->level); i++) + bool is_method = false; + fzl_gen_ctx_t *cur_ctx = gen->ctx; + while (cur_ctx != NULL) + { + if (cur_ctx && cur_ctx->type == FZL_GEN_CTX_TYPE_CLASS) + { + is_method = true; + break; + } + + cur_ctx = cur_ctx->parent; + } + + size_t method_dec = is_method; + for (size_t i = 0; i < (gen->syms_top - ctx->level + method_dec); i++) { if (returning_object) gen_op(gen, FZL_OPCODE_ESCAPE_OBJECT); diff --git a/src/compiler/generator/gen_struct.c b/src/compiler/generator/gen_struct.c index 635ca3f..d3c29a4 100644 --- a/src/compiler/generator/gen_struct.c +++ b/src/compiler/generator/gen_struct.c @@ -9,6 +9,8 @@ #include #include +char struct_typecn[256]; + // Structure gen_res_t gen_struct(fzl_gen_t *gen, fzl_node_t *node) { @@ -30,7 +32,7 @@ gen_res_t gen_struct(fzl_gen_t *gen, fzl_node_t *node) for (size_t i = 0; i < node->structure.entries_count; i++) { fzl_node_t *fnode = node->structure.entries[i]; - if (!gen_common(gen, fnode)) + if (gen_common(gen, fnode).error) { free(fields); return gen_error; @@ -50,23 +52,23 @@ gen_res_t gen_struct(fzl_gen_t *gen, fzl_node_t *node) } fzl_type_t type; - char typecn[256]; - memset(typecn, 0, sizeof(typecn)); + memset(struct_typecn, 0, sizeof(struct_typecn)); fzl_extern_struct_field_t *field = &fields[count++]; - if (node->type == FZL_NODETYPE_DECLARATION) + if (fnode->type == FZL_NODETYPE_DECLARATION) { field->name = (char *)fnode->var.identifier->token->value; - bool resolved = gen_resolve_type(gen, fnode->var.type, &type, typecn); + bool resolved = + gen_resolve_type(gen, fnode->var.type, &type, struct_typecn); if (!resolved) { free(fields); return gen_error; } - ssize_t slot = gen_resolve_extern_type(gen, typecn); + ssize_t slot = gen_resolve_extern_type(gen, struct_typecn); if (slot == -1) field->type = (fzl_extern_type_ref_t){.is_primitive = true, .primitive = type}; @@ -74,11 +76,11 @@ gen_res_t gen_struct(fzl_gen_t *gen, fzl_node_t *node) field->type = (fzl_extern_type_ref_t){.is_primitive = false, .type_slot = slot}; } - else if (node->type == FZL_NODETYPE_IDENTIFIER) + else if (fnode->type == FZL_NODETYPE_IDENTIFIER) { field->name = (char *)fnode->token->value; - ssize_t slot = gen_resolve_extern_type(gen, typecn); + ssize_t slot = gen_resolve_extern_type(gen, struct_typecn); if (slot == -1) { free(fields); diff --git a/src/compiler/generator/gen_typedef.c b/src/compiler/generator/gen_typedef.c index 9cc641c..eea1c40 100644 --- a/src/compiler/generator/gen_typedef.c +++ b/src/compiler/generator/gen_typedef.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -21,26 +22,59 @@ gen_res_t gen_typedef(fzl_gen_t *gen, fzl_node_t *node) newtype->lib_slot = gen->extern_libs_count - 1; newtype->name = node->typedefinition.typename; + fzl_type_t type; switch (type_buf.kind) { case FZL_EXTERN_KIND_REF: newtype->kind = FZL_EXTERN_KIND_REF; newtype->ref_target = type_buf.ref_target; + type = FZL_TYPE_HANDLE; break; case FZL_EXTERN_KIND_HANDLE: newtype->kind = FZL_EXTERN_KIND_HANDLE; + type = FZL_TYPE_HANDLE; break; case FZL_EXTERN_KIND_ALIAS: + newtype->kind = FZL_EXTERN_KIND_ALIAS; newtype->alias_target = type_buf.alias_target; + if (type_buf.alias_target.is_primitive) + type = type_buf.alias_target.primitive; + else + { + fzl_extern_type_t *aliased = + &gen->extern_types[type_buf.alias_target.type_slot]; + if (aliased->kind == FZL_EXTERN_KIND_ALIAS) + return gen_error; + else if (aliased->kind == FZL_EXTERN_KIND_REF) + type = FZL_TYPE_HANDLE; + else if (aliased->kind == FZL_EXTERN_KIND_STRUCT) + type = FZL_TYPE_STRUCT; + else + type = FZL_TYPE_HANDLE; + } break; case FZL_EXTERN_KIND_STRUCT: + newtype->kind = FZL_EXTERN_KIND_STRUCT; newtype->structure.fields = type_buf.structure.fields; newtype->structure.fields_count = type_buf.structure.fields_count; + type = FZL_TYPE_STRUCT; break; } + fzl_symtable_res_t res = + fzl_symt_put(gen->syms[0], node, newtype->name, type, 0); + if (res != FZL_SYMTABLE_RESULT_OK) + return gen_error; + + if (type == FZL_TYPE_STRUCT || type == FZL_TYPE_HANDLE) + { + res = fzl_symt_setobjclass(gen->syms[0], newtype->name, newtype->name); + if (res != FZL_SYMTABLE_RESULT_OK) + return gen_error; + } + return gen_ok_null; } diff --git a/src/compiler/generator/utility.c b/src/compiler/generator/utility.c index 5bbdc3d..cf1a93c 100644 --- a/src/compiler/generator/utility.c +++ b/src/compiler/generator/utility.c @@ -39,19 +39,35 @@ bool gen_resolve_type(fzl_gen_t *gen, fzl_token_t *tok, fzl_type_t *t, char *c) fzl_sym_t sym; if (!gen_resolve_name(gen, name, &sym)) - return false; + { + fzl_ctable_t *class = NULL; + for (size_t i = 0; i < gen->classes_count; i++) + { + if (strcmp(name, gen->classes[i]->name) == 0) + { + class = gen->classes[i]; + break; + } + } - if (sym.node && sym.node->type == FZL_NODETYPE_CLASS) + if (!class) + return false; + + *t = FZL_TYPE_OBJECT; + if (c && class->name) + strcpy(c, class->name); + } + else if (sym.node && sym.node->type == FZL_NODETYPE_CLASS) { *t = FZL_TYPE_OBJECT; - if (c) - c = sym.classname; + if (c && sym.classname) + strcpy(c, sym.classname); } else if (sym.node && sym.node->type == FZL_NODETYPE_TYPEDEF) { *t = sym.type; - if (c) - c = sym.classname; + if (c && sym.classname) + strcpy(c, sym.classname); } else return false; diff --git a/src/compiler/main.c b/src/compiler/main.c index 49f1adc..7db9c2d 100644 --- a/src/compiler/main.c +++ b/src/compiler/main.c @@ -1,9 +1,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -122,7 +122,6 @@ int main(int argc, char **argv) { printf("%sok%s!\n", FZL_COK, FZL_CRST); fzl_debug_print_ast(parser->root); - printf("%s> building%s\n", FZL_CDEBUG, FZL_CRST); printf("%s-> analyzing AST...%s", FZL_CDEBUG, FZL_CRST); } @@ -159,10 +158,16 @@ int main(int argc, char **argv) analyzer->warnings[i]); } - fzl_walker_t *walker = fzl_mkwalker(parser->root); - if (!walker) + if (opts->verbose) { - printf("%sError%s: failed to allocate writer\n", FZL_CERROR, FZL_CRST); + printf("%sok%s!\n", FZL_COK, FZL_CRST); + printf("%s> generate\n-> generating bytecode...%s", FZL_CDEBUG, FZL_CRST); + } + + fzl_gen_t *gen = fzl_mkgen(parser->root); + if (!gen) + { + printf("%sError%s: failed to allocate generator\n", FZL_CERROR, FZL_CRST); fzl_freeoptions(opts); fzl_freeast(parser->root); fzl_freeanalyzer(analyzer); @@ -172,12 +177,12 @@ int main(int argc, char **argv) return -1; } - result = fzl_walk(walker); - if (result != 0) + bool gen_res = fzl_gen_run(gen); + if (!gen_res) { - printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_walker_geterror()); + printf("%sError%s: couldn't generate operations\n", FZL_CERROR, FZL_CRST); fzl_freeoptions(opts); - fzl_freewalker(walker); + fzl_freegen(gen); fzl_freeast(parser->root); fzl_freeanalyzer(analyzer); fzl_freeparser(parser); @@ -191,16 +196,16 @@ int main(int argc, char **argv) printf("%sok%s!\n", FZL_COK, FZL_CRST); printf("%s--> Constants table%s:\n", FZL_CDEBUG, FZL_CRST); - for (size_t i = 0; i < walker->consts->size; i++) - printf("---> %s\n", walker->consts->array[i].as.string.chars); + for (size_t i = 0; i < gen->consts->size; i++) + printf("---> %s\n", gen->consts->array[i].as.string.chars); printf("%s--> Ops%s:\n", FZL_CDEBUG, FZL_CRST); printf("---> "); - for (size_t i = 0; i < walker->op_count; i++) + for (size_t i = 0; i < gen->ops_count; i++) { - if (i > 0 && i < walker->op_count) + if (i > 0 && i < gen->ops_count) printf("->"); - printf("%lX", walker->ops[i]); + printf("%lX", gen->ops[i]); } printf("\n"); @@ -224,7 +229,7 @@ int main(int argc, char **argv) { printf("%sError%s: failed to allocate writer\n", FZL_CERROR, FZL_CRST); fzl_freeoptions(opts); - fzl_freewalker(walker); + fzl_freegen(gen); fzl_freeast(parser->root); fzl_freeanalyzer(analyzer); fzl_freeparser(parser); @@ -233,13 +238,13 @@ int main(int argc, char **argv) return -1; } - result = fzl_write(writer, walker); + result = fzl_write(writer, gen); if (result != 0) { printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_writer_geterror()); fzl_freeoptions(opts); fzl_freewriter(writer); - fzl_freewalker(walker); + fzl_freegen(gen); fzl_freeast(parser->root); fzl_freeanalyzer(analyzer); fzl_freeparser(parser); @@ -257,7 +262,7 @@ int main(int argc, char **argv) fzl_freeast(parser->root); fzl_freeanalyzer(analyzer); fzl_freeparser(parser); - fzl_freewalker(walker); + fzl_freegen(gen); fzl_freewriter(writer); printf("%sCompiled successfully%s.\n", FZL_COK, FZL_CRST); diff --git a/src/compiler/parser/pa_primary.c b/src/compiler/parser/pa_primary.c index d6c068c..408fee7 100644 --- a/src/compiler/parser/pa_primary.c +++ b/src/compiler/parser/pa_primary.c @@ -67,7 +67,7 @@ fzl_node_t *pa_primary(fzl_parser_t *parser) } fzl_token_t *end = consume(parser); - if (end->type != FZL_TOKTYPE_STR_FORMAT_END) + if (!end || end->type != FZL_TOKTYPE_STR_FORMAT_END) { snprintf(plast_err, sizeof(plast_err), "'%s':%zu:%zu => unterminated format string", @@ -78,6 +78,7 @@ fzl_node_t *pa_primary(fzl_parser_t *parser) fzl_freeast(entries[i]); free(entries); + return NULL; } if (count < 1) diff --git a/src/compiler/utils/fzl_symtable.c b/src/compiler/utils/fzl_symtable.c index 640298a..bc8cab4 100644 --- a/src/compiler/utils/fzl_symtable.c +++ b/src/compiler/utils/fzl_symtable.c @@ -59,7 +59,9 @@ fzl_symtable_res_t fzl_symt_setobjclass(fzl_symtable_t *symt, char *name, { if (strcmp(symt->symbols[i].name, name) == 0) { - if (symt->symbols[i].type != FZL_TYPE_OBJECT) + if (symt->symbols[i].type != FZL_TYPE_OBJECT && + symt->symbols[i].type != FZL_TYPE_STRUCT && + symt->symbols[i].type != FZL_TYPE_HANDLE) return FZL_SYMTABLE_RESULT_NOT_OBJECT; symt->symbols[i].classname = classname;