diff --git a/src/compiler.c b/src/compiler.c index dc6fa75..39348e1 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -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); @@ -507,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) diff --git a/src/compiler.h b/src/compiler.h index c3bd407..2c3f322 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -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 diff --git a/src/cstatic.c b/src/cstatic.c index 7f41ed3..db476e9 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -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, @@ -229,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); @@ -318,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); diff --git a/src/lex.l b/src/lex.l index 4db861d..76c3c70 100644 --- a/src/lex.l +++ b/src/lex.l @@ -25,6 +25,8 @@ 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; } diff --git a/src/node.h b/src/node.h index 68d323d..85b8d42 100644 --- a/src/node.h +++ b/src/node.h @@ -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_IS) + G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \ + G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK) #include "mutils.h" diff --git a/src/opcodes.h b/src/opcodes.h index afa97ad..cf985f0 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -45,7 +45,9 @@ G(OP_STORE), \ G(OP_LOAD), \ G(OP_ASTORE), \ - G(OP_TEQ) + G(OP_TEQ), \ + G(OP_BRF), \ + G(OP_BR) enum Opcodes { diff --git a/src/parser.y b/src/parser.y index febaf7b..5a0d2a1 100644 --- a/src/parser.y +++ b/src/parser.y @@ -21,10 +21,12 @@ size_t n_children; }; +%token IF_COND +%token ELSE_COND %left ASSERT %token TYPE BOOLEAN INTEGER FLOAT STRING IDENT %type expr exprs prog array builtins -%type expr_list type type_list ident +%type expr_list type type_list ident if %left EQ NE %left LT GT LE GE %left AND @@ -36,7 +38,7 @@ %token OPAR CPAR %token OSQUARE CSQUARE COMMA %token LET LET_MUT ASSIGN DO END -%type expr_unop +%type expr_unop block if_rec %left IS %% @@ -75,6 +77,7 @@ exprs: exprs expr { $$ = $1 + $2; } | expr { $$ = $1; } + ; @@ -93,29 +96,19 @@ expr: stack_push(n); $$ = 1; } + + | if {} // BLOCK - | DO exprs END { + | 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; ipool.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; iinstrs.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) diff --git a/src/program.h b/src/program.h index 784733f..14e678d 100644 --- a/src/program.h +++ b/src/program.h @@ -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); diff --git a/src/symtable.c b/src/symtable.c index c1f7ca8..bfc2776 100644 --- a/src/symtable.c +++ b/src/symtable.c @@ -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; } diff --git a/src/vm.c b/src/vm.c index 54d4ea9..924be02 100644 --- a/src/vm.c +++ b/src/vm.c @@ -104,6 +104,9 @@ 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: { @@ -1117,3 +1120,25 @@ void vm_teq(vm* self) 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; +} diff --git a/src/vm.h b/src/vm.h index 0119718..2457c55 100644 --- a/src/vm.h +++ b/src/vm.h @@ -92,4 +92,7 @@ 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 diff --git a/tests/err_if.wuz b/tests/err_if.wuz new file mode 100644 index 0000000..2061a87 --- /dev/null +++ b/tests/err_if.wuz @@ -0,0 +1,4 @@ +if 4 0 end +if int 0 end +if "salut" 0 end +if 400.7 0 end diff --git a/tests/test_if.wuz b/tests/test_if.wuz new file mode 100644 index 0000000..1b469a5 --- /dev/null +++ b/tests/test_if.wuz @@ -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