extern "C" { #include "parser.h" } #include "parser.hpp" #include "pattern.hpp" namespace lily { std::string tree_str(pgs_tree* tree, const char* source) { size_t from = PGS_TREE_T_FROM(*tree); size_t to = PGS_TREE_T_TO(*tree); return std::string(source + from, to - from); } static ast_ptr expr_tree(pgs_tree*, const char*); static ast_ptr expr_app_bottom(pgs_tree* base, const char* source) { if(PGS_TREE_NT_COUNT(*base) == 2) { return expr_tree(PGS_TREE_NT_CHILD(*base, 1), source); } else { pgs_tree* child = PGS_TREE_NT_CHILD(*base, 0); if(isdigit(source[PGS_TREE_T_FROM(*child)])) { return ast_ptr(new ast_num(atoi(source + PGS_TREE_T_FROM(*child)))); } else { return ast_ptr(new ast_var(tree_str(child, source))); } } } static ast_ptr expr_app(pgs_tree* app, const char* source) { ast_ptr into; ast_ptr* into_ptr = &into; while(PGS_TREE_NT_COUNT(*app) > 1) { ast_app* new_app = new ast_app(nullptr, nullptr); *into_ptr = ast_ptr(new_app); into_ptr = &new_app->left; new_app->right = expr_app_bottom(PGS_TREE_NT_CHILD(*app, 1), source); app = PGS_TREE_NT_CHILD(*app, 0); } *into_ptr = expr_app_bottom(PGS_TREE_NT_CHILD(*app, 0), source); return into; } static ast_ptr expr_mul(pgs_tree* mul, const char* source) { if(PGS_TREE_NT_COUNT(*mul) == 1) { return expr_app(PGS_TREE_NT_CHILD(*mul, 0), source); } else { pgs_tree* left = PGS_TREE_NT_CHILD(*mul, 0); pgs_tree* right = PGS_TREE_NT_CHILD(*mul, 2); pgs_tree* op = PGS_TREE_NT_CHILD(*mul, 1); enum ast_op::op o = source[PGS_TREE_T_FROM(*op)] == '*' ? ast_op::op::times : ast_op::op::divide; ast_ptr aleft = expr_mul(left, source); ast_ptr aright = expr_app(right, source); return ast_ptr(new ast_op(o, std::move(aleft), std::move(aright))); } } static ast_ptr expr_add(pgs_tree* add, const char* source) { if(PGS_TREE_NT_COUNT(*add) == 1) { return expr_mul(PGS_TREE_NT_CHILD(*add, 0), source); } else { pgs_tree* left = PGS_TREE_NT_CHILD(*add, 0); pgs_tree* right = PGS_TREE_NT_CHILD(*add, 2); pgs_tree* op = PGS_TREE_NT_CHILD(*add, 1); enum ast_op::op o = source[PGS_TREE_T_FROM(*op)] == '+' ? ast_op::op::add : ast_op::op::subtract; ast_ptr aleft = expr_add(left, source); ast_ptr aright = expr_mul(right, source); return ast_ptr(new ast_op(o, std::move(aleft), std::move(aright))); } } template static ast_ptr expr_let(pgs_tree* let, const char* source) { std::string name = tree_str(PGS_TREE_NT_CHILD(*let, Offset + 1), source); ast_ptr eq_expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*let, Offset + 3), 1), source); ast_ptr in_expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*let, Offset + 5), 1), source); return ast_ptr(new T(name, std::move(eq_expr), std::move(in_expr))); } static pattern_ptr pattern_tree(pgs_tree* tree, const char* source) { if(PGS_TREE_NT_COUNT(*tree) == 1) { std::string new_str = tree_str(PGS_TREE_NT_CHILD(*tree, 0), source); if(isupper(new_str[0])) return pattern_ptr(new pattern_cons(new_str)); else return pattern_ptr(new pattern_var(new_str)); } else { std::string cons_name = tree_str(PGS_TREE_NT_CHILD(*tree, 0), source); pattern_cons* new_pattern = new pattern_cons(cons_name); pattern_ptr ptr = pattern_ptr(new_pattern); pgs_tree* patterns = PGS_TREE_NT_CHILD(*tree, 2); while(PGS_TREE_NT_COUNT(*patterns) > 1) { new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*tree, 0), source)); patterns = PGS_TREE_NT_CHILD(*tree, 2); } new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*tree, 0), source)); return ptr; } } static ast_case::branch expr_branch(pgs_tree* c, const char* source) { ast_case::branch branch; branch.pattern = pattern_tree(PGS_TREE_NT_CHILD(*c, 0), source); branch.expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*c, 2), 1), source); return branch; } static ast_ptr expr_case(pgs_tree* c, const char* source) { ast_case* new_case = new ast_case(); ast_ptr case_ptr = ast_ptr(new_case); new_case->of = expr_tree(PGS_TREE_NT_CHILD(*c, 1), source); pgs_tree* branches = PGS_TREE_NT_CHILD(*c, 4); while(PGS_TREE_NT_COUNT(*branches) == 2) { pgs_tree* branch = PGS_TREE_NT_CHILD(*branches, 0); branches = PGS_TREE_NT_CHILD(*branches, 1); new_case->branches.push_back(expr_branch(branch, source)); } new_case->branches.push_back(expr_branch(PGS_TREE_NT_CHILD(*branches, 0), source)); return case_ptr; } static ast_ptr expr_tree(pgs_tree* body, const char* source) { pgs_tree* expr = PGS_TREE_NT_CHILD(*body, 0); int type = PGS_TREE_NT(*expr); if(type == PGS_NONTERMINAL_EXPR_ADD) { return expr_add(expr, source); } else if(type == PGS_NONTERMINAL_EXPR_LET) { return expr_let(expr, source); } else if(type == PGS_NONTERMINAL_EXPR_LETREC) { return expr_let(expr, source); } else if(type == PGS_NONTERMINAL_EXPR_CASE) { return expr_case(expr, source); } throw error("unknown expression type"); } static void collect_params(std::vector& into, pgs_tree* def, const char* source) { if(PGS_TREE_NT_COUNT(*def) == 5) { pgs_tree* params = PGS_TREE_NT_CHILD(*def, 2); do { pgs_tree* param = PGS_TREE_NT_CHILD(*def, 0); params = (PGS_TREE_NT_COUNT(*def) == 2) ? PGS_TREE_NT_CHILD(*def, 1) : nullptr; size_t from = PGS_TREE_T_FROM(*param); size_t to = PGS_TREE_T_TO(*param); std::string new_string = std::string(source + from, to - from); into.push_back(new_string); } while(params); } } static void add_definition(program& prog, pgs_tree* def, const char* source) { char kw = source[PGS_TREE_T_FROM(*PGS_TREE_NT_CHILD(*def, 0))]; if(kw == 'd') { function new_function; collect_params(new_function.params, def, source); new_function.body = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*def, PGS_TREE_NT_COUNT(*def) - 1), 1), source); } else if(kw == 't') { // skip for now } else { // skip for now } } static program_ptr build_program(pgs_tree* tree, const char* source) { program_ptr prog = std::make_unique(); pgs_tree* program = PGS_TREE_NT_CHILD(*tree, 0); do { pgs_tree* definition = PGS_TREE_NT_CHILD(*program, 0); program = (PGS_TREE_NT_COUNT(*tree) == 2) ? PGS_TREE_NT_CHILD(*tree, 1) : nullptr; add_definition(*prog, definition, source); } while(program); return prog; } program_ptr parse(std::string s) { pgs_state state; pgs_tree* into; pgs_error err; pgs_state_init(&state); if((err = pgs_do_all(&state, &into, s.c_str())) != PGS_NONE) { throw error("failed to parse input string"); } program_ptr prog = build_program(into, s.c_str()); pgs_free_tree(into); return prog; } }