• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vla5924-practice / compiler-project / 13871470507

15 Mar 2025 09:12AM UTC coverage: 76.643% (+1.7%) from 74.945%
13871470507

Pull #208

github

web-flow
Merge f00268d08 into 640b4d135
Pull Request #208: Support dynamically sized lists

54 of 68 new or added lines in 6 files covered. (79.41%)

1 existing line in 1 file now uncovered.

4246 of 5540 relevant lines covered (76.64%)

222.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.69
/compiler/lib/frontend/parser/parser.cpp
1
#include "parser/parser.hpp"
2

3
#include <cassert>
4
#include <functional>
5
#include <iterator>
6
#include <memory>
7
#include <stack>
8
#include <stdexcept>
9
#include <string>
10
#include <unordered_map>
11
#include <variant>
12

13
#include "compiler/ast/node.hpp"
14
#include "compiler/ast/node_type.hpp"
15
#include "compiler/utils/error_buffer.hpp"
16

17
#include "lexer/token.hpp"
18
#include "lexer/token_types.hpp"
19
#include "parser/parser_context.hpp"
20
#include "parser/parser_error.hpp"
21
#include "parser/type_registry.hpp"
22

23
using namespace ast;
24
using namespace lexer;
25
using namespace parser;
26

27
namespace {
28

29
using SubExpression = std::variant<TokenIterator, Node::Ptr>;
30

31
bool isVariableDeclaration(const TokenIterator &tokenIter, const TokenIterator &tokenEnd) {
272✔
32
    if (tokenIter == tokenEnd || std::next(tokenIter) == tokenEnd || std::next(tokenIter, 2) == tokenEnd)
272✔
33
        return false;
8✔
34

35
    const Token &varName = *tokenIter;
264✔
36
    const Token &colon = *std::next(tokenIter);
264✔
37
    const Token &varType = *std::next(tokenIter, 2);
264✔
38
    return varName.type == TokenType::Identifier && colon.is(Special::Colon) || TypeRegistry::isTypename(varType);
264✔
39
}
40

41
enum class OperationType {
42
    Unknown,
43
    Unary,
44
    Binary,
45
};
46

47
enum class ExpressionTokenType {
48
    Unknown,
49
    Operation,
50
    Operand,
51
    OpeningBrace,
52
    ClosingBrace,
53
    RectBrace,
54
};
55

56
OperationType getOperationType(const Token &token) {
627✔
57
    if (token.type == TokenType::Operator) {
627✔
58
        const auto &op = token.op();
607✔
59
        switch (op) {
607✔
60
        case Operator::Add:
607✔
61
        case Operator::Sub:
62
        case Operator::Mult:
63
        case Operator::Div:
64
        case Operator::Equal:
65
        case Operator::NotEqual:
66
        case Operator::Less:
67
        case Operator::Greater:
68
        case Operator::LessEqual:
69
        case Operator::GreaterEqual:
70
        case Operator::Assign:
71
            return OperationType::Binary;
607✔
72
        default:
×
73
            return OperationType::Unknown;
×
74
        }
75
    }
76
    if (token.type == TokenType::Keyword) {
20✔
77
        const auto &kw = token.kw();
20✔
78
        switch (kw) {
20✔
79
        case Keyword::And:
20✔
80
        case Keyword::Or:
81
            return OperationType::Binary;
20✔
82
        case Keyword::Not:
×
83
            return OperationType::Unary;
×
84
        default:
×
85
            return OperationType::Unknown;
×
86
        }
87
    }
88
    return OperationType::Unknown;
×
89
}
90

91
OperationType getOperationType(const Node &node) {
1,008✔
92
    switch (node.type) {
1,008✔
93
    case NodeType::BinaryOperation:
612✔
94
        return OperationType::Binary;
612✔
95
    case NodeType::UnaryOperation:
×
96
        return OperationType::Unary;
×
97
    default:
396✔
98
        return OperationType::Unknown;
396✔
99
    }
100
}
101

102
ExpressionTokenType getExpressionTokenType(const Token &token) {
1,492✔
103
    if (token.type == TokenType::Identifier || token.type == TokenType::IntegerLiteral ||
1,054✔
104
        token.type == TokenType::FloatingPointLiteral || token.type == TokenType::StringLiteral ||
628✔
105
        token.is(Keyword::True) || token.is(Keyword::False))
2,546✔
106
        return ExpressionTokenType::Operand;
954✔
107
    if (token.is(Operator::LeftBrace))
538✔
108
        return ExpressionTokenType::OpeningBrace;
46✔
109
    if (token.is(Operator::RightBrace))
492✔
110
        return ExpressionTokenType::ClosingBrace;
23✔
111
    if (token.is(Operator::RectLeftBrace) || token.is(Operator::RectRightBrace))
469✔
112
        return ExpressionTokenType::RectBrace;
46✔
113
    if (getOperationType(token) != OperationType::Unknown)
423✔
114
        return ExpressionTokenType::Operation;
423✔
115
    return ExpressionTokenType::Unknown;
×
116
}
117

118
ExpressionTokenType getExpressionTokenType(const SubExpression &subexpr) {
×
119
    if (std::holds_alternative<Node::Ptr>(subexpr))
×
120
        return ExpressionTokenType::Operand;
×
121
    return getExpressionTokenType(*std::get<TokenIterator>(subexpr));
×
122
}
123

124
BinaryOperation getBinaryOperation(const Token &token) {
362✔
125
    if (token.type == TokenType::Operator) {
362✔
126
        const auto &op = token.op();
351✔
127
        switch (op) {
351✔
128
        case Operator::Add:
129✔
129
            return BinaryOperation::Add;
129✔
130
        case Operator::Sub:
6✔
131
            return BinaryOperation::Sub;
6✔
132
        case Operator::Mult:
48✔
133
            return BinaryOperation::Mult;
48✔
134
        case Operator::Div:
14✔
135
            return BinaryOperation::Div;
14✔
136
        case Operator::Equal:
8✔
137
            return BinaryOperation::Equal;
8✔
138
        case Operator::NotEqual:
×
139
            return BinaryOperation::NotEqual;
×
140
        case Operator::Less:
2✔
141
            return BinaryOperation::Less;
2✔
142
        case Operator::Greater:
5✔
143
            return BinaryOperation::Greater;
5✔
144
        case Operator::LessEqual:
×
145
            return BinaryOperation::LessEqual;
×
146
        case Operator::GreaterEqual:
×
147
            return BinaryOperation::GreaterEqual;
×
148
        case Operator::Assign:
119✔
149
            return BinaryOperation::Assign;
119✔
150
        default:
20✔
151
            return BinaryOperation::Unknown;
20✔
152
        }
153
    }
154
    if (token.type == TokenType::Keyword) {
11✔
155
        const auto &kw = token.kw();
11✔
156
        switch (kw) {
11✔
157
        case Keyword::And:
7✔
158
            return BinaryOperation::And;
7✔
159
        case Keyword::Or:
4✔
160
            return BinaryOperation::Or;
4✔
161
        default:
×
162
            return BinaryOperation::Unknown;
×
163
        }
164
    }
165
    return BinaryOperation::Unknown;
×
166
}
167

168
UnaryOperation getUnaryOperation(const Token &token) {
43✔
169
    if (token.type == TokenType::Operator) {
43✔
170
        const auto &op = token.op();
34✔
171
        switch (op) {
34✔
172
        case Operator::Sub:
34✔
173
            return UnaryOperation::Negative;
34✔
174
        default:
×
175
            return UnaryOperation::Unknown;
×
176
        }
177
    }
178
    if (token.type == TokenType::Keyword) {
9✔
179
        const auto &kw = token.kw();
9✔
180
        switch (kw) {
9✔
181
        case Keyword::Not:
9✔
182
            return UnaryOperation::Not;
9✔
183
        default:
×
184
            return UnaryOperation::Unknown;
×
185
        }
186
    }
187
    return UnaryOperation::Unknown;
×
188
}
189

190
size_t getOperationPriority(const Token &token) {
158✔
191
    BinaryOperation op = getBinaryOperation(token);
158✔
192
    switch (op) {
158✔
193
    case BinaryOperation::Mult:
37✔
194
    case BinaryOperation::Div:
195
        return 10;
37✔
196
    case BinaryOperation::Add:
71✔
197
    case BinaryOperation::Sub:
198
        return 20;
71✔
199
    case BinaryOperation::Less:
×
200
    case BinaryOperation::LessEqual:
201
    case BinaryOperation::Greater:
202
    case BinaryOperation::GreaterEqual:
203
        return 30;
×
204
    case BinaryOperation::Equal:
1✔
205
    case BinaryOperation::NotEqual:
206
        return 35;
1✔
207
    case BinaryOperation::And:
3✔
208
        return 40;
3✔
209
    case BinaryOperation::Or:
2✔
210
        return 50;
2✔
211
    case BinaryOperation::Assign:
24✔
212
        return 60;
24✔
213
    default:
20✔
214
        return -1;
20✔
215
    }
216
    return -1;
217
}
218

219
size_t getOperandCount(OperationType type) {
1,008✔
220
    if (type == OperationType::Binary)
1,008✔
221
        return 2u;
612✔
222
    if (type == OperationType::Unary)
396✔
223
        return 1u;
×
224
    return -1;
396✔
225
}
226

227
bool isFunctionCall(const TokenIterator &tokenIter) {
939✔
228
    return tokenIter->type == TokenType::Identifier && std::next(tokenIter)->is(Operator::LeftBrace);
939✔
229
}
230

231
bool isListAccessor(const TokenIterator &tokenIter) {
878✔
232
    return tokenIter->type == TokenType::Identifier && std::next(tokenIter)->is(Operator::RectLeftBrace);
878✔
233
}
234

235
bool canBeUnaryOperation(const TokenIterator &tokenIter) {
816✔
236
    if (tokenIter->type == TokenType::Operator) {
816✔
237
        return tokenIter->op() == Operator::Sub || tokenIter->op() == Operator::Add;
324✔
238
    }
239
    if (tokenIter->type == TokenType::Keyword) {
492✔
240
        return tokenIter->kw() == Keyword::Not;
19✔
241
    }
242
    return false;
473✔
243
}
244

245
bool isUnaryOperation(const TokenIterator &tokenIter, const ExpressionTokenType &prevTokenIter) {
816✔
246
    return canBeUnaryOperation(tokenIter) &&
923✔
247
           (prevTokenIter == ExpressionTokenType::Operation || prevTokenIter == ExpressionTokenType::OpeningBrace);
923✔
248
}
249

250
void buildExpressionSubtree(std::stack<SubExpression> &postfixForm, const Node::Ptr &root, ErrorBuffer &errors) {
396✔
251
    Node::Ptr currNode = root;
396✔
252
    while (!postfixForm.empty()) {
1,200✔
253
        const SubExpression &subexpr = postfixForm.top();
804✔
254
        if (std::holds_alternative<TokenIterator>(subexpr)) {
804✔
255
            const Token &token = *std::get<TokenIterator>(subexpr);
681✔
256
            ExpressionTokenType expType = getExpressionTokenType(token);
681✔
257
            if (expType == ExpressionTokenType::Operation) {
681✔
258
                OperationType opType = getOperationType(token);
204✔
259
                if (opType == OperationType::Binary) {
204✔
260
                    currNode = ParserContext::unshiftChildNode(currNode, NodeType::BinaryOperation, token.ref);
204✔
261
                    currNode->value = getBinaryOperation(token);
204✔
262
                } else if (opType == OperationType::Unary) {
×
263
                    currNode = ParserContext::unshiftChildNode(currNode, NodeType::UnaryOperation, token.ref);
×
264
                } else {
265
                    errors.push<ParserError>(token,
×
266
                                             "Unknown operator found in expression, it must be either unary or binary");
267
                }
268
            } else if (expType == ExpressionTokenType::Operand) {
477✔
269
                if (token.type == TokenType::Identifier) {
477✔
270
                    Node::Ptr node = ParserContext::unshiftChildNode(currNode, NodeType::VariableName, token.ref);
219✔
271
                    node->value = token.id();
219✔
272
                } else if (token.type == TokenType::IntegerLiteral) {
477✔
273
                    Node::Ptr node =
274
                        ParserContext::unshiftChildNode(currNode, NodeType::IntegerLiteralValue, token.ref);
213✔
275
                    try {
276
                        node->value = std::stol(token.literal().c_str());
215✔
277
                    } catch (const std::out_of_range &) {
1✔
278
                        errors.push<ParserError>(token,
1✔
279
                                                 "Failed to convert integer literal. The number is out of range");
280
                    }
1✔
281
                } else if (token.type == TokenType::FloatingPointLiteral) {
258✔
282
                    Node::Ptr node =
283
                        ParserContext::unshiftChildNode(currNode, NodeType::FloatingPointLiteralValue, token.ref);
35✔
284
                    try {
285
                        node->value = std::stod(token.literal());
35✔
286
                    } catch (const std::out_of_range &) {
2✔
287
                        errors.push<ParserError>(token, "Failed to convert float literal. The number is out of range");
2✔
288
                    }
2✔
289
                } else if (token.type == TokenType::StringLiteral) {
45✔
290
                    Node::Ptr node = ParserContext::unshiftChildNode(currNode, NodeType::StringLiteralValue, token.ref);
6✔
291
                    node->value = token.literal();
6✔
292
                } else if (token.is(Keyword::False) || token.is(Keyword::True)) {
10✔
293
                    Node::Ptr node =
294
                        ParserContext::unshiftChildNode(currNode, NodeType::BooleanLiteralValue, token.ref);
4✔
295
                    if (token.is(Keyword::True))
4✔
296
                        node->value = true;
2✔
297
                    else if (token.is(Keyword::False))
2✔
298
                        node->value = false;
2✔
299
                }
4✔
300
            }
301
        } else {
302
            // can be FunctionCall node and list ListAccessor
303
            Node::Ptr callNode = std::get<Node::Ptr>(subexpr);
123✔
304
            assert(callNode->type == NodeType::FunctionCall or callNode->type == NodeType::ListAccessor or
123✔
305
                   callNode->type == NodeType::UnaryOperation);
306
            callNode->parent = currNode;
123✔
307
            currNode->children.push_front(callNode);
123✔
308
        }
123✔
309
        while (currNode->children.size() >= getOperandCount(getOperationType(*currNode)))
1,008✔
310
            currNode = currNode->parent;
204✔
311
        postfixForm.pop();
804✔
312
    }
313
}
396✔
314

315
std::stack<SubExpression> generatePostfixForm(TokenIterator tokenIterBegin, TokenIterator tokenIterEnd,
396✔
316
                                              ErrorBuffer &errors) {
317
    std::stack<SubExpression> postfixForm;
396✔
318
    std::stack<TokenIterator> operations;
396✔
319
    ExpressionTokenType prevExpType = ExpressionTokenType::Operation;
396✔
320
    for (auto tokenIter = tokenIterBegin; tokenIter != tokenIterEnd; tokenIter++) {
1,292✔
321
        const Token &token = *tokenIter;
896✔
322
        if (isFunctionCall(tokenIter)) {
896✔
323
            Node::Ptr funcCallNode = std::make_shared<Node>(NodeType::FunctionCall);
57✔
324
            auto node = ParserContext::pushChildNode(funcCallNode, NodeType::FunctionName, token.ref);
57✔
325
            node->value = token.id();
57✔
326
            auto argsBegin = std::next(tokenIter);
57✔
327
            auto it = argsBegin;
57✔
328
            unsigned nestingLevel = 0;
57✔
329
            do {
330
                if (it->is(Operator::RightBrace))
317✔
331
                    nestingLevel--;
70✔
332
                else if (it->is(Operator::LeftBrace))
247✔
333
                    nestingLevel++;
70✔
334
                it++;
317✔
335
            } while (nestingLevel > 0);
317✔
336
            auto argsEnd = std::prev(it);
57✔
337
            if (std::distance(argsBegin, argsEnd) > 1) {
57✔
338
                auto argsNode = ParserContext::pushChildNode(funcCallNode, NodeType::FunctionArguments, token.ref);
43✔
339
                auto argBegin = std::next(argsBegin);
43✔
340
                for (auto argsIter = argBegin; argsIter != std::next(argsEnd); argsIter++) {
289✔
341
                    if (!argsIter->is(Operator::Comma) && argsIter != argsEnd)
246✔
342
                        continue;
175✔
343
                    const Token &token = *argsIter;
71✔
344
                    std::stack<SubExpression> argPostfixForm = generatePostfixForm(argBegin, argsIter, errors);
71✔
345
                    auto exprNode = ParserContext::pushChildNode(argsNode, NodeType::Expression, token.ref);
71✔
346
                    buildExpressionSubtree(argPostfixForm, exprNode, errors);
71✔
347
                    argBegin = std::next(argsIter);
71✔
348
                }
71✔
349
            }
43✔
350
            postfixForm.emplace(funcCallNode);
57✔
351
            tokenIter = argsEnd;
57✔
352
            prevExpType = ExpressionTokenType::Operand;
57✔
353
            continue;
57✔
354
        }
57✔
355
        if (isListAccessor(tokenIter)) {
839✔
356
            Node::Ptr listAccessorNode = std::make_shared<Node>(NodeType::ListAccessor);
23✔
357
            auto node = ParserContext::pushChildNode(listAccessorNode, NodeType::VariableName, token.ref);
23✔
358
            node->value = token.id();
23✔
359
            auto exprBegin = std::next(tokenIter);
23✔
360
            auto it = exprBegin;
23✔
361
            unsigned nestingLevel = 0;
23✔
362
            do {
363
                if (it->is(Operator::RectRightBrace))
118✔
364
                    nestingLevel--;
32✔
365
                else if (it->is(Operator::RectLeftBrace))
86✔
366
                    nestingLevel++;
32✔
367
                it++;
118✔
368
            } while (nestingLevel > 0);
118✔
369
            std::stack<SubExpression> argPostfixForm = generatePostfixForm(exprBegin, it, errors);
23✔
370
            auto exprNode = ParserContext::pushChildNode(listAccessorNode, NodeType::Expression, token.ref);
23✔
371
            buildExpressionSubtree(argPostfixForm, exprNode, errors);
23✔
372
            postfixForm.emplace(listAccessorNode);
23✔
373
            tokenIter = std::prev(it);
23✔
374
            prevExpType = ExpressionTokenType::Operand;
23✔
375
            continue;
23✔
376
        }
23✔
377
        if (isUnaryOperation(tokenIter, prevExpType)) {
816✔
378
            auto unaryNode = std::make_shared<Node>(NodeType::UnaryOperation);
43✔
379
            unaryNode->value = getUnaryOperation(*tokenIter);
43✔
380
            auto argsBegin = std::next(tokenIter);
43✔
381
            auto it = argsBegin;
43✔
382
            unsigned nestingLevel = 0;
43✔
383
            if (isFunctionCall(it) || isListAccessor(it)) {
43✔
384
                nestingLevel++;
7✔
385
                std::advance(it, 2);
7✔
386
            }
387
            do {
388
                if (it->is(Operator::RightBrace) or it->is(Operator::RectRightBrace))
127✔
389
                    nestingLevel--;
26✔
390
                else if (it->is(Operator::LeftBrace) or it->is(Operator::RectLeftBrace))
101✔
391
                    nestingLevel++;
19✔
392
                it++;
127✔
393
            } while (nestingLevel > 0);
127✔
394
            std::stack<SubExpression> argPostfixForm = generatePostfixForm(argsBegin, it, errors);
43✔
395
            auto exprNode = ParserContext::pushChildNode(unaryNode, NodeType::Expression, token.ref);
43✔
396
            buildExpressionSubtree(argPostfixForm, exprNode, errors);
43✔
397
            postfixForm.emplace(unaryNode);
43✔
398
            tokenIter = std::prev(it);
43✔
399
            prevExpType = ExpressionTokenType::Operand;
43✔
400
            continue;
43✔
401
        }
43✔
402
        ExpressionTokenType expType = getExpressionTokenType(token);
773✔
403
        if (expType == ExpressionTokenType::Operand) {
773✔
404
            postfixForm.emplace(tokenIter);
477✔
405
        } else if (expType == ExpressionTokenType::OpeningBrace) {
296✔
406
            operations.emplace(tokenIter);
23✔
407
        } else if (expType == ExpressionTokenType::ClosingBrace) {
273✔
408
            bool foundBrace = false;
23✔
409
            while (!operations.empty()) {
38✔
410
                if (getExpressionTokenType(*operations.top()) != ExpressionTokenType::OpeningBrace) {
38✔
411
                    postfixForm.emplace(operations.top());
15✔
412
                    operations.pop();
15✔
413
                } else {
414
                    foundBrace = true;
23✔
415
                    break;
23✔
416
                }
417
            }
418
            if (!foundBrace) {
23✔
419
                errors.push<ParserError>(token, "Unexpected closing brance in an expression");
×
420
            }
421
            if (!operations.empty())
23✔
422
                operations.pop(); // remove opening brace
23✔
423
        } else if (expType == ExpressionTokenType::Operation) {
250✔
424
            if (operations.empty() || getOperationPriority(token) < getOperationPriority(*operations.top())) {
204✔
425
                operations.emplace(tokenIter);
191✔
426
            } else {
427
                while (!operations.empty() && getOperationPriority(*operations.top()) <= getOperationPriority(token)) {
26✔
428
                    postfixForm.emplace(operations.top());
13✔
429
                    operations.pop();
13✔
430
                }
431
                operations.emplace(tokenIter);
13✔
432
            }
433
        } else if (expType == ExpressionTokenType::RectBrace) {
46✔
434
            continue;
46✔
435
        } else {
436
            errors.push<ParserError>(token, "Unexpected token inside an expression");
×
437
        }
438
        prevExpType = expType;
727✔
439
    }
440
    while (!operations.empty()) {
572✔
441
        postfixForm.emplace(operations.top());
176✔
442
        operations.pop();
176✔
443
    }
444
    return postfixForm;
792✔
445
}
396✔
446

447
void parseSimpleStatement(ParserContext &ctx) {
5✔
448
    assert(ctx.tokenIter->is(Keyword::Break) || ctx.tokenIter->is(Keyword::Continue) ||
5✔
449
           ctx.tokenIter->is(Keyword::Pass));
450
    ctx.goNextToken();
5✔
451
    if (!ctx.token().is(Special::EndOfExpression)) {
5✔
452
        ctx.pushError("Unexpected token in a break|continue|pass statement");
×
453
        ctx.goNextExpression();
×
454
    }
455
    ctx.goParentNode();
5✔
456
    ctx.goNextToken();
5✔
457
}
5✔
458

459
void parseBranchRoot(ParserContext &ctx) {
173✔
460
    while (ctx.nestingLevel > 0) {
482✔
461
        if (ctx.tokenIter == ctx.tokenEnd)
482✔
462
            return;
39✔
463
        while (ctx.token().is(Special::EndOfExpression) || ctx.token().is(Special::Colon)) {
778✔
464
            ctx.goNextToken();
425✔
465
            if (ctx.tokenIter == ctx.tokenEnd)
425✔
466
                return;
90✔
467
        }
468
        int currNestingLevel = 0;
353✔
469
        while (ctx.token().is(Special::Indentation)) {
742✔
470
            currNestingLevel++;
389✔
471
            ctx.goNextToken();
389✔
472
        }
473
        if (currNestingLevel > ctx.nestingLevel) {
353✔
474
            ctx.pushError("Unexpected indentation mismatch: " + std::to_string(ctx.nestingLevel) +
×
475
                          " indentation(s) expected, " + std::to_string(currNestingLevel) + " indentation(s) given");
×
476
        } else if (currNestingLevel < ctx.nestingLevel) {
353✔
477
            ctx.goParentNode();
44✔
478
            while (ctx.node->type != NodeType::BranchRoot) {
92✔
479
                if (!ctx.node->parent)
68✔
480
                    break;
20✔
481
                ctx.goParentNode();
48✔
482
            }
483
            ctx.nestingLevel--;
44✔
484
            std::advance(ctx.tokenIter, -currNestingLevel);
44✔
485
            return;
44✔
486
        }
487

488
        const Token &currToken = ctx.token();
309✔
489
        if (currToken.is(Keyword::If)) {
309✔
490
            ctx.node = ctx.pushChildNode(NodeType::IfStatement);
22✔
491
        } else if (currToken.is(Keyword::While)) {
287✔
492
            ctx.node = ctx.pushChildNode(NodeType::WhileStatement);
5✔
493
        } else if (currToken.is(Keyword::For)) {
282✔
494
            ctx.node = ctx.pushChildNode(NodeType::ForStatement);
10✔
495
        } else if (isVariableDeclaration(ctx.tokenIter, ctx.tokenEnd)) {
272✔
496
            ctx.node = ctx.pushChildNode(NodeType::VariableDeclaration);
121✔
497
        } else if (currToken.is(Keyword::Elif) || currToken.is(Keyword::Else)) {
151✔
498
            auto lastNode = ctx.node->children.back();
13✔
499
            if (lastNode->type == NodeType::IfStatement) {
13✔
500
                auto nodeType = currToken.is(Keyword::Elif) ? NodeType::ElifStatement : NodeType::ElseStatement;
13✔
501
                ctx.node = ParserContext::pushChildNode(lastNode, nodeType, currToken.ref);
13✔
502
            } else {
503
                ctx.pushError((currToken.is(Keyword::Elif) ? std::string("elif") : std::string("else")) +
×
504
                              " is not allowed here");
505
            }
506
        } else if (currToken.is(Keyword::Return)) {
151✔
507
            ctx.node = ctx.pushChildNode(NodeType::ReturnStatement);
21✔
508
        } else if (currToken.is(Keyword::Continue)) {
117✔
509
            ctx.node = ctx.pushChildNode(NodeType::ContinueStatement);
1✔
510
            parseSimpleStatement(ctx);
1✔
511
            continue;
1✔
512
        } else if (currToken.is(Keyword::Break)) {
116✔
513
            ctx.node = ctx.pushChildNode(NodeType::BreakStatement);
1✔
514
            parseSimpleStatement(ctx);
1✔
515
            continue;
1✔
516
        } else if (currToken.is(Keyword::Pass)) {
115✔
517
            ctx.node = ctx.pushChildNode(NodeType::PassStatement);
3✔
518
            parseSimpleStatement(ctx);
3✔
519
            continue;
3✔
520
        } else {
521
            ctx.node = ctx.pushChildNode(NodeType::Expression);
112✔
522
        }
523
        ctx.propagate();
304✔
524
    }
525
}
526

527
void parseElifStatement(ParserContext &ctx) {
8✔
528
    assert(ctx.tokenIter->is(Keyword::Elif));
8✔
529
    ctx.goNextToken();
8✔
530
    ctx.node = ctx.pushChildNode(NodeType::Expression);
8✔
531
    ctx.propagate();
8✔
532
    if (!ctx.token().is(Special::Colon)) {
8✔
533
        ctx.pushError("Colon expected here");
×
534
        ctx.goNextExpression();
×
535
    }
536
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
8✔
537
    ctx.nestingLevel++;
8✔
538
    ctx.propagate();
8✔
539
}
8✔
540

541
void parseElseStatement(ParserContext &ctx) {
5✔
542
    assert(ctx.tokenIter->is(Keyword::Else));
5✔
543
    ctx.goNextToken();
5✔
544
    if (!ctx.token().is(Special::Colon)) {
5✔
545
        ctx.pushError("Colon expected here");
×
546
        ctx.goNextExpression();
×
547
    }
548
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
5✔
549
    ctx.nestingLevel++;
5✔
550
    ctx.propagate();
5✔
551
}
5✔
552

553
void parseExpression(ParserContext &ctx) {
245✔
554
    auto it = ctx.tokenIter;
245✔
555
    while (!it->is(Special::Colon) && !it->is(Special::EndOfExpression))
1,263✔
556
        it++;
1,018✔
557
    const auto &tokenIterBegin = ctx.tokenIter;
245✔
558
    const auto &tokenIterEnd = it;
245✔
559
    std::stack<SubExpression> postfixForm = generatePostfixForm(tokenIterBegin, tokenIterEnd, ctx.errors);
245✔
560
    buildExpressionSubtree(postfixForm, ctx.node, ctx.errors);
245✔
561
    ctx.tokenIter = tokenIterEnd;
245✔
562
    ctx.goParentNode();
245✔
563
}
245✔
564

565
void parseFunctionArguments(ParserContext &ctx) {
123✔
566
    assert(ctx.token().is(Operator::LeftBrace));
123✔
567
    ctx.goNextToken();
123✔
568
    while (!ctx.token().is(Operator::RightBrace)) {
145✔
569
        const Token &argName = *ctx.tokenIter;
22✔
570
        const Token &colon = *std::next(ctx.tokenIter);
22✔
571
        const Token &argType = *std::next(ctx.tokenIter, 2);
22✔
572
        if (argName.type != TokenType::Identifier || !colon.is(Special::Colon) || !TypeRegistry::isTypename(argType)) {
22✔
573
            ctx.pushError("Function argument declaration is ill-formed");
×
574
            while (!ctx.token().is(Operator::RightBrace) && !ctx.token().is(Special::Colon))
×
575
                ctx.goNextToken();
×
576
            break;
×
577
        }
578
        auto node = ctx.pushChildNode(NodeType::FunctionArgument);
22✔
579
        auto argTypeNode = ParserContext::pushChildNode(node, NodeType::TypeName, argType.ref);
22✔
580
        argTypeNode->value = TypeRegistry::typeId(argType);
22✔
581
        auto argNameNode = ParserContext::pushChildNode(node, NodeType::VariableName, argName.ref);
22✔
582
        argNameNode->value = argName.id();
22✔
583

584
        const Token &last = *std::next(ctx.tokenIter, 3);
22✔
585
        if (last.is(Operator::Comma))
22✔
586
            std::advance(ctx.tokenIter, 4);
9✔
587
        else
588
            std::advance(ctx.tokenIter, 3);
13✔
589
    }
22✔
590
    ctx.goParentNode();
123✔
591
    ctx.goNextToken();
123✔
592
}
123✔
593

594
void parseFunctionDefinition(ParserContext &ctx) {
123✔
595
    assert(ctx.tokenIter->is(Keyword::Definition));
123✔
596
    ctx.goNextToken();
123✔
597
    if (ctx.token().type != TokenType::Identifier) {
123✔
598
        ctx.pushError("Given token is not allowed here in function definition");
×
599
    }
600
    ctx.pushChildNode(NodeType::FunctionName)->value = ctx.token().id();
123✔
601
    ctx.goNextToken();
123✔
602
    if (!ctx.token().is(Operator::LeftBrace)) {
123✔
603
        ctx.pushError("Given token is not allowed here in function definition");
×
604
    }
605
    ctx.node = ctx.pushChildNode(NodeType::FunctionArguments);
123✔
606
    ctx.propagate();
123✔
607
    if (!ctx.token().is(Special::Arrow)) {
123✔
608
        ctx.pushError("Function return type is mandatory in its header");
×
609
    }
610
    ctx.goNextToken();
123✔
611
    if (!TypeRegistry::isTypename(ctx.token())) {
123✔
612
        ctx.pushError("Type name not found");
×
613
    }
614
    ctx.pushChildNode(NodeType::FunctionReturnType)->value = TypeRegistry::typeId(ctx.token());
123✔
615
    ctx.goNextToken();
123✔
616
    if (!ctx.token().is(Special::Colon)) {
123✔
617
        ctx.pushError("Colon expected at the end of function header");
×
618
    }
619
    ctx.goNextToken();
123✔
620
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
123✔
621
    ctx.nestingLevel = 1;
123✔
622
    ctx.propagate();
123✔
623
}
123✔
624

625
void parseIfStatement(ParserContext &ctx) {
22✔
626
    assert(ctx.tokenIter->is(Keyword::If));
22✔
627
    ctx.goNextToken();
22✔
628
    ctx.node = ctx.pushChildNode(NodeType::Expression);
22✔
629
    ctx.propagate();
22✔
630
    if (!ctx.token().is(Special::Colon)) {
22✔
631
        ctx.pushError("Colon expected here");
×
632
        ctx.goNextExpression();
×
633
    }
634
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
22✔
635
    ctx.nestingLevel++;
22✔
636
    ctx.propagate();
22✔
637
}
22✔
638

639
void parseProgramRoot(ParserContext &ctx) {
103✔
640
    while (ctx.tokenIter != ctx.tokenEnd) {
226✔
641
        if (ctx.token().is(Keyword::Definition)) {
123✔
642
            ctx.node = ctx.pushChildNode(NodeType::FunctionDefinition);
123✔
643
            ctx.propagate();
123✔
644
        } else {
645
            ctx.pushError("Function definition was expected");
×
646
            return;
×
647
        }
648
    }
649
}
650

651
void parseReturnStatement(ParserContext &ctx) {
21✔
652
    assert(ctx.tokenIter->is(Keyword::Return));
21✔
653
    ctx.goNextToken();
21✔
654
    if (ctx.token().is(Special::EndOfExpression)) {
21✔
655
        ctx.goParentNode();
7✔
656
        ctx.goNextToken();
7✔
657
        return;
7✔
658
    }
659
    const Token &currToken = ctx.token();
14✔
660
    if (currToken.type != TokenType::FloatingPointLiteral && currToken.type != TokenType::Identifier &&
12✔
661
        currToken.type != TokenType::IntegerLiteral && currToken.type != TokenType::StringLiteral &&
26✔
662
        !currToken.is(Operator::LeftBrace)) {
14✔
663
        ctx.pushError("Expression as function return value was expected");
×
664
        ctx.goNextExpression();
×
665
        return;
×
666
    }
667
    ctx.node = ctx.pushChildNode(NodeType::Expression);
14✔
668
    ctx.propagate();
14✔
669
    ctx.goParentNode();
14✔
670
}
671

672
void parseVariableDeclaration(ParserContext &ctx) {
121✔
673
    ctx.goNextToken();
121✔
674
    const Token &colon = ctx.token();
121✔
675
    const Token &varName = *std::prev(ctx.tokenIter);
121✔
676
    const Token &varType = (std::advance(ctx.tokenIter, 1), ctx.token());
121✔
677
    auto node = ctx.pushChildNode(NodeType::TypeName);
121✔
678
    node->value = TypeRegistry::typeId(varType);
121✔
679
    bool isListType = varType.is(Keyword::List);
121✔
680
    if (isListType) {
121✔
681
        const Token &leftBrace = (std::advance(ctx.tokenIter, 1), ctx.token());
6✔
682
        const Token &varTypeList = (std::advance(ctx.tokenIter, 1), ctx.token());
6✔
683
        const Token &rightBrace = (std::advance(ctx.tokenIter, 1), ctx.token());
6✔
684
        if (!leftBrace.is(Operator::RectLeftBrace) || !rightBrace.is(Operator::RectRightBrace)) {
6✔
685
            ctx.pushError("Unexepted syntax for list declaration");
×
686
        }
687
        auto listTypeNode = ParserContext::pushChildNode(node, NodeType::TypeName, ctx.tokenIter->ref);
6✔
688
        listTypeNode->value = TypeRegistry::typeId(varTypeList);
6✔
689
    }
6✔
690
    node = ctx.pushChildNode(NodeType::VariableName);
121✔
691
    node->value = varName.id();
121✔
692

693
    auto endOfDecl = std::next(ctx.tokenIter);
121✔
694
    if (endOfDecl->is(Special::EndOfExpression)) {
121✔
695
        // declaration without definition
696
        std::advance(ctx.tokenIter, 2);
43✔
697
        ctx.goParentNode();
43✔
698
    } else if (endOfDecl->is(Operator::Assign)) {
78✔
699
        // declaration with definition
700
        ctx.node = ctx.pushChildNode(NodeType::Expression);
78✔
701
        if (isListType) {
78✔
702
            ctx.node = ctx.pushChildNode(NodeType::ListStatement);
5✔
703
        }
704
        std::advance(ctx.tokenIter, 2);
78✔
705
        ctx.propagate();
78✔
706
        ctx.goParentNode();
78✔
707
    } else {
708
        ctx.errors.push<ParserError>(*endOfDecl, "Definition expression or line break was expected");
×
709
    }
710
}
121✔
711

712
void parseWhileStatement(ParserContext &ctx) {
5✔
713
    assert(ctx.tokenIter->is(Keyword::While));
5✔
714
    ctx.goNextToken();
5✔
715
    ctx.node = ctx.pushChildNode(NodeType::Expression);
5✔
716
    ctx.propagate();
5✔
717
    if (!ctx.token().is(Special::Colon)) {
5✔
718
        ctx.pushError("Colon expected here");
×
719
        ctx.goNextExpression();
×
720
    }
721
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
5✔
722
    ctx.nestingLevel++;
5✔
723
    ctx.propagate();
5✔
724
}
5✔
725

726
void parseForStatement(ParserContext &ctx) {
10✔
727
    assert(ctx.tokenIter->is(Keyword::For));
10✔
728
    ctx.goNextToken();
10✔
729
    auto forNode = ctx.node;
10✔
730
    auto it = ctx.tokenIter;
10✔
731
    auto forTargets = ParserContext::pushChildNode(forNode, NodeType::ForTargets, ctx.tokenIter->ref);
10✔
732
    while (!it->is(Keyword::In) && !it->is(Special::EndOfExpression)) {
24✔
733
        if (it->type == TokenType::Identifier) {
14✔
734
            auto targetNode = ParserContext::pushChildNode(forTargets, NodeType::VariableName, ctx.tokenIter->ref);
12✔
735
            targetNode->value = it->id();
12✔
736
            it++;
12✔
737
        } else if (it->is(Operator::Comma)) {
14✔
738
            it++;
2✔
739
        } else {
740
            ctx.pushError("Unexpected token in a for statement");
×
741
        }
742
    }
743
    ctx.tokenIter = it;
10✔
744
    ctx.goNextToken();
10✔
745
    ctx.node = ctx.pushChildNode(NodeType::ForIterable);
10✔
746
    ctx.node = ctx.pushChildNode(NodeType::Expression);
10✔
747
    ctx.propagate();
10✔
748
    ctx.goParentNode();
10✔
749
    if (!ctx.token().is(Special::Colon)) {
10✔
750
        ctx.pushError("Colon expected here");
1✔
751
        ctx.goNextExpression();
1✔
752
    }
753
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
10✔
754
    ctx.nestingLevel++;
10✔
755
    ctx.propagate();
10✔
756
}
10✔
757

758
void parseListStatement(ParserContext &ctx) {
5✔
759
    assert(ctx.tokenIter->is(Operator::RectLeftBrace));
5✔
760
    while (!ctx.token().is(Operator::RectRightBrace)) {
19✔
761
        ctx.goNextToken();
14✔
762
        auto it = ctx.tokenIter;
14✔
763
        while (!it->is(Operator::Comma) && !it->is(Operator::RectRightBrace))
34✔
764
            it++;
20✔
765
        const auto &tokenIterBegin = ctx.tokenIter;
14✔
766
        const auto &tokenIterEnd = it;
14✔
767
        if (tokenIterEnd->is(Special::EndOfExpression)) {
14✔
768
            ctx.errors.push<ParserError>(*tokenIterEnd, "']' was expected");
×
769
        }
770
        ctx.node = ctx.pushChildNode(NodeType::Expression);
14✔
771
        std::stack<SubExpression> postfixForm = generatePostfixForm(tokenIterBegin, tokenIterEnd, ctx.errors);
14✔
772
        buildExpressionSubtree(postfixForm, ctx.node, ctx.errors);
14✔
773
        ctx.tokenIter = tokenIterEnd;
14✔
774
        ctx.goParentNode();
14✔
775
    }
14✔
776
    ctx.goNextToken();
5✔
777
    if (ctx.token().is(Special::EndOfExpression)) {
5✔
778
        ctx.goParentNode();
4✔
779
    } else if (ctx.token().is(Operator::Mult)) {
1✔
780
        ctx.goNextToken();
1✔
781
        ctx.node = ctx.pushChildNode(NodeType::ListDynamicSize);
1✔
782
        ctx.node = ctx.pushChildNode(NodeType::Expression);
1✔
783
        ctx.propagate();
1✔
784
        ctx.goParentNode();
1✔
785
        ctx.goParentNode();
1✔
786
    } else {
NEW
787
        ctx.pushError("Either end of line or '*' was expected");
×
788
    }
789
    ctx.goParentNode();
5✔
790
}
5✔
791

792
// clang-format off
793
#define SUBPARSER(NodeTypeVal) {NodeType::NodeTypeVal, parse##NodeTypeVal}
794

795
static std::unordered_map<NodeType, std::function<void(ParserContext &)>> subparsers = {
796
    SUBPARSER(BranchRoot),
797
    SUBPARSER(ElifStatement),
798
    SUBPARSER(ElseStatement),
799
    SUBPARSER(Expression),
800
    SUBPARSER(FunctionArguments),
801
    SUBPARSER(FunctionDefinition),
802
    SUBPARSER(IfStatement),
803
    SUBPARSER(ProgramRoot),
804
    SUBPARSER(ReturnStatement),
805
    SUBPARSER(VariableDeclaration),
806
    SUBPARSER(WhileStatement),
807
    SUBPARSER(ListStatement),
808
    SUBPARSER(ForStatement),
809
};
810
// clang-format on
811

812
} // namespace
813

814
SyntaxTree Parser::process(const TokenList &tokens) {
103✔
815
    SyntaxTree tree;
103✔
816
    tree.root = std::make_shared<Node>(NodeType::ProgramRoot);
103✔
817

818
    ParserContext ctx = {subparsers, tree.root, tokens.begin(), tokens.end(), 0};
103✔
819
    ctx.propagate();
103✔
820
    if (!ctx.errors.empty()) {
103✔
821
        throw ctx.errors;
4✔
822
    }
823

824
    return tree;
198✔
825
}
107✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc