From 76e0cdbeeff28e21294da8b5f228c22bdb383191 Mon Sep 17 00:00:00 2001 From: bog Date: Sat, 17 Feb 2024 21:49:39 +0100 Subject: [PATCH] :sparkles: native function support. --- guxi/src/main.c | 39 +++++- lang/CMakeLists.txt | 1 + lang/src/compiler.c | 44 +++++- lang/src/compiler.h | 5 +- lang/src/lexer.c | 26 +++- lang/src/native.c | 274 ++++++++++++++++++++++++++++++++++++++ lang/src/native.h | 40 ++++++ lang/src/opcodes.h | 2 +- lang/src/parser.c | 1 + lang/src/sym_table.c | 46 ++++++- lang/src/sym_table.h | 9 +- lang/src/type_checker.c | 44 +++++- lang/src/type_checker.h | 2 +- lang/src/value.c | 31 ++++- lang/src/value.h | 5 + lang/tests/lexer.c | 11 +- lang/tests/sym_table.c | 8 +- lang/tests/type_checker.c | 4 +- tests/cast.gux | 23 ++++ vm/src/vm.c | 44 +++++- vm/src/vm.h | 3 +- 21 files changed, 627 insertions(+), 35 deletions(-) create mode 100644 lang/src/native.c create mode 100644 lang/src/native.h create mode 100644 tests/cast.gux diff --git a/guxi/src/main.c b/guxi/src/main.c index 8390359..c63ebc5 100644 --- a/guxi/src/main.c +++ b/guxi/src/main.c @@ -6,6 +6,7 @@ #include #include #include +#include char* load_new_source(char const* path) { @@ -159,8 +160,16 @@ int main(int argc, char** argv) printf("%s\n", msg); } + struct vec natives; + vec_init(&natives, 1); + + struct sym_table globals; + sym_table_init(&globals, NULL); + + populate_native(&natives, &globals); + struct type_checker checker; - type_checker_init(&checker); + type_checker_init(&checker, &globals); if (type_checker_check(&checker, ast) != 0) { @@ -171,6 +180,12 @@ int main(int argc, char** argv) type_checker_free(&checker); + sym_table_free(&globals); + for (size_t i=0; isym_table); + sym_table_init(&self->sym_table, global); memset(self->error_msg, 0, GUX_STR_SIZE); self->stack_size = 0; vec_init(&self->loops, 1); @@ -55,7 +56,7 @@ int compiler_compile(struct compiler* self, sym_table_push_table(&self->sym_table); struct compiler compiler; - compiler_init(&compiler); + compiler_init(&compiler, self->sym_table.prev); struct vec idents; vec_init(&idents, 1); @@ -75,7 +76,7 @@ int compiler_compile(struct compiler* self, struct node* ident = idents.data[j]; struct type* ty = malloc(sizeof(struct type)); - type_init_from_node(ty, param); + compiler_get_type(self, param, ty); sym_table_declare_const(&compiler.sym_table, ident->value, @@ -129,7 +130,15 @@ int compiler_compile(struct compiler* self, assert(entry); - compiler_gen_instr(self, program, OP_LOAD, entry->addr); + if (entry->is_global) + { + compiler_gen_instr(self, program, OP_GLOAD, entry->addr); + } + else + { + compiler_gen_instr(self, program, OP_LOAD, entry->addr); + } + compiler_gen_instr(self, program, OP_CALL, args->children.size); } break; @@ -261,7 +270,14 @@ int compiler_compile(struct compiler* self, return 1; } - compiler_gen_instr(self, program, OP_LOAD, entry->addr); + if (entry->is_global) + { + compiler_gen_instr(self, program, OP_GLOAD, entry->addr); + } + else + { + compiler_gen_instr(self, program, OP_LOAD, entry->addr); + } } break; case NODE_CONSTDECL: @@ -278,7 +294,8 @@ int compiler_compile(struct compiler* self, } struct type* ty = malloc(sizeof(struct type)); - type_init_from_node(ty, node->children.data[0]); + type_init(ty, TYPE_VOID); + compiler_get_type(self, node->children.data[0], ty); sym_table_declare(&self->sym_table, node->value, ty, node->type == NODE_VARDECL); @@ -315,6 +332,7 @@ int compiler_compile(struct compiler* self, case NODE_STRING: { struct value* val = malloc(sizeof(struct value)); + value_init_string(val, node->value, node->line); size_t addr = program_push_constant(program, val); compiler_gen_instr(self, program, OP_PUSH, addr); @@ -598,6 +616,7 @@ size_t compiler_gen_instr(struct compiler* self, case OP_CALL: break; case OP_LOAD: + case OP_GLOAD: case OP_PUSH: self->stack_size += 1; break; case OP_LT: @@ -627,3 +646,14 @@ size_t compiler_gen_instr(struct compiler* self, return addr; } + +size_t compiler_get_type(struct compiler* self, + struct node* node, + struct type* type) +{ + struct type_resolver resolver; + type_resolver_init(&resolver, &self->sym_table); + size_t err = type_resolver_resolve(&resolver, node, type); + type_resolver_free(&resolver); + return err; +} diff --git a/lang/src/compiler.h b/lang/src/compiler.h index d471ac7..27384d6 100644 --- a/lang/src/compiler.h +++ b/lang/src/compiler.h @@ -19,7 +19,7 @@ struct compiler { struct vec loops; }; -void compiler_init(struct compiler* self); +void compiler_init(struct compiler* self, struct sym_table* global); void compiler_free(struct compiler* self); int compiler_compile(struct compiler* self, @@ -36,4 +36,7 @@ size_t compiler_gen_instr(struct compiler* self, enum Opcodes op, int param); +size_t compiler_get_type(struct compiler* self, + struct node* node, + struct type* type); #endif diff --git a/lang/src/lexer.c b/lang/src/lexer.c index aeb4b00..0ef8b81 100644 --- a/lang/src/lexer.c +++ b/lang/src/lexer.c @@ -430,7 +430,31 @@ int lexer_scan_string(struct lexer* self, break; } - value[sz++] = self->source[cursor++]; + if (cursor + 1 < strlen(self->source) + && self->source[cursor] == '\\') + { + char val = self->source[cursor + 1]; + + switch (val) + { + case 'n': value[sz++] = '\n'; break; + case 'r': value[sz++] = '\r'; break; + case 't': value[sz++] = '\t'; break; + case '\'': value[sz++] = '\''; break; + case '"': value[sz++] = '"'; break; + case '\\': value[sz++] = '\\'; break; + + default: + fprintf(stderr, "unknown escaped char '%c'\n", val); + abort(); + } + + cursor += 2; + } + else + { + value[sz++] = self->source[cursor++]; + } } if (found) diff --git a/lang/src/native.c b/lang/src/native.c new file mode 100644 index 0000000..46318ae --- /dev/null +++ b/lang/src/native.c @@ -0,0 +1,274 @@ +#include "native.h" +#include "commons.h" +#include "type.h" +#include "value.h" + +void native_init(struct native* self, native_fun_t fun) +{ + assert(self); + assert(fun); + self->fun = fun; +} + +void native_free(struct native* self) +{ + assert(self); +} + +void populate_native(struct vec* natives, struct sym_table* table) +{ + struct type* ty; + + // IO + // == + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_VOID); + type_add_subtype(ty, TYPE_STRING); + populate_add_native(natives, table, "println", ty, fun_println); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_VOID); + type_add_subtype(ty, TYPE_STRING); + populate_add_native(natives, table, "print", ty, fun_print); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_STRING); + populate_add_native(natives, table, "readln", ty, fun_readln); + + // CAST + // ==== + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_STRING); + type_add_subtype(ty, TYPE_INT); + populate_add_native(natives, table, "itos", ty, fun_itos); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_FLOAT); + type_add_subtype(ty, TYPE_INT); + populate_add_native(natives, table, "itof", ty, fun_itof); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_STRING); + type_add_subtype(ty, TYPE_FLOAT); + populate_add_native(natives, table, "ftos", ty, fun_ftos); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_INT); + type_add_subtype(ty, TYPE_FLOAT); + populate_add_native(natives, table, "ftoi", ty, fun_ftoi); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_INT); + type_add_subtype(ty, TYPE_STRING); + populate_add_native(natives, table, "stoi", ty, fun_stoi); + + ty = malloc(sizeof(struct type)); + type_init(ty, TYPE_FUN); + type_add_subtype(ty, TYPE_FLOAT); + type_add_subtype(ty, TYPE_STRING); + populate_add_native(natives, table, "stof", ty, fun_stof); +} + +void populate_add_native(struct vec* natives, + struct sym_table* table, + char* name, + struct type* type, + native_fun_t fun) +{ + assert(natives); + assert(table); + assert(type); + + sym_table_declare_global(table, name, type, natives->size); + + struct value* val = malloc(sizeof(struct value)); + value_init_new_native(val, fun, type, 0); + vec_push(natives, val); +} + +struct value* fun_println(struct vec* args) +{ + struct value* arg = args->data[0]; + + printf("%s\n", arg->data.s); + + return NULL; +} + +struct value* fun_print(struct vec* args) +{ + struct value* arg = args->data[0]; + + printf("%s", arg->data.s); + + return NULL; +} + +struct value* fun_readln(struct vec* args) +{ + (void) args; + + char* input = NULL; + size_t len = 0; + + getline(&input, &len, stdin); + + struct value* val = malloc(sizeof(struct value)); + value_init_string(val, input, 0); + + free(input); + + return val; +} + +// CAST +// ==== +struct value* fun_itos(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + + char str[GUX_STR_SIZE]; + memset(str, 0, GUX_STR_SIZE); + snprintf(str, GUX_STR_SIZE, "%d", value->data.i); + + struct value* result = malloc(sizeof(struct value)); + value_init_string(result, str, value->line); + + return result; +} + +struct value* fun_itof(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + + struct value* result = malloc(sizeof(struct value)); + value_init_float(result, (float) value->data.i, value->line); + + return result; +} + +struct value* fun_ftos(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + + char str[GUX_STR_SIZE]; + memset(str, 0, GUX_STR_SIZE); + snprintf(str, GUX_STR_SIZE, "%f", value->data.f); + + struct value* result = malloc(sizeof(struct value)); + value_init_string(result, str, value->line); + + return result; +} + +struct value* fun_ftoi(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + + struct value* result = malloc(sizeof(struct value)); + value_init_int(result, (int) value->data.f, value->line); + + return result; +} + +struct value* fun_stoi(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + char* str = value->data.s; + int res = 0; + + size_t k = 0; + size_t const N = strlen(str); + + while (k < N && isspace(str[k])) + { + k++; + } + + int neg = 0; + + if (k < N && str[k] == '-') + { + k++; + neg = 1; + } + + while (k < N && isdigit(str[k])) + { + res *= 10; + res += (str[k] - '0'); + k++; + } + + struct value* result = malloc(sizeof(struct value)); + value_init_int(result, neg ? -res : res, value->line); + + return result; +} + +struct value* fun_stof(struct vec* args) +{ + assert(args); + struct value* value = args->data[0]; + char* str = value->data.s; + float res = 0.0f; + + size_t k = 0; + + size_t const N = strlen(str); + + while (k < N && isspace(str[k])) + { + k++; + } + + int neg = 0; + + if (k < N && str[k] == '-') + { + k++; + neg = 1; + } + + while (k < N && isdigit(str[k])) + { + res *= 10; + res += (str[k] - '0'); + k++; + } + + if (k < N && str[k] == '.') + { + k++; + } + + float power = 0.0f; + + while (k < N && isdigit(str[k])) + { + res *= 10; + power++; + res += (str[k] - '0'); + k++; + } + + res /= powf(10.0f, power); + + struct value* result = malloc(sizeof(struct value)); + value_init_float(result, neg ? -res : res, value->line); + + return result; +} diff --git a/lang/src/native.h b/lang/src/native.h new file mode 100644 index 0000000..f360520 --- /dev/null +++ b/lang/src/native.h @@ -0,0 +1,40 @@ +#ifndef NATIVE_H +#define NATIVE_H + +#include +#include "sym_table.h" + +typedef struct value* (*native_fun_t)(struct vec*); + +struct native { + native_fun_t fun; +}; + +void native_init(struct native* self, native_fun_t fun); +void native_free(struct native* self); + +void populate_native(struct vec* natives, struct sym_table* table); +void populate_add_native(struct vec* natives, + struct sym_table* table, + char* name, + struct type* type, + native_fun_t fun); + +// IO +// == +struct value* fun_println(struct vec* args); +struct value* fun_print(struct vec* args); +struct value* fun_readln(struct vec* args); + +// CAST +// ==== +struct value* fun_itos(struct vec* args); +struct value* fun_itof(struct vec* args); + +struct value* fun_ftos(struct vec* args); +struct value* fun_ftoi(struct vec* args); + +struct value* fun_stoi(struct vec* args); +struct value* fun_stof(struct vec* args); + +#endif diff --git a/lang/src/opcodes.h b/lang/src/opcodes.h index 6ce5b81..9acb946 100644 --- a/lang/src/opcodes.h +++ b/lang/src/opcodes.h @@ -6,7 +6,7 @@ G(OP_BRT), G(OP_NOP), G(OP_NOT), G(OP_EQ), \ G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), G(OP_MOD), G(OP_POW), \ G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE), G(OP_LOAD), G(OP_STORE), \ - G(OP_SWAP), G(OP_CALL), G(OP_RET) + G(OP_SWAP), G(OP_CALL), G(OP_RET), G(OP_GLOAD) #include diff --git a/lang/src/parser.c b/lang/src/parser.c index 66f49f3..07bcdfe 100644 --- a/lang/src/parser.c +++ b/lang/src/parser.c @@ -459,6 +459,7 @@ struct node* parser_try_new_params(struct parser* self) node->children.data[idx] = node_new_clone(type); } + vec_free_elements(&types); vec_free(&types); vec_init(&types, 1); } diff --git a/lang/src/sym_table.c b/lang/src/sym_table.c index 1a575e0..94e6829 100644 --- a/lang/src/sym_table.c +++ b/lang/src/sym_table.c @@ -1,13 +1,16 @@ #include "sym_table.h" +#include "commons.h" #include "vec.h" -void sym_table_init(struct sym_table* self) +void sym_table_init(struct sym_table* self, struct sym_table* prev) { assert(self); self->root = NULL; sym_table_push_table(self); self->addr_counter = 0; + + self->prev = prev; } void sym_table_free(struct sym_table* self) @@ -87,6 +90,11 @@ struct sym* sym_table_try_by_name(struct sym_table* self, char* const name) table = table->prev; } + if (self->prev) + { + return sym_table_try_by_name(self->prev, name); + } + return NULL; } @@ -124,6 +132,7 @@ int sym_table_declare(struct sym_table* self, sym->name = strdup(name); sym->type = new_type; sym->parent = self->root; + sym->is_global = 0; sym->is_var = is_var; sym->addr = self->addr_counter; vec_push(&table->syms, sym); @@ -133,6 +142,34 @@ int sym_table_declare(struct sym_table* self, return 0; } +int sym_table_declare_global(struct sym_table* self, + char* const name, + struct type* new_type, + int addr) +{ + assert(self); + assert(strcmp(name, "") != 0); + + struct sym* s = sym_table_try_by_name(self, name); + + if (s && s->parent == self->root && s->is_global) + { + return 1; + } + + struct table* table = self->root; + struct sym* sym = malloc(sizeof(struct sym)); + sym->name = strdup(name); + sym->type = new_type; + sym->parent = self->root; + sym->is_global = 1; + sym->is_var = 0; + sym->addr = addr; + vec_push(&table->syms, sym); + + return 0; +} + size_t sym_table_str(struct sym_table* self, char* buffer, size_t size) { assert(self); @@ -147,9 +184,12 @@ size_t sym_table_str(struct sym_table* self, char* buffer, size_t size) for (size_t i=0; isyms.size; i++) { struct sym* sym = table->syms.data[i]; + char type[GUX_STR_SIZE]; + type_str(sym->type, type, GUX_STR_SIZE); + sz += snprintf(buffer + sz, size - sz, - "[%s::%p] -> %d\n", - sym->name, sym->parent, sym->addr); + "[%s::%p, %s] -> %d\n", + sym->name, sym->parent, type, sym->addr); } return sz; diff --git a/lang/src/sym_table.h b/lang/src/sym_table.h index fffc140..0ddb9ea 100644 --- a/lang/src/sym_table.h +++ b/lang/src/sym_table.h @@ -9,6 +9,7 @@ struct sym { struct table* parent; char* name; int is_var; + int is_global; int addr; struct type* type; }; @@ -19,11 +20,12 @@ struct table { }; struct sym_table { + struct sym_table* prev; struct table* root; int addr_counter; }; -void sym_table_init(struct sym_table* self); +void sym_table_init(struct sym_table* self, struct sym_table* prev); void sym_table_free(struct sym_table* self); void sym_table_push_table(struct sym_table* self); @@ -43,6 +45,11 @@ int sym_table_declare(struct sym_table* self, struct type* new_type, int is_var); +int sym_table_declare_global(struct sym_table* self, + char* const name, + struct type* new_type, + int addr); + size_t sym_table_str(struct sym_table* self, char* buffer, size_t size); #endif diff --git a/lang/src/type_checker.c b/lang/src/type_checker.c index 8f0d7c3..bb05c1f 100644 --- a/lang/src/type_checker.c +++ b/lang/src/type_checker.c @@ -6,10 +6,10 @@ #include "type_resolver.h" #include "fun.h" -void type_checker_init(struct type_checker* self) +void type_checker_init(struct type_checker* self, struct sym_table* global) { assert(self); - sym_table_init(&self->sym_table); + sym_table_init(&self->sym_table, global); type_resolver_init(&self->resolver, &self->sym_table); memset(self->error_msg, 0, GUX_STR_SIZE); vec_init(&self->fun_stack, 1); @@ -81,7 +81,6 @@ int type_checker_check(struct type_checker* self, case NODE_CALL: { struct node* target = node->children.data[0]; struct node* args = node->children.data[1]; - struct sym* entry = sym_table_try_by_name(&self->sym_table, target->value); @@ -96,6 +95,7 @@ int type_checker_check(struct type_checker* self, struct type* ty = entry->type; assert(ty); + if (ty->subtypes.size - 1 != args->children.size) { self->error_line = node->line; @@ -104,6 +104,29 @@ int type_checker_check(struct type_checker* self, return 1; } + for (size_t i=0; ichildren.size; i++) + { + struct type* sub = ty->subtypes.data[i + 1]; + struct node* sub_node = args->children.data[i]; + struct type t; + type_init(&t, TYPE_VOID); + + if (type_resolver_resolve(&self->resolver, sub_node, &t) != 0) + { + type_free(&t); + return 1; + } + + if (!type_equals(&t, sub)) + { + type_checker_error_msg(self, sub_node, sub, &t); + type_free(&t); + return 1; + } + + type_free(&t); + } + } return 0; case NODE_FUN: { @@ -463,7 +486,10 @@ int type_checker_check(struct type_checker* self, } return 0; - case NODE_ASSERT: + case NODE_ASSERT: { + return type_checker_check(self, node->children.data[0]); + } return 0; + case NODE_NOT: case NODE_AND: case NODE_OR: { @@ -480,6 +506,16 @@ int type_checker_check(struct type_checker* self, case NODE_EQ: case NODE_NE: { + for (size_t i=1; ichildren.size; i++) + { + struct node* child = node->children.data[i]; + + if ( type_checker_check(self, child) != 0 ) + { + return 1; + } + } + struct type type; type_init(&type, TYPE_VOID); type_resolver_resolve(&self->resolver, node->children.data[0], &type); diff --git a/lang/src/type_checker.h b/lang/src/type_checker.h index d65cd1e..39f3944 100644 --- a/lang/src/type_checker.h +++ b/lang/src/type_checker.h @@ -14,7 +14,7 @@ struct type_checker { struct vec fun_stack; }; -void type_checker_init(struct type_checker* self); +void type_checker_init(struct type_checker* self, struct sym_table* global); void type_checker_free(struct type_checker* self); int type_checker_check(struct type_checker* self, diff --git a/lang/src/value.c b/lang/src/value.c index f19c9fd..6dae366 100644 --- a/lang/src/value.c +++ b/lang/src/value.c @@ -1,4 +1,5 @@ #include "value.h" +#include "native.h" #include "type.h" #include "fun.h" @@ -9,6 +10,7 @@ void value_init_bool(struct value* self, int value, int line) type_init(&self->type, TYPE_BOOL); self->data.b = value; self->line = line; + self->is_native = 0; } void value_init_int(struct value* self, int value, int line) @@ -18,6 +20,7 @@ void value_init_int(struct value* self, int value, int line) type_init(&self->type, TYPE_INT); self->data.i = value; self->line = line; + self->is_native = 0; } @@ -28,15 +31,17 @@ void value_init_float(struct value* self, float value, int line) type_init(&self->type, TYPE_FLOAT); self->data.f = value; self->line = line; + self->is_native = 0; } void value_init_string(struct value* self, char* value, int line) { assert(self); - + assert(value); type_init(&self->type, TYPE_STRING); self->data.s = strdup(value); self->line = line; + self->is_native = 0; } void value_init_new_fun(struct value* self, struct fun* value, int line) @@ -46,6 +51,19 @@ void value_init_new_fun(struct value* self, struct fun* value, int line) type_init_from_node(&self->type, value->node); self->data.fun = value; self->line = line; + self->is_native = 0; +} + +void value_init_new_native(struct value* self, native_fun_t native, + struct type* type, int line) +{ + assert(self); + type_init(&self->type, TYPE_FUN); + type_copy(type, &self->type); + + self->data.native = native; + self->line = line; + self->is_native = 1; } void value_free(struct value* self) @@ -56,7 +74,7 @@ void value_free(struct value* self) { free(self->data.s); } - else if (self->type.kind == TYPE_FUN) + else if (self->type.kind == TYPE_FUN && !self->is_native) { fun_free(self->data.fun); free(self->data.fun); @@ -68,17 +86,24 @@ void value_free(struct value* self) struct value* value_new_clone(struct value* self) { assert(self); + struct value* clone = malloc(sizeof(struct value)); type_init(&clone->type, TYPE_VOID); type_copy(&self->type, &clone->type); clone->data = self->data; + clone->is_native = self->is_native; - if (clone->type.kind == TYPE_FUN) + if (clone->type.kind == TYPE_FUN && !self->is_native) { clone->data.fun = fun_new_clone(self->data.fun); } + if (clone->type.kind == TYPE_STRING) + { + clone->data.s = strdup(self->data.s); + } + return clone; } diff --git a/lang/src/value.h b/lang/src/value.h index 7056ca8..172dbce 100644 --- a/lang/src/value.h +++ b/lang/src/value.h @@ -3,6 +3,7 @@ #include #include +#include "native.h" #define VAL_TRUE 1 #define VAL_FALSE 0 @@ -13,11 +14,13 @@ union value_data { float f; int i; struct fun* fun; + native_fun_t native; }; struct value { struct type type; int line; + int is_native; union value_data data; }; @@ -26,6 +29,8 @@ void value_init_int(struct value* self, int value, int line); void value_init_float(struct value* self, float value, int line); void value_init_string(struct value* self, char* value, int line); void value_init_new_fun(struct value* self, struct fun* value, int line); +void value_init_new_native(struct value* self, native_fun_t native, + struct type* type, int line); void value_free(struct value* self); diff --git a/lang/tests/lexer.c b/lang/tests/lexer.c index 9de7ac1..afac7fc 100644 --- a/lang/tests/lexer.c +++ b/lang/tests/lexer.c @@ -85,7 +85,16 @@ Test(lexer, string) { test_lexer("'hello world ' \" bim\" '\\\"hello\\\"'", 3, "STRING[hello world ]", "STRING[ bim]", - "STRING[\\\"hello\\\"]"); + "STRING[\"hello\"]"); + + test_lexer("' \\'coucou\\' '", 1, + "STRING[ 'coucou' ]"); + + test_lexer("' \\'cou\\ncou\\' '", 1, + "STRING[ 'cou\ncou' ]"); + + test_lexer("' \\'cou\\r\\tcou\\' '", 1, + "STRING[ 'cou\r\tcou' ]"); } Test(lexer, arithemtic) { diff --git a/lang/tests/sym_table.c b/lang/tests/sym_table.c index 30fb658..a76312a 100644 --- a/lang/tests/sym_table.c +++ b/lang/tests/sym_table.c @@ -4,7 +4,7 @@ Test(sym_table, simple) { struct sym_table table; - sym_table_init(&table); + sym_table_init(&table, NULL); struct sym* sym = sym_table_try_by_name(&table, "hello"); cr_assert_eq(sym, 0); @@ -24,7 +24,7 @@ Test(sym_table, simple) { Test(sym_table, already_exists) { struct sym_table table; - sym_table_init(&table); + sym_table_init(&table, NULL); struct type* ty = malloc(sizeof(struct type)); type_init(ty, TYPE_INT); @@ -40,7 +40,7 @@ Test(sym_table, already_exists) { Test(sym_table, scope) { struct sym_table table; - sym_table_init(&table); + sym_table_init(&table, NULL); struct type* ty_int = malloc(sizeof(struct type)); type_init(ty_int, TYPE_INT); @@ -74,7 +74,7 @@ Test(sym_table, scope) { Test(sym_table, outer_scope) { struct sym_table table; - sym_table_init(&table); + sym_table_init(&table, NULL); struct type* ty_int = malloc(sizeof(struct type)); type_init(ty_int, TYPE_INT); diff --git a/lang/tests/type_checker.c b/lang/tests/type_checker.c index 26cad62..6f9b3b3 100644 --- a/lang/tests/type_checker.c +++ b/lang/tests/type_checker.c @@ -14,7 +14,7 @@ static void test_check_ok(char const* source) cr_assert_neq(ast, NULL); struct type_checker tc; - type_checker_init(&tc); + type_checker_init(&tc, NULL); char buf[GUX_STR_SIZE]; node_str(ast, buf, GUX_STR_SIZE); @@ -38,7 +38,7 @@ static void test_check_ko(char const* source) cr_assert_neq(ast, NULL, "cannot parse: %s", source); struct type_checker tc; - type_checker_init(&tc); + type_checker_init(&tc, NULL); cr_assert_neq(type_checker_check(&tc, ast), 0, "%s shouldn't pass check test", source); diff --git a/tests/cast.gux b/tests/cast.gux new file mode 100644 index 0000000..bd07e11 --- /dev/null +++ b/tests/cast.gux @@ -0,0 +1,23 @@ +# from int +# -------- +assert 37.0 == itof(37); +assert '37' == itos(37); + +# from float +# ---------- +assert 2 == ftoi(2.8); +assert '3.100000' == ftos(3.1); + +# from string +# ----------- +assert 128 == stoi('128'); +assert 328 == stoi(' 328 '); +assert 24 == stoi(' 24 7 '); +assert -34 == stoi('-34'); +assert -34 == stoi(' -34 '); +assert 0 == stoi('abc'); + +assert 2.4 == stof('2.4'); +assert -2.4 == stof('-2.4'); +assert 322.4 == stof(' 322.4 '); +assert -2.4 == stof(' -2.4 '); \ No newline at end of file diff --git a/vm/src/vm.c b/vm/src/vm.c index 0d0f42d..73990b5 100644 --- a/vm/src/vm.c +++ b/vm/src/vm.c @@ -6,11 +6,12 @@ #include "vec.h" #include "fun.h" -void vm_init(struct vm* self) +void vm_init(struct vm* self, struct vec* natives) { assert(self); self->pc = 0; self->fp = 0; + self->natives = natives; self->error_line = 0; memset(self->error_msg, 0, GUX_STR_SIZE); @@ -133,7 +134,6 @@ int vm_exec(struct vm* self, struct program* program) case OP_CALL: { int fun_addr = vm_pop(self); struct value* fun_val = program->constant_pool.data[fun_addr]; - struct fun* fun = fun_val->data.fun; struct vec args; vec_init(&args, 1); @@ -145,9 +145,38 @@ int vm_exec(struct vm* self, struct program* program) vec_push(&args, addr); } + if (fun_val->is_native) + { + native_fun_t fun = fun_val->data.native; + struct vec fun_args; + vec_init(&fun_args, 1); + + for (size_t i=0; iconstant_pool.data[addr]); + } + + struct value* res = fun(&fun_args); + + if (res) + { + vm_push(self, program_push_constant(program, res)); + } + + vec_free(&fun_args); + vec_free_elements(&args); + vec_free(&args); + + self->pc++; + break; + } + vm_add_frame(self); struct frame* my_frame = self->stack[self->fp - 1]; + struct fun* fun = fun_val->data.fun; + for (size_t i=0; ipc++; } break; + case OP_GLOAD: { + struct value* value = self->natives->data[param]; + + size_t addr = + program_push_constant(program, value_new_clone(value)); + + vm_push(self, addr); + + self->pc++; + } break; + case OP_LOAD: { int stack_addr = vm_load(self, param); struct frame* myframe = self->stack[self->fp - 1]; diff --git a/vm/src/vm.h b/vm/src/vm.h index fe91fd1..0a3f1ed 100644 --- a/vm/src/vm.h +++ b/vm/src/vm.h @@ -25,9 +25,10 @@ struct vm { size_t pc; size_t fp; struct frame* stack[FRAME_DEPTH]; + struct vec* natives; }; -void vm_init(struct vm* self); +void vm_init(struct vm* self, struct vec* natives); void vm_free(struct vm* self); void vm_add_frame(struct vm* self); void vm_remove_frame(struct vm* self);