11#include " wheel_parser/parser.hxx"
2- #include " include/wheel_parser/ast/nodes.hxx"
2+ #include " wheel_parser/ast/keywords.hxx"
3+ #include " wheel_parser/ast/nodes.hxx"
4+ #include < utility>
35#include < wheel_utils/logging.hxx>
46
57using wheel_memory::Arena;
68using wheel_parser::WheelParser;
79using wheel_parser::ast::VariableDeclaration;
10+ using wheel_parser::ast::StatementNode;
11+ using wheel_parser::ast::ErrorStatement;
812using wheel_parser::ast::LiteralExpression;
913using wheel_lexer::Lexer;
14+ using wheel_parser::ast::k_keywords;
1015
11- WheelParser::WheelParser (Lexer &lexer, Arena &arena, StringInterner &interner) noexcept :
12- m_lexer(lexer), m_arena(arena),
13- m_interner(interner) {
14-
15- }
16+ #if defined(WHEEL_EXPERIMENT) && defined(WHEEL_SMALL_VEC)
17+ WheelParser::WheelParser (Lexer &lexer, Arena &arena, StringInterner &interner) noexcept :
18+ m_lexer(lexer), m_arena(arena), m_interner(interner), m_errors(&arena) {}
19+ #else
20+ WheelParser::WheelParser (Lexer &lexer, Arena &arena, StringInterner &interner) noexcept :
21+ m_lexer(lexer), m_arena(arena), m_interner(interner), m_errors() {}
22+ #endif
1623
1724const Token& WheelParser::consume () noexcept {
1825 const Token& consumed = m_current_token;
@@ -21,12 +28,47 @@ const Token& WheelParser::consume() noexcept {
2128 return consumed;
2229}
2330
24- bool WheelParser::str_matches (string_view str) noexcept {
25- return m_current_token.str == str ;
31+ bool WheelParser::token_matches (TokenKind token_kind) const noexcept {
32+ return m_current_token.kind == token_kind ;
2633}
2734
28- bool WheelParser::token_matches (TokenKind token_kind) noexcept {
29- return m_current_token.kind == token_kind;
35+ bool WheelParser::keyword_matches (Keyword keyword) const noexcept {
36+ if (m_current_token.kind != TokenKind::IDENT) {
37+ return false ;
38+ }
39+
40+ return m_current_token.str == k_keywords[static_cast <size_t >(keyword)].text ;
41+ }
42+
43+ void WheelParser::skip_spaces () noexcept {
44+ while (true ) {
45+ consume ();
46+ if (m_current_token.kind != TokenKind::SPACE && m_current_token.kind != TokenKind::TAB) {
47+ break ;
48+ }
49+ }
50+ }
51+
52+ void WheelParser::synchronize_statement () noexcept {
53+ while (m_current_token.kind != TokenKind::EOF_ && m_current_token.kind != TokenKind::NEWLINE) {
54+ consume ();
55+ }
56+ }
57+
58+ StatementNode *WheelParser::emit_error (
59+ ParseErrorCode code
60+ ) noexcept {
61+ const auto *token = copy_token ();
62+ const auto error = make_parse_error (
63+ code,
64+ token,
65+ token->kind ,
66+ m_lexer.get_source_location (*token)
67+ );
68+ m_errors.push_back (error);
69+
70+ synchronize_statement ();
71+ return m_arena.allocate <ErrorStatement>(token);
3072}
3173
3274const Token *WheelParser::copy_token () const noexcept {
@@ -38,49 +80,89 @@ const Token *WheelParser::copy_token() const noexcept {
3880 );
3981}
4082
41- // TODO: Implement error reporting, avoid returning `nullptr`
42- // We also need to improve error handling and avoid assuming everything is literal.
43- VariableDeclaration *WheelParser::parse_variable_declaration () noexcept {
83+ StatementNode *WheelParser::parse_variable_declaration () noexcept {
4484 consume ();
85+ if (!keyword_matches (Keyword::Var)) {
86+ return nullptr ;
87+ }
88+
4589 const auto start_token = copy_token ();
4690
47- if (token_matches (TokenKind::IDENT) && str_matches (" int" )) {
48- while (true ) {
49- consume ();
50- if (m_current_token.kind != TokenKind::SPACE) break ;
51- }
91+ skip_spaces ();
5292
53- const auto var_type = m_interner.intern (" int" );
54- const auto var_name = m_interner.intern (m_current_token.str );
93+ if (!token_matches (TokenKind::IDENT)) {
94+ return emit_error (ParseErrorCode::ExpectedIdentifier);
95+ }
96+ const auto var_name = m_interner.intern (m_current_token.str );
5597
56- while ( true ) {
57- consume ();
58- if (m_current_token. kind != TokenKind::SPACE) break ;
59- }
98+ skip_spaces ();
99+ if (! token_matches (TokenKind::COLON)) {
100+ return emit_error (ParseErrorCode::ExpectedColon) ;
101+ }
60102
61- const auto var_operator = m_current_token ;
62- if (var_operator. kind != TokenKind::EQUAL ) {
63- return nullptr ;
64- }
103+ skip_spaces () ;
104+ if (! token_matches ( TokenKind::IDENT) ) {
105+ return emit_error (ParseErrorCode::ExpectedType) ;
106+ }
65107
66- while (true ) {
67- consume ();
68- if (m_current_token.kind != TokenKind::SPACE) break ;
69- }
108+ const auto var_type = m_interner.intern (m_current_token.str );
70109
71- const auto var_value = m_interner. intern (m_current_token. str );
72- const auto literal = m_arena. allocate <LiteralExpression>(
73- &m_current_token
74- );
110+ skip_spaces ( );
111+ if (! token_matches (TokenKind::EQUAL)) {
112+ return emit_error (ParseErrorCode::ExpectedEqual);
113+ }
75114
76- return m_arena.allocate <VariableDeclaration>(
77- start_token,
78- var_type, var_name, literal
79- );
115+ skip_spaces ();
116+ switch (m_current_token.kind ) {
117+ case TokenKind::INT_LITERAL:
118+ case TokenKind::FLOAT_LITERAL:
119+ case TokenKind::STRING_LITERAL:
120+ case TokenKind::RAW_STRING_LITERAL:
121+ break ;
122+ default :
123+ return emit_error (ParseErrorCode::ExpectedLiteral);
80124 }
81125
82- return nullptr ;
126+ const auto literal_token = copy_token ();
127+ const auto literal = m_arena.allocate <LiteralExpression>(
128+ literal_token
129+ );
130+
131+ return m_arena.allocate <VariableDeclaration>(
132+ start_token,
133+ var_type, var_name, literal
134+ );
83135}
84136
85137void WheelParser::parse () noexcept {
86138}
139+
140+ size_t WheelParser::error_count () const noexcept {
141+ return m_errors.size ();
142+ }
143+
144+ const wheel_parser::ParseError *WheelParser::errors_data () const noexcept {
145+ return m_errors.data ();
146+ }
147+
148+ void WheelParser::clear_errors () noexcept {
149+ m_errors.clear ();
150+ }
151+
152+ wheel_parser::ParseDiagnosticList WheelParser::collect_diagnostics (std::string_view file_name) const {
153+ #if defined(WHEEL_EXPERIMENT) && defined(WHEEL_SMALL_VEC)
154+ ParseDiagnosticList diagnostics (&m_arena);
155+ #else
156+ ParseDiagnosticList diagnostics;
157+ diagnostics.reserve (m_errors.size ());
158+ #endif
159+
160+ const auto *errors = m_errors.data ();
161+
162+ for (size_t index = 0 ; index < m_errors.size (); ++index) {
163+ const auto line_view = m_lexer.get_source_line (errors[index].location .offset );
164+ diagnostics.push_back (build_parse_diagnostic (errors[index], line_view, file_name));
165+ }
166+
167+ return ParseDiagnosticList (std::move (diagnostics));
168+ }
0 commit comments