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

vla5924-practice / compiler-project / 13547595351

26 Feb 2025 03:35PM UTC coverage: 83.626% (+0.08%) from 83.551%
13547595351

Pull #193

github

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

33 of 35 new or added lines in 2 files covered. (94.29%)

40 existing lines in 2 files now uncovered.

3284 of 3927 relevant lines covered (83.63%)

281.2 hits per line

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

88.34
/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) {
238✔
30
    if (tokenIter == tokenEnd || std::next(tokenIter) == tokenEnd || std::next(tokenIter, 2) == tokenEnd)
238✔
31
        return false;
5✔
32

33
    const Token &varName = *tokenIter;
233✔
34
    const Token &colon = *std::next(tokenIter);
233✔
35
    const Token &varType = *std::next(tokenIter, 2);
233✔
36
    return varName.type == TokenType::Identifier && colon.is(Special::Colon) || TypeRegistry::isTypename(varType);
233✔
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) {
905✔
90
    switch (node.type) {
905✔
91
    case NodeType::BinaryOperation:
567✔
92
        return OperationType::Binary;
567✔
UNCOV
93
    case NodeType::UnaryOperation:
×
94
        return OperationType::Unary;
×
95
    default:
338✔
96
        return OperationType::Unknown;
338✔
97
    }
98
}
99

100
ExpressionTokenType getExpressionTokenType(const Token &token) {
1,342✔
101
    if (token.type == TokenType::Identifier || token.type == TokenType::IntegerLiteral ||
934✔
102
        token.type == TokenType::FloatingPointLiteral || token.type == TokenType::StringLiteral ||
556✔
103
        token.is(Keyword::True) || token.is(Keyword::False))
2,276✔
104
        return ExpressionTokenType::Operand;
846✔
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) {
905✔
218
    if (type == OperationType::Binary)
905✔
219
        return 2u;
567✔
220
    if (type == OperationType::Unary)
338✔
UNCOV
221
        return 1u;
×
222
    return -1;
338✔
223
}
224

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

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

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

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

248
void buildExpressionSubtree(std::stack<SubExpression> &postfixForm, const Node::Ptr &root, ErrorBuffer &errors) {
338✔
249
    Node::Ptr currNode = root;
338✔
250
    while (!postfixForm.empty()) {
1,054✔
251
        const SubExpression &subexpr = postfixForm.top();
716✔
252
        if (std::holds_alternative<TokenIterator>(subexpr)) {
716✔
253
            const Token &token = *std::get<TokenIterator>(subexpr);
612✔
254
            ExpressionTokenType expType = getExpressionTokenType(token);
612✔
255
            if (expType == ExpressionTokenType::Operation) {
612✔
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) {
423✔
267
                if (token.type == TokenType::Identifier) {
423✔
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) {
423✔
271
                    Node::Ptr node =
272
                        ParserContext::unshiftChildNode(currNode, NodeType::IntegerLiteralValue, token.ref);
189✔
273
                    try {
274
                        node->value = std::stol(token.literal().c_str());
191✔
275
                    } catch (const std::out_of_range &ex) {
1✔
276
                        errors.push<ParserError>(token,
1✔
277
                                                 "Failed to convert integer literal. The number is out of range");
278
                    }
1✔
279
                } else if (token.type == TokenType::FloatingPointLiteral) {
219✔
280
                    Node::Ptr node =
281
                        ParserContext::unshiftChildNode(currNode, NodeType::FloatingPointLiteralValue, token.ref);
26✔
282
                    try {
283
                        node->value = std::stod(token.literal());
26✔
284
                    } catch (const std::out_of_range &ex) {
2✔
285
                        errors.push<ParserError>(token, "Failed to convert float literal. The number is out of range");
2✔
286
                    }
2✔
287
                } else if (token.type == TokenType::StringLiteral) {
30✔
288
                    Node::Ptr node = ParserContext::unshiftChildNode(currNode, NodeType::StringLiteralValue, token.ref);
×
289
                    node->value = token.literal();
×
290
                } else if (token.is(Keyword::False) || token.is(Keyword::True)) {
4✔
291
                    Node::Ptr node =
292
                        ParserContext::unshiftChildNode(currNode, NodeType::BooleanLiteralValue, token.ref);
4✔
293
                    if (token.is(Keyword::True))
4✔
294
                        node->value = true;
2✔
295
                    else if (token.is(Keyword::False))
2✔
296
                        node->value = false;
2✔
297
                }
4✔
298
            }
299
        } else {
300
            // can be FunctionCall node and list ListAccessor
301
            Node::Ptr callNode = std::get<Node::Ptr>(subexpr);
104✔
302
            assert(callNode->type == NodeType::FunctionCall or callNode->type == NodeType::ListAccessor or
104✔
303
                   callNode->type == NodeType::UnaryOperation);
304
            callNode->parent = currNode;
104✔
305
            currNode->children.push_front(callNode);
104✔
306
        }
104✔
307
        while (currNode->children.size() >= getOperandCount(getOperationType(*currNode)))
905✔
308
            currNode = currNode->parent;
189✔
309
        postfixForm.pop();
716✔
310
    }
311
}
338✔
312

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

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

457
void parseBranchRoot(ParserContext &ctx) {
159✔
458
    while (ctx.nestingLevel > 0) {
431✔
459
        if (ctx.tokenIter == ctx.tokenEnd)
431✔
460
            return;
36✔
461
        while (ctx.token().is(Special::EndOfExpression) || ctx.token().is(Special::Colon)) {
689✔
462
            ctx.goNextToken();
380✔
463
            if (ctx.tokenIter == ctx.tokenEnd)
380✔
464
                return;
86✔
465
        }
466
        int currNestingLevel = 0;
309✔
467
        while (ctx.token().is(Special::Indentation)) {
651✔
468
            currNestingLevel++;
342✔
469
            ctx.goNextToken();
342✔
470
        }
471
        if (currNestingLevel > ctx.nestingLevel) {
309✔
UNCOV
472
            ctx.pushError("Unexpected indentation mismatch: " + std::to_string(ctx.nestingLevel) +
×
473
                          " indentation(s) expected, " + std::to_string(currNestingLevel) + " indentation(s) given");
×
474
        } else if (currNestingLevel < ctx.nestingLevel) {
309✔
475
            ctx.goParentNode();
37✔
476
            while (ctx.node->type != NodeType::BranchRoot) {
77✔
477
                if (!ctx.node->parent)
57✔
478
                    break;
17✔
479
                ctx.goParentNode();
40✔
480
            }
481
            ctx.nestingLevel--;
37✔
482
            std::advance(ctx.tokenIter, -currNestingLevel);
37✔
483
            return;
37✔
484
        }
485

486
        const Token &currToken = ctx.token();
272✔
487
        if (currToken.is(Keyword::If)) {
272✔
488
            ctx.node = ctx.pushChildNode(NodeType::IfStatement);
21✔
489
        } else if (currToken.is(Keyword::While)) {
251✔
490
            ctx.node = ctx.pushChildNode(NodeType::WhileStatement);
4✔
491
        } else if (currToken.is(Keyword::For)) {
247✔
492
            ctx.node = ctx.pushChildNode(NodeType::ForStatement);
9✔
493
        } else if (isVariableDeclaration(ctx.tokenIter, ctx.tokenEnd)) {
238✔
494
            ctx.node = ctx.pushChildNode(NodeType::VariableDeclaration);
106✔
495
        } else if (currToken.is(Keyword::Elif) || currToken.is(Keyword::Else)) {
132✔
496
            auto lastNode = ctx.node->children.back();
12✔
497
            if (lastNode->type == NodeType::IfStatement) {
12✔
498
                auto nodeType = currToken.is(Keyword::Elif) ? NodeType::ElifStatement : NodeType::ElseStatement;
12✔
499
                ctx.node = ParserContext::pushChildNode(lastNode, nodeType, currToken.ref);
12✔
500
            } else {
UNCOV
501
                ctx.pushError((currToken.is(Keyword::Elif) ? std::string("elif") : std::string("else")) +
×
502
                              " is not allowed here");
503
            }
504
        } else if (currToken.is(Keyword::Return)) {
132✔
505
            ctx.node = ctx.pushChildNode(NodeType::ReturnStatement);
15✔
506
        } else if (currToken.is(Keyword::Continue)) {
105✔
507
            ctx.node = ctx.pushChildNode(NodeType::ContinueStatement);
1✔
508
            parseSimpleStatement(ctx);
1✔
509
            continue;
1✔
510
        } else if (currToken.is(Keyword::Break)) {
104✔
511
            ctx.node = ctx.pushChildNode(NodeType::BreakStatement);
1✔
512
            parseSimpleStatement(ctx);
1✔
513
            continue;
1✔
514
        } else if (currToken.is(Keyword::Pass)) {
103✔
515
            ctx.node = ctx.pushChildNode(NodeType::PassStatement);
3✔
516
            parseSimpleStatement(ctx);
3✔
517
            continue;
3✔
518
        } else {
519
            ctx.node = ctx.pushChildNode(NodeType::Expression);
100✔
520
        }
521
        ctx.propagate();
267✔
522
    }
523
}
524

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

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

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

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

582
        const Token &last = *std::next(ctx.tokenIter, 3);
21✔
583
        if (last.is(Operator::Comma))
21✔
584
            std::advance(ctx.tokenIter, 4);
9✔
585
        else
586
            std::advance(ctx.tokenIter, 3);
12✔
587
    }
21✔
588
    ctx.goParentNode();
113✔
589
    ctx.goNextToken();
113✔
590
}
113✔
591

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

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

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

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

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

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

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

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

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

779
// clang-format off
780
#define SUBPARSER(NodeTypeVal) {NodeType::NodeTypeVal, parse##NodeTypeVal}
781

782
static std::unordered_map<NodeType, std::function<void(ParserContext &)>> subparsers = {
783
    SUBPARSER(BranchRoot),
784
    SUBPARSER(ElifStatement),
785
    SUBPARSER(ElseStatement),
786
    SUBPARSER(Expression),
787
    SUBPARSER(FunctionArguments),
788
    SUBPARSER(FunctionDefinition),
789
    SUBPARSER(IfStatement),
790
    SUBPARSER(ProgramRoot),
791
    SUBPARSER(ReturnStatement),
792
    SUBPARSER(VariableDeclaration),
793
    SUBPARSER(WhileStatement),
794
    SUBPARSER(ListStatement),
795
    SUBPARSER(ForStatement),
796
};
797
// clang-format on
798

799
} // namespace
800

801
SyntaxTree Parser::process(const TokenList &tokens) {
96✔
802
    SyntaxTree tree;
96✔
803
    tree.root = std::make_shared<Node>(NodeType::ProgramRoot);
96✔
804

805
    ParserContext ctx = {subparsers, tree.root, tokens.begin(), tokens.end(), 0};
96✔
806
    ctx.propagate();
96✔
807
    if (!ctx.errors.empty()) {
96✔
808
        throw ctx.errors;
4✔
809
    }
810

811
    return tree;
184✔
812
}
100✔
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