✨ native function support.
parent
09bbc31320
commit
76e0cdbeef
|
@ -6,6 +6,7 @@
|
|||
#include <compiler.h>
|
||||
#include <vm.h>
|
||||
#include <sym_table.h>
|
||||
#include <native.h>
|
||||
|
||||
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; i<natives.size; i++)
|
||||
{ value_free(natives.data[i]); }
|
||||
vec_free_elements(&natives);
|
||||
vec_free(&natives);
|
||||
|
||||
if (ast)
|
||||
{
|
||||
node_free(ast);
|
||||
|
@ -196,7 +211,7 @@ int main(int argc, char** argv)
|
|||
program_init(&program);
|
||||
|
||||
struct compiler compiler;
|
||||
compiler_init(&compiler);
|
||||
compiler_init(&compiler, &globals);
|
||||
|
||||
if (compiler_compile(&compiler, ast, &program) != 0)
|
||||
{
|
||||
|
@ -209,6 +224,12 @@ int main(int argc, char** argv)
|
|||
program_free(&program);
|
||||
|
||||
type_checker_free(&checker);
|
||||
sym_table_free(&globals);
|
||||
|
||||
for (size_t i=0; i<natives.size; i++)
|
||||
{ value_free(natives.data[i]); }
|
||||
vec_free_elements(&natives);
|
||||
vec_free(&natives);
|
||||
|
||||
if (ast)
|
||||
{
|
||||
|
@ -246,7 +267,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
struct vm vm;
|
||||
vm_init(&vm);
|
||||
vm_init(&vm, &natives);
|
||||
|
||||
err = vm_exec(&vm, &program);
|
||||
|
||||
|
@ -262,6 +283,12 @@ int main(int argc, char** argv)
|
|||
compiler_free(&compiler);
|
||||
program_free(&program);
|
||||
type_checker_free(&checker);
|
||||
sym_table_free(&globals);
|
||||
|
||||
for (size_t i=0; i<natives.size; i++)
|
||||
{ value_free(natives.data[i]); }
|
||||
vec_free_elements(&natives);
|
||||
vec_free(&natives);
|
||||
|
||||
if (ast)
|
||||
{
|
||||
|
@ -297,6 +324,12 @@ int main(int argc, char** argv)
|
|||
compiler_free(&compiler);
|
||||
program_free(&program);
|
||||
type_checker_free(&checker);
|
||||
sym_table_free(&globals);
|
||||
|
||||
for (size_t i=0; i<natives.size; i++)
|
||||
{ value_free(natives.data[i]); }
|
||||
vec_free_elements(&natives);
|
||||
vec_free(&natives);
|
||||
|
||||
if (ast)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@ add_library(gux-lang OBJECT
|
|||
src/type.c
|
||||
src/value.c
|
||||
src/fun.c
|
||||
src/native.c
|
||||
src/type_resolver.c
|
||||
src/type_checker.c
|
||||
src/sym_table.c
|
||||
|
|
|
@ -6,14 +6,15 @@
|
|||
#include "sym_table.h"
|
||||
#include "type.h"
|
||||
#include "type_checker.h"
|
||||
#include "type_resolver.h"
|
||||
#include "value.h"
|
||||
#include "vec.h"
|
||||
#include "fun.h"
|
||||
|
||||
void compiler_init(struct compiler* self)
|
||||
void compiler_init(struct compiler* self, struct sym_table* global)
|
||||
{
|
||||
assert(self);
|
||||
sym_table_init(&self->sym_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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef NATIVE_H
|
||||
#define NATIVE_H
|
||||
|
||||
#include <commons.h>
|
||||
#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
|
|
@ -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 <commons.h>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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; i<table->syms.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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; i<args->children.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; i<node->children.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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <commons.h>
|
||||
#include <type.h>
|
||||
#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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ');
|
44
vm/src/vm.c
44
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; i<args.size; i++)
|
||||
{
|
||||
int addr = *(int*)args.data[i];
|
||||
vec_push(&fun_args, program->constant_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; i<args.size; i++)
|
||||
{
|
||||
size_t k = args.size - 1 - i;
|
||||
|
@ -203,6 +232,17 @@ int vm_exec(struct vm* self, struct program* program)
|
|||
self->pc++;
|
||||
} 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];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue