Compare commits
4 Commits
a5ec909a5a
...
12f42a86f6
Author | SHA1 | Date |
---|---|---|
bog | 12f42a86f6 | |
bog | aaeedb1ba9 | |
bog | ab64ab8007 | |
bog | 43a029ebc9 |
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
)
|
|
@ -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))
|
|
@ -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))
|
23
lib/core.cpp
23
lib/core.cpp
|
@ -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;
|
||||||
|
|
|
@ -42,6 +42,24 @@ namespace grino
|
||||||
}
|
}
|
||||||
} break;
|
} 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;
|
||||||
|
|
||||||
case NODE_FUNCALL: {
|
case NODE_FUNCALL: {
|
||||||
std::string ident = node->child(0).lock()->repr();
|
std::string ident = node->child(0).lock()->repr();
|
||||||
|
|
||||||
|
@ -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,10 +175,17 @@ namespace grino
|
||||||
return m_scope.back() - 1;
|
return m_scope.back() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::enter_scope()
|
void Compiler::enter_scope(bool reset)
|
||||||
|
{
|
||||||
|
if (m_scope.empty() || reset)
|
||||||
{
|
{
|
||||||
m_scope.push_back(0);
|
m_scope.push_back(0);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_scope.push_back(m_scope.back());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Compiler::leave_scope()
|
void Compiler::leave_scope()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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 )");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue