diff --git a/exl/fn.fzs b/exl/fn.fzs new file mode 100644 index 0000000..b08dec2 --- /dev/null +++ b/exl/fn.fzs @@ -0,0 +1,24 @@ +int fib(int n) +{ + if (n <= 1) + return n + + return fib(n - 1) + fib(n - 2) +} + +uint sum(uint a, uint b) +{ + return a + b +} + +printline("Test #1: fibonacci") +int result = fib(7) +if (result == 13) + printline("Recurse test passed") +else printline("Recurse test failed") + +printline("Test #2: sum") +if (sum(2, 2) == 4) + printline("Sum test passed") +else printline("Sum test failed") + diff --git a/include/common/fzl_opcodes.h b/include/common/fzl_opcodes.h index 2ac85ae..6938b80 100644 --- a/include/common/fzl_opcodes.h +++ b/include/common/fzl_opcodes.h @@ -18,6 +18,9 @@ typedef enum FZL_OPCODE_JMP = 0xF20001, // Jump to specified IP address FZL_OPCODE_JZ = 0xF20002, // Jump if top value in dstack is zero + FZL_OPCODE_CALL = 0xF30001, // Call function + FZL_OPCODE_RET = 0xF30002, // Return from function + FZL_OPCODE_ADD = 0xA00001, // Sum two numbers in dstack FZL_OPCODE_SUB = 0xA00002, // Subract two numbers in dstack FZL_OPCODE_MUL = 0xA00003, // Multiply two numbers in dstack diff --git a/include/compiler/fzl_parser.h b/include/compiler/fzl_parser.h index 21b361f..363d8c0 100644 --- a/include/compiler/fzl_parser.h +++ b/include/compiler/fzl_parser.h @@ -1,6 +1,7 @@ #ifndef FZL_PARSER_H #define FZL_PARSER_H +#include "common/fzl_types.h" #include #include #include @@ -13,6 +14,8 @@ typedef enum FZL_NODETYPE_LITERAL, FZL_NODETYPE_IDENTIFIER, FZL_NODETYPE_CONDITIONAL, + FZL_NODETYPE_FUNCTION, + FZL_NODETYPE_RETURN, FZL_NODETYPE_ADD, FZL_NODETYPE_SUB, @@ -93,6 +96,23 @@ typedef struct fzl_node struct fzl_node *true_block; struct fzl_node *else_block; } cond; + + // Function declaration + struct + { + struct fzl_node **args; + size_t args_count; + + struct fzl_node *body; + fzl_token_t *name; + fzl_token_t *type; + } fn; + + // Return value + struct + { + struct fzl_node *value; + } ret; }; } fzl_node_t; diff --git a/include/compiler/fzl_token.h b/include/compiler/fzl_token.h index 911a76d..bcc8de1 100644 --- a/include/compiler/fzl_token.h +++ b/include/compiler/fzl_token.h @@ -8,6 +8,8 @@ // Token type typedef enum { + FZL_TOKTYPE_RETURN, // return + FZL_TOKTYPE_IF, // if FZL_TOKTYPE_ELSE, // else diff --git a/include/compiler/fzl_walker.h b/include/compiler/fzl_walker.h index e51a34c..7b5ee8a 100644 --- a/include/compiler/fzl_walker.h +++ b/include/compiler/fzl_walker.h @@ -18,6 +18,13 @@ typedef struct bool error; } fzl_walk_res_t; +// Function context descriptor +typedef struct +{ + fzl_node_t *fn; + size_t initial_env_lvl; +} fzl_walk_ctx_t; + // Walker descriptor typedef struct { @@ -30,6 +37,8 @@ typedef struct fzl_symtable_t *syms[64]; size_t sym_top; + + fzl_walk_ctx_t *ctx; } fzl_walker_t; // Allocate new walker diff --git a/include/compiler/utils/fzl_symtable.h b/include/compiler/utils/fzl_symtable.h index e81f0dc..1a591a9 100644 --- a/include/compiler/utils/fzl_symtable.h +++ b/include/compiler/utils/fzl_symtable.h @@ -4,6 +4,7 @@ #include #include #include +#include typedef enum { @@ -17,6 +18,7 @@ typedef struct { char *name; fzl_type_t type; + size_t ip; } fzl_sym_t; // Symbols table descriptor @@ -33,7 +35,7 @@ fzl_symtable_t *fzl_mksymt(); // Put new entry into symtable fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name, - fzl_type_t type); + fzl_type_t type, uint64_t ip); // Get entry from specified symtable bool fzl_symt_get(fzl_symtable_t *symt, char *name, fzl_sym_t *res); diff --git a/include/vm/fzl_vm_env.h b/include/vm/fzl_vm_env.h index a50831a..3bd1ecc 100644 --- a/include/vm/fzl_vm_env.h +++ b/include/vm/fzl_vm_env.h @@ -33,7 +33,7 @@ typedef struct fzl_vm_env_t *fzl_mkenv(); // Try get value by name -fzl_value_t fzl_env_lookup(fzl_vm_env_t *env, char *name); +bool fzl_env_lookup(fzl_vm_env_t *env, char *name, fzl_value_t *res); // Check name in env table bool fzl_env_contains(fzl_vm_env_t *env, char *name); diff --git a/src/compiler/fzl_debug.c b/src/compiler/fzl_debug.c index 14e5f95..c11f9c2 100644 --- a/src/compiler/fzl_debug.c +++ b/src/compiler/fzl_debug.c @@ -96,6 +96,22 @@ void print_node(fzl_node_t *node, int level) print_node(node->unary_op.operand, level + 1); break; + case FZL_NODETYPE_FUNCTION: + printf("%s Function named '%s' with ret type '%s':\n", levelbuf, + (char *)node->fn.name->value, (char *)node->fn.type->value); + printf("-%s Args:\n", levelbuf); + for (size_t i = 0; i < node->fn.args_count; i++) + print_node(node->fn.args[i], level + 2); + printf("-%s Body:\n", levelbuf); + print_node(node->fn.body, level + 2); + break; + + case FZL_NODETYPE_RETURN: + printf("%s Return:\n", levelbuf); + if (node->ret.value) + print_node(node->ret.value, level + 1); + break; + case FZL_NODETYPE_EQUAL: case FZL_NODETYPE_NEQUAL: case FZL_NODETYPE_LESS: diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 373d106..a581727 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -514,6 +514,79 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (type->type == FZL_TOKTYPE_TYPE) consume(parser); + if (type->type == FZL_TOKTYPE_TYPE && + next(parser)->type == FZL_TOKTYPE_LPAREN) + { + fzl_token_t *tok = consume(parser); + if (tok->type != FZL_TOKTYPE_NAME) + { + snprintf(plast_err, sizeof(plast_err), + "expected name in function definition at %ld:%ld", tok->ln, + tok->cn); + return NULL; + } + + fzl_token_t *lparen = consume(parser); + if (lparen->type != FZL_TOKTYPE_LPAREN) + { + snprintf(plast_err, sizeof(plast_err), + "expected '(' after name at %ld:%ld", lparen->ln, lparen->cn); + return NULL; + } + + size_t remainder = 1; + size_t count = 0; + fzl_node_t **args = malloc(remainder * sizeof(fzl_node_t *)); + + while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN)) + { + fzl_node_t *arg = parse_statement(parser); + if (!arg) + return NULL; + + if (remainder <= count) + { + remainder *= 2; + args = realloc(args, remainder * sizeof(fzl_node_t *)); + } + + args[count++] = arg; + + if (is(parser, FZL_TOKTYPE_COMMA)) + consume(parser); + } + + fzl_token_t *rparen = consume(parser); + if (rparen->type != FZL_TOKTYPE_RPAREN) + { + snprintf(plast_err, sizeof(plast_err), + "expected ')' after argument list at %ld:%ld", rparen->ln, + rparen->cn); + return NULL; + } + + if (!is(parser, FZL_TOKTYPE_LBRACE)) + { + fzl_token_t *tok = peek(parser); + snprintf(plast_err, sizeof(plast_err), "expected '{' at %ld:%ld", + tok->ln, tok->cn); + return NULL; + } + + fzl_node_t *body = parse_statement(parser); + if (!body) + return NULL; + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FUNCTION, tok); + node->fn.args = args; + node->fn.args_count = count; + node->fn.body = body; + node->fn.name = tok; + node->fn.type = type; + + return node; + } + if (type->type == FZL_TOKTYPE_TYPE || next(parser)->type == FZL_TOKTYPE_EQ) { @@ -574,6 +647,25 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) return left; } + if (is(parser, FZL_TOKTYPE_RETURN)) + { + fzl_token_t *ret = consume(parser); + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_RETURN, ret); + + if (is(parser, FZL_TOKTYPE_DOT)) + { + consume(parser); + return node; + } + + fzl_node_t *retval = parse_expression(parser); + if (!retval) + return NULL; + + node->ret.value = retval; + return node; + } + if (is(parser, FZL_TOKTYPE_IF)) { fzl_token_t *if_tok = consume(parser); @@ -637,7 +729,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (remainder <= count) { remainder *= 2; - stmts = realloc(stmts, remainder); + stmts = realloc(stmts, remainder * sizeof(fzl_node_t *)); } stmts[count++] = node; @@ -758,6 +850,14 @@ void fzl_freeast(fzl_node_t *root) if (root->unary_op.operand) fzl_freeast(root->unary_op.operand); } + else if (root->type == FZL_NODETYPE_FUNCTION) + { + if (root->fn.args_count) + for (size_t i = 0; i < root->fn.args_count; i++) + fzl_freenode(root->fn.args[i]); + free(root->fn.args); + fzl_freenode(root->fn.body); + } fzl_freenode(root); root = root->next; diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index 91305d1..18d5426 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -74,7 +74,9 @@ fzl_token_t *parse_name(fzl_reader_t *reader) size_t line = reader->line_n; size_t pos = start - reader->line_start; - if (strcmp(value, "if") == 0) + if (strcmp(value, "return") == 0) + tok = fzl_mktoken(FZL_TOKTYPE_RETURN, line, pos, value, size); + else if (strcmp(value, "if") == 0) tok = fzl_mktoken(FZL_TOKTYPE_IF, line, pos, value, size); else if (strcmp(value, "else") == 0) tok = fzl_mktoken(FZL_TOKTYPE_ELSE, line, pos, value, size); diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index f83b1ef..8daeadb 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -52,6 +52,8 @@ fzl_walker_t *fzl_mkwalker(fzl_node_t *root) return NULL; } + walker->ctx = NULL; + return walker; } @@ -152,6 +154,101 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { switch (node->type) { + 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->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), + "cannot define already declared name '%s' at %ld:%ld", + (char *)node->fn.name->value, node->token->ln, + node->token->cn); + else + snprintf(wlast_err, sizeof(wlast_err), "failed to store name '%s'", + (char *)node->fn.name->value); + + return (fzl_walk_res_t){.error = true}; + } + + // NOTE: add sym_top limit check + size_t lvl = walker->sym_top; + walker->syms[walker->sym_top++] = fzl_mksymt(); + walker->ctx = malloc(sizeof(fzl_walk_ctx_t)); + walker->ctx->fn = node; + walker->ctx->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); + walker->ops[skip_ip] = walker->op_count; + + walker->ctx = NULL; // NOTE: think about nested function defs (not now) + for (ssize_t i = walker->sym_top - 1; i >= lvl; i--) + fzl_freesymt(walker->syms[--walker->sym_top]); + + break; + } + + case FZL_NODETYPE_RETURN: + { + if (!walker->ctx) + { + snprintf(wlast_err, sizeof(wlast_err), + "return cannot be used outside of functions"); + return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + } + + if (node->ret.value) + { + fzl_walk_res_t retres = walk(walker, node->ret.value); + if (retres.error) + return retres; + + if (!is_compatible(retres.type, + tok_to_type(walker->ctx->fn->fn.type))) + { + snprintf(wlast_err, sizeof(wlast_err), + "incompatible types between return and function type at " + "%ld:%ld", + node->token->ln, node->token->cn); + return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + } + + current_res = (fzl_walk_res_t){.type = retres.type, .error = false}; + } + 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++) + 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); @@ -294,8 +391,12 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) .as.string.length = node->token->value_sz}); fzl_sym_t sym; - bool exists = fzl_symt_get(walker->syms[walker->sym_top - 1], - node->token->value, &sym); + bool exists = false; + for (ssize_t i = walker->sym_top - 1; i >= 0; i--) + if ((exists = + fzl_symt_get(walker->syms[i], node->token->value, &sym))) + break; + if (!exists) { snprintf(wlast_err, sizeof(wlast_err), @@ -314,6 +415,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) } 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++) @@ -322,6 +424,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (res.error) return res; } + fzl_freesymt(walker->syms[--walker->sym_top]); push_op(walker, FZL_OPCODE_RM_ENVTABLE); break; @@ -335,11 +438,10 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) return res; } } - // NOTE: you need to implement dynamic names call too - push_op(walker, FZL_OPCODE_CALL_BUILTIN); if (strcmp(node->token->value, "printline") == 0) { + push_op(walker, FZL_OPCODE_CALL_BUILTIN); push_word(walker, FZL_BUILTIN_PRINTLINE); if (node->call.args_count < 1) { @@ -348,14 +450,37 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) 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 { - snprintf(wlast_err, sizeof(wlast_err), - "call to unknown function '%s'", (char *)node->token->value); - return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + 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), + "call to unknown function '%s'", + (char *)node->token->value); + 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}; } - current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; break; case FZL_NODETYPE_LITERAL: @@ -475,7 +600,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { fzl_symtable_res_t res = fzl_symt_put( walker->syms[walker->sym_top - 1], - node->var.identifier->token->value, tok_to_type(node->var.type)); + node->var.identifier->token->value, tok_to_type(node->var.type), 0); fzl_token_t *id_tok = node->var.identifier->token; size_t const_n = add_const( @@ -509,9 +634,14 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) else if (node->binary_op.left->type == FZL_NODETYPE_IDENTIFIER) { fzl_sym_t sym; - bool res = fzl_symt_get(walker->syms[walker->sym_top - 1], - node->binary_op.left->token->value, &sym); - if (!res) // NOTE: refactor this before implement blocks, fns, etc + bool found = false; + for (ssize_t i = walker->sym_top - 1; 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->value; snprintf(wlast_err, sizeof(wlast_err), diff --git a/src/compiler/utils/fzl_symtable.c b/src/compiler/utils/fzl_symtable.c index 3d4afa8..262958e 100644 --- a/src/compiler/utils/fzl_symtable.c +++ b/src/compiler/utils/fzl_symtable.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -20,7 +21,7 @@ fzl_symtable_t *fzl_mksymt() } fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name, - fzl_type_t type) + fzl_type_t type, uint64_t ip) { if (!symt) return FZL_SYMTABLE_RESULT_ERR; @@ -35,7 +36,8 @@ fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name, symt->symbols = realloc(symt->symbols, symt->remainder * sizeof(fzl_sym_t)); } - symt->symbols[symt->size++] = (fzl_sym_t){.name = name, .type = type}; + symt->symbols[symt->size++] = + (fzl_sym_t){.name = name, .type = type, .ip = ip}; return FZL_SYMTABLE_RESULT_OK; } diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index c762ac4..662dd2f 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,27 @@ int fzl_vm_run(fzl_vm_t *vm) switch (opcode) { + case FZL_OPCODE_CALL: + { + uint64_t ip = vm->ops[++vm->ip]; + vm->cstack[vm->ctop++] = vm->ip; + vm->ip = ip - 1; + break; + } + + case FZL_OPCODE_RET: + { + if (vm->ctop < 1) + { + snprintf(last_err, sizeof(last_err), + "runtime error - no place to jump"); + return -1; + } + + vm->ip = vm->cstack[--vm->ctop]; + break; + } + case FZL_OPCODE_CMP_EQ: if (vm->dtop < 2) { @@ -131,10 +153,10 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t leq = vm->dstack[--vm->dtop]; fzl_value_t req = vm->dstack[--vm->dtop]; + fzl_value_t leq = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = - (fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = leq.as.b == req.as.b}; + (fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = leq.as.u == req.as.u}; break; case FZL_OPCODE_CMP_NEQ: @@ -145,8 +167,8 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t lneq = vm->dstack[--vm->dtop]; fzl_value_t rneq = vm->dstack[--vm->dtop]; + fzl_value_t lneq = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = lneq.as.u != rneq.as.u}; break; @@ -159,8 +181,8 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t llt = vm->dstack[--vm->dtop]; fzl_value_t rlt = vm->dstack[--vm->dtop]; + fzl_value_t llt = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = llt.as.u < rlt.as.u}; break; @@ -173,8 +195,8 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t llteq = vm->dstack[--vm->dtop]; fzl_value_t rlteq = vm->dstack[--vm->dtop]; + fzl_value_t llteq = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = (fzl_value_t){ .type = FZL_TYPE_BOOL, .as.b = llteq.as.u <= rlteq.as.u}; break; @@ -187,8 +209,8 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t lgt = vm->dstack[--vm->dtop]; fzl_value_t rgt = vm->dstack[--vm->dtop]; + fzl_value_t lgt = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = lgt.as.u > rgt.as.u}; break; @@ -201,8 +223,8 @@ int fzl_vm_run(fzl_vm_t *vm) return -1; } - fzl_value_t lgteq = vm->dstack[--vm->dtop]; fzl_value_t rgteq = vm->dstack[--vm->dtop]; + fzl_value_t lgteq = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = (fzl_value_t){ .type = FZL_TYPE_BOOL, .as.b = lgteq.as.u >= rgteq.as.u}; break; @@ -319,7 +341,9 @@ int fzl_vm_run(fzl_vm_t *vm) } } - vm->dstack[vm->dtop++] = value; + // vm->dstack[vm->dtop++] = value; + // NOTE: add POP opcode to prevent + // stack overflow! break; case FZL_OPCODE_MK_ENVTABLE: @@ -340,8 +364,14 @@ int fzl_vm_run(fzl_vm_t *vm) } fzl_value_t val = vm->dstack[--vm->dtop]; - fzl_value_t env_val = - fzl_env_lookup(vm->estack[vm->etop - 1], (char *)val.as.s.value); + fzl_value_t env_val; + bool result; + for (ssize_t i = vm->etop - 1; i >= 0; i--) + { + if ((result = fzl_env_lookup(vm->estack[i], (char *)val.as.s.value, + &env_val))) + break; + } vm->dstack[vm->dtop++] = env_val; break; @@ -411,10 +441,10 @@ int fzl_vm_run(fzl_vm_t *vm) "runtime error - expected 2 values in stack"); return -1; } - fzl_value_t sub1 = vm->dstack[--vm->dtop]; fzl_value_t sub2 = vm->dstack[--vm->dtop]; + fzl_value_t sub1 = vm->dstack[--vm->dtop]; vm->dstack[vm->dtop++] = - (fzl_value_t){.type = add1.type, .as.u = sub1.as.u - sub2.as.u}; + (fzl_value_t){.type = sub1.type, .as.u = sub1.as.u - sub2.as.u}; break; case FZL_OPCODE_MUL: @@ -450,8 +480,8 @@ int fzl_vm_run(fzl_vm_t *vm) "runtime error - expected 2 values in stack"); return -1; } - fzl_value_t pow1 = vm->dstack[--vm->dtop]; fzl_value_t pow2 = vm->dstack[--vm->dtop]; + fzl_value_t pow1 = vm->dstack[--vm->dtop]; uint64_t pow_n = pow1.as.u; uint64_t pow_res = pow_n; diff --git a/src/vm/fzl_vm_debug.c b/src/vm/fzl_vm_debug.c index c53fd19..11727a0 100644 --- a/src/vm/fzl_vm_debug.c +++ b/src/vm/fzl_vm_debug.c @@ -20,6 +20,17 @@ void fzl_vm_print_ops(fzl_vm_t *vm) switch (vm->ops[i]) { + case FZL_OPCODE_CALL: + { + size_t ip = vm->ops[++i]; + printf("Call IP: %lu\n", ip); + break; + } + + case FZL_OPCODE_RET: + printf("Return\n"); + break; + case FZL_OPCODE_LOADCONST: { size_t const_n = vm->ops[++i]; @@ -79,6 +90,7 @@ void fzl_vm_print_ops(fzl_vm_t *vm) case FZL_OPCODE_CMP_EQ: printf("CMP_EQ\n"); + break; case FZL_OPCODE_CMP_NEQ: printf("CMP_NEQ\n"); @@ -113,7 +125,7 @@ void fzl_vm_print_ops(fzl_vm_t *vm) break; case FZL_OPCODE_JMP: - printf("JMP IP %ld\n", vm->ops[++i]); + printf("JMP IP: %ld\n", vm->ops[++i]); break; default: diff --git a/src/vm/fzl_vm_env.c b/src/vm/fzl_vm_env.c index 974851f..2ca4ede 100644 --- a/src/vm/fzl_vm_env.c +++ b/src/vm/fzl_vm_env.c @@ -28,16 +28,19 @@ static void resize_env_if_needed(fzl_vm_env_t *env) env->table = realloc(env->table, env->remainder * sizeof(fzl_vm_env_entry_t)); } -fzl_value_t fzl_env_lookup(fzl_vm_env_t *env, char *name) +bool fzl_env_lookup(fzl_vm_env_t *env, char *name, fzl_value_t *res) { if (!env) - return null; + return false; for (size_t i = 0; i < env->size; i++) if (strcmp(env->table[i].name, name) == 0) - return env->table[i].value; + { + *res = env->table[i].value; + return true; + } - return (fzl_value_t){.type = FZL_TYPE_NULL}; + return false; } bool fzl_env_contains(fzl_vm_env_t *env, char *name)