✨ native function support.
parent
09bbc31320
commit
76e0cdbeef
|
@ -6,6 +6,7 @@
|
||||||
#include <compiler.h>
|
#include <compiler.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
#include <sym_table.h>
|
#include <sym_table.h>
|
||||||
|
#include <native.h>
|
||||||
|
|
||||||
char* load_new_source(char const* path)
|
char* load_new_source(char const* path)
|
||||||
{
|
{
|
||||||
|
@ -159,8 +160,16 @@ int main(int argc, char** argv)
|
||||||
printf("%s\n", msg);
|
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;
|
struct type_checker checker;
|
||||||
type_checker_init(&checker);
|
type_checker_init(&checker, &globals);
|
||||||
|
|
||||||
if (type_checker_check(&checker, ast) != 0)
|
if (type_checker_check(&checker, ast) != 0)
|
||||||
{
|
{
|
||||||
|
@ -171,6 +180,12 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
type_checker_free(&checker);
|
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)
|
if (ast)
|
||||||
{
|
{
|
||||||
node_free(ast);
|
node_free(ast);
|
||||||
|
@ -196,7 +211,7 @@ int main(int argc, char** argv)
|
||||||
program_init(&program);
|
program_init(&program);
|
||||||
|
|
||||||
struct compiler compiler;
|
struct compiler compiler;
|
||||||
compiler_init(&compiler);
|
compiler_init(&compiler, &globals);
|
||||||
|
|
||||||
if (compiler_compile(&compiler, ast, &program) != 0)
|
if (compiler_compile(&compiler, ast, &program) != 0)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +224,12 @@ int main(int argc, char** argv)
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
|
|
||||||
type_checker_free(&checker);
|
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)
|
if (ast)
|
||||||
{
|
{
|
||||||
|
@ -246,7 +267,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vm vm;
|
struct vm vm;
|
||||||
vm_init(&vm);
|
vm_init(&vm, &natives);
|
||||||
|
|
||||||
err = vm_exec(&vm, &program);
|
err = vm_exec(&vm, &program);
|
||||||
|
|
||||||
|
@ -262,6 +283,12 @@ int main(int argc, char** argv)
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
type_checker_free(&checker);
|
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)
|
if (ast)
|
||||||
{
|
{
|
||||||
|
@ -297,6 +324,12 @@ int main(int argc, char** argv)
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
type_checker_free(&checker);
|
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)
|
if (ast)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@ add_library(gux-lang OBJECT
|
||||||
src/type.c
|
src/type.c
|
||||||
src/value.c
|
src/value.c
|
||||||
src/fun.c
|
src/fun.c
|
||||||
|
src/native.c
|
||||||
src/type_resolver.c
|
src/type_resolver.c
|
||||||
src/type_checker.c
|
src/type_checker.c
|
||||||
src/sym_table.c
|
src/sym_table.c
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
#include "sym_table.h"
|
#include "sym_table.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "type_checker.h"
|
#include "type_checker.h"
|
||||||
|
#include "type_resolver.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self)
|
void compiler_init(struct compiler* self, struct sym_table* global)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
sym_table_init(&self->sym_table);
|
sym_table_init(&self->sym_table, global);
|
||||||
memset(self->error_msg, 0, GUX_STR_SIZE);
|
memset(self->error_msg, 0, GUX_STR_SIZE);
|
||||||
self->stack_size = 0;
|
self->stack_size = 0;
|
||||||
vec_init(&self->loops, 1);
|
vec_init(&self->loops, 1);
|
||||||
|
@ -55,7 +56,7 @@ int compiler_compile(struct compiler* self,
|
||||||
sym_table_push_table(&self->sym_table);
|
sym_table_push_table(&self->sym_table);
|
||||||
|
|
||||||
struct compiler compiler;
|
struct compiler compiler;
|
||||||
compiler_init(&compiler);
|
compiler_init(&compiler, self->sym_table.prev);
|
||||||
|
|
||||||
struct vec idents;
|
struct vec idents;
|
||||||
vec_init(&idents, 1);
|
vec_init(&idents, 1);
|
||||||
|
@ -75,7 +76,7 @@ int compiler_compile(struct compiler* self,
|
||||||
struct node* ident = idents.data[j];
|
struct node* ident = idents.data[j];
|
||||||
|
|
||||||
struct type* ty = malloc(sizeof(struct type));
|
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,
|
sym_table_declare_const(&compiler.sym_table,
|
||||||
ident->value,
|
ident->value,
|
||||||
|
@ -129,7 +130,15 @@ int compiler_compile(struct compiler* self,
|
||||||
|
|
||||||
assert(entry);
|
assert(entry);
|
||||||
|
|
||||||
|
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_LOAD, entry->addr);
|
||||||
|
}
|
||||||
|
|
||||||
compiler_gen_instr(self, program, OP_CALL, args->children.size);
|
compiler_gen_instr(self, program, OP_CALL, args->children.size);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -261,7 +270,14 @@ int compiler_compile(struct compiler* self,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_LOAD, entry->addr);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_CONSTDECL:
|
case NODE_CONSTDECL:
|
||||||
|
@ -278,7 +294,8 @@ int compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct type* ty = malloc(sizeof(struct type));
|
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,
|
sym_table_declare(&self->sym_table, node->value, ty,
|
||||||
node->type == NODE_VARDECL);
|
node->type == NODE_VARDECL);
|
||||||
|
@ -315,6 +332,7 @@ int compiler_compile(struct compiler* self,
|
||||||
|
|
||||||
case NODE_STRING: {
|
case NODE_STRING: {
|
||||||
struct value* val = malloc(sizeof(struct value));
|
struct value* val = malloc(sizeof(struct value));
|
||||||
|
|
||||||
value_init_string(val, node->value, node->line);
|
value_init_string(val, node->value, node->line);
|
||||||
size_t addr = program_push_constant(program, val);
|
size_t addr = program_push_constant(program, val);
|
||||||
compiler_gen_instr(self, program, OP_PUSH, addr);
|
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_CALL: break;
|
||||||
|
|
||||||
case OP_LOAD:
|
case OP_LOAD:
|
||||||
|
case OP_GLOAD:
|
||||||
case OP_PUSH: self->stack_size += 1; break;
|
case OP_PUSH: self->stack_size += 1; break;
|
||||||
|
|
||||||
case OP_LT:
|
case OP_LT:
|
||||||
|
@ -627,3 +646,14 @@ size_t compiler_gen_instr(struct compiler* self,
|
||||||
|
|
||||||
return addr;
|
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;
|
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);
|
void compiler_free(struct compiler* self);
|
||||||
|
|
||||||
int compiler_compile(struct compiler* self,
|
int compiler_compile(struct compiler* self,
|
||||||
|
@ -36,4 +36,7 @@ size_t compiler_gen_instr(struct compiler* self,
|
||||||
enum Opcodes op,
|
enum Opcodes op,
|
||||||
int param);
|
int param);
|
||||||
|
|
||||||
|
size_t compiler_get_type(struct compiler* self,
|
||||||
|
struct node* node,
|
||||||
|
struct type* type);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -430,8 +430,32 @@ int lexer_scan_string(struct lexer* self,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++];
|
value[sz++] = self->source[cursor++];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (found)
|
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_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_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_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>
|
#include <commons.h>
|
||||||
|
|
||||||
|
|
|
@ -459,6 +459,7 @@ struct node* parser_try_new_params(struct parser* self)
|
||||||
node->children.data[idx] = node_new_clone(type);
|
node->children.data[idx] = node_new_clone(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec_free_elements(&types);
|
||||||
vec_free(&types);
|
vec_free(&types);
|
||||||
vec_init(&types, 1);
|
vec_init(&types, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
#include "sym_table.h"
|
#include "sym_table.h"
|
||||||
|
#include "commons.h"
|
||||||
#include "vec.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);
|
assert(self);
|
||||||
self->root = NULL;
|
self->root = NULL;
|
||||||
|
|
||||||
sym_table_push_table(self);
|
sym_table_push_table(self);
|
||||||
self->addr_counter = 0;
|
self->addr_counter = 0;
|
||||||
|
|
||||||
|
self->prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_table_free(struct sym_table* self)
|
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;
|
table = table->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->prev)
|
||||||
|
{
|
||||||
|
return sym_table_try_by_name(self->prev, name);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +132,7 @@ int sym_table_declare(struct sym_table* self,
|
||||||
sym->name = strdup(name);
|
sym->name = strdup(name);
|
||||||
sym->type = new_type;
|
sym->type = new_type;
|
||||||
sym->parent = self->root;
|
sym->parent = self->root;
|
||||||
|
sym->is_global = 0;
|
||||||
sym->is_var = is_var;
|
sym->is_var = is_var;
|
||||||
sym->addr = self->addr_counter;
|
sym->addr = self->addr_counter;
|
||||||
vec_push(&table->syms, sym);
|
vec_push(&table->syms, sym);
|
||||||
|
@ -133,6 +142,34 @@ int sym_table_declare(struct sym_table* self,
|
||||||
return 0;
|
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)
|
size_t sym_table_str(struct sym_table* self, char* buffer, size_t size)
|
||||||
{
|
{
|
||||||
assert(self);
|
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++)
|
for (size_t i=0; i<table->syms.size; i++)
|
||||||
{
|
{
|
||||||
struct sym* sym = table->syms.data[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,
|
sz += snprintf(buffer + sz, size - sz,
|
||||||
"[%s::%p] -> %d\n",
|
"[%s::%p, %s] -> %d\n",
|
||||||
sym->name, sym->parent, sym->addr);
|
sym->name, sym->parent, type, sym->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
@ -9,6 +9,7 @@ struct sym {
|
||||||
struct table* parent;
|
struct table* parent;
|
||||||
char* name;
|
char* name;
|
||||||
int is_var;
|
int is_var;
|
||||||
|
int is_global;
|
||||||
int addr;
|
int addr;
|
||||||
struct type* type;
|
struct type* type;
|
||||||
};
|
};
|
||||||
|
@ -19,11 +20,12 @@ struct table {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sym_table {
|
struct sym_table {
|
||||||
|
struct sym_table* prev;
|
||||||
struct table* root;
|
struct table* root;
|
||||||
int addr_counter;
|
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_free(struct sym_table* self);
|
||||||
|
|
||||||
void sym_table_push_table(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,
|
struct type* new_type,
|
||||||
int is_var);
|
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);
|
size_t sym_table_str(struct sym_table* self, char* buffer, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#include "type_resolver.h"
|
#include "type_resolver.h"
|
||||||
#include "fun.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);
|
assert(self);
|
||||||
sym_table_init(&self->sym_table);
|
sym_table_init(&self->sym_table, global);
|
||||||
type_resolver_init(&self->resolver, &self->sym_table);
|
type_resolver_init(&self->resolver, &self->sym_table);
|
||||||
memset(self->error_msg, 0, GUX_STR_SIZE);
|
memset(self->error_msg, 0, GUX_STR_SIZE);
|
||||||
vec_init(&self->fun_stack, 1);
|
vec_init(&self->fun_stack, 1);
|
||||||
|
@ -81,7 +81,6 @@ int type_checker_check(struct type_checker* self,
|
||||||
case NODE_CALL: {
|
case NODE_CALL: {
|
||||||
struct node* target = node->children.data[0];
|
struct node* target = node->children.data[0];
|
||||||
struct node* args = node->children.data[1];
|
struct node* args = node->children.data[1];
|
||||||
|
|
||||||
struct sym* entry = sym_table_try_by_name(&self->sym_table,
|
struct sym* entry = sym_table_try_by_name(&self->sym_table,
|
||||||
target->value);
|
target->value);
|
||||||
|
|
||||||
|
@ -96,6 +95,7 @@ int type_checker_check(struct type_checker* self,
|
||||||
struct type* ty = entry->type;
|
struct type* ty = entry->type;
|
||||||
assert(ty);
|
assert(ty);
|
||||||
|
|
||||||
|
|
||||||
if (ty->subtypes.size - 1 != args->children.size)
|
if (ty->subtypes.size - 1 != args->children.size)
|
||||||
{
|
{
|
||||||
self->error_line = node->line;
|
self->error_line = node->line;
|
||||||
|
@ -104,6 +104,29 @@ int type_checker_check(struct type_checker* self,
|
||||||
return 1;
|
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;
|
} return 0;
|
||||||
|
|
||||||
case NODE_FUN: {
|
case NODE_FUN: {
|
||||||
|
@ -463,7 +486,10 @@ int type_checker_check(struct type_checker* self,
|
||||||
|
|
||||||
} return 0;
|
} return 0;
|
||||||
|
|
||||||
case NODE_ASSERT:
|
case NODE_ASSERT: {
|
||||||
|
return type_checker_check(self, node->children.data[0]);
|
||||||
|
} return 0;
|
||||||
|
|
||||||
case NODE_NOT:
|
case NODE_NOT:
|
||||||
case NODE_AND:
|
case NODE_AND:
|
||||||
case NODE_OR: {
|
case NODE_OR: {
|
||||||
|
@ -480,6 +506,16 @@ int type_checker_check(struct type_checker* self,
|
||||||
|
|
||||||
case NODE_EQ:
|
case NODE_EQ:
|
||||||
case NODE_NE: {
|
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;
|
struct type type;
|
||||||
type_init(&type, TYPE_VOID);
|
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);
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct type_checker {
|
||||||
struct vec fun_stack;
|
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);
|
void type_checker_free(struct type_checker* self);
|
||||||
|
|
||||||
int type_checker_check(struct type_checker* self,
|
int type_checker_check(struct type_checker* self,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "native.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "fun.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);
|
type_init(&self->type, TYPE_BOOL);
|
||||||
self->data.b = value;
|
self->data.b = value;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
|
self->is_native = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void value_init_int(struct value* self, int value, int line)
|
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);
|
type_init(&self->type, TYPE_INT);
|
||||||
self->data.i = value;
|
self->data.i = value;
|
||||||
self->line = line;
|
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);
|
type_init(&self->type, TYPE_FLOAT);
|
||||||
self->data.f = value;
|
self->data.f = value;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
|
self->is_native = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void value_init_string(struct value* self, char* value, int line)
|
void value_init_string(struct value* self, char* value, int line)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
assert(value);
|
||||||
type_init(&self->type, TYPE_STRING);
|
type_init(&self->type, TYPE_STRING);
|
||||||
self->data.s = strdup(value);
|
self->data.s = strdup(value);
|
||||||
self->line = line;
|
self->line = line;
|
||||||
|
self->is_native = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void value_init_new_fun(struct value* self, struct fun* value, int line)
|
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);
|
type_init_from_node(&self->type, value->node);
|
||||||
self->data.fun = value;
|
self->data.fun = value;
|
||||||
self->line = line;
|
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)
|
void value_free(struct value* self)
|
||||||
|
@ -56,7 +74,7 @@ void value_free(struct value* self)
|
||||||
{
|
{
|
||||||
free(self->data.s);
|
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);
|
fun_free(self->data.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)
|
struct value* value_new_clone(struct value* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
struct value* clone = malloc(sizeof(struct value));
|
struct value* clone = malloc(sizeof(struct value));
|
||||||
type_init(&clone->type, TYPE_VOID);
|
type_init(&clone->type, TYPE_VOID);
|
||||||
type_copy(&self->type, &clone->type);
|
type_copy(&self->type, &clone->type);
|
||||||
|
|
||||||
clone->data = self->data;
|
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);
|
clone->data.fun = fun_new_clone(self->data.fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clone->type.kind == TYPE_STRING)
|
||||||
|
{
|
||||||
|
clone->data.s = strdup(self->data.s);
|
||||||
|
}
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <commons.h>
|
#include <commons.h>
|
||||||
#include <type.h>
|
#include <type.h>
|
||||||
|
#include "native.h"
|
||||||
|
|
||||||
#define VAL_TRUE 1
|
#define VAL_TRUE 1
|
||||||
#define VAL_FALSE 0
|
#define VAL_FALSE 0
|
||||||
|
@ -13,11 +14,13 @@ union value_data {
|
||||||
float f;
|
float f;
|
||||||
int i;
|
int i;
|
||||||
struct fun* fun;
|
struct fun* fun;
|
||||||
|
native_fun_t native;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct value {
|
struct value {
|
||||||
struct type type;
|
struct type type;
|
||||||
int line;
|
int line;
|
||||||
|
int is_native;
|
||||||
union value_data data;
|
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_float(struct value* self, float value, int line);
|
||||||
void value_init_string(struct value* self, char* 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_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);
|
void value_free(struct value* self);
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,16 @@ Test(lexer, string) {
|
||||||
test_lexer("'hello world ' \" bim\" '\\\"hello\\\"'", 3,
|
test_lexer("'hello world ' \" bim\" '\\\"hello\\\"'", 3,
|
||||||
"STRING[hello world ]",
|
"STRING[hello world ]",
|
||||||
"STRING[ bim]",
|
"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) {
|
Test(lexer, arithemtic) {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
Test(sym_table, simple) {
|
Test(sym_table, simple) {
|
||||||
struct sym_table table;
|
struct sym_table table;
|
||||||
sym_table_init(&table);
|
sym_table_init(&table, NULL);
|
||||||
|
|
||||||
struct sym* sym = sym_table_try_by_name(&table, "hello");
|
struct sym* sym = sym_table_try_by_name(&table, "hello");
|
||||||
cr_assert_eq(sym, 0);
|
cr_assert_eq(sym, 0);
|
||||||
|
@ -24,7 +24,7 @@ Test(sym_table, simple) {
|
||||||
|
|
||||||
Test(sym_table, already_exists) {
|
Test(sym_table, already_exists) {
|
||||||
struct sym_table table;
|
struct sym_table table;
|
||||||
sym_table_init(&table);
|
sym_table_init(&table, NULL);
|
||||||
|
|
||||||
struct type* ty = malloc(sizeof(struct type));
|
struct type* ty = malloc(sizeof(struct type));
|
||||||
type_init(ty, TYPE_INT);
|
type_init(ty, TYPE_INT);
|
||||||
|
@ -40,7 +40,7 @@ Test(sym_table, already_exists) {
|
||||||
|
|
||||||
Test(sym_table, scope) {
|
Test(sym_table, scope) {
|
||||||
struct sym_table table;
|
struct sym_table table;
|
||||||
sym_table_init(&table);
|
sym_table_init(&table, NULL);
|
||||||
|
|
||||||
struct type* ty_int = malloc(sizeof(struct type));
|
struct type* ty_int = malloc(sizeof(struct type));
|
||||||
type_init(ty_int, TYPE_INT);
|
type_init(ty_int, TYPE_INT);
|
||||||
|
@ -74,7 +74,7 @@ Test(sym_table, scope) {
|
||||||
|
|
||||||
Test(sym_table, outer_scope) {
|
Test(sym_table, outer_scope) {
|
||||||
struct sym_table table;
|
struct sym_table table;
|
||||||
sym_table_init(&table);
|
sym_table_init(&table, NULL);
|
||||||
|
|
||||||
struct type* ty_int = malloc(sizeof(struct type));
|
struct type* ty_int = malloc(sizeof(struct type));
|
||||||
type_init(ty_int, TYPE_INT);
|
type_init(ty_int, TYPE_INT);
|
||||||
|
|
|
@ -14,7 +14,7 @@ static void test_check_ok(char const* source)
|
||||||
cr_assert_neq(ast, NULL);
|
cr_assert_neq(ast, NULL);
|
||||||
|
|
||||||
struct type_checker tc;
|
struct type_checker tc;
|
||||||
type_checker_init(&tc);
|
type_checker_init(&tc, NULL);
|
||||||
|
|
||||||
char buf[GUX_STR_SIZE];
|
char buf[GUX_STR_SIZE];
|
||||||
node_str(ast, 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);
|
cr_assert_neq(ast, NULL, "cannot parse: %s", source);
|
||||||
|
|
||||||
struct type_checker tc;
|
struct type_checker tc;
|
||||||
type_checker_init(&tc);
|
type_checker_init(&tc, NULL);
|
||||||
|
|
||||||
cr_assert_neq(type_checker_check(&tc, ast), 0,
|
cr_assert_neq(type_checker_check(&tc, ast), 0,
|
||||||
"%s shouldn't pass check test", source);
|
"%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 "vec.h"
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
|
|
||||||
void vm_init(struct vm* self)
|
void vm_init(struct vm* self, struct vec* natives)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
self->pc = 0;
|
self->pc = 0;
|
||||||
self->fp = 0;
|
self->fp = 0;
|
||||||
|
self->natives = natives;
|
||||||
|
|
||||||
self->error_line = 0;
|
self->error_line = 0;
|
||||||
memset(self->error_msg, 0, GUX_STR_SIZE);
|
memset(self->error_msg, 0, GUX_STR_SIZE);
|
||||||
|
@ -133,7 +134,6 @@ int vm_exec(struct vm* self, struct program* program)
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
int fun_addr = vm_pop(self);
|
int fun_addr = vm_pop(self);
|
||||||
struct value* fun_val = program->constant_pool.data[fun_addr];
|
struct value* fun_val = program->constant_pool.data[fun_addr];
|
||||||
struct fun* fun = fun_val->data.fun;
|
|
||||||
|
|
||||||
struct vec args;
|
struct vec args;
|
||||||
vec_init(&args, 1);
|
vec_init(&args, 1);
|
||||||
|
@ -145,9 +145,38 @@ int vm_exec(struct vm* self, struct program* program)
|
||||||
vec_push(&args, addr);
|
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);
|
vm_add_frame(self);
|
||||||
struct frame* my_frame = self->stack[self->fp - 1];
|
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++)
|
for (size_t i=0; i<args.size; i++)
|
||||||
{
|
{
|
||||||
size_t k = args.size - 1 - i;
|
size_t k = args.size - 1 - i;
|
||||||
|
@ -203,6 +232,17 @@ int vm_exec(struct vm* self, struct program* program)
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} 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: {
|
case OP_LOAD: {
|
||||||
int stack_addr = vm_load(self, param);
|
int stack_addr = vm_load(self, param);
|
||||||
struct frame* myframe = self->stack[self->fp - 1];
|
struct frame* myframe = self->stack[self->fp - 1];
|
||||||
|
|
|
@ -25,9 +25,10 @@ struct vm {
|
||||||
size_t pc;
|
size_t pc;
|
||||||
size_t fp;
|
size_t fp;
|
||||||
struct frame* stack[FRAME_DEPTH];
|
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_free(struct vm* self);
|
||||||
void vm_add_frame(struct vm* self);
|
void vm_add_frame(struct vm* self);
|
||||||
void vm_remove_frame(struct vm* self);
|
void vm_remove_frame(struct vm* self);
|
||||||
|
|
Loading…
Reference in New Issue