diff --git a/src/ast.h b/src/ast.h index de210c3..f27cbf3 100644 --- a/src/ast.h +++ b/src/ast.h @@ -15,12 +15,16 @@ namespace AST { class IntLiteralExpression : public Expression { private: int m_value; + public: + IntLiteralExpression(int value) : m_value{ value } {} }; class ReturnStatement : public Statement { private: std::unique_ptr m_expr; + public: + ReturnStatement(std::unique_ptr expr) : m_expr{ std::move(expr) } {} }; class TopLevelStatement : public Node {}; @@ -33,7 +37,7 @@ namespace AST { std::vector> m_statements; public: Function( - Type* return_ty, + std::unique_ptr return_ty, std::vector>> params, std::string name, std::vector> statements) @@ -51,6 +55,8 @@ namespace AST { class FundamentalType : public Type { private: FundamentalTypeKind m_ty; + public: + FundamentalType(FundamentalTypeKind kind) : m_ty{ kind } {} }; } diff --git a/src/main.cpp b/src/main.cpp index e2ecaac..1e52ed6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,6 +59,7 @@ int main() { statements.push_back(statement.unwrap()); statement = parsing::parse_top_level_statement(stream); } + stream.expect(token::Type::Eof); // LLVM Hello World // llvm_hello_world(); diff --git a/src/parsing.cpp b/src/parsing.cpp index 2e32aab..79f6e13 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -2,8 +2,86 @@ namespace parsing { + namespace { + Result, std::string> parse_type(token::TokenStream& stream) { + token::TokenStream inner{ stream }; + try { + auto token = inner.expect(token::Type::Ident); + + stream.m_position = inner.m_position; + + auto ty = new AST::FundamentalType{ AST::FundamentalTypeKind::Int }; + return std::unique_ptr {ty}; + } + catch (std::runtime_error error) { + return std::string{ error.what() }; + } + } + + Result, std::string> parse_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{ 5 }; + 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_statement(token::TokenStream& stream) { + token::TokenStream inner{ stream }; + 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{ std::move(expression) }; + return std::unique_ptr{ ret }; + } + 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) { - auto fun = new AST::Function{ nullptr, {}, "main", {} }; - return Result, std::string>{ std::unique_ptr{ fun } }; + token::TokenStream inner{ stream }; + try { + auto type = parse_type(inner).unwrap(); + auto name_token = inner.expect(token::Type::Ident); + inner.expect(token::Type::Symbol, "("); + inner.expect(token::Type::Symbol, ")"); + inner.expect(token::Type::Symbol, "{"); + + std::vector> statements{}; + statements.push_back(parse_statement(inner).unwrap()); + + inner.expect(token::Type::Symbol, "}"); + + stream.m_position = inner.m_position; + + auto fun = new AST::Function{ std::move(type), {}, "main", std::move(statements) }; + return std::unique_ptr{ fun }; + } + catch (std::runtime_error error) { + return std::string(error.what()); + } } } \ No newline at end of file diff --git a/src/tokens.cpp b/src/tokens.cpp index 6864e74..2a4ea46 100644 --- a/src/tokens.cpp +++ b/src/tokens.cpp @@ -64,7 +64,9 @@ namespace token { } Token TokenStream::next() { - return this->peek(++m_position); + token::Token got = this->peek(0); + m_position++; + return got; } Token TokenStream::expect(Type type) { @@ -75,6 +77,14 @@ namespace token { throw std::runtime_error("Expected " + type_name(type) + ", got " + next.formatted()); } + Token TokenStream::expect(Type type, std::string_view content) { + auto next = this->next(); + if (next.type == type && next.content == content) { + return next; + } + throw std::runtime_error("Expected " + type_name(type) + "(" + std::string{ content } + "), got " + next.formatted()); + } + std::vector tokenize(std::string_view text) { std::vector tokens{}; @@ -108,7 +118,8 @@ namespace token { content += c; c = text[++i]; } while (iswhitespace(c)); - tokens.push_back(token::Token{ token::Type::Whitespace, content }); + // tokens.push_back(token::Token{ token::Type::Whitespace, content }); + // Just skip whitespace tokens } else { tokens.push_back(token::Token{ token::Type::Symbol, std::string{c} }); diff --git a/src/tokens.h b/src/tokens.h index 38f3d93..9892bc5 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -30,13 +30,14 @@ namespace token { class TokenStream { private: std::vector& m_tokens; - int m_position; public: + int m_position; TokenStream(std::vector& tokens); Token peek(int length); Token peek(); Token next(); Token expect(Type type); + Token expect(Type type, std::string_view content); }; std::ostream& operator<<(std::ostream& stream, Token& token);