diff --git a/include/common/fzl_opcodes.h b/include/common/fzl_opcodes.h index 625883b..cd1c0e2 100644 --- a/include/common/fzl_opcodes.h +++ b/include/common/fzl_opcodes.h @@ -4,17 +4,17 @@ // Available opcodes typedef enum { - FZL_OPCODE_LOADCONST, // Load const into T (temp) reg - FZL_OPCODE_CALL_BUILTIN, // Call builtin function - FZL_OPCODE_PUSHNUM, // Push number into stack + FZL_OPCODE_LOADCONST = 0xF00001, // Load const into T (temp) reg + FZL_OPCODE_CALL_BUILTIN = 0xF00002, // Call builtin function + FZL_OPCODE_PUSHNUM = 0xF00003, // Push number into stack - FZL_OPCODE_ADD, // Sum two numbers in arg strack - FZL_OPCODE_SUB, // Subract two numbers in arg stack - FZL_OPCODE_MUL, // Multiply two numbers in arg stack - FZL_OPCODE_DIV, // Divide two numbers in arg stack - FZL_OPCODE_POW, // Power first number in arg stack by second - FZL_OPCODE_MOD, // Get module of two numbers in arg stack - FZL_OPCODE_NEG, // Negotiate number in arg stack + FZL_OPCODE_ADD = 0xA00001, // Sum two numbers in arg strack + FZL_OPCODE_SUB = 0xA00002, // Subract two numbers in arg stack + FZL_OPCODE_MUL = 0xA00003, // Multiply two numbers in arg stack + FZL_OPCODE_DIV = 0xA00004, // Divide two numbers in arg stack + FZL_OPCODE_POW = 0xA00005, // Power first number in arg stack by second + FZL_OPCODE_MOD = 0xA00006, // Get module of two numbers in arg stack + FZL_OPCODE_NEG = 0xA00007, // Negotiate number in arg stack } fzl_opcode_t; #endif // FZL_OPCODES_H diff --git a/include/common/fzl_types.h b/include/common/fzl_types.h index 82fe549..cde0312 100644 --- a/include/common/fzl_types.h +++ b/include/common/fzl_types.h @@ -3,8 +3,23 @@ typedef enum { + FZL_TYPE_NULL, + FZL_TYPE_STRING, - FZL_TYPE_NUMBER + FZL_TYPE_CHAR, + + FZL_TYPE_INT8, + FZL_TYPE_UINT8, + FZL_TYPE_INT16, + FZL_TYPE_UINT16, + FZL_TYPE_INT32, + FZL_TYPE_UINT32, + FZL_TYPE_INT64, + FZL_TYPE_UINT64, + FZL_TYPE_INT, // machine word int + FZL_TYPE_UINT, // machine word unsigned int + + FZL_TYPE_BOOL } fzl_type_t; #endif // FZL_TYPES_H diff --git a/include/common/fzl_value.h b/include/common/fzl_value.h new file mode 100644 index 0000000..df8d68c --- /dev/null +++ b/include/common/fzl_value.h @@ -0,0 +1,42 @@ +#ifndef FZL_VALUE_H +#define FZL_VALUE_H + +#include +#include +#include +#include + +// Value container descriptor +typedef struct +{ + fzl_type_t type; + + union + { + struct + { + const char *value; + size_t length; + } s; + + char c; + bool b; + + int8_t i8; + uint8_t u8; + + int16_t i16; + uint16_t u16; + + int32_t i32; + uint32_t u32; + + int64_t i64; + uint64_t u64; + + intptr_t i; + uintptr_t u; + } as; +} fzl_value_t; + +#endif // FZL_VALUE_H diff --git a/include/compiler/fzl_parser.h b/include/compiler/fzl_parser.h index ce2c31e..a0064e2 100644 --- a/include/compiler/fzl_parser.h +++ b/include/compiler/fzl_parser.h @@ -21,7 +21,10 @@ typedef enum FZL_NODETYPE_MOD, FZL_NODETYPE_UNARY_PLUS, - FZL_NODETYPE_UNARY_MINUS + FZL_NODETYPE_UNARY_MINUS, + + FZL_NODETYPE_DECLARATION, + FZL_NODETYPE_ASSIGN } fzl_nodetype_t; // AST node descriptor diff --git a/include/compiler/fzl_reader.h b/include/compiler/fzl_reader.h index 73898ee..2a85dac 100644 --- a/include/compiler/fzl_reader.h +++ b/include/compiler/fzl_reader.h @@ -21,8 +21,10 @@ typedef struct char *source; size_t size; + size_t position; - bool at_end; + size_t line_start; + size_t line_n; } fzl_reader_t; // Allocate new reader diff --git a/include/compiler/fzl_token.h b/include/compiler/fzl_token.h index 1abf141..a289fe5 100644 --- a/include/compiler/fzl_token.h +++ b/include/compiler/fzl_token.h @@ -9,11 +9,13 @@ typedef enum { FZL_TOKTYPE_NAME, // abc + FZL_TOKTYPE_TYPE, // i16 FZL_TOKTYPE_LPAREN, // ( FZL_TOKTYPE_RPAREN, // ) FZL_TOKTYPE_COMMA, // , + FZL_TOKTYPE_DOT, // . FZL_TOKTYPE_STR_LITERAL, // "" FZL_TOKTYPE_NUM_LITERAL, // 123 @@ -24,21 +26,23 @@ typedef enum FZL_TOKTYPE_MINUS, // - FZL_TOKTYPE_CARET, // ^ FZL_TOKTYPE_PERCENT, // % + + FZL_TOKTYPE_EQ // = } fzl_toktype_t; // Token descriptor typedef struct { fzl_toktype_t type; - uint16_t i0; - uint16_t i1; + size_t ln; + size_t cn; bool store_value; void *value; uint16_t value_sz; } fzl_token_t; // Allocate new token -fzl_token_t *fzl_mktoken(const fzl_toktype_t type, uint16_t from, uint16_t to, +fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, void *value, size_t value_sz); // Free token and its contents diff --git a/include/compiler/fzl_walker.h b/include/compiler/fzl_walker.h index 0300873..cd733c7 100644 --- a/include/compiler/fzl_walker.h +++ b/include/compiler/fzl_walker.h @@ -2,10 +2,21 @@ #define FZL_WALKER_H #include +#include #include #include +#include #include +// Internal walk function result +typedef struct +{ + fzl_type_t type; + + char *error_msg; + bool error; +} fzl_walk_res_t; + // Walker descriptor typedef struct { diff --git a/include/vm/fzl_vm.h b/include/vm/fzl_vm.h index 6d8e54e..31fa17f 100644 --- a/include/vm/fzl_vm.h +++ b/include/vm/fzl_vm.h @@ -1,6 +1,7 @@ #ifndef FZL_VM_H #define FZL_VM_H +#include #include // NOTE: move outside compiler scope to common #include #include @@ -16,8 +17,16 @@ typedef struct size_t ip; - fzl_const_t stack[256]; - size_t stack_top; + // Data stack + fzl_value_t dstack[256]; + size_t dtop; + + // Call stack + size_t cstack[256]; + size_t ctop; + + // Environment stack + // TODO: implement `estack` and `etop` } fzl_vm_t; // Allocate FZL VM diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 5ba7e26..c311aa3 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -19,7 +19,7 @@ fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) if (!parser) return NULL; - parser->root = NULL; + parser->root = NULL; parser->cursor = first->next; if (!parser->cursor) return NULL; @@ -36,10 +36,10 @@ fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token) if (!node) return NULL; - node->type = type; - node->token = token; + node->type = type; + node->token = token; node->parent = NULL; - node->next = NULL; + node->next = NULL; return node; } @@ -71,7 +71,7 @@ static fzl_token_t *consume(fzl_parser_t *parser) if (!parser || !parser->cursor) return NULL; fzl_token_t *tok = parser->cursor->token; - parser->cursor = parser->cursor->next; + parser->cursor = parser->cursor->next; return tok; } @@ -149,8 +149,8 @@ fzl_node_t *parse_primary(fzl_parser_t *parser) fzl_node_t *node = parse_expression(parser); if (!is(parser, FZL_TOKTYPE_RPAREN)) { - snprintf(plast_err, sizeof(plast_err), "expected rparen at %d", - parser->cursor->token->i0); + snprintf(plast_err, sizeof(plast_err), "expected ')' at %ld:%ld", + parser->cursor->token->ln, parser->cursor->token->cn); return NULL; } consume(parser); @@ -162,8 +162,8 @@ fzl_node_t *parse_primary(fzl_parser_t *parser) return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); } - snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %d", - peek(parser)->i0); + snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %ld:%ld", + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -173,13 +173,13 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) if (!parser) return NULL; - fzl_node_t *left = parse_primary(parser); + fzl_node_t *left = parse_primary(parser); fzl_node_t *right = NULL; if (!left) { - snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %d", - peek(parser)->i0); + snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %ld:%ld", + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -188,8 +188,8 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) consume(parser); size_t args_capacity = 2; - size_t args_count = 0; - fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *)); + size_t args_count = 0; + fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *)); while (!is(parser, FZL_TOKTYPE_RPAREN)) { @@ -218,13 +218,14 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) { free(args); snprintf(plast_err, sizeof(plast_err), - "expected ')' after argument list at %d", peek(parser)->i0); + "expected ')' after argument list at %ld:%ld", peek(parser)->ln, + peek(parser)->cn); return NULL; } - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token); - node->call.callee = left; - node->call.args = args; + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token); + node->call.callee = left; + node->call.args = args; node->call.args_count = args_count; left = node; @@ -242,13 +243,13 @@ fzl_node_t *parse_unary(fzl_parser_t *parser) if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS)) return parse_postfix(parser); - fzl_token_t *op = consume(parser); + fzl_token_t *op = consume(parser); fzl_node_t *operand = parse_unary(parser); if (!operand) return NULL; - fzl_node_t *result = fzl_mknode(unary_op_to_type(op->type), op); + fzl_node_t *result = fzl_mknode(unary_op_to_type(op->type), op); result->unary_op.operand = operand; return result; @@ -259,13 +260,13 @@ fzl_node_t *parse_power(fzl_parser_t *parser) if (!parser) return NULL; - fzl_node_t *left = parse_unary(parser); + fzl_node_t *left = parse_unary(parser); fzl_node_t *right = NULL; if (!left) { - snprintf(plast_err, sizeof(plast_err), "failed to parse power at %d", - peek(parser)->i0); + snprintf(plast_err, sizeof(plast_err), "failed to parse power at %ld:%ld", + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -277,12 +278,13 @@ fzl_node_t *parse_power(fzl_parser_t *parser) if (!right) { snprintf(plast_err, sizeof(plast_err), - "failed to parse right side of power at %d", peek(parser)->i0); + "failed to parse right side of power at %ld:%ld", + peek(parser)->ln, peek(parser)->cn); return NULL; } - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_POW, caret); - node->binary_op.left = left; + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_POW, caret); + node->binary_op.left = left; node->binary_op.right = right; left = node; @@ -297,14 +299,14 @@ fzl_node_t *parse_factor(fzl_parser_t *parser) if (!parser) return NULL; - fzl_node_t *left = parse_power(parser); + fzl_node_t *left = parse_power(parser); fzl_node_t *right = NULL; if (!left) { if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), "invalid expression at %u", - parser->cursor->token->i0); + snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", + parser->cursor->token->ln, parser->cursor->token->cn); return NULL; } @@ -317,14 +319,15 @@ fzl_node_t *parse_factor(fzl_parser_t *parser) if (!right) { snprintf(plast_err, sizeof(plast_err), - "unfinished factor (mul/div) expression at %u", left->token->i0); + "unfinished factor (mul/div) expression at %ld:%ld", + left->token->ln, left->token->cn); return NULL; } - fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); - node->binary_op.left = left; + fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); + node->binary_op.left = left; node->binary_op.right = right; - left = node; + left = node; } return left; @@ -336,13 +339,13 @@ fzl_node_t *parse_term(fzl_parser_t *parser) if (!parser) return NULL; - fzl_node_t *left = parse_factor(parser); + fzl_node_t *left = parse_factor(parser); fzl_node_t *right = NULL; if (!left) { - snprintf(plast_err, sizeof(plast_err), "invalid expression at %u", - parser->cursor->token->i0); + snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", + parser->cursor->token->ln, parser->cursor->token->cn); return NULL; } @@ -354,14 +357,15 @@ fzl_node_t *parse_term(fzl_parser_t *parser) if (!right) { snprintf(plast_err, sizeof(plast_err), - "unfinished term (add/sub) expression at %u", left->token->i0); + "unfinished term (add/sub) expression at %ld:%ld", + left->token->ln, left->token->cn); return NULL; } - fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); - node->binary_op.left = left; + fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); + node->binary_op.left = left; node->binary_op.right = right; - left = node; + left = node; } return left; @@ -383,8 +387,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) fzl_node_t *parse_program(fzl_parser_t *parser) { fzl_node_t *first = NULL; - fzl_node_t *last = NULL; - fzl_node_t *node = NULL; + fzl_node_t *last = NULL; + fzl_node_t *node = NULL; while (peek(parser) != NULL) { node = parse_statement(parser); @@ -394,18 +398,18 @@ fzl_node_t *parse_program(fzl_parser_t *parser) if (!last) { first = node; - last = node; + last = node; } else { last->next = node; - last = node; + last = node; } } if (!first) { - snprintf(plast_err, sizeof(plast_err), "empty ;("); + snprintf(plast_err, sizeof(plast_err), "nothing to parse >:("); return NULL; } diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index 35c6c1e..c7e4889 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -12,22 +12,42 @@ static char last_err[256] = {0}; fzl_reader_t *fzl_mkreader(char *source) { fzl_reader_ll_t *first_node = malloc(sizeof(fzl_reader_ll_t)); - first_node->token = NULL; - first_node->next = NULL; + first_node->token = NULL; + first_node->next = NULL; fzl_reader_t *reader = malloc(sizeof(fzl_reader_t)); - reader->first = first_node; - reader->last = first_node; - reader->source = source; - reader->size = strlen(source); - reader->position = 0; - reader->at_end = true; + reader->first = first_node; + reader->last = first_node; + reader->source = source; + reader->size = strlen(source); + reader->position = 0; + reader->line_n = 1; + reader->line_start = 0; return reader; } // --- Read zone --- +// Move cursor forward +static size_t move(fzl_reader_t *reader, size_t len) +{ + if (!reader) + return 0; + + char *src = reader->source; + for (size_t i = 0; i < len; i++) + { + if (src[reader->position + i] == '\n') + { + reader->line_n++; + reader->line_start = reader->position + i + 1; + } + } + + return reader->position += len; +} + // Try parse name fzl_token_t *parse_name(fzl_reader_t *reader) { @@ -45,10 +65,10 @@ fzl_token_t *parse_name(fzl_reader_t *reader) memcpy(value, reader->source + reader->position, size); size_t start = reader->position; - reader->position += size; + move(reader, size); - fzl_token_t *tok = - fzl_mktoken(FZL_TOKTYPE_NAME, start, reader->position - 1, value, size); + fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NAME, reader->line_n, + start - reader->line_start, value, size); free(value); return tok; @@ -63,7 +83,7 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader) if (reader->source[lpos] != '\'' && reader->source[lpos] != '"') return NULL; - char open_symbol = reader->source[lpos]; + char open_symbol = reader->source[lpos]; char close_symbol = '\0'; do @@ -78,23 +98,27 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader) size++; if (close_symbol != open_symbol) + { + snprintf(last_err, sizeof(last_err), "unterminated string at %ld:%ld", + reader->line_n, reader->position - reader->line_start); return NULL; + } if (size == 2) { - fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->position, - reader->position + 1, "", 0); - reader->position += 2; + fzl_token_t *tok = + fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, + reader->position - reader->line_start, "", 0); + move(reader, 2); return tok; } char *value = malloc(size - 2); memcpy(value, reader->source + reader->position + 1, size - 2); - fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->position, - lpos, value, size - 2); + fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, + lpos - reader->line_start, value, size - 2); free(value); - - reader->position += size; + move(reader, size); return tok; } @@ -119,22 +143,22 @@ fzl_token_t *parse_number(fzl_reader_t *reader) memcpy(value, reader->source + reader->position, size); value[size] = '\0'; - fzl_token_t *tok = - fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->position, lpos, value, size); + fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->line_n, + lpos - reader->line_start, value, size); free(value); if (!tok) return NULL; - reader->position += size; + move(reader, size); return tok; } // Add single-char token fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type) { - size_t p = reader->position++; - return fzl_mktoken(type, p, p, NULL, 0); + size_t p = move(reader, 1); + return fzl_mktoken(type, reader->line_n, p - reader->line_start, NULL, 0); } int fzl_read(fzl_reader_t *reader) @@ -180,37 +204,26 @@ int fzl_read(fzl_reader_t *reader) token = parse_number(reader); else { - sprintf(last_err, "undefined token '%c'", curr); + sprintf(last_err, "undefined token '%c' at %ld:%ld", curr, reader->line_n, + p - reader->line_start); return -1; } if (!token) { - size_t line = 1, linepos = 1; - for (size_t i = 0; i < p; i++) - { - char sym = reader->source[i]; - if (sym == '\n') - { - linepos = 1; - line++; - } - else - linepos++; - } - - sprintf(last_err, "cannot parse token (%ld:%ld)", line, linepos); + if (!last_err[0]) + sprintf(last_err, "cannot parse token at %ld:%ld", reader->line_n, + p - reader->line_start); return -1; } fzl_reader_ll_t *tok_node = malloc(sizeof(fzl_reader_ll_t)); - tok_node->token = token; + tok_node->token = token; reader->last->next = tok_node; - reader->last = tok_node; + reader->last = tok_node; } while (reader->position < reader->size); - reader->at_end = true; return 0; } diff --git a/src/compiler/fzl_token.c b/src/compiler/fzl_token.c index 67f6660..96e761e 100644 --- a/src/compiler/fzl_token.c +++ b/src/compiler/fzl_token.c @@ -1,8 +1,9 @@ #include +#include #include #include -fzl_token_t *fzl_mktoken(const fzl_toktype_t type, uint16_t from, uint16_t to, +fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, void *value, size_t value_len) { char *valholder = malloc(value_len + 1); @@ -10,12 +11,12 @@ fzl_token_t *fzl_mktoken(const fzl_toktype_t type, uint16_t from, uint16_t to, valholder[value_len] = '\0'; fzl_token_t *token = malloc(sizeof(fzl_token_t)); - token->type = type; - token->i0 = from; - token->i1 = to; + token->type = type; + token->ln = line; + token->cn = col; token->store_value = value_len > 0; - token->value = valholder; - token->value_sz = value_len; + token->value = valholder; + token->value_sz = value_len; return token; } diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index 87aff38..2ba4717 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -1,3 +1,4 @@ +#include "common/fzl_types.h" #include #include #include @@ -35,12 +36,12 @@ fzl_walker_t *fzl_mkwalker(fzl_node_t *root) return NULL; } - walker->root = root; + walker->root = root; walker->consts = pool; - walker->op_count = 0; + walker->op_count = 0; walker->op_remainder = 2; - walker->ops = malloc(walker->op_remainder * sizeof(uint64_t)); + walker->ops = malloc(walker->op_remainder * sizeof(uint64_t)); return walker; } @@ -88,116 +89,171 @@ void push_word(fzl_walker_t *walker, uint64_t word) walker->ops[walker->op_count++] = word; } -bool walk(fzl_walker_t *walker, fzl_node_t *node) +fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { if (!walker || !node) - return false; + 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_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_UNARY_PLUS: + case FZL_NODETYPE_IDENTIFIER: + break; - case FZL_NODETYPE_CALL: - if (node->list.entry_count > 0) - { - for (size_t i = 0; i < node->call.args_count; i++) + case FZL_NODETYPE_BLOCK: + 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; + } + break; + + case FZL_NODETYPE_CALL: + if (node->list.entry_count > 0) { - if (!walk(walker, node->call.args[i])) - return false; + 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; + } } - } - // NOTE: you need to implement dynamic names call - push_op(walker, FZL_OPCODE_CALL_BUILTIN); + // NOTE: you need to implement dynamic names call too + 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; + if (strcmp(node->token->value, "printline") == 0) + { + push_word(walker, FZL_BUILTIN_PRINTLINE); + if (node->call.args_count < 1) + { + snprintf(wlast_err, sizeof(wlast_err), + "'printline' call with zero arguments at %ld:%ld", + node->token->ln, node->token->cn); + return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + } + } + 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}; + } + current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = 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}); + 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); + 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); - } - break; + 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}; + } + 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; - - if (!walk(walker, node->binary_op.right)) - return false; - - 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); + { + 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_STRING) + { + fzl_token_t *ltok = node->binary_op.left->token; + snprintf(wlast_err, sizeof(wlast_err), + "left operand at %ld:%ld is not compatible to integer types", + ltok->ln, ltok->cn); + return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + } + + if (rres.type == FZL_TYPE_STRING) + { + fzl_token_t *rtok = node->binary_op.right->token; + snprintf( + wlast_err, sizeof(wlast_err), + "right operand at %ld:%ld is not compatible to integer types", + 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; - - default: - return false; } - break; - case FZL_NODETYPE_UNARY_MINUS: - if (!walk(walker, node->unary_op.operand)) - return false; + case FZL_NODETYPE_UNARY_MINUS: + { + fzl_walk_res_t res = walk(walker, node->unary_op.operand); + if (res.error) + return res; - push_op(walker, FZL_OPCODE_NEG); - break; + if (res.type == FZL_TYPE_STRING) + { + fzl_token_t *tok = node->unary_op.operand->token; + snprintf(wlast_err, sizeof(wlast_err), + "incompatible with unary operator type at %ld:%ld", 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}; + } } node = node->next; } - return true; + return current_res; } // Walk entire AST recursevily @@ -209,8 +265,12 @@ int fzl_walk(fzl_walker_t *walker) return -1; } - bool result = walk(walker, walker->root); - return !result && wlast_err[0] ? -1 : 0; + fzl_walk_res_t result = walk(walker, walker->root); + + if (result.error && !wlast_err[0]) + snprintf(wlast_err, sizeof(wlast_err), "%s", result.error_msg); + + return result.error ? -1 : 0; } // --- Walking zone end --- diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index d666bd2..7df9d0a 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -1,3 +1,5 @@ +#include "common/fzl_types.h" +#include "common/fzl_value.h" #include #include #include @@ -20,13 +22,13 @@ fzl_vm_t *fzl_mkvm(const char *filepath) return NULL; } - vm->consts = NULL; + vm->consts = NULL; vm->consts_count = 0; - vm->ops = NULL; - vm->ops_count = 0; - vm->ip = 0; - memset(vm->stack, 0, sizeof(vm->stack)); - vm->stack_top = 0; + vm->ops = NULL; + vm->ops_count = 0; + vm->ip = 0; + memset(vm->dstack, 0, sizeof(vm->dstack)); + vm->dtop = 0; FILE *fd = fopen(filepath, "rb"); if (!fd) @@ -56,7 +58,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath) if (consts_count > 0) { vm->consts_count = consts_count; - vm->consts = malloc(consts_count * sizeof(fzl_const_t)); + vm->consts = malloc(consts_count * sizeof(fzl_value_t)); for (size_t i = 0; i < consts_count; i++) { @@ -87,7 +89,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath) } vm->ops_count = ops_count; - vm->ops = malloc(ops_count * sizeof(uint64_t)); + vm->ops = malloc(ops_count * sizeof(uint64_t)); for (size_t i = 0; i < ops_count; i++) { uint64_t op; @@ -113,148 +115,173 @@ int fzl_vm_run(fzl_vm_t *vm) switch (opcode) { - case FZL_OPCODE_CALL_BUILTIN: - uint64_t fn_id = vm->ops[++vm->ip]; - if (fn_id == FZL_BUILTIN_PRINTLINE) + case FZL_OPCODE_CALL_BUILTIN: { - fzl_const_t arg = vm->stack[--vm->stack_top]; - if (arg.type == FZL_CONSTTYPE_STRING) - printf("%s\n", arg.as.string.chars); - else if (arg.type == FZL_CONSTTYPE_NUMBER) - printf("%lu\n", arg.as.num.value); + uint64_t fn_id = vm->ops[++vm->ip]; + if (fn_id == FZL_BUILTIN_PRINTLINE) + { + fzl_value_t arg = vm->dstack[--vm->dtop]; + if (arg.type == FZL_TYPE_STRING) + printf("%s\n", arg.as.s.value); + else if (arg.type == FZL_TYPE_CHAR) + printf("%c\n", arg.as.c); + else if (arg.type == FZL_TYPE_INT8) + printf("%d\n", arg.as.i8); + else if (arg.type == FZL_TYPE_INT16) + printf("%d\n", arg.as.i16); + else if (arg.type == FZL_TYPE_INT32) + printf("%d\n", arg.as.i32); + else if (arg.type == FZL_TYPE_INT64) + printf("%ld\n", arg.as.i64); + else if (arg.type == FZL_TYPE_INT) + printf("%ld\n", arg.as.i); + else if (arg.type == FZL_TYPE_UINT8) + printf("%u\n", arg.as.u8); + else if (arg.type == FZL_TYPE_UINT16) + printf("%u\n", arg.as.u16); + else if (arg.type == FZL_TYPE_UINT32) + printf("%u\n", arg.as.u32); + else if (arg.type == FZL_TYPE_UINT64) + printf("%lu\n", arg.as.u64); + else if (arg.type == FZL_TYPE_UINT) + printf("%lu\n", arg.as.u); + else if (arg.type == FZL_TYPE_BOOL) + printf("%b\n", arg.as.b); + } + else + { + snprintf(last_err, sizeof(last_err), + "runtime error - undefined builtin %lu", fn_id); + return -1; + } } - else + break; + + case FZL_OPCODE_LOADCONST: { + uint64_t cn = vm->ops[++vm->ip]; + if (vm->consts_count <= cn) + { + snprintf(last_err, sizeof(last_err), "runtime error - unknown const"); + return -1; + } + fzl_const_t c = vm->consts[cn]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = FZL_TYPE_STRING, + .as.s.length = c.as.string.length, + .as.s.value = c.as.string.chars}; + } + break; + + case FZL_OPCODE_ADD: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in stack"); + return -1; + } + fzl_value_t add1 = vm->dstack[--vm->dtop]; + fzl_value_t add2 = vm->dstack[--vm->dtop]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = add1.type, .as.u = add1.as.u + add2.as.u}; + break; + + case FZL_OPCODE_SUB: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "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]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = add1.type, .as.u = sub1.as.u - sub2.as.u}; + break; + + case FZL_OPCODE_MUL: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in stack"); + return -1; + } + fzl_value_t mul1 = vm->dstack[--vm->dtop]; + fzl_value_t mul2 = vm->dstack[--vm->dtop]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = mul1.type, .as.u = mul1.as.u * mul2.as.u}; + break; + + case FZL_OPCODE_DIV: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in stack"); + return -1; + } + fzl_value_t div1 = vm->dstack[--vm->dtop]; + fzl_value_t div2 = vm->dstack[--vm->dtop]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = div1.type, .as.u = div2.as.u / div1.as.u}; + break; + + case FZL_OPCODE_POW: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "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]; + + uint64_t pow_n = pow1.as.u; + uint64_t pow_res = pow_n; + uint64_t pow_times = pow2.as.u; + for (size_t i = 1; i < pow_times; i++) + pow_res *= pow_n; + + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = pow1.type, .as.u = pow_res}; + break; + + case FZL_OPCODE_MOD: + if (vm->dtop < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in stack"); + return -1; + } + fzl_value_t mod1 = vm->dstack[--vm->dtop]; + fzl_value_t mod2 = vm->dstack[--vm->dtop]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = mod1.type, .as.u = mod2.as.u % mod1.as.u}; + break; + + case FZL_OPCODE_NEG: + if (vm->dtop < 1) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected value in stack"); + return -1; + } + fzl_value_t neg_n = vm->dstack[--vm->dtop]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = neg_n.type, .as.u = -neg_n.as.u}; + break; + + case FZL_OPCODE_PUSHNUM: + { + uint64_t push_n = vm->ops[++vm->ip]; + vm->dstack[vm->dtop++] = + (fzl_value_t){.type = FZL_TYPE_UINT, .as.u = push_n}; + } + break; + + default: snprintf(last_err, sizeof(last_err), - "runtime error - undefined builtin %lu", fn_id); + "runtime error - unknown opcode %u", opcode); return -1; - } - - break; - - case FZL_OPCODE_LOADCONST: - uint64_t cn = vm->ops[++vm->ip]; - if (vm->consts_count <= cn) - { - snprintf(last_err, sizeof(last_err), "runtime error - unknown const"); - return -1; - } - fzl_const_t c = vm->consts[cn]; - vm->stack[vm->stack_top++] = c; - break; - - case FZL_OPCODE_ADD: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t add1 = vm->stack[--vm->stack_top]; - fzl_const_t add2 = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, - .as.num.value = add1.as.num.value + add2.as.num.value}; - break; - - case FZL_OPCODE_SUB: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t sub1 = vm->stack[--vm->stack_top]; - fzl_const_t sub2 = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, - .as.num.value = sub1.as.num.value - sub2.as.num.value}; - break; - - case FZL_OPCODE_MUL: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t mul1 = vm->stack[--vm->stack_top]; - fzl_const_t mul2 = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, - .as.num.value = mul1.as.num.value * mul2.as.num.value}; - break; - - case FZL_OPCODE_DIV: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t div1 = vm->stack[--vm->stack_top]; - fzl_const_t div2 = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, - .as.num.value = div2.as.num.value / div1.as.num.value}; - break; - - case FZL_OPCODE_POW: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t pow1 = vm->stack[--vm->stack_top]; - fzl_const_t pow2 = vm->stack[--vm->stack_top]; - - uint64_t pow_n = pow1.as.num.value; - uint64_t pow_res = pow_n; - uint64_t pow_times = pow2.as.num.value; - for (size_t i = 1; i < pow_times; i++) - pow_res *= pow_n; - - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, .as.num.value = pow_res}; - break; - - case FZL_OPCODE_MOD: - if (vm->stack_top < 2) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected 2 values in stack"); - return -1; - } - fzl_const_t mod1 = vm->stack[--vm->stack_top]; - fzl_const_t mod2 = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, - .as.num.value = mod2.as.num.value % mod1.as.num.value}; - break; - - case FZL_OPCODE_NEG: - if (vm->stack_top < 1) - { - snprintf(last_err, sizeof(last_err), - "runtime error - expected value in stack"); - return -1; - } - fzl_const_t neg_n = vm->stack[--vm->stack_top]; - vm->stack[vm->stack_top++] = (fzl_const_t){ - .type = FZL_CONSTTYPE_NUMBER, .as.num.value = -neg_n.as.num.value}; - break; - - case FZL_OPCODE_PUSHNUM: - uint64_t push_n = vm->ops[++vm->ip]; - vm->stack[vm->stack_top++] = - (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, .as.num.value = push_n}; - break; - - default: - snprintf(last_err, sizeof(last_err), "runtime error - unknown opcode %u", - opcode); - return -1; } vm->ip++;