Compare commits

...

2 Commits

Author SHA1 Message Date
bog 3b7b0b4295 if statement. 2024-02-13 05:14:56 +01:00
bog bb300a1a93 clear blocks. 2024-02-13 03:53:19 +01:00
15 changed files with 362 additions and 40 deletions

View File

@ -2,6 +2,7 @@
#include "commons.h" #include "commons.h"
#include "node.h" #include "node.h"
#include "opcodes.h" #include "opcodes.h"
#include "program.h"
#include "syms.h" #include "syms.h"
#include "value.h" #include "value.h"
#include "vec.h" #include "vec.h"
@ -11,6 +12,7 @@ void compiler_init(struct compiler* self, struct syms* syms)
assert(self); assert(self);
self->syms = syms; self->syms = syms;
memset(self->error_msg, 0, GUX_STR_SIZE); memset(self->error_msg, 0, GUX_STR_SIZE);
self->stack_size = 0;
} }
void compiler_free(struct compiler* self) void compiler_free(struct compiler* self)
@ -28,6 +30,46 @@ int compiler_compile(struct compiler* self,
switch (node->type) switch (node->type)
{ {
case NODE_IF: {
struct vec to_end;
vec_init(&to_end, 1);
compiler_compile_if(self, node, program, &to_end);
size_t end = program->instructions.size;
for (size_t i=0; i<to_end.size; i++)
{
size_t* addr = to_end.data[i];
((struct instruction*) program->instructions.data[*addr])->param
= end;
}
vec_free_elements(&to_end);
vec_free(&to_end);
} break;
case NODE_BLOCK: {
int stack_base = self->stack_size;
for (size_t i=0; i<node->children.size; i++)
{
if (compiler_compile(self, node->children.data[i], program) != 0)
{
return 1;
}
}
int top = self->stack_size - stack_base;
for (int i=0; i<top; i++)
{
compiler_gen_instr(self, program, OP_POP, NO_PARAM);
}
} break;
case NODE_ASSIGN: { case NODE_ASSIGN: {
struct node* ident = node->children.data[0]; struct node* ident = node->children.data[0];
struct node* expr = node->children.data[1]; struct node* expr = node->children.data[1];
@ -40,7 +82,7 @@ int compiler_compile(struct compiler* self,
return 1; return 1;
} }
program_push_instr(program, OP_STORE, entry->addr); compiler_gen_instr(self, program, OP_STORE, entry->addr);
} break; } break;
case NODE_IDENT: { case NODE_IDENT: {
@ -56,7 +98,7 @@ int compiler_compile(struct compiler* self,
return 1; return 1;
} }
program_push_instr(program, OP_LOAD, entry->addr); compiler_gen_instr(self, program, OP_LOAD, entry->addr);
} break; } break;
case NODE_CONSTDECL: case NODE_CONSTDECL:
@ -76,7 +118,7 @@ int compiler_compile(struct compiler* self,
node); node);
assert(entry); assert(entry);
program_push_instr(program, OP_STORE, entry->addr); compiler_gen_instr(self, program, OP_STORE, entry->addr);
} break; } break;
case NODE_BOOL: { case NODE_BOOL: {
struct value* val = malloc(sizeof(struct value)); struct value* val = malloc(sizeof(struct value));
@ -84,28 +126,28 @@ int compiler_compile(struct compiler* self,
strcmp(node->value, "true") == 0 ? 1 : 0, strcmp(node->value, "true") == 0 ? 1 : 0,
node->line); node->line);
size_t addr = program_push_constant(program, val); size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr); compiler_gen_instr(self, program, OP_PUSH, addr);
} break; } break;
case NODE_INT: { case NODE_INT: {
struct value* val = malloc(sizeof(struct value)); struct value* val = malloc(sizeof(struct value));
value_init_int(val, atoi(node->value), node->line); value_init_int(val, atoi(node->value), node->line);
size_t addr = program_push_constant(program, val); size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr); compiler_gen_instr(self, program, OP_PUSH, addr);
} break; } break;
case NODE_FLOAT: { case NODE_FLOAT: {
struct value* val = malloc(sizeof(struct value)); struct value* val = malloc(sizeof(struct value));
value_init_float(val, atof(node->value), node->line); value_init_float(val, atof(node->value), node->line);
size_t addr = program_push_constant(program, val); size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr); compiler_gen_instr(self, program, OP_PUSH, addr);
} break; } break;
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);
program_push_instr(program, OP_PUSH, addr); compiler_gen_instr(self, program, OP_PUSH, addr);
} break; } break;
case NODE_ASSERT: { case NODE_ASSERT: {
@ -114,21 +156,21 @@ int compiler_compile(struct compiler* self,
return 1; return 1;
} }
size_t brt = program_push_instr(program, OP_BRT, NO_PARAM); size_t brt = compiler_gen_instr(self, program, OP_BRT, NO_PARAM);
program_push_instr(program, OP_PUSH, GUX_RET_ASSERT); compiler_gen_instr(self, program, OP_PUSH, GUX_RET_ASSERT);
size_t halt = program_push_instr(program, OP_HALT, node->line); size_t halt = compiler_gen_instr(self, program, OP_HALT, node->line);
struct instruction* instr = program->instructions.data[brt]; struct instruction* instr = program->instructions.data[brt];
instr->param = halt + 1; instr->param = halt + 1;
if (halt + 1 >= program->instructions.size) if (halt + 1 >= program->instructions.size)
{ {
program_push_instr(program, OP_NOP, NO_PARAM); compiler_gen_instr(self, program, OP_NOP, NO_PARAM);
} }
struct value* value = malloc(sizeof(struct value)); struct value* value = malloc(sizeof(struct value));
value_init_bool(value, VAL_TRUE, node->line); value_init_bool(value, VAL_TRUE, node->line);
program_push_instr(program, OP_PUSH, compiler_gen_instr(self, program, OP_PUSH,
program_push_constant(program, value)); program_push_constant(program, value));
} break; } break;
@ -140,7 +182,7 @@ int compiler_compile(struct compiler* self,
{ {
return 1; return 1;
} }
program_push_instr(program, OP_EQ, NO_PARAM); compiler_gen_instr(self, program, OP_EQ, NO_PARAM);
} break; } break;
case NODE_NE: { case NODE_NE: {
@ -152,8 +194,8 @@ int compiler_compile(struct compiler* self,
return 1; return 1;
} }
program_push_instr(program, OP_EQ, NO_PARAM); compiler_gen_instr(self, program, OP_EQ, NO_PARAM);
program_push_instr(program, OP_NOT, NO_PARAM); compiler_gen_instr(self, program, OP_NOT, NO_PARAM);
} break; } break;
case NODE_NOT: { case NODE_NOT: {
@ -162,7 +204,7 @@ int compiler_compile(struct compiler* self,
return 1; return 1;
} }
program_push_instr(program, OP_NOT, NO_PARAM); compiler_gen_instr(self, program, OP_NOT, NO_PARAM);
} break; } break;
case NODE_AND: { case NODE_AND: {
@ -177,17 +219,17 @@ int compiler_compile(struct compiler* self,
} }
size_t* addr = malloc(sizeof(size_t)); size_t* addr = malloc(sizeof(size_t));
*addr = program_push_instr(program, OP_BRF, NO_PARAM); // to pivot *addr = compiler_gen_instr(self, program, OP_BRF, NO_PARAM); // to pivot
vec_push(&to_pivot, addr); vec_push(&to_pivot, addr);
} }
// true case // true case
struct value* true_val = malloc(sizeof(struct value)); struct value* true_val = malloc(sizeof(struct value));
value_init_bool(true_val, VAL_TRUE, node->line); value_init_bool(true_val, VAL_TRUE, node->line);
program_push_instr(program, OP_PUSH, compiler_gen_instr(self, program, OP_PUSH,
program_push_constant(program, true_val)); program_push_constant(program, true_val));
size_t to_end = program_push_instr(program, OP_BR, NO_PARAM); // to end size_t to_end = compiler_gen_instr(self, program, OP_BR, NO_PARAM); // to end
// pivot // pivot
size_t pivot_point = program->instructions.size; size_t pivot_point = program->instructions.size;
@ -195,7 +237,7 @@ int compiler_compile(struct compiler* self,
// false case // false case
struct value* false_val = malloc(sizeof(struct value)); struct value* false_val = malloc(sizeof(struct value));
value_init_bool(false_val, VAL_FALSE, node->line); value_init_bool(false_val, VAL_FALSE, node->line);
program_push_instr(program, OP_PUSH, compiler_gen_instr(self, program, OP_PUSH,
program_push_constant(program, false_val)); program_push_constant(program, false_val));
// end // end
@ -229,17 +271,17 @@ int compiler_compile(struct compiler* self,
} }
size_t* addr = malloc(sizeof(size_t)); size_t* addr = malloc(sizeof(size_t));
*addr = program_push_instr(program, OP_BRT, NO_PARAM); // to pivot *addr = compiler_gen_instr(self, program, OP_BRT, NO_PARAM); // to pivot
vec_push(&to_pivot, addr); vec_push(&to_pivot, addr);
} }
// false case // false case
struct value* false_val = malloc(sizeof(struct value)); struct value* false_val = malloc(sizeof(struct value));
value_init_bool(false_val, VAL_FALSE, node->line); value_init_bool(false_val, VAL_FALSE, node->line);
program_push_instr(program, OP_PUSH, compiler_gen_instr(self, program, OP_PUSH,
program_push_constant(program, false_val)); program_push_constant(program, false_val));
size_t to_end = program_push_instr(program, OP_BR, NO_PARAM); // to end size_t to_end = compiler_gen_instr(self, program, OP_BR, NO_PARAM); // to end
// pivot // pivot
size_t pivot_point = program->instructions.size; size_t pivot_point = program->instructions.size;
@ -247,7 +289,7 @@ int compiler_compile(struct compiler* self,
// false case // false case
struct value* true_val = malloc(sizeof(struct value)); struct value* true_val = malloc(sizeof(struct value));
value_init_bool(true_val, VAL_TRUE, node->line); value_init_bool(true_val, VAL_TRUE, node->line);
program_push_instr(program, OP_PUSH, compiler_gen_instr(self, program, OP_PUSH,
program_push_constant(program, true_val)); program_push_constant(program, true_val));
// end // end
@ -291,16 +333,16 @@ int compiler_compile(struct compiler* self,
switch (node->type) switch (node->type)
{ {
case NODE_ADD: program_push_instr(program, OP_ADD, NO_PARAM); break; case NODE_ADD: compiler_gen_instr(self, program, OP_ADD, NO_PARAM); break;
case NODE_SUB: program_push_instr(program, OP_SUB, NO_PARAM); break; case NODE_SUB: compiler_gen_instr(self, program, OP_SUB, NO_PARAM); break;
case NODE_MUL: program_push_instr(program, OP_MUL, NO_PARAM); break; case NODE_MUL: compiler_gen_instr(self, program, OP_MUL, NO_PARAM); break;
case NODE_DIV: program_push_instr(program, OP_DIV, NO_PARAM); break; case NODE_DIV: compiler_gen_instr(self, program, OP_DIV, NO_PARAM); break;
case NODE_MOD: program_push_instr(program, OP_MOD, NO_PARAM); break; case NODE_MOD: compiler_gen_instr(self, program, OP_MOD, NO_PARAM); break;
case NODE_POW: program_push_instr(program, OP_POW, NO_PARAM); break; case NODE_POW: compiler_gen_instr(self, program, OP_POW, NO_PARAM); break;
case NODE_LT: program_push_instr(program, OP_LT, NO_PARAM); break; case NODE_LT: compiler_gen_instr(self, program, OP_LT, NO_PARAM); break;
case NODE_LE: program_push_instr(program, OP_LE, NO_PARAM); break; case NODE_LE: compiler_gen_instr(self, program, OP_LE, NO_PARAM); break;
case NODE_GT: program_push_instr(program, OP_GT, NO_PARAM); break; case NODE_GT: compiler_gen_instr(self, program, OP_GT, NO_PARAM); break;
case NODE_GE: program_push_instr(program, OP_GE, NO_PARAM); break; case NODE_GE: compiler_gen_instr(self, program, OP_GE, NO_PARAM); break;
default: break; default: break;
} }
@ -320,3 +362,95 @@ int compiler_compile(struct compiler* self,
return 0; return 0;
} }
int compiler_compile_if(struct compiler* self,
struct node* node,
struct program* program,
struct vec* to_end)
{
assert(node->children.size >= 2);
struct instruction* instr = NULL;
// if expr
if (compiler_compile(self, node->children.data[0], program) != 0)
{
return 1;
}
size_t goto_else = compiler_gen_instr(self, program, OP_BRF, 0);
// block
if (compiler_compile(self, node->children.data[1], program) != 0)
{
return 1;
}
size_t* goto_end = malloc(sizeof(size_t));
*goto_end = compiler_gen_instr(self, program, OP_BR, 0);
vec_push(to_end, goto_end);
instr = program->instructions.data[goto_else];
instr->param = program->instructions.size;
// else block
if (node->children.size > 2
&& ((struct node*) node->children.data[2])->type == NODE_BLOCK
&& compiler_compile(self, node->children.data[2], program) != 0)
{
return 1;
}
// else
if (node->children.size > 2
&& ((struct node*) node->children.data[2])->type == NODE_IF
&& compiler_compile_if(self, node->children.data[2], program,
to_end) != 0)
{
return 1;
}
return 0;
}
size_t compiler_gen_instr(struct compiler* self,
struct program* program,
enum Opcodes op,
int param)
{
assert(self);
assert(program);
size_t addr = program_push_instr(program, op, param);
switch (op)
{
case OP_LOAD:
case OP_PUSH: self->stack_size += 1; break;
case OP_LT:
case OP_LE:
case OP_GT:
case OP_GE:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_MOD:
case OP_POW:
case OP_EQ:
case OP_POP:
case OP_HALT:
case OP_BRF:
case OP_BRT:
self->stack_size -= 1; break;
case OP_SWAP:
case OP_BR:
case OP_NOT:
case OP_NOP:
case OP_STORE: break;
}
return addr;
}

View File

@ -10,6 +10,7 @@ struct compiler {
char error_msg[GUX_STR_SIZE]; char error_msg[GUX_STR_SIZE];
struct syms* syms; struct syms* syms;
int error_line; int error_line;
int stack_size;
}; };
void compiler_init(struct compiler* self, struct syms* syms); void compiler_init(struct compiler* self, struct syms* syms);
@ -19,4 +20,14 @@ int compiler_compile(struct compiler* self,
struct node* node, struct node* node,
struct program* program); struct program* program);
int compiler_compile_if(struct compiler* self,
struct node* node,
struct program* program,
struct vec* to_end);
size_t compiler_gen_instr(struct compiler* self,
struct program* program,
enum Opcodes op,
int param);
#endif #endif

View File

@ -5,7 +5,8 @@
G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \ G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \
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)
#include <commons.h> #include <commons.h>

View File

@ -13,7 +13,14 @@ LEXPR ::=
| CONSTDECL | CONSTDECL
| ASSIGN | ASSIGN
BEXPR ::= BLOCK BEXPR ::=
| BLOCK
| IF
IF ::=
| if EXPR BLOCK
| if EXPR BLOCK else BLOCK
| if EXPR BLOCK else IF
BLOCK ::= obrace INSTR* cbrace BLOCK ::= obrace INSTR* cbrace
VARDECL ::= var ident colon type? assign EXPR VARDECL ::= var ident colon type? assign EXPR

View File

@ -12,6 +12,12 @@ void lexer_init(struct lexer* self, char const* source)
vec_init(&self->toks, 1); vec_init(&self->toks, 1);
lexer_add_tok(self, "if", NODE_IF, "", 1);
lexer_add_tok(self, "else", NODE_ELSE, "", 1);
lexer_add_tok(self, "cond", NODE_COND, "", 1);
lexer_add_tok(self, "while", NODE_WHILE, "", 1);
lexer_add_tok(self, "for", NODE_FOR, "", 1);
lexer_add_tok(self, "var", NODE_VAR, "", 1); lexer_add_tok(self, "var", NODE_VAR, "", 1);
lexer_add_tok(self, "int", NODE_TYPE, "int", 1); lexer_add_tok(self, "int", NODE_TYPE, "int", 1);

View File

@ -14,7 +14,9 @@
G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \ G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
G(NODE_GE), G(NODE_COLON), G(NODE_ASSIGN), G(NODE_IDENT), \ G(NODE_GE), G(NODE_COLON), G(NODE_ASSIGN), G(NODE_IDENT), \
G(NODE_TYPE), G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_VAR), \ G(NODE_TYPE), G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_VAR), \
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK) G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK), \
G(NODE_IF), G(NODE_ELSE), G(NODE_COND), G(NODE_WHILE), G(NODE_FOR)
GUX_ENUM_H(NodeType, NODE_TYPE); GUX_ENUM_H(NodeType, NODE_TYPE);

View File

@ -132,7 +132,8 @@ int parser_start_bexpr(struct parser* self)
assert(self); assert(self);
struct node* tok = self->tokens.data[self->cursor]; struct node* tok = self->tokens.data[self->cursor];
return tok->type == NODE_OBRACE; return tok->type == NODE_OBRACE
|| tok->type == NODE_IF;
} }
struct node* parser_try_new_root(struct parser* self, char const* source) struct node* parser_try_new_root(struct parser* self, char const* source)
@ -254,9 +255,41 @@ struct node* parser_try_new_lexpr(struct parser* self)
struct node* parser_try_new_bexpr(struct parser* self) struct node* parser_try_new_bexpr(struct parser* self)
{ {
assert(self); assert(self);
if (parser_type_is(self, NODE_IF, 0))
{
return parser_try_new_if(self);
}
return parser_try_new_block(self); return parser_try_new_block(self);
} }
struct node* parser_try_new_if(struct parser* self)
{
assert(self);
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_IF, "", parser_current_line(self));
self->cursor++; // if
node_add_child(node, parser_try_new_expr(self));
node_add_child(node, parser_try_new_block(self));
if (parser_try_consume(self, NODE_ELSE) == 0)
{
if (parser_type_is(self, NODE_IF, 0))
{
node_add_child(node, parser_try_new_if(self));
}
if (parser_type_is(self, NODE_OBRACE, 0))
{
node_add_child(node, parser_try_new_block(self));
}
}
return node;
}
struct node* parser_try_new_block(struct parser* self) struct node* parser_try_new_block(struct parser* self)
{ {

View File

@ -31,6 +31,7 @@ struct node* parser_try_new_instr(struct parser* self);
struct node* parser_try_new_expr(struct parser* self); struct node* parser_try_new_expr(struct parser* self);
struct node* parser_try_new_lexpr(struct parser* self); struct node* parser_try_new_lexpr(struct parser* self);
struct node* parser_try_new_bexpr(struct parser* self); struct node* parser_try_new_bexpr(struct parser* self);
struct node* parser_try_new_if(struct parser* self);
struct node* parser_try_new_block(struct parser* self); struct node* parser_try_new_block(struct parser* self);
struct node* parser_try_new_assign(struct parser* self); struct node* parser_try_new_assign(struct parser* self);
struct node* parser_try_new_vardecl(struct parser* self); struct node* parser_try_new_vardecl(struct parser* self);

View File

@ -27,6 +27,42 @@ int type_checker_check(struct type_checker* self,
switch (node->type) switch (node->type)
{ {
case NODE_IF: {
struct type expr;
type_init(&expr, TYPE_VOID);
if (type_resolver_resolve(&self->resolver,
node->children.data[0],
&expr) != 0)
{
type_free(&expr);
return 1;
}
if (!type_is(&expr, "BOOL"))
{
struct type bool_ty;
type_init(&bool_ty, TYPE_BOOL);
type_checker_error_msg(self, node, &bool_ty, &expr);
type_free(&bool_ty);
type_free(&expr);
return 1;
}
type_free(&expr);
if (node->children.size > 2)
{
if (type_checker_check(self, node->children.data[2]) != 0)
{
return 1;
}
}
} return 0;
case NODE_ASSIGN: { case NODE_ASSIGN: {
struct node* ident = node->children.data[0]; struct node* ident = node->children.data[0];
struct node* expr = node->children.data[1]; struct node* expr = node->children.data[1];

View File

@ -53,7 +53,7 @@ int type_resolver_resolve(struct type_resolver* self,
case NODE_IDENT: { case NODE_IDENT: {
struct syms_entry* entry = syms_try_get(self->syms, struct syms_entry* entry = syms_try_get(self->syms,
node->value, node->value,
node_depth(node)); node);
if (!entry) if (!entry)
{ {

View File

@ -125,3 +125,8 @@ Test(lexer, var_types) {
Test(lexer, blocks) { Test(lexer, blocks) {
test_lexer("{}", 2, "OBRACE", "CBRACE"); test_lexer("{}", 2, "OBRACE", "CBRACE");
} }
Test(lexer, flow_control) {
test_lexer("if else cond while for", 5,
"IF", "ELSE", "COND", "WHILE", "FOR");
}

View File

@ -132,3 +132,20 @@ Test(parser, block) {
test_parser("ROOT(BLOCK(ASSIGN(IDENT[x],INT[2]),ADD(INT[1],INT[1])))", test_parser("ROOT(BLOCK(ASSIGN(IDENT[x],INT[2]),ADD(INT[1],INT[1])))",
"{ x = 2; 1 + 1;}"); "{ x = 2; 1 + 1;}");
} }
Test(parser, if_block) {
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0])))",
"if a { 0; }");
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0]),BLOCK(INT[1])))",
"if a { 0; } else { 1; }");
test_parser("ROOT(IF(IDENT[a],BLOCK("
"INT[0]"
"),IF(IDENT[b],BLOCK("
"INT[1]"
"),BLOCK("
"INT[2]"
"))))",
"if a { 0; } else if b { 1; } else { 2; }");
}

View File

@ -9,7 +9,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#define GUX_STR_SIZE 256 #define GUX_STR_SIZE 512
#define GUX_ENUM_IDENT(X) X #define GUX_ENUM_IDENT(X) X
#define GUX_ENUM_STR(X) #X #define GUX_ENUM_STR(X) #X
#define GUX_ENUM_H(Prefix, Types) \ #define GUX_ENUM_H(Prefix, Types) \

61
tests/flow_control.gux Normal file
View File

@ -0,0 +1,61 @@
var a := 0;
if true { a = 1; }
assert a == 1;
if false { a = 2; }
assert a == 1;
if true { a = 3; } else { a = 4; }
assert a == 3;
if false { a = 3; } else { a = 4; }
assert a == 4;
if true {
a = 5;
} else if false {
a = 6;
} else if false {
a = 7;
} else {
a = 8;
}
assert a == 5;
if false {
a = 5;
} else if true {
a = 6;
} else if false {
a = 7;
} else {
a = 8;
}
assert a == 6;
if false {
a = 5;
} else if false {
a = 6;
} else if true {
a = 7;
} else {
a = 8;
}
assert a == 7;
if false {
a = 5;
} else if false {
a = 6;
} else if false {
a = 7;
} else {
a = 8;
}
assert a == 8;

View File

@ -124,6 +124,14 @@ int vm_exec(struct vm* self, struct program* program)
switch (opcode) switch (opcode)
{ {
case OP_SWAP: {
assert(frame->sp > 1);
int tmp = frame->stack[frame->sp - 1];
frame->stack[frame->sp - 1] = frame->stack[frame->sp - 2];
frame->stack[frame->sp - 2] = tmp;
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];