✨ 'if then else' expressions.
parent
400f31025a
commit
a27eda5eda
|
@ -3,12 +3,15 @@ EXPR ::=
|
||||||
| ASSERT
|
| ASSERT
|
||||||
| VARDECL
|
| VARDECL
|
||||||
| VARSET
|
| VARSET
|
||||||
| BLOCK
|
| SCOPE
|
||||||
|
| IF
|
||||||
| OR
|
| OR
|
||||||
ASSERT ::= assert EXPR
|
ASSERT ::= assert EXPR
|
||||||
VARDECL ::= let ident assign EXPR
|
VARDECL ::= let ident assign EXPR
|
||||||
VARSET ::= ident assign EXPR
|
VARSET ::= ident assign EXPR
|
||||||
BLOCK ::= begin EXPR* end
|
BLOCK ::= EXPR*
|
||||||
|
SCOPE ::= begin BLOCK end
|
||||||
|
IF ::= if EXPR then BLOCK (else BLOCK | IF)? end
|
||||||
OR ::= AND (or AND)*
|
OR ::= AND (or AND)*
|
||||||
AND ::= EQNE (and EQNE)*
|
AND ::= EQNE (and EQNE)*
|
||||||
EQNE ::=
|
EQNE ::=
|
||||||
|
|
|
@ -309,6 +309,10 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_SCOPE: {
|
||||||
|
compiler_run(compiler, (node_t*) node->children.data[0]);
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_BLOCK: {
|
case NODE_BLOCK: {
|
||||||
compiler->scope++;
|
compiler->scope++;
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
@ -319,6 +323,23 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
||||||
compiler->scope--;
|
compiler->scope--;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_IF: {
|
||||||
|
size_t const IF_LIMIT = 1024;
|
||||||
|
|
||||||
|
int end_points[IF_LIMIT];
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
compiler_run_if(compiler, node, end_points, &size);
|
||||||
|
assert(size < IF_LIMIT);
|
||||||
|
|
||||||
|
for (size_t i=0; i<size; i++)
|
||||||
|
{
|
||||||
|
compiler->mod->program.params[end_points[i]]
|
||||||
|
= compiler->mod->program.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compile unknown node '%s'",
|
fprintf(stderr, "Cannot compile unknown node '%s'",
|
||||||
NodeTypeStr[node->type]);
|
NodeTypeStr[node->type]);
|
||||||
|
@ -328,3 +349,39 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compiler_run_if(compiler_t* compiler, node_t* node,
|
||||||
|
int* end_points, size_t* sz)
|
||||||
|
{
|
||||||
|
assert(compiler);
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
// if
|
||||||
|
compiler_run(compiler, (node_t*) node->children.data[0]);
|
||||||
|
// if false goto next
|
||||||
|
int to_next = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM);
|
||||||
|
|
||||||
|
// then
|
||||||
|
compiler_run(compiler, (node_t*) node->children.data[1]);
|
||||||
|
// goto end
|
||||||
|
int to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM);
|
||||||
|
end_points[*sz] = to_end;
|
||||||
|
(*sz)++;
|
||||||
|
|
||||||
|
compiler->mod->program.params[to_next]
|
||||||
|
= compiler->mod->program.size;
|
||||||
|
|
||||||
|
if (node->children.size >= 3)
|
||||||
|
{
|
||||||
|
node_t* next = (node_t*) node->children.data[2];
|
||||||
|
|
||||||
|
if (next->type == NODE_BLOCK)
|
||||||
|
{
|
||||||
|
compiler_run(compiler, next);
|
||||||
|
}
|
||||||
|
else if (next->type == NODE_IF)
|
||||||
|
{
|
||||||
|
compiler_run_if(compiler, next, end_points, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,5 +26,7 @@ void compiler_init(compiler_t* compiler,
|
||||||
void compiler_free(compiler_t* compiler);
|
void compiler_free(compiler_t* compiler);
|
||||||
|
|
||||||
int compiler_run(compiler_t* compiler, node_t* node);
|
int compiler_run(compiler_t* compiler, node_t* node);
|
||||||
|
void compiler_run_if(compiler_t* compiler, node_t* node,
|
||||||
|
int* end_points, size_t* sz);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,6 +71,9 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
// ========
|
// ========
|
||||||
|
RZ_KEYWORD("if", NODE_IF, 0);
|
||||||
|
RZ_KEYWORD("then", NODE_THEN, 0);
|
||||||
|
RZ_KEYWORD("else", NODE_ELSE, 0);
|
||||||
RZ_KEYWORD("begin", NODE_BEGIN, 0);
|
RZ_KEYWORD("begin", NODE_BEGIN, 0);
|
||||||
RZ_KEYWORD("end", NODE_END, 0);
|
RZ_KEYWORD("end", NODE_END, 0);
|
||||||
RZ_KEYWORD("let", NODE_LET, 0);
|
RZ_KEYWORD("let", NODE_LET, 0);
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
|
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
|
||||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
||||||
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL), \
|
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL), \
|
||||||
G(NODE_VARSET), G(NODE_BEGIN), G(NODE_END), G(NODE_BLOCK)
|
G(NODE_VARSET), G(NODE_BEGIN), G(NODE_END), G(NODE_BLOCK), \
|
||||||
|
G(NODE_SCOPE), G(NODE_IF), G(NODE_THEN), G(NODE_ELSE)
|
||||||
|
|
||||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
|
70
lib/parser.c
70
lib/parser.c
|
@ -64,6 +64,11 @@ node_t* parser_try_new_expr(parser_t* parser)
|
||||||
return parser_try_new_varset(parser);
|
return parser_try_new_varset(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type_1 == NODE_IF)
|
||||||
|
{
|
||||||
|
return parser_try_new_if(parser);
|
||||||
|
}
|
||||||
|
|
||||||
if (type_1 == NODE_ASSERT)
|
if (type_1 == NODE_ASSERT)
|
||||||
{
|
{
|
||||||
return parser_try_new_assert(parser);
|
return parser_try_new_assert(parser);
|
||||||
|
@ -76,7 +81,7 @@ node_t* parser_try_new_expr(parser_t* parser)
|
||||||
|
|
||||||
if (type_1 == NODE_BEGIN)
|
if (type_1 == NODE_BEGIN)
|
||||||
{
|
{
|
||||||
return parser_try_new_block(parser);
|
return parser_try_new_scope(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser_try_new_or(parser);
|
return parser_try_new_or(parser);
|
||||||
|
@ -141,18 +146,69 @@ node_t* parser_try_new_block(parser_t* parser)
|
||||||
node_t* block = malloc(sizeof(node_t));
|
node_t* block = malloc(sizeof(node_t));
|
||||||
node_init(block, NODE_BLOCK, "", parser->lexer->line);
|
node_init(block, NODE_BLOCK, "", parser->lexer->line);
|
||||||
|
|
||||||
parser_skip(parser, NODE_BEGIN);
|
while (1)
|
||||||
|
|
||||||
NodeType next;
|
|
||||||
|
|
||||||
while ( (next = lexer_peek(parser->lexer, 1)) != NODE_END)
|
|
||||||
{
|
{
|
||||||
|
NodeType next = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
if (next == NODE_END
|
||||||
|
|| next == NODE_ELSE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
node_add_new_child(block, parser_try_new_expr(parser));
|
node_add_new_child(block, parser_try_new_expr(parser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_scope(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
parser_skip(parser, NODE_BEGIN);
|
||||||
|
node_t* block = parser_try_new_block(parser);
|
||||||
parser_skip(parser, NODE_END);
|
parser_skip(parser, NODE_END);
|
||||||
|
|
||||||
return block;
|
node_t* scope = malloc(sizeof(node_t));
|
||||||
|
node_init(scope, NODE_SCOPE, "", parser->lexer->line);
|
||||||
|
node_add_new_child(scope, block);
|
||||||
|
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_if(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_consume(parser, NODE_IF);
|
||||||
|
node_add_new_child(node, parser_try_new_expr(parser));
|
||||||
|
|
||||||
|
parser_skip(parser, NODE_THEN);
|
||||||
|
node_add_new_child(node, parser_try_new_block(parser));
|
||||||
|
|
||||||
|
int next = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
if (next == NODE_ELSE)
|
||||||
|
{
|
||||||
|
parser_skip(parser, NODE_ELSE);
|
||||||
|
int n = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
if (n == NODE_IF)
|
||||||
|
{
|
||||||
|
node_add_new_child(node, parser_try_new_if(parser));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node_add_new_child(node, parser_try_new_block(parser));
|
||||||
|
parser_skip(parser, NODE_END);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parser_skip(parser, NODE_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_or(parser_t* parser)
|
node_t* parser_try_new_or(parser_t* parser)
|
||||||
|
|
|
@ -20,6 +20,8 @@ node_t* parser_try_new_assert(parser_t* parser);
|
||||||
node_t* parser_try_new_vardecl(parser_t* parser);
|
node_t* parser_try_new_vardecl(parser_t* parser);
|
||||||
node_t* parser_try_new_varset(parser_t* parser);
|
node_t* parser_try_new_varset(parser_t* parser);
|
||||||
node_t* parser_try_new_block(parser_t* parser);
|
node_t* parser_try_new_block(parser_t* parser);
|
||||||
|
node_t* parser_try_new_scope(parser_t* parser);
|
||||||
|
node_t* parser_try_new_if(parser_t* parser);
|
||||||
node_t* parser_try_new_or(parser_t* parser);
|
node_t* parser_try_new_or(parser_t* parser);
|
||||||
node_t* parser_try_new_and(parser_t* parser);
|
node_t* parser_try_new_and(parser_t* parser);
|
||||||
node_t* parser_try_new_eqne(parser_t* parser);
|
node_t* parser_try_new_eqne(parser_t* parser);
|
||||||
|
|
|
@ -34,7 +34,6 @@ int sym_declare(sym_t* sym, char* name, type_t* type,
|
||||||
{
|
{
|
||||||
assert(sym);
|
assert(sym);
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(type);
|
|
||||||
|
|
||||||
sym_entry_t* res = sym_try_find_by_name(sym,
|
sym_entry_t* res = sym_try_find_by_name(sym,
|
||||||
name,
|
name,
|
||||||
|
|
12
lib/type.c
12
lib/type.c
|
@ -23,9 +23,15 @@ int type_eq(type_t* type, type_t* rhs)
|
||||||
|
|
||||||
size_t type_str(type_t* type, char* buffer, size_t size)
|
size_t type_str(type_t* type, char* buffer, size_t size)
|
||||||
{
|
{
|
||||||
assert(type);
|
|
||||||
assert(buffer);
|
assert(buffer);
|
||||||
|
|
||||||
return snprintf(buffer, size, "%s",
|
if (type)
|
||||||
TypeKindStr[type->kind] + strlen("TYPE_"));
|
{
|
||||||
|
return snprintf(buffer, size, "%s",
|
||||||
|
TypeKindStr[type->kind] + strlen("TYPE_"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return snprintf(buffer, size, "*unknown*");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,10 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
|
||||||
return ty;
|
return ty;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_IF: {
|
||||||
|
return NULL;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
tysolver_error(tysolver, node);
|
tysolver_error(tysolver, node);
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
# SIMPLE IF
|
||||||
|
# =========
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
if true then
|
||||||
|
count = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if false then
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 1
|
||||||
|
|
||||||
|
# ELSE
|
||||||
|
# ====
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if true then
|
||||||
|
count = count + 1
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
|
if false then
|
||||||
|
else
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 2
|
||||||
|
|
||||||
|
# ELSE IF
|
||||||
|
# =======
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if true then
|
||||||
|
count = 1
|
||||||
|
else if true then
|
||||||
|
count = 0
|
||||||
|
else if true then
|
||||||
|
count = 0
|
||||||
|
else
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 1
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if false then
|
||||||
|
count = 0
|
||||||
|
else if true then
|
||||||
|
count = 1
|
||||||
|
else if true then
|
||||||
|
count = 0
|
||||||
|
else
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 1
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if false then
|
||||||
|
count = 0
|
||||||
|
else if false then
|
||||||
|
count = 0
|
||||||
|
else if true then
|
||||||
|
count = 1
|
||||||
|
else
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 1
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if false then
|
||||||
|
count = 0
|
||||||
|
else if false then
|
||||||
|
count = 0
|
||||||
|
else if false then
|
||||||
|
count = 0
|
||||||
|
else
|
||||||
|
count = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
assert count == 1
|
||||||
|
|
||||||
|
# IF AS EXPR
|
||||||
|
# ==========
|
||||||
|
let a = if true then 5 else 6 end
|
||||||
|
let b = if false then 5 else 6 end
|
||||||
|
|
||||||
|
assert a == 5
|
||||||
|
assert b == 6
|
||||||
|
|
||||||
|
# IF BLOCKS
|
||||||
|
# =========
|
||||||
|
let c = 34
|
||||||
|
|
||||||
|
if true then
|
||||||
|
let c = 9
|
||||||
|
assert c == 9
|
||||||
|
end
|
||||||
|
|
||||||
|
assert c == 34
|
||||||
|
|
||||||
|
let d = "bim"
|
||||||
|
|
||||||
|
if false then
|
||||||
|
else
|
||||||
|
let d = "bam"
|
||||||
|
assert d == "bam"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert d == "bim"
|
|
@ -158,7 +158,8 @@ Test(lexer, let_var) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(lexer, blocks) {
|
Test(lexer, blocks) {
|
||||||
test_lexer("begin end", 2,
|
test_lexer("if then else", 3,
|
||||||
"BEGIN",
|
"IF",
|
||||||
"END");
|
"THEN",
|
||||||
|
"ELSE");
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,13 +116,26 @@ Test(parser, var_set) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(parser, block) {
|
Test(parser, block) {
|
||||||
test_parser_ok("MOD(BLOCK)",
|
test_parser_ok("MOD(SCOPE(BLOCK))",
|
||||||
" begin end ");
|
" begin end ");
|
||||||
|
|
||||||
test_parser_ok("MOD(BLOCK(ADD(NUM[1],NUM[2])))",
|
test_parser_ok("MOD(SCOPE(BLOCK(ADD(NUM[1],NUM[2]))))",
|
||||||
" begin 1 + 2 end ");
|
" begin 1 + 2 end ");
|
||||||
|
|
||||||
test_parser_ok("MOD(BLOCK(VARSET(IDENT[y],BOOL[true])"
|
test_parser_ok("MOD(SCOPE(BLOCK(VARSET(IDENT[y],BOOL[true])"
|
||||||
",VARSET(IDENT[z],BOOL[false])))",
|
",VARSET(IDENT[z],BOOL[false]))))",
|
||||||
" begin y = true z = false end ");
|
" begin y = true z = false end ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(parser, if_then_else) {
|
||||||
|
test_parser_ok("MOD(IF(IDENT[x],BLOCK(IDENT[y])))",
|
||||||
|
"if x then y end");
|
||||||
|
|
||||||
|
test_parser_ok("MOD(IF(IDENT[x],BLOCK(IDENT[y]),BLOCK(IDENT[z])))",
|
||||||
|
"if x then y else z end");
|
||||||
|
|
||||||
|
test_parser_ok("MOD(IF(IDENT[x],"
|
||||||
|
"BLOCK(IDENT[y]),"
|
||||||
|
"IF(IDENT[z],BLOCK(IDENT[u]),BLOCK(IDENT[v]))))",
|
||||||
|
"if x then y else if z then u else v end");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue