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