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