raw pointers.

main
bog 2024-02-20 22:23:58 +01:00
parent bf91985e00
commit d1286c008b
24 changed files with 597 additions and 79 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 <commons.h>

View File

@ -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

View File

@ -14,10 +14,13 @@ void program_free(struct program* self)
for (size_t i=0; i<self->constant_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);

View File

@ -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);

View File

@ -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;

View File

@ -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; i<params->children.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; i<self->subtypes.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_"));

View File

@ -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);

View File

@ -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; i<params->children.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,

View File

@ -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);

View File

@ -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, "<raw ptr: %d>",
self->data.addr);
return sz;
}
if (self->type.kind == TYPE_FUN)
{
sz += snprintf(buffer + sz, size - sz, "<function>");

View File

@ -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);

View File

@ -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");
}

View File

@ -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;");
}

View File

@ -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);

View File

@ -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);

15
tests/mem.gux Normal file
View File

@ -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;

View File

@ -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; i<self->heap.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; i<self->fp; 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; i<self->heap.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; i<self->heap.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; i<self->heap.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; i<self->heap.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;
}
}

View File

@ -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