ADD: var declaration.
parent
e8e4906cfc
commit
749f6c0a95
|
@ -3,4 +3,20 @@
|
|||
|
||||
extern "C" void lib(jk::Loader& loader)
|
||||
{
|
||||
loader.declare("dump", [](auto args){
|
||||
std::string sep;
|
||||
|
||||
for (auto arg: args)
|
||||
{
|
||||
std::cout << sep << arg->string();
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
if (args.empty() == false)
|
||||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return jk::Value::make_nil();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
PROG ::= FUNCALL*
|
||||
EXPR ::= LITERAL | FUNCALL
|
||||
EXPR ::=
|
||||
LITERAL
|
||||
| FUNCALL
|
||||
| VARDECL
|
||||
VARDECL ::= opar decl ident EXPR cpar
|
||||
FUNCALL ::= opar ident EXPR* cpar
|
||||
LITERAL ::= int | ident
|
||||
|
|
|
@ -36,18 +36,19 @@ namespace jk
|
|||
program->push_instr(OPCODE_CALL, node->size() - 1);
|
||||
} break;
|
||||
|
||||
case NODE_VARDECL: {
|
||||
std::string ident = node->child(0).lock()->repr();
|
||||
auto entry = m_sym->find(ident);
|
||||
assert(entry);
|
||||
|
||||
compile(node->child(1).lock(), program);
|
||||
program->push_instr(OPCODE_STORE, entry->addr);
|
||||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
std::string ident = node->repr();
|
||||
auto sym = m_sym->find(ident);
|
||||
|
||||
if (!sym)
|
||||
{
|
||||
m_logger.log<compile_error>(LOG_ERROR, node->loc(),
|
||||
std::string()
|
||||
+ "'"
|
||||
+ ident
|
||||
+ "' is undefined");
|
||||
}
|
||||
assert(sym);
|
||||
|
||||
OpcodeType op_load = OPCODE_LOAD;
|
||||
|
||||
|
@ -56,10 +57,7 @@ namespace jk
|
|||
op_load = OPCODE_LOAD_GLOBAL;
|
||||
}
|
||||
|
||||
if (sym->type->type() == TYPE_FUNCTION)
|
||||
{
|
||||
program->push_instr(op_load, sym->addr);
|
||||
}
|
||||
program->push_instr(op_load, sym->addr);
|
||||
|
||||
} break;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace jk
|
|||
, m_loc { loc }
|
||||
{
|
||||
std::vector<std::tuple<NodeType, std::string, bool>> texts = {
|
||||
{NODE_DECL, "$", false},
|
||||
{NODE_OPAR, "(", false},
|
||||
{NODE_CPAR, ")", false}
|
||||
};
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
G(NODE_OPAR), \
|
||||
G(NODE_CPAR), \
|
||||
G(NODE_IDENT), \
|
||||
G(NODE_FUNCALL),
|
||||
G(NODE_DECL), \
|
||||
G(NODE_FUNCALL), \
|
||||
G(NODE_VARDECL)
|
||||
|
||||
|
||||
namespace jk
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace jk
|
|||
|
||||
while (m_cursor < m_tokens.size())
|
||||
{
|
||||
root->add_child(parse_funcall());
|
||||
root->add_child(parse_expr());
|
||||
}
|
||||
|
||||
return root;
|
||||
|
@ -99,14 +99,33 @@ namespace jk
|
|||
|
||||
std::shared_ptr<Node> Parser::parse_expr()
|
||||
{
|
||||
if (type_is(NODE_OPAR))
|
||||
if (type_is(NODE_OPAR)
|
||||
&& type_is(NODE_IDENT, 1))
|
||||
{
|
||||
return parse_funcall();
|
||||
}
|
||||
|
||||
if (type_is(NODE_OPAR)
|
||||
&& type_is(NODE_DECL, 1))
|
||||
{
|
||||
return parse_vardecl();
|
||||
}
|
||||
|
||||
return parse_literal();
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_vardecl()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_VARDECL, "", loc());
|
||||
consume(NODE_OPAR);
|
||||
consume(NODE_DECL);
|
||||
root->add_child(consume(NODE_IDENT));
|
||||
root->add_child(parse_expr());
|
||||
consume(NODE_CPAR);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_funcall()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_FUNCALL, "", loc());
|
||||
|
@ -134,8 +153,10 @@ namespace jk
|
|||
loc(),
|
||||
std::string()
|
||||
+ "unexpected token '"
|
||||
+ NodeTypeStr[current()->type()]
|
||||
+ "' ('"
|
||||
+ current()->repr()
|
||||
+ "'");
|
||||
+ "')");
|
||||
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace jk
|
|||
|
||||
std::shared_ptr<Node> parse_prog();
|
||||
std::shared_ptr<Node> parse_expr();
|
||||
std::shared_ptr<Node> parse_vardecl();
|
||||
std::shared_ptr<Node> parse_funcall();
|
||||
std::shared_ptr<Node> parse_literal();
|
||||
};
|
||||
|
|
|
@ -21,11 +21,46 @@ namespace jk
|
|||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
pass(node->child(i).lock());
|
||||
pop();
|
||||
}
|
||||
} break;
|
||||
|
||||
case NODE_FUNCALL: {
|
||||
case NODE_INT: {
|
||||
push(std::make_shared<Type>(TYPE_INT));
|
||||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
std::string ident = node->repr();
|
||||
auto entry = m_sym->find(ident);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
m_logger.log<symbolic_error>(LOG_ERROR, node->loc(),
|
||||
std::string()
|
||||
+ "'"
|
||||
+ ident
|
||||
+ "' is undefined");
|
||||
}
|
||||
|
||||
push(entry->type);
|
||||
} break;
|
||||
|
||||
case NODE_VARDECL: {
|
||||
std::string ident = node->child(0).lock()->repr();
|
||||
pass(node->child(1).lock());
|
||||
auto type = pop();
|
||||
m_sym->declare(ident, type, node->loc());
|
||||
push(type);
|
||||
} break;
|
||||
|
||||
case NODE_FUNCALL: {
|
||||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
pass(node->child(i).lock());
|
||||
pop();
|
||||
}
|
||||
// TODO find actual returned type
|
||||
push(std::make_shared<Type>(TYPE_NIL));
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
@ -34,4 +69,17 @@ namespace jk
|
|||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void StaticPass::push(std::shared_ptr<Type> type)
|
||||
{
|
||||
m_types.push_back(type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> StaticPass::pop()
|
||||
{
|
||||
auto type = m_types.back();
|
||||
m_types.pop_back();
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ namespace jk
|
|||
private:
|
||||
std::shared_ptr<SymTable> m_sym;
|
||||
Logger& m_logger;
|
||||
std::vector<std::shared_ptr<Type>> m_types;
|
||||
|
||||
void push(std::shared_ptr<Type> type);
|
||||
std::shared_ptr<Type> pop();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -137,5 +137,4 @@ namespace jk
|
|||
m_stack.pop_back();
|
||||
return param;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace jk
|
|||
{
|
||||
case TYPE_NIL: return "<nil>";
|
||||
case TYPE_INT: return std::to_string(*m_int_val);
|
||||
case TYPE_REF: return "<ref:" + std::to_string(*m_ref_val) + ">";
|
||||
|
||||
default:
|
||||
std::cerr << "cannot stringify value '"
|
||||
|
|
|
@ -83,8 +83,6 @@ int main(int argc, char** argv)
|
|||
|
||||
auto sym = std::make_shared<jk::SymTable>(logger);
|
||||
|
||||
auto static_pass = std::make_shared<jk::StaticPass>(sym, logger);
|
||||
static_pass->pass(ast);
|
||||
|
||||
auto compiler = std::make_shared<jk::Compiler>(sym, logger);
|
||||
auto program = std::make_shared<jk::Program>();
|
||||
|
@ -92,6 +90,9 @@ int main(int argc, char** argv)
|
|||
auto loader = std::make_shared<jk::Loader>(vm, sym);
|
||||
loader->load();
|
||||
|
||||
auto static_pass = std::make_shared<jk::StaticPass>(sym, logger);
|
||||
static_pass->pass(ast);
|
||||
|
||||
compiler->compile(ast, program);
|
||||
|
||||
if (debug_mode)
|
||||
|
|
|
@ -65,3 +65,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_funcall")
|
|||
test_next(*lexer, "IDENT[salut/monde]");
|
||||
test_end(*lexer);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_vardecl")
|
||||
{
|
||||
auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer();
|
||||
lexer->scan(" $ ");
|
||||
test_next(*lexer, "DECL");
|
||||
test_end(*lexer);
|
||||
}
|
||||
|
|
|
@ -34,3 +34,13 @@ TEST_CASE_METHOD(ParserTest, "Parser_funcall")
|
|||
test_parser("PROG(FUNCALL(IDENT[hello],INT[1],INT[2],IDENT[bim!]))",
|
||||
" (hello 1 2 bim!) ");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_vardecl")
|
||||
{
|
||||
test_parser("PROG(VARDECL(IDENT[hello],INT[4]))",
|
||||
" ($ hello 4) ");
|
||||
|
||||
test_parser("PROG(VARDECL(IDENT[world],"
|
||||
"FUNCALL(IDENT[f],INT[3],INT[2])))",
|
||||
" ($ world (f 3 2)) ");
|
||||
}
|
||||
|
|
Reference in New Issue