Compare commits

...

2 Commits

Author SHA1 Message Date
bog ba26851487 ADD: if-then-else expression. 2023-08-26 19:01:15 +02:00
bog 9bb5a60b2a ADD: 'is' keyword to test an expression against a type. 2023-08-26 11:26:51 +02:00
15 changed files with 356 additions and 29 deletions

View File

@ -24,13 +24,17 @@ void compile_node(compiler* self, node* root, program* prog)
assert(root);
assert(prog);
if (root->type == NODE_DO)
if (root->type == NODE_BLOCK)
{
symtable_enter_scope(self->sym);
compile_children(self, root, prog);
symtable_leave_scope(self->sym);
}
else if (root->type == NODE_IF)
{
compile_if(self, root, prog);
program_set_mark_params(prog, prog->instrs.size);
}
else if (root->type == NODE_INDEX)
{
compile_children(self, root, prog);
@ -60,6 +64,11 @@ void compile_node(compiler* self, node* root, program* prog)
free(ty);
cstatic_free(&cs);
}
else if (root->type == NODE_IS)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_TEQ, NO_PARAM);
}
else if (root->type == NODE_VARDECL)
{
cstatic cs;
@ -463,6 +472,11 @@ type* compile_get_type(compiler* self, node* root)
type_init(ty, TY_BOOLEAN);
}
else if (strcmp(root->value, "type") == 0)
{
type_init(ty, TY_TYPE);
}
else if (strcmp(root->value, "array") == 0)
{
type_init(ty, TY_ARRAY);
@ -497,6 +511,36 @@ type* compile_get_type(compiler* self, node* root)
return ty;
}
void compile_if(compiler* self, node* root, program* prog)
{
if (root->children.size == 1)
{
compile_children(self, root, prog);
return;
}
// if cond
node* cond = root->children.data[0];
compile_node(self, cond, prog);
size_t const cond_addr = prog->instrs.size;
program_add_instr(prog, OP_BRF, 0 /* to next */);
// then block
node* then_block = root->children.data[1];
compile_node(self, then_block, prog);
program_add_instr(prog, OP_BR, MARK_PARAM);
// next
program_set_instr(prog, cond_addr, OP_BRF, prog->instrs.size);
if (root->children.size >= 3)
{
node* next_node = root->children.data[2];
//char c [512]; node_str(next_node, c, 512); printf("=> %s\n", c);
compile_if(self, next_node, prog);
}
}
void compile_number(compiler* self, node* root, program* prog,
int integer_op,
int float_op)

View File

@ -22,4 +22,7 @@ type* compile_get_type(compiler* self, node* root);
void compile_number(compiler* self, node* root, program* prog,
int integer_op,
int float_op);
void compile_if(compiler* self, node* root, program* prog);
#endif

View File

@ -43,6 +43,14 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
return ty;
}
if (ast->type == NODE_IF)
{
type* ty = cstatic_resolve_new(self,
sym,
ast->children.data[1]);
return ty;
}
if (ast->type == NODE_DO)
{
type* ty = cstatic_resolve_new(self,
@ -201,7 +209,8 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|| ast->type == NODE_GT
|| ast->type == NODE_GE
|| ast->type == NODE_EQ
|| ast->type == NODE_NE)
|| ast->type == NODE_NE
|| ast->type == NODE_IS)
{
return cstatic_new_type(self, TY_BOOLEAN);
@ -228,8 +237,8 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
assert(self);
assert(ast);
// DO BLOCK
if (ast->type == NODE_DO)
// BLOCK
if (ast->type == NODE_BLOCK)
{
symtable_enter_scope(sym);
@ -317,6 +326,26 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
return 1;
}
else if (ast->type == NODE_IF && ast->children.size > 1)
{
assert(ast->children.size > 0);
type* right = cstatic_resolve_new(self, sym, ast->children.data[0]);
type* left = cstatic_new_type(self, TY_BOOLEAN);
int status = cstatic_check_same_type_ptr(
self,
ast->children.data[0],
left, right, sym, msg, size
);
if (status)
{
type_free(left); free(left);
type_free(right); free(right);
}
return status;
}
else if (ast->type == NODE_ARRAY)
{
assert(ast->children.size > 0);

View File

@ -13,7 +13,7 @@ BOOLEAN true|false
INTEGER -?[0-9]+
FLOAT -?[0-9]+\.[0-9]+
STRING \"[^"]*\"
TYPE (int|float|bool|str|array)
TYPE (int|float|bool|str|array|type)
IDENT [_A-Za-z][_A-Za-z0-9]*
%%
@ -25,7 +25,9 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
yylval.str = str_new(yytext);
return TYPE;
}
"if" { return IF_COND; }
"else" { return ELSE_COND; }
"is" { return IS; }
"do" { return DO; }
"end" { return END; }
"let!" { return LET_MUT; }

View File

@ -12,7 +12,8 @@
G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \
G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \
G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO)
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK)
#include "mutils.h"

View File

@ -44,7 +44,10 @@
G(OP_FGE), \
G(OP_STORE), \
G(OP_LOAD), \
G(OP_ASTORE)
G(OP_ASTORE), \
G(OP_TEQ), \
G(OP_BRF), \
G(OP_BR)
enum Opcodes {

View File

@ -21,10 +21,12 @@
size_t n_children;
};
%token IF_COND
%token ELSE_COND
%left ASSERT
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
%type <n_children> expr exprs prog array builtins
%type <n_children> expr_list type type_list ident
%type <n_children> expr_list type type_list ident if
%left EQ NE
%left LT GT LE GE
%left AND
@ -36,7 +38,8 @@
%token OPAR CPAR
%token OSQUARE CSQUARE COMMA
%token LET LET_MUT ASSIGN DO END
%type <n_children> expr_unop
%type <n_children> expr_unop block if_rec
%left IS
%%
@ -74,32 +77,38 @@ exprs:
exprs expr { $$ = $1 + $2; }
| expr { $$ = $1; }
;
expr:
// TYPE OPERATORS
expr IS type {
node* n = malloc(sizeof(node));
node_init(n, NODE_IS, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| if {}
// BLOCK
DO exprs END {
node *n = malloc(sizeof(node));
| DO block END {
node* n = malloc(sizeof(node));
node_init(n, NODE_DO, "", line);
size_t const SZ = $2;
node* all[SZ];
for (size_t i=0; i<SZ; i++)
{
all[SZ - 1 - i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(n, all[i]);
}
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
// INDEX
@ -375,6 +384,73 @@ expr:
;
if_rec:
ELSE_COND IF_COND expr block if_rec {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
node* next_node = stack_pop();
node* block_node = stack_pop();
node* expr_node = stack_pop();
node_add_child(n, expr_node);
node_add_child(n, block_node);
node_add_child(n, next_node);
stack_push(n);
$$ = 1;
}
| ELSE_COND expr END {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
node* expr_node = stack_pop();
node_add_child(n, expr_node);
stack_push(n);
$$ = 1;
}
;
if:
IF_COND expr block if_rec {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
node* rec_node = stack_pop();
node* block_node = stack_pop();
node* expr_node = stack_pop();
node_add_child(n, expr_node);
node_add_child(n, block_node);
node_add_child(n, rec_node);
stack_push(n);
$$ = 1;
}
| IF_COND expr block END {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
node* block_node = stack_pop();
node* expr_node = stack_pop();
node_add_child(n, expr_node);
node_add_child(n, block_node);
stack_push(n);
$$ = 1;
}
;
expr_unop:
ADD expr {
node *n = malloc(sizeof(node));
@ -399,6 +475,30 @@ type_list:
;
block:
exprs {
node* n = malloc(sizeof(node));
node_init(n, NODE_BLOCK, "", line);
size_t const SZ = $1;
node* all[SZ];
for (size_t i=0; i<SZ; i++)
{
all[SZ - 1 - i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(n, all[i]);
}
stack_push(n);
$$ = 1;
}
;
type:
TYPE LT type_list GT {
node* n = malloc(sizeof(node));

View File

@ -37,7 +37,27 @@ void program_free(program* self)
self->pool.capacity = 0;
}
void program_add_instr(program* self, int opcode, int param)
void program_set_instr(program* self, size_t index, int opcode, int param)
{
assert(self);
assert(index < self->instrs.size);
self->instrs.data[index]->opcode = opcode;
self->instrs.data[index]->param = param;
}
void program_set_mark_params(program* self, int param)
{
for (size_t i=0; i<self->instrs.size; i++)
{
if (self->instrs.data[i]->param == MARK_PARAM)
{
self->instrs.data[i]->param = param;
}
}
}
size_t program_add_instr(program* self, int opcode, int param)
{
assert(self);
@ -62,6 +82,8 @@ void program_add_instr(program* self, int opcode, int param)
self->instrs.data[idx]->param = param;
self->instrs.size++;
return self->instrs.size - 1;
}
size_t program_add_pool(program* self, value* val)

View File

@ -6,6 +6,7 @@
#include "value.h"
#define NO_PARAM (-1)
#define MARK_PARAM (-2)
typedef struct {
int opcode;
@ -29,7 +30,10 @@ typedef struct {
void program_init(program* self);
void program_free(program* self);
void program_add_instr(program* self, int opcode, int param);
size_t program_add_instr(program* self, int opcode, int param);
void program_set_instr(program* self, size_t index, int opcode, int param);
void program_set_mark_params(program* self, int param);
size_t program_add_pool(program* self, value* val);
size_t program_str(program* self, char* buffer, size_t size);

View File

@ -47,7 +47,7 @@ size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sy
assert(self);
size_t id = symtable_declare(self, name, ty, sym_node);
self->entries.data[id]->is_mut = 1;
self->entries.data[self->entries.size - 1]->is_mut = 1;
return id;
}

View File

@ -104,6 +104,11 @@ void vm_exec(vm* self, program* prog)
case OP_STORE: vm_store(self, param); break;
case OP_ASTORE: vm_astore(self, param); break;
case OP_BRF: vm_brf(self, param); break;
case OP_BR: vm_br(self, param); break;
case OP_TEQ: vm_teq(self); break;
default: {
fprintf(stderr, "unknown opcode %s\n",
OpcodesStr[opcode]);
@ -1093,3 +1098,47 @@ void vm_astore(vm* self, int param)
self->pc++;
}
void vm_teq(vm* self)
{
assert(self);
value* type_val = vm_pop_value(self);
value* expr_val = vm_pop_value(self);
type* ty = type_val->val.type_val;
int equals = type_equals(ty, expr_val->type);
value* val = malloc(sizeof(value));
value_init_boolean(val, equals, expr_val->lineno);
vm_push_value(self, val);
value_free(type_val); free(type_val);
value_free(expr_val); free(expr_val);
self->pc++;
}
void vm_brf(vm* self, int param)
{
assert(self);
value* val = vm_pop_value(self);
if (!val->val.boolean)
{
self->pc = param;
}
else
{
self->pc++;
}
value_free(val); free(val);
}
void vm_br(vm* self, int param)
{
assert(self);
self->pc = param;
}

View File

@ -90,4 +90,9 @@ void vm_store(vm* self, int param);
void vm_load(vm* self, int param);
void vm_astore(vm* self, int param);
void vm_teq(vm* self);
void vm_brf(vm* self, int param);
void vm_br(vm* self, int param);
#endif

4
tests/err_if.wuz Normal file
View File

@ -0,0 +1,4 @@
if 4 0 end
if int 0 end
if "salut" 0 end
if 400.7 0 end

45
tests/test_if.wuz Normal file
View File

@ -0,0 +1,45 @@
let! a = 0
let b = 12
if true
a = 1
let b = 34
assert 34 == b
end
assert 1 == a
assert 12 == b
if false
a = 2
let b = 76
assert 76 == b
end
assert 1 == a
assert 12 == b
let! c = 0
if true
c = 1
else
c = 2
end
assert 1 == c
if false
c = 3
else
c = 4
end
assert 4 == c
let d = if true 1 else 2 end
assert 1 == d
let e = if false 1 else 2 end
assert 2 == e

16
tests/test_is.wuz Normal file
View File

@ -0,0 +1,16 @@
assert 5 is int
assert 5.9 is float
assert false is bool
assert "salut" is str
assert !(5 is float)
assert !(5.9 is bool)
assert !(false is str)
assert !("salut" is int)
assert [2, 4, 6] is array<int>
assert [[2, 4], [7, 9]] is array<array<int>>
assert int is type
assert type is type
assert (5.2 is int) is bool