module; #include #include #include #include #include export module jlx:ast; import :tokenizer; namespace jlx { export enum ast_type { Root, Expression, Block, FunctionDeclaration, SimpleIdentifier, LiteralValue }; export template concept token_iterator = requires() { requires std::same_as; std::bidirectional_iterator; }; struct statement { ast_type type; statement(ast_type type) : type(type) { } }; struct root_statement : public statement { root_statement() : statement(Root) { } std::vector> statements; }; struct expression : public statement { expression() : statement(Expression) { } }; struct block : public statement { block() : statement(Block) { } std::vector> statements; }; struct function_parameter { std::string name; std::string type; }; struct function_declaration : public statement { function_declaration() : statement(FunctionDeclaration) { } std::string name; std::vector parameters; std::optional return_type; std::unique_ptr body; }; export template E> class parser { T current; E last; inline void fail_invalid_token(const token& t) { throw std::runtime_error(std::format("Invalid token {} at {}:{}", t.content, t.line, t.col).c_str()); } inline void fail_invalid_eof() { throw std::runtime_error("Unexpected end-of-file"); } void next() { current++; if (current == last) { fail_invalid_eof(); } } std::unique_ptr parse_block() { if (current->type != Punctuation || current->content != "{") { fail_invalid_token(*current); } next(); while(current->type != Punctuation && current->type != "}") { } } std::unique_ptr parse_function() { if (current->type != Keyword || current->content != "fun") { fail_invalid_token(*current); } next(); if (current->type != Identifier) { fail_invalid_token(*current); } std::string function_name = current->content; next(); if (current->type != Punctuation || current->content != "(") { fail_invalid_token(*current); } next(); std::vector params; std::optional return_type; bool first = true; while (current->type != Punctuation && current->content != ")") { if (!first) { if(current->type != Punctuation || current->content != ",") { fail_invalid_token(*current); } else { next(); } } std::string name; if (current->type != Identifier) { fail_invalid_token(*current); } name = current->content; next(); if (current->type != Punctuation || current->content != ":") { fail_invalid_token(*current); } next(); auto param_type = parse_type(current, last); params.push_back(std::move(name), std::move(param_type)); next(); first = false; } next(); if (current->type == Punctuation && current->content == ":") { next(); return_type = parse_type(current, last); next(); } auto block = parse_block(); return std::make_unique(std::move(function_name), std::move(params), std::move(return_type), std::move(block)); } std::string parse_type(){ if (current->type != Identifier) { fail_invalid_token(*current); } return current->content; } std::unique_ptr parse_top_level_statement() { if (current == last) { return nullptr; } if (current->type == token_type::Keyword) { switch(current->content) { case "let": case "var": parse_variable_declaration(current, last); break; case "if": parse_if_statement(current, last); break; case "fun": return parse_function(current, last); } } } public: parser(T current, E last) : current(current), last(last) { } std::unique_ptr parse() { std::vector> top_level_statements; while(current != last) { auto s = parse_top_level_statement(); if (s == nullptr) { throw std::runtime_error("No statement parsed..."); } top_level_statements.push_back(std::move(s)); } return std::make_unique(top_level_statements); } }; }