#include #include #include #include #include #include #include #include #include #include #include #include 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)); return walker; } // --- Walking zone --- // 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; } bool walk(fzl_walker_t *walker, fzl_node_t *node) { if (!walker || !node) return false; while (node != NULL) { switch (node->type) { case FZL_NODETYPE_BLOCK: // NOTE: create block env here if (node->list.entry_count > 0) for (size_t i = 0; i < node->list.entry_count; i++) if (!walk(walker, node->list.entries[i])) return false; // NOTE: destroy block env here break; case FZL_NODETYPE_CALL: if (node->list.entry_count > 0) { for (size_t i = 0; i < node->call.args_count; i++) { if (!walk(walker, node->call.args[i])) return false; push_op(walker, FZL_OPCODE_PUSHARG); } } // NOTE: you need to implement dynamic names call push_op(walker, FZL_OPCODE_CALL_BUILTIN); if (strcmp(node->token->value, "printline") == 0) push_word(walker, FZL_BUILTIN_PRINTLINE); else { snprintf(wlast_err, sizeof(wlast_err), "call to unknown function '%s'", (char *)node->token->value); return false; } 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); } 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); } 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: if (!walk(walker, node->binary_op.left)) return false; push_op(walker, FZL_OPCODE_PUSHARG); if (!walk(walker, node->binary_op.right)) return false; push_op(walker, FZL_OPCODE_PUSHARG); 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: return false; } break; case FZL_NODETYPE_UNARY_MINUS: if (!walk(walker, node->unary_op.operand)) return false; push_op(walker, FZL_OPCODE_PUSHARG); push_op(walker, FZL_OPCODE_NEG); break; } node = node->next; } return true; } // Walk entire AST recursevily int fzl_walk(fzl_walker_t *walker) { if (!walker) { snprintf(wlast_err, sizeof(wlast_err), "walker is null"); return -1; } bool result = walk(walker, walker->root); return !result && wlast_err[0] ? -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); free(walker); }