Line data Source code
1 : #include "stax/parser/parser.hpp"
2 :
3 : #include <set>
4 :
5 : #include "stax/utils/format.hpp"
6 : #include "stax/utils/result.hpp"
7 :
8 : namespace stax::parser {
9 :
10 4 : Parser::Parser(const std::string& input) : input_(input), lexer_(input_) {
11 : // TODO deal with error handling
12 4 : NextToken().value();
13 4 : NextToken().value();
14 4 : }
15 :
16 4 : auto Parser::ParseProgram() -> result_t<Program> {
17 4 : Program prog{};
18 :
19 16 : while (curr_.type != token::Type::kEOF) {
20 12 : TRY_RESULT(const auto stmt, ParseStatement());
21 12 : prog.statements.push_back(stmt);
22 12 : }
23 :
24 4 : return prog;
25 4 : }
26 :
27 14 : auto Parser::ParseStatement() -> result_t<ast_t> {
28 14 : switch (curr_.type) {
29 12 : case token::Type::kIdent: return ParseDeclaration(); break;
30 2 : case token::Type::kReturn: return ParseReturn(); break;
31 0 : default:
32 0 : return stax::result::Err(Error::InvalidToken, std::format("{}", curr_));
33 : }
34 : }
35 :
36 2 : auto Parser::ParseReturn() -> result_t<ast_t> {
37 2 : TRY_RESULT(NextToken());
38 2 : TRY_RESULT(const auto& expression, ParseExpressionStatement());
39 :
40 2 : return ReturnStatement{.expression = expression};
41 2 : }
42 :
43 12 : auto Parser::ParseDeclaration() -> result_t<ast_t> {
44 12 : TRY_RESULT(Expect(token::Type::kIdent));
45 36 : const auto& data_type = DataType{curr_, std::string{curr_.view}};
46 12 : TRY_RESULT(NextToken());
47 :
48 12 : TRY_RESULT(Expect(token::Type::kIdent));
49 36 : const auto& ident = Identifier{curr_, std::string{curr_.view}};
50 12 : TRY_RESULT(NextToken());
51 :
52 12 : if (curr_.type == token::Type::kLParen) {
53 2 : return ParseFunctionDeclaration(data_type, ident);
54 : } else {
55 10 : return ParseVariableDeclaration(data_type, ident);
56 : }
57 36 : }
58 :
59 2 : auto Parser::ParseFunctionDeclaration(const DataType& return_type,
60 : const Identifier& ident)
61 : -> result_t<ast_t> {
62 2 : if (curr_.type == token::Type::kLParen) {
63 2 : TRY_RESULT(NextToken());
64 2 : }
65 :
66 2 : std::vector<VariableDeclaration> args;
67 2 : while (curr_.type != token::Type::kRParen) {
68 0 : TRY_RESULT(Expect(token::Type::kIdent));
69 0 : const auto& data_type = DataType{curr_, std::string{curr_.view}};
70 0 : TRY_RESULT(NextToken());
71 :
72 0 : TRY_RESULT(Expect(token::Type::kIdent));
73 0 : const auto& ident = Identifier{curr_, std::string{curr_.view}};
74 0 : TRY_RESULT(NextToken());
75 :
76 0 : if (curr_.type == token::Type::kComma) {
77 0 : TRY_RESULT(NextToken());
78 0 : }
79 :
80 0 : args.emplace_back(data_type, ident);
81 0 : }
82 :
83 2 : if (curr_.type == token::Type::kRParen) {
84 2 : TRY_RESULT(NextToken());
85 2 : }
86 :
87 2 : TRY_RESULT(Expect(token::Type::kLBrace));
88 2 : TRY_RESULT(NextToken());
89 :
90 2 : std::vector<ast_t> statements;
91 4 : while (curr_.type != token::Type::kRBrace) {
92 2 : TRY_RESULT(const auto& stmt, ParseStatement());
93 2 : statements.emplace_back(stmt);
94 2 : }
95 :
96 2 : TRY_RESULT(Expect(token::Type::kRBrace));
97 2 : TRY_RESULT(NextToken());
98 :
99 2 : auto block = std::make_shared<BlockStatement>();
100 2 : if (!statements.empty()) block->statements = statements;
101 2 : return FunctionDeclaration(return_type, ident, {}, block);
102 2 : }
103 :
104 10 : auto Parser::ParseVariableDeclaration(const DataType& var_type,
105 : const Identifier& ident)
106 : -> result_t<ast_t> {
107 10 : std::optional<ExpressionStatement> expression;
108 10 : if (curr_.type == token::Type::kAssign) {
109 10 : TRY_RESULT(NextToken());
110 10 : TRY_RESULT(expression, ParseExpressionStatement());
111 10 : }
112 :
113 10 : return VariableDeclaration(var_type, ident, expression);
114 10 : }
115 :
116 12 : auto Parser::ParseExpressionStatement() -> result_t<ExpressionStatement> {
117 12 : TRY_RESULT(const auto expression, ParseExpression());
118 :
119 12 : TRY_RESULT(Expect(token::Type::kSemicolon));
120 12 : TRY_RESULT(NextToken()); // Skip semicolon
121 :
122 12 : return ExpressionStatement{.expression = expression};
123 12 : }
124 :
125 19 : auto Parser::ParseExpression() -> result_t<expression_t> {
126 : const auto generic_parser =
127 16 : [](const token::Token& tok) -> result_t<expression_t> {
128 16 : switch (tok.type) {
129 14 : case token::Type::kInt:
130 28 : return IntegerLiteral{.value = std::stoi(std::string(tok.view))};
131 2 : case token::Type::kIdent:
132 4 : return IdentifierExpression{.ident = std::string(tok.view)};
133 0 : default: {
134 0 : return stax::result::Err(Error::InvalidToken,
135 0 : std::format("Not an expression {}", tok));
136 : }
137 : }
138 : };
139 :
140 : const auto& parse_prefix =
141 19 : [this, generic_parser](const token::Token& op) -> result_t<expression_t> {
142 : const std::set<token::Type> prefix_ops = {
143 : token::Type::kPlus, token::Type::kMinus, token::Type::kTilde,
144 38 : token::Type::kBang};
145 :
146 19 : if (prefix_ops.contains(op.type)) {
147 3 : TRY_RESULT(const auto operand, ParseExpression());
148 6 : return PrefixExpression{
149 3 : .op = op, .operand = std::make_shared<expression_t>(operand)};
150 3 : }
151 :
152 16 : return generic_parser(op);
153 19 : };
154 :
155 : const auto& parse_infix =
156 4 : [this](const expression_t& left,
157 : const token::Token& op) -> result_t<std::optional<expression_t>> {
158 : const std::set<token::Type> infix_ops = {
159 : token::Type::kPlus, token::Type::kMinus, token::Type::kGreater,
160 8 : token::kLess};
161 :
162 4 : if (infix_ops.contains(op.type)) {
163 4 : TRY_RESULT(const auto operand, ParseExpression());
164 8 : return InfixExpression{
165 : .lhs = std::make_shared<expression_t>(left),
166 : .op = op,
167 : .rhs = std::make_shared<expression_t>(operand),
168 4 : };
169 4 : }
170 :
171 0 : return std::nullopt;
172 4 : };
173 :
174 19 : const auto prefix_op = curr_;
175 19 : TRY_RESULT(NextToken());
176 19 : TRY_RESULT(const auto left, parse_prefix(prefix_op));
177 :
178 19 : const auto infix_op = curr_;
179 19 : if (curr_.type != token::Type::kSemicolon) {
180 4 : TRY_RESULT(NextToken());
181 4 : TRY_RESULT(const auto infix, parse_infix(left, infix_op));
182 4 : if (infix.has_value()) {
183 4 : return infix.value();
184 : }
185 12 : }
186 :
187 15 : return left;
188 19 : }
189 :
190 87 : auto Parser::NextToken() -> result_t<void> {
191 87 : curr_ = peek_;
192 87 : TRY_RESULT(peek_, lexer_.NextToken());
193 87 : return result::Ok();
194 87 : }
195 :
196 0 : auto Parser::ExpectPeek(token::Type tok_type) -> result_t<void> {
197 0 : if (peek_.type != tok_type) {
198 0 : return result::Err(
199 0 : Error::ExpectedToken,
200 0 : std::format("Expected {}, but got: {}", tok_type, peek_.type));
201 : }
202 :
203 0 : return result::Ok();
204 : }
205 :
206 40 : auto Parser::Expect(token::Type tok_type) -> result_t<void> {
207 40 : if (curr_.type != tok_type) {
208 0 : return result::Err(
209 0 : Error::ExpectedToken,
210 0 : std::format("Expected {}, but got: {}", tok_type, curr_.type));
211 : }
212 :
213 40 : return result::Ok();
214 : }
215 :
216 : } // namespace stax::parser
|