diff --git a/src/compiler/generator/gen_break.c b/src/compiler/generator/gen_break.c new file mode 100644 index 0000000..e48edcd --- /dev/null +++ b/src/compiler/generator/gen_break.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +// Break keyword +bool gen_break(fzl_gen_t *gen, fzl_node_t *node) +{ + if (!gen || !node) + return false; + + fzl_gen_ctx_t *ctx = gen->ctx; + while (ctx != NULL) + { + if (ctx && ctx->type == FZL_GEN_CTX_TYPE_LOOP) + break; + + ctx = ctx->parent; + } + + if (!ctx || ctx->type != FZL_GEN_CTX_TYPE_LOOP) + return false; + + for (size_t i = gen->syms_top - 1; i > ctx->level + 1; i--) + gen_op(gen, FZL_OPCODE_RM_ENVTABLE); + + gen_op(gen, FZL_OPCODE_JMP); + ctx->loop.breaks[ctx->loop.breaks_count++] = gen->ops_count; + gen_word(gen, 0); + + return true; +} diff --git a/src/compiler/generator/gen_class.c b/src/compiler/generator/gen_class.c new file mode 100644 index 0000000..7a8a3f5 --- /dev/null +++ b/src/compiler/generator/gen_class.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include + +// Class definition +bool gen_class(fzl_gen_t *gen, fzl_node_t *node) +{ + if (!gen || !node) + return false; + + fzl_gen_ctx_t *ctx = gen_ctx(gen, FZL_GEN_CTX_TYPE_CLASS, node); + if (!ctx) + return false; + + 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; + + 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)); + } + + fzl_type_t type; + char typecn[256]; + memset(typecn, 0, sizeof(typecn)); + + bool resolved = + gen_resolve_type(gen, node->class.fields[i]->var.type, &type, typecn); + if (!resolved) + { + free(class->fields); + return false; + } + + class->fields[class->fields_count] = (fzl_ctable_field_t){ + .name = node->class.fields[i]->var.identifier->token->value, + .type = 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; + if (!gen_common(gen, fn)) + { + free(class->fields); + return false; + } + } + + ctx = gen_fin_ctx(gen); + if (!ctx) + { + free(class->fields); + return false; + } + + return true; +} diff --git a/src/compiler/generator/gen_fmtstr.c b/src/compiler/generator/gen_fmtstr.c new file mode 100644 index 0000000..88f134d --- /dev/null +++ b/src/compiler/generator/gen_fmtstr.c @@ -0,0 +1,18 @@ +#include +#include + +// Format string +bool gen_fmtstr(fzl_gen_t *gen, fzl_node_t *node) +{ + if (!gen || !node) + return false; + + for (size_t i = 0; i < node->list.entry_count; i++) + if (!gen_common(gen, node->list.entries[i])) + return false; + + gen_op(gen, FZL_OPCODE_BUILD_STR); + gen_word(gen, node->list.entry_count); + + return true; +} diff --git a/src/compiler/generator/gen_loop.c b/src/compiler/generator/gen_loop.c new file mode 100644 index 0000000..50a7268 --- /dev/null +++ b/src/compiler/generator/gen_loop.c @@ -0,0 +1,61 @@ +#include +#include +#include + +// While or for loops +bool gen_loop(fzl_gen_t *gen, fzl_node_t *node) +{ + if (!gen || !node) + return false; + + fzl_gen_ctx_t *ctx = gen_ctx(gen, FZL_GEN_CTX_TYPE_LOOP, node); + if (!ctx) + return false; + + gen_op(gen, FZL_OPCODE_MK_ENVTABLE); + + if (node->loop.init) + if (!gen_common(gen, node->loop.init)) + return false; + + size_t start_ip = gen->ops_count; + if (node->loop.cond) + { + if (!gen_common(gen, node->loop.cond)) + return false; + } + else + { + gen_op(gen, FZL_OPCODE_PUSHNUM); + gen_word(gen, 1); + } + + gen_op(gen, FZL_OPCODE_JZ); + ctx->loop.breaks[ctx->loop.breaks_count++] = gen->ops_count; + gen_word(gen, 0); + + if (!gen_common(gen, node->loop.body)) + return false; + + if (node->loop.step) + if (!gen_common(gen, node->loop.step)) + return false; + + gen_op(gen, FZL_OPCODE_JMP); + gen_word(gen, start_ip); + + // backpatch `break`s + for (size_t i = 0; i < ctx->loop.breaks_count; i++) + gen->ops[ctx->loop.breaks[i]] = gen->ops_count; + + gen_op(gen, FZL_OPCODE_RM_ENVTABLE); + + for (size_t i = gen->syms_top - 1; i > ctx->level; i--) + fzl_freesymt(gen->syms[--gen->syms_top]); + + ctx = gen_fin_ctx(gen); + if (!ctx) + return false; + + return true; +}