#include "types.h" #include "parsing.h" #include "tokens.h" namespace parsing { namespace { Result, std::string> parse_expression(token::TokenStream& stream); Result, std::string> parse_type(token::TokenStream& stream) { token::TokenStream inner{ stream }; try { auto token = inner.expect(token::Type::Ident); // TODO eventually make this be potentially more than one word std::string type_name = token.content; std::shared_ptr returned{}; if (type_name == "int") { auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Int }; returned = std::shared_ptr{ ty }; } else if (type_name == "char") { auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Char }; returned = std::shared_ptr{ ty }; } else if (type_name == "void") { auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Void }; returned = std::shared_ptr{ ty }; } else { throw std::runtime_error("Expected type name, got " + type_name); } while (inner.peek().type == token::Type::Symbol && inner.peek().content == "*") { inner.next(); auto ty = new types::PointerType{ std::move(returned) }; returned = std::shared_ptr{ ty }; } stream.m_position = inner.m_position; return returned; } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result, std::string> parse_plain_expression(token::TokenStream& stream) { token::TokenStream inner{ stream }; try { auto token = inner.next(); if (token.type == token::Type::LiteralInt) { stream.m_position = inner.m_position; auto expr = new AST::IntLiteralExpression{ token.metadata, std::stoi(token.content) }; return std::unique_ptr{ expr }; } else if (token.type == token::Type::LiteralStr) { stream.m_position = inner.m_position; auto expr = new AST::StringLiteralExpression{ token.metadata, token.content }; return std::unique_ptr{ expr }; } else if (token.type == token::Type::Ident) { stream.m_position = inner.m_position; auto expr = new AST::ValueReferenceExpression{ token.metadata, token.content }; return std::unique_ptr{ expr }; } else { throw std::runtime_error("Expected expression"); } } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result, std::string> parse_cast(token::TokenStream& stream) { token::TokenStream inner{ stream }; try { inner.expect(token::Type::Symbol, "("); auto ty = parse_type(inner).unwrap(); inner.expect(token::Type::Symbol, ")"); stream.m_position = inner.m_position; return ty; } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result, std::string> parse_primary_expression(token::TokenStream& stream) { token::TokenStream inner{ stream }; try { auto before_meta = inner.metadata(); if (auto cast = parse_cast(inner); cast.ok()) { auto expr = parse_expression(inner).unwrap(); stream.m_position = inner.m_position; return std::unique_ptr{ new AST::CastExpression{ before_meta + inner.metadata(), cast.unwrap(), std::move(expr) } }; } auto plain_expr = parse_plain_expression(inner); while (inner.peek().content == "(") { inner.next(); std::vector> args{}; int counter = 0; while (inner.peek().content != ")") { if (counter++ > 0) inner.expect(token::Type::Symbol, ","); args.push_back(parse_expression(inner).unwrap()); } inner.expect(token::Type::Symbol, ")"); auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) }; plain_expr = std::unique_ptr{ fn_call }; } stream.m_position = inner.m_position; return plain_expr; } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result parse_binop(token::TokenStream& stream) { token::TokenStream inner{ stream }; try { auto token = inner.next(); if (token.type != token::Type::Symbol) { throw std::runtime_error("Expected binop"); } else if (token.content == "=") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Assignment }; } else if (token.content == "+") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Add }; } else if (token.content == "-") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Sub }; } else if (token.content == "<") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::LessThan }; } else if (token.content == ">") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::GreaterThan }; } throw std::runtime_error("Expected binop"); } catch (std::runtime_error& error) { return std::string{ error.what() }; } } std::unique_ptr parse_rhs( token::TokenStream& stream, std::unique_ptr lhs, int prev_precedence) { auto before = stream.metadata(); auto binop_res = parse_binop(stream); while (binop_res.ok()) { auto binop = binop_res.unwrap(); auto rhs = parse_primary_expression(stream).unwrap(); if (types::operator_precedence(binop) > prev_precedence) { rhs = parse_rhs(stream, std::move(rhs), types::operator_precedence(binop)); } auto binop_expr = new AST::BinaryOperationExpression{ before + stream.metadata(), std::move(lhs), binop, std::move(rhs) }; lhs = std::unique_ptr{ binop_expr }; binop_res = parse_binop(stream); } return lhs; } Result, std::string> parse_expression(token::TokenStream& stream) { try { auto lhs = parse_primary_expression(stream).unwrap(); return std::unique_ptr{ parse_rhs(stream, std::move(lhs), 0) }; } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result, std::string> parse_init_statement(token::TokenStream& stream) { token::TokenStream inner{ stream }; auto before_meta = inner.metadata(); try { auto ty = parse_type(inner).unwrap(); auto name = inner.expect(token::Type::Ident); std::optional> expr = {}; if (inner.peek().type == token::Type::Symbol && inner.peek().content == "=") { inner.expect(token::Type::Symbol, "="); expr = parse_expression(inner).unwrap(); } inner.expect(token::Type::Symbol, ";"); stream.m_position = inner.m_position; auto init = new AST::InitializationStatement{ before_meta + inner.metadata(), std::move(ty), name.content, std::move(expr) }; return std::unique_ptr{ init }; } catch (std::runtime_error& error) { return std::string{ error.what() }; } } Result, std::string> parse_statement(token::TokenStream& stream) { token::TokenStream inner{ stream }; auto before_meta = inner.metadata(); try { if (inner.peek().type == token::Type::ReturnKeyword) { inner.next(); auto expression = parse_expression(inner).unwrap(); inner.expect(token::Type::Symbol, ";"); stream.m_position = inner.m_position; auto ret = new AST::ReturnStatement{ before_meta + stream.metadata(),std::move(expression) }; return std::unique_ptr{ ret }; } else if (inner.peek().type == token::Type::IfKeyword) { inner.next(); inner.expect(token::Type::Symbol, "("); auto expression = parse_expression(inner).unwrap(); inner.expect(token::Type::Symbol, ")"); auto then_statement = parse_statement(inner).unwrap(); std::optional> else_statement{}; if (inner.peek().type == token::Type::ElseKeyword) { inner.next(); else_statement = parse_statement(inner).unwrap(); } stream.m_position = inner.m_position; auto statement = new AST::IfStatement{ before_meta + stream.metadata(), std::move(expression), std::move(then_statement), std::move(else_statement) }; return std::unique_ptr{ statement }; } else if (auto init = parse_init_statement(inner); init.ok()) { stream.m_position = inner.m_position; return std::unique_ptr{ init.unwrap() }; } else if (auto expr = parse_expression(inner); expr.ok()) { stream.m_position = inner.m_position; stream.expect(token::Type::Symbol, ";"); auto expr_statement = new AST::ExpressionStatement{ before_meta + stream.metadata(), expr.unwrap() }; return std::unique_ptr{ expr_statement }; } else { throw std::runtime_error("Expected return-keyword"); } } catch (std::runtime_error& error) { return std::string{ error.what() }; } } } Result, std::string> parse_top_level_statement(token::TokenStream& stream) { token::TokenStream inner{ stream }; auto before_meta = inner.metadata(); try { auto type = parse_type(inner).unwrap(); auto name_token = inner.expect(token::Type::Ident); inner.expect(token::Type::Symbol, "("); std::vector, std::shared_ptr>> params; bool is_vararg = false; while (inner.peek().content != ")") { if (params.size() > 0) { inner.expect(token::Type::Symbol, ","); } if (inner.peek().content == ".") { inner.next(); inner.expect(token::Type::Symbol, "."); inner.expect(token::Type::Symbol, "."); is_vararg = true; break; } auto param_ty = parse_type(inner).unwrap(); std::optional param_name{}; if (inner.peek().type == token::Type::Ident) { param_name = inner.expect(token::Type::Ident).content; } params.push_back(std::pair(param_name, std::move(param_ty))); } inner.expect(token::Type::Symbol, ")"); std::optional>> statements{}; if (inner.peek().content == "{") { inner.expect(token::Type::Symbol, "{"); std::vector> statement_list{}; auto statement = parse_statement(inner); while (statement.ok()) { statement_list.push_back(statement.unwrap()); statement = parse_statement(inner); } statements = std::optional{ std::move(statement_list) }; inner.expect(token::Type::Symbol, "}"); } else { inner.expect(token::Type::Symbol, ";"); } stream.m_position = inner.m_position; auto fun = new AST::Function{ before_meta + stream.metadata(), std::move(type), std::move(params), is_vararg, name_token.content, std::move(statements) }; return std::unique_ptr{ fun }; } catch (std::runtime_error& error) { return std::string(error.what()); } } }