diff --git a/doc/gux.bnf b/doc/gux.bnf index ac268fd..df5a138 100644 --- a/doc/gux.bnf +++ b/doc/gux.bnf @@ -17,13 +17,14 @@ LEXPR ::= | continue | return EXPR? | FUN +| new EXPR +| free EXPR BEXPR ::= | BLOCK | IF | WHILE - IF ::= | if EXPR BLOCK | if EXPR BLOCK else BLOCK @@ -34,7 +35,7 @@ WHILE ::= while EXPR BLOCK FUN ::= fun PARAMS (rarrow TYPE) BLOCK PARAMS ::= -| opar ident colon TYPE (comma ident colon type)* cpar +| opar var? ident colon TYPE (comma var? ident colon type)* cpar BLOCK ::= obrace INSTR* cbrace VARDECL ::= var ident colon TYPE? assign EXPR @@ -67,3 +68,4 @@ BUILTIN ::= bool | int | float | string TYPE ::= | type | opar TYPE+ rarrow TYPE+ cpar +| rawptr TYPE diff --git a/guxi/src/main.c b/guxi/src/main.c index c63ebc5..9d447b7 100644 --- a/guxi/src/main.c +++ b/guxi/src/main.c @@ -173,7 +173,7 @@ int main(int argc, char** argv) if (type_checker_check(&checker, ast) != 0) { - fprintf(stderr, "[%s:%d] %s\n", + fprintf(stderr, "[%s:%d] type check error, %s\n", path, checker.error_line, checker.error_msg); @@ -215,7 +215,7 @@ int main(int argc, char** argv) if (compiler_compile(&compiler, ast, &program) != 0) { - fprintf(stderr, "[%s:%d] %s\n", + fprintf(stderr, "[%s:%d] compile error, %s\n", path, compiler.error_line, compiler.error_msg); diff --git a/lang/src/compiler.c b/lang/src/compiler.c index 02674b9..bb74024 100644 --- a/lang/src/compiler.c +++ b/lang/src/compiler.c @@ -18,6 +18,7 @@ void compiler_init(struct compiler* self, struct sym_table* global) memset(self->error_msg, 0, GUX_STR_SIZE); self->stack_size = 0; vec_init(&self->loops, 1); + self->heap_addr_counter = 1000; } void compiler_free(struct compiler* self) @@ -38,6 +39,21 @@ int compiler_compile(struct compiler* self, switch (node->type) { + case NODE_NEW: { + compiler_compile(self, node->children.data[0], program); + compiler_gen_instr(self, program, OP_NEW, self->heap_addr_counter++); + } break; + + case NODE_FREE: { + struct node* ident = node->children.data[0]; + + struct sym* entry = sym_table_fetch(&self->sym_table, + ident->value, + NULL); + + compiler_gen_instr(self, program, OP_FREE, entry->addr); + } break; + case NODE_RETURN: { if (node->children.size > 0) { @@ -65,7 +81,11 @@ int compiler_compile(struct compiler* self, { struct node* param = params->children.data[i]; - if (param->type != NODE_TYPE) + if (param->type == NODE_VAR) + { + continue; + } + else if (param->type != NODE_TYPE) { vec_push(&idents, param); } @@ -76,8 +96,7 @@ int compiler_compile(struct compiler* self, struct node* ident = idents.data[j]; struct type* ty = malloc(sizeof(struct type)); - type_init(ty, TYPE_VOID); - compiler_get_type(self, param, ty); + type_init_from_node(ty, param); sym_table_declare_const(&compiler.sym_table, ident->value, @@ -255,13 +274,32 @@ int compiler_compile(struct compiler* self, struct node* ident = node->children.data[0]; struct node* expr = node->children.data[1]; + struct type lhs_ty; + type_init(&lhs_ty, TYPE_VOID); + compiler_get_type(self, ident, &lhs_ty); + + int is_ptr = lhs_ty.kind == TYPE_RAW_PTR; + struct type type; type_init(&type, TYPE_VOID); compiler_get_type(self, expr, &type); - struct sym* entry = sym_table_fetch(&self->sym_table, - ident->value, - &type); + struct sym* entry; + + if (is_ptr) + { + entry = sym_table_fetch(&self->sym_table, + ident->value, + &lhs_ty); + } + else + { + entry = sym_table_fetch(&self->sym_table, + ident->value, + &type); + } + + type_free(&lhs_ty); type_free(&type); assert(entry); @@ -271,7 +309,8 @@ int compiler_compile(struct compiler* self, return 1; } - compiler_gen_instr(self, program, OP_STORE, entry->addr); + compiler_gen_instr(self, program, is_ptr ? OP_REFSTORE : OP_STORE, + entry->addr); } break; case NODE_IDENT: { @@ -299,11 +338,11 @@ int compiler_compile(struct compiler* self, case NODE_CONSTDECL: case NODE_VARDECL: { + struct node* rhs = node->children.size == 1 + ? node->children.data[0] + : node->children.data[1]; - int err = compiler_compile(self, node->children.size == 1 - ? node->children.data[0] - : node->children.data[1], - program); + int err = compiler_compile(self, rhs, program); if (err != 0) { @@ -312,7 +351,7 @@ int compiler_compile(struct compiler* self, struct type* ty = malloc(sizeof(struct type)); type_init(ty, TYPE_VOID); - compiler_get_type(self, node->children.data[0], ty); + compiler_get_type(self, rhs, ty); sym_table_declare(&self->sym_table, node->value, ty, node->type == NODE_VARDECL); @@ -320,10 +359,10 @@ int compiler_compile(struct compiler* self, struct sym* entry = sym_table_fetch(&self->sym_table, node->value, ty); - assert(entry); compiler_gen_instr(self, program, OP_STORE, entry->addr); + } break; case NODE_BOOL: { struct value* val = malloc(sizeof(struct value)); @@ -637,6 +676,7 @@ size_t compiler_gen_instr(struct compiler* self, case OP_GLOAD: case OP_PUSH: self->stack_size += 1; break; + case OP_FREE: case OP_LT: case OP_LE: case OP_GT: @@ -654,12 +694,17 @@ size_t compiler_gen_instr(struct compiler* self, case OP_BRT: self->stack_size -= 1; break; + case OP_DEREF: + case OP_NEW: case OP_RET: case OP_SWAP: case OP_BR: case OP_NOT: case OP_NOP: - case OP_STORE: break; + case OP_STORE: + case OP_REFSTORE:break; + + default: assert(0); } return addr; diff --git a/lang/src/compiler.h b/lang/src/compiler.h index 27384d6..de500e1 100644 --- a/lang/src/compiler.h +++ b/lang/src/compiler.h @@ -17,6 +17,7 @@ struct compiler { int error_line; int stack_size; struct vec loops; + int heap_addr_counter; }; void compiler_init(struct compiler* self, struct sym_table* global); diff --git a/lang/src/lexer.c b/lang/src/lexer.c index 0ef8b81..31633b5 100644 --- a/lang/src/lexer.c +++ b/lang/src/lexer.c @@ -26,11 +26,14 @@ void lexer_init(struct lexer* self, char const* source) lexer_add_tok(self, "var", NODE_VAR, "", 1); + lexer_add_tok(self, "new", NODE_NEW, "", 1); + lexer_add_tok(self, "free", NODE_FREE, "", 1); lexer_add_tok(self, "int", NODE_TYPE, "int", 1); lexer_add_tok(self, "float", NODE_TYPE, "float", 1); lexer_add_tok(self, "bool", NODE_TYPE, "bool", 1); lexer_add_tok(self, "string", NODE_TYPE, "string", 1); + lexer_add_tok(self, "^", NODE_PTR, "", 0); lexer_add_tok(self, ",", NODE_COMMA, "", 0); lexer_add_tok(self, "{", NODE_OBRACE, "", 0); lexer_add_tok(self, "}", NODE_CBRACE, "", 0); diff --git a/lang/src/node.h b/lang/src/node.h index 30f9dca..8bdfdf9 100644 --- a/lang/src/node.h +++ b/lang/src/node.h @@ -18,7 +18,7 @@ G(NODE_IF), G(NODE_ELSE), G(NODE_COND), G(NODE_WHILE), G(NODE_FOR), \ G(NODE_CONTINUE), G(NODE_BREAK), G(NODE_RARROW), G(NODE_FUN), \ G(NODE_RETURN), G(NODE_PARAMS), G(NODE_COMMA), G(NODE_CALL), \ - G(NODE_ARGS) + G(NODE_ARGS), G(NODE_RAWPTR), G(NODE_PTR), G(NODE_FREE), G(NODE_NEW) GUX_ENUM_H(NodeType, NODE_TYPE); diff --git a/lang/src/opcodes.h b/lang/src/opcodes.h index 9acb946..7605f8e 100644 --- a/lang/src/opcodes.h +++ b/lang/src/opcodes.h @@ -6,7 +6,8 @@ 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_GLOAD) + G(OP_SWAP), G(OP_CALL), G(OP_RET), G(OP_GLOAD), G(OP_NEW), \ + G(OP_FREE), G(OP_DEREF), G(OP_REFSTORE) #include diff --git a/lang/src/parser.c b/lang/src/parser.c index 07bcdfe..219f86b 100644 --- a/lang/src/parser.c +++ b/lang/src/parser.c @@ -149,7 +149,8 @@ int parser_start_type(struct parser* self) struct node* tok = self->tokens.data[self->cursor]; return tok->type == NODE_OPAR - || tok->type == NODE_TYPE; + || tok->type == NODE_TYPE + || tok->type == NODE_PTR; } struct node* parser_try_new_root(struct parser* self, char const* source) @@ -232,11 +233,29 @@ struct node* parser_try_new_lexpr(struct parser* self) { assert(self); + if (parser_try_consume(self, NODE_FREE) == 0) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_FREE, "", parser_current_line(self)); + node_add_child(node, parser_try_new_expr(self)); + return node; + } + if (parser_type_is(self, NODE_FUN, 0)) { return parser_try_new_fun(self); } + if (parser_try_consume(self, NODE_NEW) == 0) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_NEW, "", parser_current_line(self)); + + node_add_child(node, parser_try_new_expr(self)); + + return node; + } + if (parser_try_consume(self, NODE_RETURN) == 0) { struct node* node = malloc(sizeof(struct node)); @@ -425,7 +444,8 @@ struct node* parser_try_new_params(struct parser* self) while (1) { - if (!parser_type_is(self, NODE_IDENT, 0)) + if (!parser_type_is(self, NODE_IDENT, 0) + && !parser_type_is(self, NODE_VAR, 0)) { vec_free_elements(&types); vec_free(&types); @@ -434,6 +454,14 @@ struct node* parser_try_new_params(struct parser* self) return NULL; } + if (parser_try_consume(self, NODE_VAR) == 0) + { + struct node* var = malloc(sizeof(struct node)); + node_init(var, NODE_VAR, "", + parser_current_line(self)); + node_add_child(node, var); + } + // ident struct node* current = self->tokens.data[self->cursor]; struct node* ident = malloc(sizeof(struct node)); @@ -564,14 +592,9 @@ struct node* parser_try_new_vardecl(struct parser* self) return NULL; } - if (parser_type_is(self, NODE_TYPE, 0)) + if (parser_type_is(self, NODE_TYPE, 0) + || parser_type_is(self, NODE_PTR, 0)) { - /*current = self->tokens.data[self->cursor]; - struct node* ty = malloc(sizeof(struct node)); - node_init(ty, NODE_TYPE, current->value, parser_current_line(self)); - - node_add_child(node, ty); - self->cursor++;*/ node_add_child(node, parser_try_new_type(self)); } @@ -953,6 +976,14 @@ struct node* parser_try_new_type(struct parser* self) { assert(self); + if (parser_try_consume(self, NODE_PTR) == 0) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_TYPE, "rawptr", parser_current_line(self)); + node_add_child(node, parser_try_new_type(self)); + return node; + } + if (parser_type_is(self, NODE_OPAR, 0)) { self->cursor++; // opar diff --git a/lang/src/program.c b/lang/src/program.c index 557bdc7..62f43a8 100644 --- a/lang/src/program.c +++ b/lang/src/program.c @@ -14,10 +14,13 @@ void program_free(struct program* self) for (size_t i=0; iconstant_pool.size; i++) { - value_free(self->constant_pool.data[i]); + if (self->constant_pool.data[i] != NULL) + { + value_free(self->constant_pool.data[i]); + free(self->constant_pool.data[i]); + } } - vec_free_elements(&self->constant_pool); vec_free(&self->constant_pool); vec_free_elements(&self->instructions); diff --git a/lang/src/sym_table.c b/lang/src/sym_table.c index 17d109b..f58ae35 100644 --- a/lang/src/sym_table.c +++ b/lang/src/sym_table.c @@ -233,7 +233,7 @@ int sym_table_declare(struct sym_table* self, sym->type = new_type; sym->parent = self->root; sym->is_global = 0; - sym->is_var = is_var; + sym->type->is_var = is_var; sym->addr = self->addr_counter; vec_push(&table->syms, sym); @@ -264,7 +264,7 @@ int sym_table_declare_global(struct sym_table* self, sym->type = new_type; sym->parent = self->root; sym->is_global = 1; - sym->is_var = 0; + sym->type->is_var = 0; sym->addr = addr; vec_push(&table->syms, sym); diff --git a/lang/src/sym_table.h b/lang/src/sym_table.h index 74df115..9c761c4 100644 --- a/lang/src/sym_table.h +++ b/lang/src/sym_table.h @@ -8,7 +8,7 @@ struct sym { struct table* parent; char* name; - int is_var; + //int is_var; int is_global; int addr; struct type* type; diff --git a/lang/src/type.c b/lang/src/type.c index b4c478b..2238395 100644 --- a/lang/src/type.c +++ b/lang/src/type.c @@ -8,6 +8,7 @@ void type_init(struct type* self, enum TypeKind kind) { assert(self); self->kind = kind; + self->is_var = 0; vec_init(&self->subtypes, 1); } @@ -15,9 +16,17 @@ void type_init_from_node(struct type* self, struct node* node) { assert(self); + self->is_var = 0; vec_init(&self->subtypes, 1); - if (node->type == NODE_TYPE && strcmp(node->value, "fun") == 0) + if (node->type == NODE_TYPE && strcmp(node->value, "rawptr") == 0) + { + self->kind = TYPE_RAW_PTR; + type_add_subtype(self, TYPE_VOID); + type_free(self->subtypes.data[0]); + type_init_from_node(self->subtypes.data[0], node->children.data[0]); + } + else if (node->type == NODE_TYPE && strcmp(node->value, "fun") == 0) { self->kind = TYPE_FUN; int input = 1; @@ -68,14 +77,23 @@ void type_init_from_node(struct type* self, struct node* node) type_init_from_node(ret_ty, ret); vec_push(&self->subtypes, ret_ty); + int is_var = 0; + for (size_t i=0; ichildren.size; i++) { struct node* child = params->children.data[i]; + if (child->type == NODE_VAR) + { + is_var = 1; + } + if (child->type == NODE_TYPE) { struct type* param_ty = malloc(sizeof(struct type)); type_init_from_node(param_ty, child); + param_ty->is_var = is_var; + is_var = 0; vec_push(&self->subtypes, param_ty); } } @@ -94,6 +112,8 @@ void type_copy(struct type* self, struct type* dest) type_free(dest); type_init(dest, self->kind); + dest->is_var = self->is_var; + for (size_t i=0; isubtypes.size; i++) { type_add_subtype(dest, TYPE_VOID); @@ -149,6 +169,25 @@ int type_equals(struct type* self, struct type* rhs) return 1; } +int type_equiv(struct type* self, struct type* rhs) +{ + assert(self); + assert(rhs); + + if (type_equals(self, rhs)) + { + return 1; + } + + if (self->kind == TYPE_RAW_PTR + && type_equals(self->subtypes.data[0], rhs)) + { + return 1; + } + + return 0; +} + void type_add_subtype(struct type* self, enum TypeKind kind) { assert(self); @@ -164,6 +203,11 @@ size_t type_str(struct type* self, char* buffer, size_t size) assert(buffer); size_t sz = 0; + if (0 && self->is_var) + { + sz += snprintf(buffer + sz, size - sz, "VAR_"); + } + sz += snprintf(buffer + sz, size - sz, "%s", TypeKindStr[self->kind] + strlen("TYPE_")); diff --git a/lang/src/type.h b/lang/src/type.h index f0d548b..3f3b57d 100644 --- a/lang/src/type.h +++ b/lang/src/type.h @@ -7,13 +7,15 @@ #define TYPE_KIND(G) \ G(TYPE_VOID), G(TYPE_BOOL), G(TYPE_INT), \ - G(TYPE_FLOAT), G(TYPE_STRING), G(TYPE_FUN) + G(TYPE_FLOAT), G(TYPE_STRING), G(TYPE_FUN), \ + G(TYPE_RAW_PTR) GUX_ENUM_H(TypeKind, TYPE_KIND); struct type { enum TypeKind kind; struct vec subtypes; + int is_var; }; void type_init(struct type* self, enum TypeKind kind); @@ -24,6 +26,8 @@ void type_copy(struct type* self, struct type* dest); void type_clear(struct type* self); int type_equals(struct type* self, struct type* rhs); +int type_equiv(struct type* self, struct type* rhs); + void type_add_subtype(struct type* self, enum TypeKind kind); size_t type_str(struct type* self, char* buffer, size_t size); int type_is(struct type* self, char const* repr); diff --git a/lang/src/type_checker.c b/lang/src/type_checker.c index 8a66b60..6f87cf1 100644 --- a/lang/src/type_checker.c +++ b/lang/src/type_checker.c @@ -44,7 +44,7 @@ int type_checker_check(struct type_checker* self, return 1; } - if (!type_equals(&fun_ty, &ret_ty)) + if (!type_equiv(&fun_ty, &ret_ty)) { type_checker_error_msg(self, node, &fun_ty, &ret_ty); @@ -109,7 +109,6 @@ int type_checker_check(struct type_checker* self, { struct type* sub = ty->subtypes.data[i + 1]; struct node* sub_node = args->children.data[i]; - struct type t; type_init(&t, TYPE_VOID); @@ -127,13 +126,22 @@ int type_checker_check(struct type_checker* self, return 1; } - if (!type_equals(&t, sub)) + if (!type_equiv(&t, sub)) { type_checker_error_msg(self, sub_node, sub, &t); type_free(&t); return 1; } + if (!t.is_var && sub->is_var) + { + snprintf(self->error_msg, GUX_STR_SIZE, + "<%s> is not mutable", sub_node->value); + self->error_line = sub_node->line; + type_free(&t); + return 1; + } + type_free(&t); } @@ -149,6 +157,9 @@ int type_checker_check(struct type_checker* self, struct vec names; vec_init(&names, 1); + struct vec vars; + vec_init(&vars, 1); + for (size_t i=0; ichildren.size; i++) { struct node* param = params->children.data[i]; @@ -161,16 +172,34 @@ int type_checker_check(struct type_checker* self, struct type* ty = malloc(sizeof(struct type)); type_init_from_node(ty, param); - sym_table_declare_const(&self->sym_table, - n->value, - ty); + int* var = vars.data[j]; + ty->is_var = *var; + + sym_table_declare(&self->sym_table, + n->value, + ty, + *var); } vec_free(&names); vec_init(&names, 1); + vec_free_elements(&vars); + vec_free(&vars); + vec_init(&vars, 1); } - else + else if (param->type == NODE_VAR) { + int* var = malloc(sizeof(int)); + *var = 1; + vec_push(&vars, var); + vec_push(&names, params->children.data[i + 1]); + i++; + } + else if (param->type == NODE_IDENT) + { + int* var = malloc(sizeof(int)); + *var = 0; + vec_push(&vars, var); vec_push(&names, param); } } @@ -220,6 +249,8 @@ int type_checker_check(struct type_checker* self, type_free(&ret_ty); vec_free(&ret_instrs); vec_free(&names); + vec_free_elements(&vars); + vec_free(&vars); sym_table_pop_table(&self->sym_table); } @@ -235,7 +266,7 @@ int type_checker_check(struct type_checker* self, struct type want; type_init(&want, TYPE_BOOL); - if (!type_equals(&have, &want)) + if (!type_equiv(&have, &want)) { type_checker_error_msg(self, node, &want, &have); type_free(&have); @@ -301,7 +332,7 @@ int type_checker_check(struct type_checker* self, return 1; } - if (!entry->is_var) + if (!entry->type->is_var) { snprintf(self->error_msg, GUX_STR_SIZE, "<%s> is not mutable", ident->value); @@ -317,7 +348,7 @@ int type_checker_check(struct type_checker* self, type_resolver_resolve(&self->resolver, expr, &expr_type); - if (!type_equals(var_type, &expr_type)) + if (!type_equiv(var_type, &expr_type)) { type_checker_error_msg(self, node, var_type, &expr_type); type_free(&expr_type); @@ -331,8 +362,8 @@ int type_checker_check(struct type_checker* self, case NODE_CONSTDECL:{ struct type type; type_init(&type, TYPE_VOID); - - type_resolver_resolve(&self->resolver, node->children.data[0], &type); + type_resolver_resolve(&self->resolver, + node->children.data[0], &type); struct sym* entry = sym_table_fetch(&self->sym_table, node->value, @@ -370,6 +401,11 @@ int type_checker_check(struct type_checker* self, if (type_resolver_resolve(&self->resolver, expr, ty) != 0) { + char expr_str[GUX_STR_SIZE]; + node_str(expr, expr_str, GUX_STR_SIZE); + snprintf(self->error_msg, GUX_STR_SIZE * 2, + "cannot find type of <%s>.", expr_str); + self->error_line = expr->line; type_free(ty); free(ty); return 1; @@ -479,7 +515,7 @@ int type_checker_check(struct type_checker* self, lhs_msg); } } - else if (!type_equals(&lhs_type, &rhs_type)) + else if (!type_equiv(&lhs_type, &rhs_type)) { snprintf(self->error_msg, MSG_SZ, "type mismatch (<%s>, <%s>)", @@ -489,7 +525,7 @@ int type_checker_check(struct type_checker* self, if (solve_lhs != 0 || solve_rhs != 0 - || !type_equals(&lhs_type, &rhs_type) + || !type_equiv(&lhs_type, &rhs_type) || lhs_type.subtypes.size > 0 || rhs_type.subtypes.size > 0 || (lhs_type.kind != TYPE_INT && lhs_type.kind != TYPE_FLOAT) @@ -549,7 +585,7 @@ int type_checker_check(struct type_checker* self, node->children.data[i], &node_type); - if (!type_equals(&type, &node_type)) + if (!type_equiv(&type, &node_type)) { self->error_line = node->line; snprintf(self->error_msg, diff --git a/lang/src/type_resolver.c b/lang/src/type_resolver.c index 5c08062..4a65b1c 100644 --- a/lang/src/type_resolver.c +++ b/lang/src/type_resolver.c @@ -1,4 +1,5 @@ #include "type_resolver.h" +#include "commons.h" #include "node.h" #include "sym_table.h" #include "type.h" @@ -27,6 +28,14 @@ int type_resolver_resolve(struct type_resolver* self, switch (node->type) { + case NODE_NEW: { + type->kind = TYPE_RAW_PTR; + type_add_subtype(type, TYPE_VOID); + type_resolver_resolve(self, node->children.data[0], + type->subtypes.data[0]); + + } return 0; + case NODE_RETURN: { if (node->children.size == 0) { @@ -99,8 +108,8 @@ int type_resolver_resolve(struct type_resolver* self, type_copy(ty, type); - //sym_table_declare(self->sym_table, node->value, ty, - // node->type == NODE_VARDECL); + type_free(ty); + free(ty); } return 0; @@ -167,7 +176,7 @@ int type_resolver_resolve(struct type_resolver* self, type_init(&rhs, TYPE_VOID); type_resolver_resolve(self, node->children.data[1], &rhs); - int equals = type_equals(&lhs, &rhs); + int equals = type_equiv(&lhs, &rhs); if (type_is(&lhs, "INT") && equals) { @@ -191,6 +200,16 @@ int type_resolver_resolve(struct type_resolver* self, { type->kind = TYPE_STRING; } + else if (lhs.kind == TYPE_RAW_PTR) + { + struct type* sub = lhs.subtypes.data[0]; + type->kind = sub->kind; + } + else if (rhs.kind == TYPE_RAW_PTR) + { + struct type* sub = rhs.subtypes.data[0]; + type->kind = sub->kind; + } else { type_free(&lhs); diff --git a/lang/src/value.c b/lang/src/value.c index 6dae366..bb6a567 100644 --- a/lang/src/value.c +++ b/lang/src/value.c @@ -1,4 +1,5 @@ #include "value.h" +#include "commons.h" #include "native.h" #include "type.h" #include "fun.h" @@ -66,6 +67,18 @@ void value_init_new_native(struct value* self, native_fun_t native, self->is_native = 1; } +void value_init_new_rawptr(struct value* self, int addr, + struct type* type, int line) +{ + assert(self); + + type_init(&self->type, TYPE_VOID); + type_copy(type, &self->type); + self->data.addr = addr; + self->line = line; + self->is_native = 0; +} + void value_free(struct value* self) { assert(self); @@ -114,6 +127,13 @@ size_t value_str(struct value* self, char* buffer, size_t size) size_t sz = 0; + if (self->type.kind == TYPE_RAW_PTR) + { + sz += snprintf(buffer + sz, size - sz, "", + self->data.addr); + return sz; + } + if (self->type.kind == TYPE_FUN) { sz += snprintf(buffer + sz, size - sz, ""); diff --git a/lang/src/value.h b/lang/src/value.h index 172dbce..73ddcc6 100644 --- a/lang/src/value.h +++ b/lang/src/value.h @@ -13,6 +13,7 @@ union value_data { char* s; float f; int i; + int addr; struct fun* fun; native_fun_t native; }; @@ -31,6 +32,8 @@ 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_init_new_rawptr(struct value* self, int addr, + struct type* type, int line); void value_free(struct value* self); diff --git a/lang/tests/lexer.c b/lang/tests/lexer.c index afac7fc..863b5a0 100644 --- a/lang/tests/lexer.c +++ b/lang/tests/lexer.c @@ -127,8 +127,10 @@ Test(lexer, ident) { } Test(lexer, var_types) { - test_lexer("int float bool string", 4, - "TYPE[int]", "TYPE[float]", "TYPE[bool]", "TYPE[string]"); + test_lexer("int float bool string ^", 5, + "TYPE[int]", "TYPE[float]", + "TYPE[bool]", "TYPE[string]", + "PTR"); } Test(lexer, blocks) { @@ -143,3 +145,7 @@ Test(lexer, flow_control) { Test(lexer, fun) { test_lexer("-> fun return,", 4, "RARROW", "FUN", "RETURN", "COMMA"); } + +Test(lexer, mem) { + test_lexer("new free", 2, "NEW", "FREE"); +} diff --git a/lang/tests/parser.c b/lang/tests/parser.c index 39765e2..444a7ff 100644 --- a/lang/tests/parser.c +++ b/lang/tests/parser.c @@ -174,6 +174,9 @@ Test(parser, types) { test_parser("ROOT(CONSTDECL[x](" "TYPE[fun](TYPE[int],TYPE[int],RARROW,TYPE[float]),INT[0]))", "x : (int int -> float) = 0;"); + + test_parser("ROOT(CONSTDECL[x](TYPE[rawptr](TYPE[float]),INT[0]))", + "x : ^float = 0;"); } Test(parser, fun_call) { @@ -194,6 +197,15 @@ Test(parser, fun_decl) { test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[n],TYPE[int])," "TYPE[int],BLOCK(RETURN(IDENT[n])))))", "fun hello (n: int) -> int { return n; }"); + + test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(VAR,IDENT[n],TYPE[int])," + "TYPE[int],BLOCK(RETURN(IDENT[n])))))", + "fun hello (var n: int) -> int { return n; }"); + + test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[m],TYPE[float]," + "VAR,IDENT[n],TYPE[int])," + "TYPE[int],BLOCK(RETURN(IDENT[n])))))", + "fun hello (m: float, var n: int) -> int { return n; }"); } Test(parser, param_sugar) { @@ -202,3 +214,11 @@ Test(parser, param_sugar) { "TYPE[int],BLOCK(RETURN(IDENT[n])))))", "fun hello (n, m, k: int) -> int { return n; }"); } + +Test(parser, mem) { + test_parser("ROOT(CONSTDECL[x](NEW(INT[32])))", + "x := new 32;"); + + test_parser("ROOT(FREE(IDENT[hello]))", + "free hello;"); +} diff --git a/lib/src/vec.c b/lib/src/vec.c index 1fbc146..27f4cf7 100644 --- a/lib/src/vec.c +++ b/lib/src/vec.c @@ -44,6 +44,20 @@ void* vec_pop(struct vec* self) return element; } +void* vec_remove(struct vec* self, size_t index) +{ + assert(index < self->size); + void* to_remove = self->data[index]; + void* tmp = self->data[self->size - 1]; + + self->data[self->size - 1] = to_remove; + to_remove = tmp; + + vec_pop(self); + + return to_remove; +} + void vec_free_elements(struct vec* self) { assert(self); diff --git a/lib/src/vec.h b/lib/src/vec.h index 7eb590e..dd7db57 100644 --- a/lib/src/vec.h +++ b/lib/src/vec.h @@ -14,6 +14,7 @@ void vec_free(struct vec* self); void vec_push(struct vec* self, void* element); void* vec_pop(struct vec* self); +void* vec_remove(struct vec* self, size_t index); void vec_free_elements(struct vec* self); diff --git a/tests/mem.gux b/tests/mem.gux new file mode 100644 index 0000000..9855139 --- /dev/null +++ b/tests/mem.gux @@ -0,0 +1,15 @@ +fun incr(var n: ^int) { + n = n + 1; + n = n * 2; +} + +var a : ^int = new 43; + +assert a == 43; + +incr(a); +a = a + 1; + +assert a == 89; + +free a; \ No newline at end of file diff --git a/vm/src/vm.c b/vm/src/vm.c index 88a670a..f2499f7 100644 --- a/vm/src/vm.c +++ b/vm/src/vm.c @@ -17,6 +17,7 @@ void vm_init(struct vm* self, struct vec* natives) memset(self->error_msg, 0, GUX_STR_SIZE); vm_add_frame(self); + vec_init(&self->heap, 1); } void vm_free(struct vm* self) @@ -31,6 +32,16 @@ void vm_free(struct vm* self) } self->fp = 0; + + for (size_t i=0; iheap.size; i++) + { + struct heap_item* item = self->heap.data[i]; + value_free(item->value); + free(item->value); + } + + vec_free_elements(&self->heap); + vec_free(&self->heap); } void vm_add_frame(struct vm* self) @@ -131,6 +142,99 @@ int vm_exec(struct vm* self, struct program* program) switch (opcode) { + case OP_FREE: { + int ref_val = vm_load(self, param); + int stack_addr = frame->stack[ref_val]; + + struct value* ref = program->constant_pool.data[stack_addr]; + int addr = ref->data.addr; + + ssize_t value_idx = vm_heap_try_find(self, addr); + + if (value_idx == -1) + { + snprintf(self->error_msg, GUX_STR_SIZE, "wrong address"); + return 1; + } + + int stack_val = vm_pop(self); + struct value* stack = program->constant_pool.data[stack_val]; + assert(stack); + + struct heap_item* item = vec_remove(&self->heap, value_idx); + + value_free(item->value); + free(item->value); + free(item); + + self->pc++; + } break; + + case OP_REFSTORE: { + int ref_val = vm_load(self, param); + int stack_addr = frame->stack[ref_val]; + + struct value* ref = program->constant_pool.data[stack_addr]; + + int addr = ref->data.addr; + + ssize_t value_idx = vm_heap_try_find(self, addr); + + if (value_idx == -1) + { + snprintf(self->error_msg, GUX_STR_SIZE, "wrong address"); + return 1; + } + + int stack_val = vm_pop(self); + struct value* stack = program->constant_pool.data[stack_val]; + assert(stack); + + struct heap_item* item = self->heap.data[value_idx]; + + value_free(item->value); + free(item->value); + item->value = value_new_clone(stack); + + self->pc++; + } break; + + case OP_DEREF: { + int val = vm_pop(self); + struct value* ref = program->constant_pool.data[val]; + + struct value* value = value_new_clone + (vm_heap_try_load(self, ref->data.addr)); + assert(value); + + vm_push(self, + program_push_constant(program, value)); + + self->pc++; + } break; + + case OP_NEW: { + int val = vm_pop(self); + struct value* value = + value_new_clone(program->constant_pool.data[val]); + + vm_heap_store_new(self, param, value); + + struct type type; + type_init(&type, TYPE_RAW_PTR); + type_add_subtype(&type, TYPE_VOID); + type_copy(&value->type, type.subtypes.data[0]); + + struct value* ref = malloc(sizeof(struct value)); + value_init_new_rawptr(ref, param, &type, value->line); + type_free(&type); + + vm_push(self, + program_push_constant(program, ref)); + + self->pc++; + } break; + case OP_CALL: { int fun_addr = vm_pop(self); struct value* fun_val = program->constant_pool.data[fun_addr]; @@ -202,7 +306,12 @@ int vm_exec(struct vm* self, struct program* program) size_t ret_addr = self->pc; self->pc = 0; - vm_exec(self, &fun->program); + if (vm_exec(self, &fun->program) != 0) + { + vec_free_elements(&args); + vec_free(&args); + return 1; + } vec_free_elements(&args); vec_free(&args); @@ -327,8 +436,11 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val = + vm_try_get_val(self, program->constant_pool.data[lhs]); + + struct value* rhs_val = + vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = malloc(sizeof(struct value)); @@ -371,8 +483,11 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val = + vm_try_get_val(self, program->constant_pool.data[lhs]); + + struct value* rhs_val = + vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_add(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -384,8 +499,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val = + vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val = + vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_sub(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -397,8 +514,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_mul(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -410,8 +529,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_div(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -423,8 +544,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_mod(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -436,8 +559,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_pow(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -449,8 +574,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_lt(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -462,8 +589,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_le(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -475,8 +604,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_gt(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -488,8 +619,10 @@ int vm_exec(struct vm* self, struct program* program) int rhs = vm_pop(self); int lhs = vm_pop(self); - struct value* lhs_val = program->constant_pool.data[lhs]; - struct value* rhs_val = program->constant_pool.data[rhs]; + struct value* lhs_val + = vm_try_get_val(self, program->constant_pool.data[lhs]); + struct value* rhs_val + = vm_try_get_val(self, program->constant_pool.data[rhs]); struct value* res = value_try_new_ge(lhs_val, rhs_val); vm_push(self, program_push_constant(program, res)); @@ -512,6 +645,8 @@ size_t vm_str(struct vm* self, struct program* program, size_t sz = 0; + sz += snprintf(buffer + sz, size - sz, "--- STACKS ---\n"); + for (size_t i=0; ifp; i++) { struct frame* frame = self->stack[i]; @@ -529,5 +664,108 @@ size_t vm_str(struct vm* self, struct program* program, } } + sz += snprintf(buffer + sz, size - sz, "--- HEAP ---\n"); + + for (size_t i=0; iheap.size; i++) + { + struct heap_item* item = self->heap.data[i]; + char val_str[GUX_STR_SIZE]; + value_str(item->value, val_str, GUX_STR_SIZE); + + sz += snprintf(buffer + sz, size - sz, "%i %s\n", + item->addr, + val_str); + } + return sz; } + +void vm_heap_store_new(struct vm* self, int addr, struct value* value) +{ + assert(self); + struct heap_item* item = malloc(sizeof(struct heap_item)); + item->addr = addr; + item->value = value; + vec_push(&self->heap, item); +} + +struct value* vm_heap_try_load(struct vm* self, int addr) +{ + assert(self); + + for (size_t i=0; iheap.size; i++) + { + struct heap_item* item = self->heap.data[i]; + + if (item->addr == addr) + { + return item->value; + } + } + + return NULL; +} + +ssize_t vm_heap_try_find(struct vm* self, int addr) +{ + assert(self); + + for (size_t i=0; iheap.size; i++) + { + struct heap_item* item = self->heap.data[i]; + + if (item->addr == addr) + { + return i; + } + } + + return -1; +} + +int vm_heap_free(struct vm* self, int addr) +{ + assert(self); + + size_t idx = 0; + int found = 0; + + for (size_t i=0; iheap.size; i++) + { + struct heap_item* item = self->heap.data[i]; + + if (item->addr == addr) + { + found = 1; + idx = i; + break; + } + } + + if (!found) { return 1; } + + struct heap_item* tmp = self->heap.data[self->heap.size - 1]; + self->heap.data[self->heap.size - 1] = self->heap.data[idx]; + self->heap.data[idx] = tmp; + + vec_pop(&self->heap); + + return 0; +} + +struct value* vm_try_get_val(struct vm* self, struct value* value) +{ + assert(self); + assert(value); + + if (value->type.kind == TYPE_RAW_PTR) + { + struct value* v = vm_heap_try_load(self, value->data.addr); + assert(v); + return v; + } + else + { + return value; + } +} diff --git a/vm/src/vm.h b/vm/src/vm.h index 0a3f1ed..aa5693d 100644 --- a/vm/src/vm.h +++ b/vm/src/vm.h @@ -12,6 +12,11 @@ struct local { int stack_addr; }; +struct heap_item { + int addr; + struct value* value; +}; + struct frame { int stack[STACK_DEPTH]; size_t sp; @@ -26,6 +31,7 @@ struct vm { size_t fp; struct frame* stack[FRAME_DEPTH]; struct vec* natives; + struct vec heap; }; void vm_init(struct vm* self, struct vec* natives); @@ -44,4 +50,10 @@ int vm_exec(struct vm* self, struct program* program); size_t vm_str(struct vm* self, struct program* program, char* buffer, size_t size); +void vm_heap_store_new(struct vm* self, int addr, struct value* value); +struct value* vm_heap_try_load(struct vm* self, int addr); +ssize_t vm_heap_try_find(struct vm* self, int addr); +int vm_heap_free(struct vm* self, int addr); +struct value* vm_try_get_val(struct vm* self, struct value* value); + #endif