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

vla5924-practice / compiler-project / 13547521977

26 Feb 2025 03:31PM UTC coverage: 83.601% (+0.05%) from 83.551%
13547521977

Pull #193

github

web-flow
Merge 80b8b2b47 into 25b434a4f
Pull Request #193: Add scientific notation support

33 of 36 new or added lines in 2 files covered. (91.67%)

54 existing lines in 2 files now uncovered.

3278 of 3921 relevant lines covered (83.6%)

278.03 hits per line

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

88.23
/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 <unordered_map>
9
#include <variant>
10

11
#include "compiler/ast/node.hpp"
12
#include "compiler/ast/node_type.hpp"
13
#include "compiler/utils/error_buffer.hpp"
14

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

21
using namespace ast;
22
using namespace lexer;
23
using namespace parser;
24

25
namespace {
26

27
using SubExpression = std::variant<TokenIterator, Node::Ptr>;
28

29
bool isVariableDeclaration(const TokenIterator &tokenIter, const TokenIterator &tokenEnd) {
235✔
30
    if (tokenIter == tokenEnd || std::next(tokenIter) == tokenEnd || std::next(tokenIter, 2) == tokenEnd)
235✔
31
        return false;
5✔
32

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

39
enum class OperationType {
40
    Unknown,
41
    Unary,
42
    Binary,
43
};
44

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

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

89
OperationType getOperationType(const Node &node) {
902✔
90
    switch (node.type) {
902✔
91
    case NodeType::BinaryOperation:
567✔
92
        return OperationType::Binary;
567✔
UNCOV
93
    case NodeType::UnaryOperation:
×
94
        return OperationType::Unary;
×
95
    default:
335✔
96
        return OperationType::Unknown;
335✔
97
    }
98
}
99

100
ExpressionTokenType getExpressionTokenType(const Token &token) {
1,336✔
101
    if (token.type == TokenType::Identifier || token.type == TokenType::IntegerLiteral ||
928✔
102
        token.type == TokenType::FloatingPointLiteral || token.type == TokenType::StringLiteral ||
552✔
103
        token.is(Keyword::True) || token.is(Keyword::False))
2,264✔
104
        return ExpressionTokenType::Operand;
840✔
105
    if (token.is(Operator::LeftBrace))
496✔
106
        return ExpressionTokenType::OpeningBrace;
44✔
107
    if (token.is(Operator::RightBrace))
452✔
108
        return ExpressionTokenType::ClosingBrace;
22✔
109
    if (token.is(Operator::RectLeftBrace) || token.is(Operator::RectRightBrace))
430✔
110
        return ExpressionTokenType::RectBrace;
38✔
111
    if (getOperationType(token) != OperationType::Unknown)
392✔
112
        return ExpressionTokenType::Operation;
392✔
UNCOV
113
    return ExpressionTokenType::Unknown;
×
114
}
115

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

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

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

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

217
size_t getOperandCount(OperationType type) {
902✔
218
    if (type == OperationType::Binary)
902✔
219
        return 2u;
567✔
220
    if (type == OperationType::Unary)
335✔
UNCOV
221
        return 1u;
×
222
    return -1;
335✔
223
}
224

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

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

233
bool canBeUnaryOperation(const TokenIterator &tokenIter) {
731✔
234
    if (tokenIter->type == TokenType::Operator) {
731✔
235
        return tokenIter->op() == Operator::Sub || tokenIter->op() == Operator::Add;
296✔
236
    }
237
    if (tokenIter->type == TokenType::Keyword) {
435✔
238
        return tokenIter->kw() == Keyword::Not;
19✔
239
    }
240
    return false;
416✔
241
}
242

243
bool isUnaryOperation(const TokenIterator &tokenIter, const ExpressionTokenType &prevTokenIter) {
731✔
244
    return canBeUnaryOperation(tokenIter) &&
830✔
245
           (prevTokenIter == ExpressionTokenType::Operation || prevTokenIter == ExpressionTokenType::OpeningBrace);
830✔
246
}
247

248
void buildExpressionSubtree(std::stack<SubExpression> &postfixForm, const Node::Ptr &root, ErrorBuffer &errors) {
335✔
249
    Node::Ptr currNode = root;
335✔
250
    while (!postfixForm.empty()) {
1,048✔
251
        const SubExpression &subexpr = postfixForm.top();
713✔
252
        if (std::holds_alternative<TokenIterator>(subexpr)) {
713✔
253
            const Token &token = *std::get<TokenIterator>(subexpr);
609✔
254
            ExpressionTokenType expType = getExpressionTokenType(token);
609✔
255
            if (expType == ExpressionTokenType::Operation) {
609✔
256
                OperationType opType = getOperationType(token);
189✔
257
                if (opType == OperationType::Binary) {
189✔
258
                    currNode = ParserContext::unshiftChildNode(currNode, NodeType::BinaryOperation, token.ref);
189✔
259
                    currNode->value = getBinaryOperation(token);
189✔
UNCOV
260
                } else if (opType == OperationType::Unary) {
×
261
                    currNode = ParserContext::unshiftChildNode(currNode, NodeType::UnaryOperation, token.ref);
×
262
                } else {
UNCOV
263
                    errors.push<ParserError>(token,
×
264
                                             "Unknown operator found in expression, it must be either unary or binary");
265
                }
266
            } else if (expType == ExpressionTokenType::Operand) {
420✔
267
                if (token.type == TokenType::Identifier) {
420✔
268
                    Node::Ptr node = ParserContext::unshiftChildNode(currNode, NodeType::VariableName, token.ref);
204✔
269
                    node->value = token.id();
204✔
270
                } else if (token.type == TokenType::IntegerLiteral) {
420✔
271
                    Node::Ptr node =
272
                        ParserContext::unshiftChildNode(currNode, NodeType::IntegerLiteralValue, token.ref);
188✔
273
                    node->value = std::atol(token.literal().c_str());
188✔
274
                } else if (token.type == TokenType::FloatingPointLiteral) {
216✔
275
                    Node::Ptr node =
276
                        ParserContext::unshiftChildNode(currNode, NodeType::FloatingPointLiteralValue, token.ref);
24✔
277
                    node->value = std::stod(token.literal());
24✔
278
                } else if (token.type == TokenType::StringLiteral) {
28✔
NEW
279
                    Node::Ptr node = ParserContext::unshiftChildNode(currNode, NodeType::StringLiteralValue, token.ref);
×
UNCOV
280
                    node->value = token.literal();
×
281
                } else if (token.is(Keyword::False) || token.is(Keyword::True)) {
4✔
282
                    Node::Ptr node =
283
                        ParserContext::unshiftChildNode(currNode, NodeType::BooleanLiteralValue, token.ref);
4✔
284
                    if (token.is(Keyword::True))
4✔
285
                        node->value = true;
2✔
286
                    else if (token.is(Keyword::False))
2✔
287
                        node->value = false;
2✔
288
                }
4✔
289
            }
290
        } else {
291
            // can be FunctionCall node and list ListAccessor
292
            Node::Ptr callNode = std::get<Node::Ptr>(subexpr);
104✔
293
            assert(callNode->type == NodeType::FunctionCall or callNode->type == NodeType::ListAccessor or
104✔
294
                   callNode->type == NodeType::UnaryOperation);
295
            callNode->parent = currNode;
104✔
296
            currNode->children.push_front(callNode);
104✔
297
        }
104✔
298
        while (currNode->children.size() >= getOperandCount(getOperationType(*currNode)))
902✔
299
            currNode = currNode->parent;
189✔
300
        postfixForm.pop();
713✔
301
    }
302
}
335✔
303

304
std::stack<SubExpression> generatePostfixForm(TokenIterator tokenIterBegin, TokenIterator tokenIterEnd,
335✔
305
                                              ErrorBuffer &errors) {
306
    std::stack<SubExpression> postfixForm;
335✔
307
    std::stack<TokenIterator> operations;
335✔
308
    ExpressionTokenType prevExpType = ExpressionTokenType::Operation;
335✔
309
    for (auto tokenIter = tokenIterBegin; tokenIter != tokenIterEnd; tokenIter++) {
1,130✔
310
        const Token &token = *tokenIter;
795✔
311
        if (isFunctionCall(tokenIter)) {
795✔
312
            Node::Ptr funcCallNode = std::make_shared<Node>(NodeType::FunctionCall);
45✔
313
            auto node = ParserContext::pushChildNode(funcCallNode, NodeType::FunctionName, token.ref);
45✔
314
            node->value = token.id();
45✔
315
            auto argsBegin = std::next(tokenIter);
45✔
316
            auto it = argsBegin;
45✔
317
            unsigned nestingLevel = 0;
45✔
318
            do {
319
                if (it->is(Operator::RightBrace))
248✔
320
                    nestingLevel--;
58✔
321
                else if (it->is(Operator::LeftBrace))
190✔
322
                    nestingLevel++;
58✔
323
                it++;
248✔
324
            } while (nestingLevel > 0);
248✔
325
            auto argsEnd = std::prev(it);
45✔
326
            if (std::distance(argsBegin, argsEnd) > 1) {
45✔
327
                auto argsNode = ParserContext::pushChildNode(funcCallNode, NodeType::FunctionArguments, token.ref);
34✔
328
                auto argBegin = std::next(argsBegin);
34✔
329
                for (auto argsIter = argBegin; argsIter != std::next(argsEnd); argsIter++) {
226✔
330
                    if (!argsIter->is(Operator::Comma) && argsIter != argsEnd)
192✔
331
                        continue;
138✔
332
                    const Token &token = *argsIter;
54✔
333
                    std::stack<SubExpression> argPostfixForm = generatePostfixForm(argBegin, argsIter, errors);
54✔
334
                    auto exprNode = ParserContext::pushChildNode(argsNode, NodeType::Expression, token.ref);
54✔
335
                    buildExpressionSubtree(argPostfixForm, exprNode, errors);
54✔
336
                    argBegin = std::next(argsIter);
54✔
337
                }
54✔
338
            }
34✔
339
            postfixForm.emplace(funcCallNode);
45✔
340
            tokenIter = argsEnd;
45✔
341
            prevExpType = ExpressionTokenType::Operand;
45✔
342
            continue;
45✔
343
        }
45✔
344
        if (isListAccessor(tokenIter)) {
750✔
345
            Node::Ptr listAccessorNode = std::make_shared<Node>(NodeType::ListAccessor);
19✔
346
            auto node = ParserContext::pushChildNode(listAccessorNode, NodeType::VariableName, token.ref);
19✔
347
            node->value = token.id();
19✔
348
            auto exprBegin = std::next(tokenIter);
19✔
349
            auto it = exprBegin;
19✔
350
            unsigned nestingLevel = 0;
19✔
351
            do {
352
                if (it->is(Operator::RectRightBrace))
102✔
353
                    nestingLevel--;
28✔
354
                else if (it->is(Operator::RectLeftBrace))
74✔
355
                    nestingLevel++;
28✔
356
                it++;
102✔
357
            } while (nestingLevel > 0);
102✔
358
            std::stack<SubExpression> argPostfixForm = generatePostfixForm(exprBegin, it, errors);
19✔
359
            auto exprNode = ParserContext::pushChildNode(listAccessorNode, NodeType::Expression, token.ref);
19✔
360
            buildExpressionSubtree(argPostfixForm, exprNode, errors);
19✔
361
            postfixForm.emplace(listAccessorNode);
19✔
362
            tokenIter = std::prev(it);
19✔
363
            prevExpType = ExpressionTokenType::Operand;
19✔
364
            continue;
19✔
365
        }
19✔
366
        if (isUnaryOperation(tokenIter, prevExpType)) {
731✔
367
            auto unaryNode = std::make_shared<Node>(NodeType::UnaryOperation);
40✔
368
            unaryNode->value = getUnaryOperation(*tokenIter);
40✔
369
            auto argsBegin = std::next(tokenIter);
40✔
370
            auto it = argsBegin;
40✔
371
            unsigned nestingLevel = 0;
40✔
372
            if (isFunctionCall(it) || isListAccessor(it)) {
40✔
373
                nestingLevel++;
7✔
374
                std::advance(it, 2);
7✔
375
            }
376
            do {
377
                if (it->is(Operator::RightBrace) or it->is(Operator::RectRightBrace))
124✔
378
                    nestingLevel--;
26✔
379
                else if (it->is(Operator::LeftBrace) or it->is(Operator::RectLeftBrace))
98✔
380
                    nestingLevel++;
19✔
381
                it++;
124✔
382
            } while (nestingLevel > 0);
124✔
383
            std::stack<SubExpression> argPostfixForm = generatePostfixForm(argsBegin, it, errors);
40✔
384
            auto exprNode = ParserContext::pushChildNode(unaryNode, NodeType::Expression, token.ref);
40✔
385
            buildExpressionSubtree(argPostfixForm, exprNode, errors);
40✔
386
            postfixForm.emplace(unaryNode);
40✔
387
            tokenIter = std::prev(it);
40✔
388
            prevExpType = ExpressionTokenType::Operand;
40✔
389
            continue;
40✔
390
        }
40✔
391
        ExpressionTokenType expType = getExpressionTokenType(token);
691✔
392
        if (expType == ExpressionTokenType::Operand) {
691✔
393
            postfixForm.emplace(tokenIter);
420✔
394
        } else if (expType == ExpressionTokenType::OpeningBrace) {
271✔
395
            operations.emplace(tokenIter);
22✔
396
        } else if (expType == ExpressionTokenType::ClosingBrace) {
249✔
397
            bool foundBrace = false;
22✔
398
            while (!operations.empty()) {
36✔
399
                if (getExpressionTokenType(*operations.top()) != ExpressionTokenType::OpeningBrace) {
36✔
400
                    postfixForm.emplace(operations.top());
14✔
401
                    operations.pop();
14✔
402
                } else {
403
                    foundBrace = true;
22✔
404
                    break;
22✔
405
                }
406
            }
407
            if (!foundBrace) {
22✔
UNCOV
408
                errors.push<ParserError>(token, "Unexpected closing brance in an expression");
×
409
            }
410
            if (!operations.empty())
22✔
411
                operations.pop(); // remove opening brace
22✔
412
        } else if (expType == ExpressionTokenType::Operation) {
227✔
413
            if (operations.empty() || getOperationPriority(token) < getOperationPriority(*operations.top())) {
189✔
414
                operations.emplace(tokenIter);
178✔
415
            } else {
416
                while (!operations.empty() && getOperationPriority(*operations.top()) <= getOperationPriority(token)) {
22✔
417
                    postfixForm.emplace(operations.top());
11✔
418
                    operations.pop();
11✔
419
                }
420
                operations.emplace(tokenIter);
11✔
421
            }
422
        } else if (expType == ExpressionTokenType::RectBrace) {
38✔
423
            continue;
38✔
424
        } else {
UNCOV
425
            errors.push<ParserError>(token, "Unexpected token inside an expression");
×
426
        }
427
        prevExpType = expType;
653✔
428
    }
429
    while (!operations.empty()) {
499✔
430
        postfixForm.emplace(operations.top());
164✔
431
        operations.pop();
164✔
432
    }
433
    return postfixForm;
670✔
434
}
335✔
435

436
void parseSimpleStatement(ParserContext &ctx) {
5✔
437
    assert(ctx.tokenIter->is(Keyword::Break) || ctx.tokenIter->is(Keyword::Continue) ||
5✔
438
           ctx.tokenIter->is(Keyword::Pass));
439
    ctx.goNextToken();
5✔
440
    if (!ctx.token().is(Special::EndOfExpression)) {
5✔
UNCOV
441
        ctx.pushError("Unexpected token in a break|continue|pass statement");
×
UNCOV
442
        ctx.goNextExpression();
×
443
    }
444
    ctx.goParentNode();
5✔
445
    ctx.goNextToken();
5✔
446
}
5✔
447

448
void parseBranchRoot(ParserContext &ctx) {
156✔
449
    while (ctx.nestingLevel > 0) {
425✔
450
        if (ctx.tokenIter == ctx.tokenEnd)
425✔
451
            return;
36✔
452
        while (ctx.token().is(Special::EndOfExpression) || ctx.token().is(Special::Colon)) {
680✔
453
            ctx.goNextToken();
374✔
454
            if (ctx.tokenIter == ctx.tokenEnd)
374✔
455
                return;
83✔
456
        }
457
        int currNestingLevel = 0;
306✔
458
        while (ctx.token().is(Special::Indentation)) {
645✔
459
            currNestingLevel++;
339✔
460
            ctx.goNextToken();
339✔
461
        }
462
        if (currNestingLevel > ctx.nestingLevel) {
306✔
UNCOV
463
            ctx.pushError("Unexpected indentation mismatch: " + std::to_string(ctx.nestingLevel) +
×
UNCOV
464
                          " indentation(s) expected, " + std::to_string(currNestingLevel) + " indentation(s) given");
×
465
        } else if (currNestingLevel < ctx.nestingLevel) {
306✔
466
            ctx.goParentNode();
37✔
467
            while (ctx.node->type != NodeType::BranchRoot) {
77✔
468
                if (!ctx.node->parent)
57✔
469
                    break;
17✔
470
                ctx.goParentNode();
40✔
471
            }
472
            ctx.nestingLevel--;
37✔
473
            std::advance(ctx.tokenIter, -currNestingLevel);
37✔
474
            return;
37✔
475
        }
476

477
        const Token &currToken = ctx.token();
269✔
478
        if (currToken.is(Keyword::If)) {
269✔
479
            ctx.node = ctx.pushChildNode(NodeType::IfStatement);
21✔
480
        } else if (currToken.is(Keyword::While)) {
248✔
481
            ctx.node = ctx.pushChildNode(NodeType::WhileStatement);
4✔
482
        } else if (currToken.is(Keyword::For)) {
244✔
483
            ctx.node = ctx.pushChildNode(NodeType::ForStatement);
9✔
484
        } else if (isVariableDeclaration(ctx.tokenIter, ctx.tokenEnd)) {
235✔
485
            ctx.node = ctx.pushChildNode(NodeType::VariableDeclaration);
103✔
486
        } else if (currToken.is(Keyword::Elif) || currToken.is(Keyword::Else)) {
132✔
487
            auto lastNode = ctx.node->children.back();
12✔
488
            if (lastNode->type == NodeType::IfStatement) {
12✔
489
                auto nodeType = currToken.is(Keyword::Elif) ? NodeType::ElifStatement : NodeType::ElseStatement;
12✔
490
                ctx.node = ParserContext::pushChildNode(lastNode, nodeType, currToken.ref);
12✔
491
            } else {
UNCOV
492
                ctx.pushError((currToken.is(Keyword::Elif) ? std::string("elif") : std::string("else")) +
×
493
                              " is not allowed here");
494
            }
495
        } else if (currToken.is(Keyword::Return)) {
132✔
496
            ctx.node = ctx.pushChildNode(NodeType::ReturnStatement);
15✔
497
        } else if (currToken.is(Keyword::Continue)) {
105✔
498
            ctx.node = ctx.pushChildNode(NodeType::ContinueStatement);
1✔
499
            parseSimpleStatement(ctx);
1✔
500
            continue;
1✔
501
        } else if (currToken.is(Keyword::Break)) {
104✔
502
            ctx.node = ctx.pushChildNode(NodeType::BreakStatement);
1✔
503
            parseSimpleStatement(ctx);
1✔
504
            continue;
1✔
505
        } else if (currToken.is(Keyword::Pass)) {
103✔
506
            ctx.node = ctx.pushChildNode(NodeType::PassStatement);
3✔
507
            parseSimpleStatement(ctx);
3✔
508
            continue;
3✔
509
        } else {
510
            ctx.node = ctx.pushChildNode(NodeType::Expression);
100✔
511
        }
512
        ctx.propagate();
264✔
513
    }
514
}
515

516
void parseElifStatement(ParserContext &ctx) {
8✔
517
    assert(ctx.tokenIter->is(Keyword::Elif));
8✔
518
    ctx.goNextToken();
8✔
519
    ctx.node = ctx.pushChildNode(NodeType::Expression);
8✔
520
    ctx.propagate();
8✔
521
    if (!ctx.token().is(Special::Colon)) {
8✔
UNCOV
522
        ctx.pushError("Colon expected here");
×
UNCOV
523
        ctx.goNextExpression();
×
524
    }
525
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
8✔
526
    ctx.nestingLevel++;
8✔
527
    ctx.propagate();
8✔
528
}
8✔
529

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

542
void parseExpression(ParserContext &ctx) {
213✔
543
    auto it = ctx.tokenIter;
213✔
544
    while (!it->is(Special::Colon) && !it->is(Special::EndOfExpression))
1,103✔
545
        it++;
890✔
546
    const auto &tokenIterBegin = ctx.tokenIter;
213✔
547
    const auto &tokenIterEnd = it;
213✔
548
    std::stack<SubExpression> postfixForm = generatePostfixForm(tokenIterBegin, tokenIterEnd, ctx.errors);
213✔
549
    buildExpressionSubtree(postfixForm, ctx.node, ctx.errors);
213✔
550
    ctx.tokenIter = tokenIterEnd;
213✔
551
    ctx.goParentNode();
213✔
552
}
213✔
553

554
void parseFunctionArguments(ParserContext &ctx) {
110✔
555
    assert(ctx.token().is(Operator::LeftBrace));
110✔
556
    ctx.goNextToken();
110✔
557
    while (!ctx.token().is(Operator::RightBrace)) {
131✔
558
        const Token &argName = *ctx.tokenIter;
21✔
559
        const Token &colon = *std::next(ctx.tokenIter);
21✔
560
        const Token &argType = *std::next(ctx.tokenIter, 2);
21✔
561
        if (argName.type != TokenType::Identifier || !colon.is(Special::Colon) || !TypeRegistry::isTypename(argType)) {
21✔
UNCOV
562
            ctx.pushError("Function argument declaration is ill-formed");
×
UNCOV
563
            while (!ctx.token().is(Operator::RightBrace) && !ctx.token().is(Special::Colon))
×
UNCOV
564
                ctx.goNextToken();
×
UNCOV
565
            break;
×
566
        }
567
        auto node = ctx.pushChildNode(NodeType::FunctionArgument);
21✔
568
        auto argTypeNode = ParserContext::pushChildNode(node, NodeType::TypeName, argType.ref);
21✔
569
        argTypeNode->value = TypeRegistry::typeId(argType);
21✔
570
        auto argNameNode = ParserContext::pushChildNode(node, NodeType::VariableName, argName.ref);
21✔
571
        argNameNode->value = argName.id();
21✔
572

573
        const Token &last = *std::next(ctx.tokenIter, 3);
21✔
574
        if (last.is(Operator::Comma))
21✔
575
            std::advance(ctx.tokenIter, 4);
9✔
576
        else
577
            std::advance(ctx.tokenIter, 3);
12✔
578
    }
21✔
579
    ctx.goParentNode();
110✔
580
    ctx.goNextToken();
110✔
581
}
110✔
582

583
void parseFunctionDefinition(ParserContext &ctx) {
110✔
584
    assert(ctx.tokenIter->is(Keyword::Definition));
110✔
585
    ctx.goNextToken();
110✔
586
    if (ctx.token().type != TokenType::Identifier) {
110✔
UNCOV
587
        ctx.pushError("Given token is not allowed here in function definition");
×
588
    }
589
    ctx.pushChildNode(NodeType::FunctionName)->value = ctx.token().id();
110✔
590
    ctx.goNextToken();
110✔
591
    if (!ctx.token().is(Operator::LeftBrace)) {
110✔
UNCOV
592
        ctx.pushError("Given token is not allowed here in function definition");
×
593
    }
594
    ctx.node = ctx.pushChildNode(NodeType::FunctionArguments);
110✔
595
    ctx.propagate();
110✔
596
    if (!ctx.token().is(Special::Arrow)) {
110✔
597
        ctx.pushError("Function return type is mandatory in its header");
×
598
    }
599
    ctx.goNextToken();
110✔
600
    if (!TypeRegistry::isTypename(ctx.token())) {
110✔
UNCOV
601
        ctx.pushError("Type name not found");
×
602
    }
603
    ctx.pushChildNode(NodeType::FunctionReturnType)->value = TypeRegistry::typeId(ctx.token());
110✔
604
    ctx.goNextToken();
110✔
605
    if (!ctx.token().is(Special::Colon)) {
110✔
UNCOV
606
        ctx.pushError("Colon expected at the end of function header");
×
607
    }
608
    ctx.goNextToken();
110✔
609
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
110✔
610
    ctx.nestingLevel = 1;
110✔
611
    ctx.propagate();
110✔
612
}
110✔
613

614
void parseIfStatement(ParserContext &ctx) {
21✔
615
    assert(ctx.tokenIter->is(Keyword::If));
21✔
616
    ctx.goNextToken();
21✔
617
    ctx.node = ctx.pushChildNode(NodeType::Expression);
21✔
618
    ctx.propagate();
21✔
619
    if (!ctx.token().is(Special::Colon)) {
21✔
UNCOV
620
        ctx.pushError("Colon expected here");
×
UNCOV
621
        ctx.goNextExpression();
×
622
    }
623
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
21✔
624
    ctx.nestingLevel++;
21✔
625
    ctx.propagate();
21✔
626
}
21✔
627

628
void parseProgramRoot(ParserContext &ctx) {
93✔
629
    while (ctx.tokenIter != ctx.tokenEnd) {
203✔
630
        if (ctx.token().is(Keyword::Definition)) {
110✔
631
            ctx.node = ctx.pushChildNode(NodeType::FunctionDefinition);
110✔
632
            ctx.propagate();
110✔
633
        } else {
UNCOV
634
            ctx.pushError("Function definition was expected");
×
UNCOV
635
            return;
×
636
        }
637
    }
638
}
639

640
void parseReturnStatement(ParserContext &ctx) {
15✔
641
    assert(ctx.tokenIter->is(Keyword::Return));
15✔
642
    ctx.goNextToken();
15✔
643
    if (ctx.token().is(Special::EndOfExpression)) {
15✔
644
        ctx.goParentNode();
2✔
645
        ctx.goNextToken();
2✔
646
        return;
2✔
647
    }
648
    const Token &currToken = ctx.token();
13✔
649
    if (currToken.type != TokenType::FloatingPointLiteral && currToken.type != TokenType::Identifier &&
12✔
650
        currToken.type != TokenType::IntegerLiteral && currToken.type != TokenType::StringLiteral &&
25✔
651
        !currToken.is(Operator::LeftBrace)) {
13✔
UNCOV
652
        ctx.pushError("Expression as function return value was expected");
×
UNCOV
653
        ctx.goNextExpression();
×
UNCOV
654
        return;
×
655
    }
656
    ctx.node = ctx.pushChildNode(NodeType::Expression);
13✔
657
    ctx.propagate();
13✔
658
    ctx.goParentNode();
13✔
659
}
660

661
void parseVariableDeclaration(ParserContext &ctx) {
103✔
662
    ctx.goNextToken();
103✔
663
    const Token &colon = ctx.token();
103✔
664
    const Token &varName = *std::prev(ctx.tokenIter);
103✔
665
    const Token &varType = (std::advance(ctx.tokenIter, 1), ctx.token());
103✔
666
    auto node = ctx.pushChildNode(NodeType::TypeName);
103✔
667
    node->value = TypeRegistry::typeId(varType);
103✔
668
    bool isListType = varType.is(Keyword::List);
103✔
669
    if (isListType) {
103✔
670
        const Token &leftBrace = (std::advance(ctx.tokenIter, 1), ctx.token());
4✔
671
        const Token &varTypeList = (std::advance(ctx.tokenIter, 1), ctx.token());
4✔
672
        const Token &rightBrace = (std::advance(ctx.tokenIter, 1), ctx.token());
4✔
673
        if (!leftBrace.is(Operator::RectLeftBrace) || !rightBrace.is(Operator::RectRightBrace)) {
4✔
UNCOV
674
            ctx.pushError("Unexepted syntax for list declaration");
×
675
        }
676
        auto listTypeNode = ParserContext::pushChildNode(node, NodeType::TypeName, ctx.tokenIter->ref);
4✔
677
        listTypeNode->value = TypeRegistry::typeId(varTypeList);
4✔
678
    }
4✔
679
    node = ctx.pushChildNode(NodeType::VariableName);
103✔
680
    node->value = varName.id();
103✔
681

682
    auto endOfDecl = std::next(ctx.tokenIter);
103✔
683
    if (endOfDecl->is(Special::EndOfExpression)) {
103✔
684
        // declaration without definition
685
        std::advance(ctx.tokenIter, 2);
42✔
686
        ctx.goParentNode();
42✔
687
    } else if (endOfDecl->is(Operator::Assign)) {
61✔
688
        // declaration with definition
689
        ctx.node = ctx.pushChildNode(NodeType::Expression);
61✔
690
        if (isListType) {
61✔
691
            ctx.node = ctx.pushChildNode(NodeType::ListStatement);
3✔
692
        }
693
        std::advance(ctx.tokenIter, 2);
61✔
694
        ctx.propagate();
61✔
695
        ctx.goParentNode();
61✔
696
    } else {
UNCOV
697
        ctx.errors.push<ParserError>(*endOfDecl, "Definition expression or line break was expected");
×
698
    }
699
}
103✔
700

701
void parseWhileStatement(ParserContext &ctx) {
4✔
702
    assert(ctx.tokenIter->is(Keyword::While));
4✔
703
    ctx.goNextToken();
4✔
704
    ctx.node = ctx.pushChildNode(NodeType::Expression);
4✔
705
    ctx.propagate();
4✔
706
    if (!ctx.token().is(Special::Colon)) {
4✔
707
        ctx.pushError("Colon expected here");
×
UNCOV
708
        ctx.goNextExpression();
×
709
    }
710
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
4✔
711
    ctx.nestingLevel++;
4✔
712
    ctx.propagate();
4✔
713
}
4✔
714

715
void parseForStatement(ParserContext &ctx) {
9✔
716
    assert(ctx.tokenIter->is(Keyword::For));
9✔
717
    ctx.goNextToken();
9✔
718
    auto forNode = ctx.node;
9✔
719
    auto it = ctx.tokenIter;
9✔
720
    auto forTargets = ParserContext::pushChildNode(forNode, NodeType::ForTargets, ctx.tokenIter->ref);
9✔
721
    while (!it->is(Keyword::In) && !it->is(Special::EndOfExpression)) {
22✔
722
        if (it->type == TokenType::Identifier) {
13✔
723
            auto targetNode = ParserContext::pushChildNode(forTargets, NodeType::VariableName, ctx.tokenIter->ref);
11✔
724
            targetNode->value = it->id();
11✔
725
            it++;
11✔
726
        } else if (it->is(Operator::Comma)) {
13✔
727
            it++;
2✔
728
        } else {
UNCOV
729
            ctx.pushError("Unexpected token in a for statement");
×
730
        }
731
    }
732
    ctx.tokenIter = it;
9✔
733
    ctx.goNextToken();
9✔
734
    ctx.node = ctx.pushChildNode(NodeType::ForIterable);
9✔
735
    ctx.node = ctx.pushChildNode(NodeType::Expression);
9✔
736
    ctx.propagate();
9✔
737
    ctx.goParentNode();
9✔
738
    if (!ctx.token().is(Special::Colon)) {
9✔
739
        ctx.pushError("Colon expected here");
1✔
740
        ctx.goNextExpression();
1✔
741
    }
742
    ctx.node = ctx.pushChildNode(NodeType::BranchRoot);
9✔
743
    ctx.nestingLevel++;
9✔
744
    ctx.propagate();
9✔
745
}
9✔
746

747
void parseListStatement(ParserContext &ctx) {
3✔
748
    assert(ctx.tokenIter->is(Operator::RectLeftBrace));
3✔
749
    while (!ctx.token().is(Operator::RectRightBrace)) {
12✔
750
        ctx.goNextToken();
9✔
751
        auto it = ctx.tokenIter;
9✔
752
        while (!it->is(Operator::Comma) && !it->is(Operator::RectRightBrace))
24✔
753
            it++;
15✔
754
        const auto &tokenIterBegin = ctx.tokenIter;
9✔
755
        const auto &tokenIterEnd = it;
9✔
756
        if (tokenIterEnd->is(Special::EndOfExpression)) {
9✔
UNCOV
757
            ctx.errors.push<ParserError>(*tokenIterEnd, "']' was expected");
×
758
        }
759
        ctx.node = ctx.pushChildNode(NodeType::Expression);
9✔
760
        std::stack<SubExpression> postfixForm = generatePostfixForm(tokenIterBegin, tokenIterEnd, ctx.errors);
9✔
761
        buildExpressionSubtree(postfixForm, ctx.node, ctx.errors);
9✔
762
        ctx.tokenIter = tokenIterEnd;
9✔
763
        ctx.goParentNode();
9✔
764
    }
9✔
765
    ctx.goNextToken();
3✔
766
    ctx.goParentNode();
3✔
767
    ctx.goParentNode();
3✔
768
}
3✔
769

770
// clang-format off
771
#define SUBPARSER(NodeTypeVal) {NodeType::NodeTypeVal, parse##NodeTypeVal}
772

773
static std::unordered_map<NodeType, std::function<void(ParserContext &)>> subparsers = {
774
    SUBPARSER(BranchRoot),
775
    SUBPARSER(ElifStatement),
776
    SUBPARSER(ElseStatement),
777
    SUBPARSER(Expression),
778
    SUBPARSER(FunctionArguments),
779
    SUBPARSER(FunctionDefinition),
780
    SUBPARSER(IfStatement),
781
    SUBPARSER(ProgramRoot),
782
    SUBPARSER(ReturnStatement),
783
    SUBPARSER(VariableDeclaration),
784
    SUBPARSER(WhileStatement),
785
    SUBPARSER(ListStatement),
786
    SUBPARSER(ForStatement),
787
};
788
// clang-format on
789

790
} // namespace
791

792
SyntaxTree Parser::process(const TokenList &tokens) {
93✔
793
    SyntaxTree tree;
93✔
794
    tree.root = std::make_shared<Node>(NodeType::ProgramRoot);
93✔
795

796
    ParserContext ctx = {subparsers, tree.root, tokens.begin(), tokens.end(), 0};
93✔
797
    ctx.propagate();
93✔
798
    if (!ctx.errors.empty()) {
93✔
799
        throw ctx.errors;
1✔
800
    }
801

802
    return tree;
184✔
803
}
94✔
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