Compare commits

..

4 Commits

Author SHA1 Message Date
bog 12f42a86f6 FIX: nested block scopes. 2023-09-12 06:46:07 +02:00
bog aaeedb1ba9 ADD: if core function.
FIX: block scope.
2023-09-12 06:36:55 +02:00
bog ab64ab8007 ADD: blocks. 2023-09-12 05:53:16 +02:00
bog 43a029ebc9 ADD: syntaxic sugar for function declaration. 2023-09-11 22:18:11 +02:00
13 changed files with 170 additions and 6 deletions

View File

@ -4,10 +4,14 @@ EXPR ::=
| int | int
| ident | ident
| VARDECL | VARDECL
| FUNDECL
| FUNCALL | FUNCALL
| LAMBDA | LAMBDA
| BLOCK
VARDECL ::= opar decl ident EXPR cpar VARDECL ::= opar decl ident EXPR cpar
FUNDECL ::= opar decl opar ident* cpar BODY cpar
FUNCALL ::= opar EXPR EXPR* cpar FUNCALL ::= opar EXPR EXPR* cpar
LAMBDA ::= opar lambda opar PARAMS cpar BODY cpar LAMBDA ::= opar lambda opar PARAMS cpar BODY cpar
PARAMS ::= ident* PARAMS ::= ident*
BODY ::= EXPR* BODY ::= EXPR*
BLOCK ::= opar colon EXPR* cpar

14
examples/block.gri Normal file
View File

@ -0,0 +1,14 @@
(assert-eq? 6 (: 2 4 6))
(assert-eq? 9 (: 2 4 (: 3 0 9)))
(:
($ a 4)
(assert-eq? 4 a)
(:
($ a 7)
(assert-eq? 7 a)
)
(assert-eq? 4 a)
)

View File

@ -8,3 +8,11 @@
;; calling function literal ;; calling function literal
(assert-eq? 7 ( (-> (x y) (+ x y 1)) 2 4 )) (assert-eq? 7 ( (-> (x y) (+ x y 1)) 2 4 ))
;; syntaxic sugar for function declaration
($ (c n) (* 2 n))
(assert-eq? 18 (c 9))
;; inner variable
($ (d x) ($ y 3) (+ x y))
(assert-eq? 7 (d 4))

11
examples/if.gri Normal file
View File

@ -0,0 +1,11 @@
(assert-eq? 7 (if true 7 9))
(assert-eq? 9 (if false 7 9))
($ (max x y)
(if (> x y)
x
y
))
(assert-eq? 32 (max 3 32))
(assert-eq? 329 (max 329 32))

View File

@ -4,6 +4,28 @@
GRINO_ERROR(assertion_error); GRINO_ERROR(assertion_error);
extern "C" void lib_flow_control(grino::Loader& loader)
{
loader.add_static("if", [](auto& compiler, auto node, auto& prog, auto& sym) {
auto cond_node = node->child(1).lock();
auto then_node = node->child(2).lock();
auto else_node = node->child(3).lock();
compiler.compile(cond_node, prog, sym);
size_t brf = prog.size();
prog.push_instr(grino::OPCODE_BRF, 0);
compiler.compile(then_node, prog, sym);
size_t br = prog.size();
prog.push_instr(grino::OPCODE_BR, 0);
prog.set_param(brf, prog.size());
compiler.compile(else_node, prog, sym);
prog.set_param(br, prog.size());
});
}
extern "C" void lib_int(grino::Loader& loader) extern "C" void lib_int(grino::Loader& loader)
{ {
loader.add_native("+", [](auto args){ loader.add_native("+", [](auto args){
@ -306,6 +328,7 @@ extern "C" void lib(grino::Loader& loader)
lib_int(loader); lib_int(loader);
lib_cmp(loader); lib_cmp(loader);
lib_bool(loader); lib_bool(loader);
lib_flow_control(loader);
loader.add_native("dump", [](auto args){ loader.add_native("dump", [](auto args){
std::string sep; std::string sep;

View File

@ -40,6 +40,24 @@ namespace grino
program.push_instr(OPCODE_POP); program.push_instr(OPCODE_POP);
} }
} }
} break;
case NODE_BLOCK: {
enter_scope();
for (size_t i=0; i<node->size(); i++)
{
compile(node->child(i).lock(), program, sym);
if (i < node->size() - 1)
{
program.push_instr(OPCODE_POP);
}
}
leave_scope();
sym.purge(m_scope.size());
} break; } break;
case NODE_FUNCALL: { case NODE_FUNCALL: {
@ -66,7 +84,7 @@ namespace grino
case NODE_LAMBDA: { case NODE_LAMBDA: {
auto params = node->child(0).lock(); auto params = node->child(0).lock();
enter_scope(); enter_scope(true);
for (size_t i=0; i<params->size(); i++) for (size_t i=0; i<params->size(); i++)
{ {
@ -157,9 +175,16 @@ namespace grino
return m_scope.back() - 1; return m_scope.back() - 1;
} }
void Compiler::enter_scope() void Compiler::enter_scope(bool reset)
{ {
m_scope.push_back(0); if (m_scope.empty() || reset)
{
m_scope.push_back(0);
}
else
{
m_scope.push_back(m_scope.back());
}
} }
void Compiler::leave_scope() void Compiler::leave_scope()

View File

@ -35,7 +35,7 @@ namespace grino
std::vector<size_t> m_scope; std::vector<size_t> m_scope;
size_t get_local_address(); size_t get_local_address();
void enter_scope(); void enter_scope(bool reset=false);
void leave_scope(); void leave_scope();
}; };
} }

View File

@ -7,6 +7,7 @@ namespace grino
: m_logger { logger } : m_logger { logger }
, m_loc {source_path, 1} , m_loc {source_path, 1}
{ {
add_text(NODE_COLON, ":", false);
add_text(NODE_OPAR, "(", false); add_text(NODE_OPAR, "(", false);
add_text(NODE_CPAR, ")", false); add_text(NODE_CPAR, ")", false);
add_text(NODE_DECL, "$", false); add_text(NODE_DECL, "$", false);

View File

@ -16,7 +16,9 @@
G(NODE_DECL), \ G(NODE_DECL), \
G(NODE_LAMBDA), \ G(NODE_LAMBDA), \
G(NODE_PARAMS), \ G(NODE_PARAMS), \
G(NODE_BODY), G(NODE_BODY), \
G(NODE_COLON), \
G(NODE_BLOCK)
namespace grino namespace grino
{ {

View File

@ -118,6 +118,16 @@ namespace grino
std::shared_ptr<Node> Parser::parse_expr() std::shared_ptr<Node> Parser::parse_expr()
{ {
if (type_is({NODE_OPAR, NODE_COLON}))
{
return parse_block();
}
if (type_is({NODE_OPAR, NODE_DECL, NODE_OPAR}))
{
return parse_fundecl();
}
if (type_is({NODE_OPAR, NODE_DECL})) if (type_is({NODE_OPAR, NODE_DECL}))
{ {
return parse_vardecl(); return parse_vardecl();
@ -164,6 +174,31 @@ namespace grino
return node; return node;
} }
std::shared_ptr<Node> Parser::parse_fundecl()
{
consume(NODE_OPAR);
consume(NODE_DECL);
consume(NODE_OPAR);
auto ident = consume(NODE_IDENT);
auto params = parse_params();
consume(NODE_CPAR);
auto body = parse_body();
consume(NODE_CPAR);
auto lambda = make_node(NODE_LAMBDA);
lambda->add_child(params);
lambda->add_child(body);
auto node = make_node(NODE_VARDECL);
node->add_child(ident);
node->add_child(lambda);
return node;
}
std::shared_ptr<Node> Parser::parse_funcall() std::shared_ptr<Node> Parser::parse_funcall()
{ {
consume(NODE_OPAR); consume(NODE_OPAR);
@ -220,4 +255,21 @@ namespace grino
return node; return node;
} }
std::shared_ptr<Node> Parser::parse_block()
{
auto node = make_node(NODE_BLOCK);
consume(NODE_OPAR);
consume(NODE_COLON);
while (!type_is(NODE_CPAR))
{
node->add_child(parse_expr());
}
consume(NODE_CPAR);
return node;
}
} }

View File

@ -35,10 +35,12 @@ namespace grino
std::shared_ptr<Node> parse_module(); std::shared_ptr<Node> parse_module();
std::shared_ptr<Node> parse_expr(); std::shared_ptr<Node> parse_expr();
std::shared_ptr<Node> parse_vardecl(); std::shared_ptr<Node> parse_vardecl();
std::shared_ptr<Node> parse_fundecl();
std::shared_ptr<Node> parse_funcall(); std::shared_ptr<Node> parse_funcall();
std::shared_ptr<Node> parse_lambda(); std::shared_ptr<Node> parse_lambda();
std::shared_ptr<Node> parse_params(); std::shared_ptr<Node> parse_params();
std::shared_ptr<Node> parse_body(); std::shared_ptr<Node> parse_body();
std::shared_ptr<Node> parse_block();
}; };
} }

View File

@ -99,3 +99,12 @@ TEST_CASE_METHOD(LexerTest, "Lexer_lambda")
test_next(lexer, "LAMBDA"); test_next(lexer, "LAMBDA");
test_end(lexer); test_end(lexer);
} }
TEST_CASE_METHOD(LexerTest, "Lexer_block")
{
grino::Lexer lexer {m_logger, "tests/lexer"};
lexer.scan(" : ");
test_next(lexer, "COLON");
test_end(lexer);
}

View File

@ -74,3 +74,16 @@ TEST_CASE_METHOD(ParserTest, "Parser_lambda")
"( (-> (x) x ) 4 )"); "( (-> (x) x ) 4 )");
} }
TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
{
test_parse("MODULE(VARDECL(IDENT[f],LAMBDA(PARAMS(IDENT[x]),"
"BODY(FUNCALL(IDENT[+],IDENT[x],INT[1])))))",
"($ (f x) (+ x 1))");
}
TEST_CASE_METHOD(ParserTest, "Parser_block")
{
test_parse("MODULE(BLOCK(INT[1],BOOL[true],IDENT[salut]))",
"(: 1 true salut )");
}