Coverage Report

Created: 2025-12-31 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsonnet/core/parser.cpp
Line
Count
Source
1
/*
2
Copyright 2015 Google Inc. All rights reserved.
3
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
    http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
#include <cassert>
18
#include <cmath>
19
#include <cstdlib>
20
21
#include <iomanip>
22
#include <list>
23
#include <memory>
24
#include <set>
25
#include <sstream>
26
#include <locale>
27
#include <string>
28
29
#include "ast.h"
30
#include "desugarer.h"
31
#include "lexer.h"
32
#include "parser.h"
33
#include "static_error.h"
34
35
namespace jsonnet::internal {
36
37
std::string jsonnet_unparse_number(double v)
38
8.65M
{
39
8.65M
    std::stringstream ss;
40
    // Make sure we output the same thing, even if the user
41
    // of the library changed the global locale
42
8.65M
    ss.imbue(std::locale::classic());
43
8.65M
    if (v == floor(v)) {
44
8.44M
        ss << std::fixed << std::setprecision(0) << v;
45
8.44M
    } else {
46
        // See "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
47
        // Theorem 15
48
        // https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
49
206k
        ss << std::setprecision(17);
50
206k
        ss << v;
51
206k
    }
52
8.65M
    return ss.str();
53
8.65M
}
54
55
namespace {
56
57
static const Fodder EMPTY_FODDER;
58
59
/** Maximum parsing depth to avoid stack overflow due to pathological or malicious code.
60
 * This is especially important when parsing deeply nested structures that could lead to
61
 * excessive recursion in the parser functions.
62
 */
63
static const unsigned MAX_PARSER_DEPTH = 1000;
64
65
static bool op_is_unary(const std::string &op, UnaryOp &uop)
66
1.77M
{
67
1.77M
    auto it = unary_map.find(op);
68
1.77M
    if (it == unary_map.end())
69
618
        return false;
70
1.77M
    uop = it->second;
71
1.77M
    return true;
72
1.77M
}
73
74
static bool op_is_binary(const std::string &op, BinaryOp &bop)
75
26.3M
{
76
26.3M
    auto it = binary_map.find(op);
77
26.3M
    if (it == binary_map.end())
78
472
        return false;
79
26.3M
    bop = it->second;
80
26.3M
    return true;
81
26.3M
}
82
83
LocationRange span(const Token &begin)
84
111M
{
85
111M
    return LocationRange(begin.location.file, begin.location.begin, begin.location.end);
86
111M
}
87
88
LocationRange span(const Token &begin, const Token &end)
89
49.9M
{
90
49.9M
    return LocationRange(begin.location.file, begin.location.begin, end.location.end);
91
49.9M
}
92
93
LocationRange span(const Token &begin, AST *end)
94
41.4M
{
95
41.4M
    return LocationRange(begin.location.file, begin.location.begin, end->location.end);
96
41.4M
}
97
98
/** Holds state while parsing a given token list.
99
 */
100
class Parser {
101
    // The private member functions are utilities for dealing with the token stream.
102
103
    StaticError unexpected(const Token &tok, const std::string &while_)
104
1.02k
    {
105
1.02k
        std::stringstream ss;
106
1.02k
        ss << "unexpected: " << tok.kind << " while " << while_;
107
1.02k
        return StaticError(tok.location, ss.str());
108
1.02k
    }
109
110
    Token pop(void)
111
353M
    {
112
353M
        Token tok = peek();
113
353M
        tokens.pop_front();
114
353M
        return tok;
115
353M
    }
116
117
    void push(Token tok)
118
0
    {
119
0
        tokens.push_front(tok);
120
0
    }
121
122
    const Token &peek(void)
123
1.12G
    {
124
1.12G
        return tokens.front();
125
1.12G
    }
126
127
    /** Only call this is peek() is not an EOF token. */
128
    Token doublePeek(void)
129
39.2M
    {
130
39.2M
        Tokens::iterator it = tokens.begin();  // First one.
131
39.2M
        it++;                                  // Now pointing at the second one.
132
39.2M
        return *(it);
133
39.2M
    }
134
135
    Token popExpect(Token::Kind k, const char *data = nullptr)
136
55.0M
    {
137
55.0M
        Token tok = pop();
138
55.0M
        if (tok.kind != k) {
139
680
            std::stringstream ss;
140
680
            ss << "expected token " << k << " but got " << tok;
141
680
            throw StaticError(tok.location, ss.str());
142
680
        }
143
55.0M
        if (data != nullptr && tok.data != data) {
144
56
            std::stringstream ss;
145
56
            ss << "expected operator " << data << " but got " << tok.data;
146
56
            throw StaticError(tok.location, ss.str());
147
56
        }
148
55.0M
        return tok;
149
55.0M
    }
150
151
    std::list<Token> &tokens;
152
    Allocator *alloc;
153
154
   public:
155
48.7k
    Parser(Tokens &tokens, Allocator *alloc) : tokens(tokens), alloc(alloc) {}
156
157
    /** Parse a comma-separated list of expressions.
158
     *
159
     * Allows an optional ending comma.
160
     * \param args Expressions added here.
161
     * \param element_kind Used in error messages when a comma was not found.
162
     * \param got_comma Whether a trailing comma was found.
163
     * \param current_depth Current recursion depth to prevent stack overflow.
164
     * \returns The last token (the one that matched parameter end).
165
     */
166
    Token parseArgs(ArgParams &args, const std::string &element_kind, bool &got_comma, unsigned current_depth)
167
26.3M
    {
168
26.3M
        got_comma = false;
169
26.3M
        bool first = true;
170
72.9M
        do {
171
72.9M
            Token next = peek();
172
72.9M
            if (next.kind == Token::PAREN_R) {
173
                // got_comma can be true or false here.
174
26.3M
                return pop();
175
26.3M
            }
176
46.6M
            if (!first && !got_comma) {
177
293
                std::stringstream ss;
178
293
                ss << "expected a comma before next " << element_kind << ".";
179
293
                throw StaticError(next.location, ss.str());
180
293
            }
181
            // Either id=expr or id or expr, but note that expr could be id==1 so this needs
182
            // look-ahead.
183
46.6M
            Fodder id_fodder;
184
46.6M
            const Identifier *id = nullptr;
185
46.6M
            Fodder eq_fodder;
186
46.6M
            if (peek().kind == Token::IDENTIFIER) {
187
39.2M
                Token maybe_eq = doublePeek();
188
39.2M
                if (maybe_eq.kind == Token::OPERATOR && maybe_eq.data == "=") {
189
623k
                    id_fodder = peek().fodder;
190
623k
                    id = alloc->makeIdentifier(peek().data32());
191
623k
                    eq_fodder = maybe_eq.fodder;
192
623k
                    pop();  // id
193
623k
                    pop();  // eq
194
623k
                }
195
39.2M
            }
196
46.6M
            AST *expr = parse(MAX_PRECEDENCE, current_depth + 1);
197
46.6M
            got_comma = false;
198
46.6M
            first = false;
199
46.6M
            Fodder comma_fodder;
200
46.6M
            if (peek().kind == Token::COMMA) {
201
20.2M
                Token comma = pop();
202
20.2M
                comma_fodder = comma.fodder;
203
20.2M
                got_comma = true;
204
20.2M
            }
205
46.6M
            args.emplace_back(id_fodder, id, eq_fodder, expr, comma_fodder);
206
46.6M
        } while (true);
207
26.3M
    }
208
209
    /** Parse function parameters.
210
     *
211
     * \param element_kind Used in error messages.
212
     * \param got_comma Whether a trailing comma was found.
213
     * \param close_fodder Fodder after the closing parenthesis.
214
     * \param current_depth Current recursion depth to prevent stack overflow.
215
     * \returns The parameters as ArgParams.
216
     */
217
    ArgParams parseParams(const std::string &element_kind, bool &got_comma, Fodder &close_fodder, unsigned current_depth)
218
5.63M
    {
219
5.63M
        ArgParams params;
220
5.63M
        Token paren_r = parseArgs(params, element_kind, got_comma, current_depth);
221
222
        // Check they're all identifiers
223
        // parseArgs returns f(x) with x as an expression.  Convert it here.
224
11.0M
        for (auto &p : params) {
225
11.0M
            if (p.id == nullptr) {
226
10.5M
                if (p.expr->type != AST_VAR) {
227
11
                    throw StaticError(p.expr->location, "could not parse parameter here.");
228
11
                }
229
10.5M
                auto *pv = static_cast<Var *>(p.expr);
230
10.5M
                p.id = pv->id;
231
10.5M
                p.idFodder = pv->openFodder;
232
10.5M
                p.expr = nullptr;
233
10.5M
            }
234
11.0M
        }
235
236
5.63M
        close_fodder = paren_r.fodder;
237
238
5.63M
        return params;
239
5.63M
    }
240
241
    /** Parse a local bind statement.
242
     *
243
     * \param binds The bindings to be populated.
244
     * \param current_depth Current recursion depth to prevent stack overflow.
245
     * \returns The token after the binding (comma or semicolon).
246
     */
247
    Token parseBind(Local::Binds &binds, unsigned current_depth)
248
6.47M
    {
249
6.47M
        Token var_id = popExpect(Token::IDENTIFIER);
250
6.47M
        auto *id = alloc->makeIdentifier(var_id.data32());
251
6.47M
        for (const auto &bind : binds) {
252
907k
            if (bind.var == id)
253
15
                throw StaticError(var_id.location, "duplicate local var: " + var_id.data);
254
907k
        }
255
6.47M
        bool is_function = false;
256
6.47M
        ArgParams params;
257
6.47M
        bool trailing_comma = false;
258
6.47M
        Fodder fodder_l, fodder_r;
259
6.47M
        if (peek().kind == Token::PAREN_L) {
260
1.89M
            Token paren_l = pop();
261
1.89M
            fodder_l = paren_l.fodder;
262
1.89M
            params = parseParams("function parameter", trailing_comma, fodder_r, current_depth);
263
1.89M
            is_function = true;
264
1.89M
        }
265
6.47M
        Token eq = popExpect(Token::OPERATOR, "=");
266
6.47M
        AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
267
6.47M
        Token delim = pop();
268
6.47M
        binds.emplace_back(var_id.fodder,
269
6.47M
                           id,
270
6.47M
                           eq.fodder,
271
6.47M
                           body,
272
6.47M
                           is_function,
273
6.47M
                           fodder_l,
274
6.47M
                           params,
275
6.47M
                           trailing_comma,
276
6.47M
                           fodder_r,
277
6.47M
                           delim.fodder);
278
6.47M
        return delim;
279
6.47M
    }
280
281
    /** Parse the remainder of an object after the opening brace.
282
     *
283
     * \param obj The object AST to be populated.
284
     * \param tok The opening brace token.
285
     * \param current_depth Current recursion depth to prevent stack overflow.
286
     * \returns The closing brace token.
287
     */
288
    Token parseObjectRemainder(AST *&obj, const Token &tok, unsigned current_depth)
289
1.54M
    {
290
1.54M
        if (current_depth >= MAX_PARSER_DEPTH) {
291
5
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
292
5
        }
293
294
1.54M
        ObjectFields fields;
295
1.54M
        std::set<std::string> literal_fields;  // For duplicate fields detection.
296
1.54M
        std::set<const Identifier *> binds;    // For duplicate locals detection.
297
298
1.54M
        bool got_comma = false;
299
1.54M
        bool first = true;
300
1.54M
        Token next = pop();
301
302
8.01M
        do {
303
8.01M
            if (next.kind == Token::BRACE_R) {
304
1.38M
                obj = alloc->make<Object>(
305
1.38M
                    span(tok, next), tok.fodder, fields, got_comma, next.fodder);
306
1.38M
                return next;
307
308
6.63M
            } else if (next.kind == Token::FOR) {
309
                // It's a comprehension
310
142k
                unsigned num_fields = 0;
311
142k
                unsigned num_asserts = 0;
312
142k
                const ObjectField *field_ptr = nullptr;
313
142k
                for (const auto &field : fields) {
314
142k
                    if (field.kind == ObjectField::LOCAL)
315
3
                        continue;
316
142k
                    if (field.kind == ObjectField::ASSERT) {
317
387
                        num_asserts++;
318
387
                        continue;
319
387
                    }
320
142k
                    field_ptr = &field;
321
142k
                    num_fields++;
322
142k
                }
323
142k
                if (num_asserts > 0) {
324
30
                    auto msg = "object comprehension cannot have asserts.";
325
30
                    throw StaticError(next.location, msg);
326
30
                }
327
142k
                if (num_fields != 1) {
328
12
                    auto msg = "object comprehension can only have one field.";
329
12
                    throw StaticError(next.location, msg);
330
12
                }
331
142k
                const ObjectField &field = *field_ptr;
332
333
142k
                if (field.hide != ObjectField::INHERIT) {
334
3
                    auto msg = "object comprehensions cannot have hidden fields.";
335
3
                    throw StaticError(next.location, msg);
336
3
                }
337
338
142k
                if (field.kind != ObjectField::FIELD_EXPR) {
339
3
                    auto msg = "object comprehensions can only have [e] fields.";
340
3
                    throw StaticError(next.location, msg);
341
3
                }
342
343
142k
                std::vector<ComprehensionSpec> specs;
344
142k
                Token last = parseComprehensionSpecs(Token::BRACE_R, next.fodder, specs, current_depth + 1);
345
142k
                obj = alloc->make<ObjectComprehension>(
346
142k
                    span(tok, last), tok.fodder, fields, got_comma, specs, last.fodder);
347
348
142k
                return last;
349
142k
            }
350
351
6.48M
            if (!got_comma && !first)
352
333
                throw StaticError(next.location, "expected a comma before next field.");
353
354
6.48M
            first = false;
355
6.48M
            got_comma = false;
356
357
6.48M
            switch (next.kind) {
358
156k
                case Token::BRACKET_L:
359
5.94M
                case Token::IDENTIFIER:
360
6.11M
                case Token::STRING_DOUBLE:
361
6.21M
                case Token::STRING_SINGLE:
362
6.22M
                case Token::STRING_BLOCK:
363
6.22M
                case Token::VERBATIM_STRING_DOUBLE:
364
6.22M
                case Token::VERBATIM_STRING_SINGLE: {
365
6.22M
                    ObjectField::Kind kind;
366
6.22M
                    AST *expr1 = nullptr;
367
6.22M
                    const Identifier *id = nullptr;
368
6.22M
                    Fodder fodder1, fodder2;
369
6.22M
                    LocationRange idLocation;
370
6.22M
                    if (next.kind == Token::IDENTIFIER) {
371
5.78M
                        fodder1 = next.fodder;
372
5.78M
                        kind = ObjectField::FIELD_ID;
373
5.78M
                        id = alloc->makeIdentifier(next.data32());
374
5.78M
                        idLocation = next.location;
375
5.78M
                    } else if (next.kind == Token::STRING_DOUBLE) {
376
167k
                        kind = ObjectField::FIELD_STR;
377
167k
                        expr1 = alloc->make<LiteralString>(next.location,
378
167k
                                                           next.fodder,
379
167k
                                                           next.data32(),
380
167k
                                                           LiteralString::DOUBLE,
381
167k
                                                           "",
382
167k
                                                           "");
383
268k
                    } else if (next.kind == Token::STRING_SINGLE) {
384
103k
                        kind = ObjectField::FIELD_STR;
385
103k
                        expr1 = alloc->make<LiteralString>(next.location,
386
103k
                                                           next.fodder,
387
103k
                                                           next.data32(),
388
103k
                                                           LiteralString::SINGLE,
389
103k
                                                           "",
390
103k
                                                           "");
391
164k
                    } else if (next.kind == Token::STRING_BLOCK) {
392
4.50k
                        kind = ObjectField::FIELD_STR;
393
4.50k
                        expr1 = alloc->make<LiteralString>(next.location,
394
4.50k
                                                           next.fodder,
395
4.50k
                                                           next.data32(),
396
4.50k
                                                           LiteralString::BLOCK,
397
4.50k
                                                           next.stringBlockIndent,
398
4.50k
                                                           next.stringBlockTermIndent);
399
160k
                    } else if (next.kind == Token::VERBATIM_STRING_SINGLE) {
400
1.27k
                        kind = ObjectField::FIELD_STR;
401
1.27k
                        expr1 = alloc->make<LiteralString>(next.location,
402
1.27k
                                                           next.fodder,
403
1.27k
                                                           next.data32(),
404
1.27k
                                                           LiteralString::VERBATIM_SINGLE,
405
1.27k
                                                           "",
406
1.27k
                                                           "");
407
158k
                    } else if (next.kind == Token::VERBATIM_STRING_DOUBLE) {
408
2.82k
                        kind = ObjectField::FIELD_STR;
409
2.82k
                        expr1 = alloc->make<LiteralString>(next.location,
410
2.82k
                                                           next.fodder,
411
2.82k
                                                           next.data32(),
412
2.82k
                                                           LiteralString::VERBATIM_DOUBLE,
413
2.82k
                                                           "",
414
2.82k
                                                           "");
415
156k
                    } else {
416
156k
                        kind = ObjectField::FIELD_EXPR;
417
156k
                        fodder1 = next.fodder;
418
156k
                        expr1 = parse(MAX_PRECEDENCE, current_depth + 1);
419
156k
                        Token bracket_r = popExpect(Token::BRACKET_R);
420
156k
                        fodder2 = bracket_r.fodder;
421
156k
                    }
422
423
6.22M
                    bool is_method = false;
424
6.22M
                    bool meth_comma = false;
425
6.22M
                    ArgParams params;
426
6.22M
                    Fodder fodder_l;
427
6.22M
                    Fodder fodder_r;
428
6.22M
                    if (peek().kind == Token::PAREN_L) {
429
3.19M
                        Token paren_l = pop();
430
3.19M
                        fodder_l = paren_l.fodder;
431
3.19M
                        params = parseParams("method parameter", meth_comma, fodder_r, current_depth);
432
3.19M
                        is_method = true;
433
3.19M
                    }
434
435
6.22M
                    bool plus_sugar = false;
436
437
6.22M
                    Token op = popExpect(Token::OPERATOR);
438
6.22M
                    const char *od = op.data.c_str();
439
6.22M
                    if (*od == '+') {
440
55.8k
                        plus_sugar = true;
441
55.8k
                        od++;
442
55.8k
                    }
443
6.22M
                    unsigned colons = 0;
444
15.6M
                    for (; *od != '\0'; ++od) {
445
9.41M
                        if (*od != ':') {
446
56
                            throw StaticError(
447
56
                                next.location,
448
56
                                "expected one of :, ::, :::, +:, +::, +:::, got: " + op.data);
449
56
                        }
450
9.41M
                        ++colons;
451
9.41M
                    }
452
6.22M
                    ObjectField::Hide field_hide;
453
6.22M
                    switch (colons) {
454
3.02M
                        case 1: field_hide = ObjectField::INHERIT; break;
455
456
3.19M
                        case 2: field_hide = ObjectField::HIDDEN; break;
457
458
59
                        case 3: field_hide = ObjectField::VISIBLE; break;
459
460
29
                        default:
461
29
                            throw StaticError(
462
29
                                next.location,
463
29
                                "expected one of :, ::, :::, +:, +::, +:::, got: " + op.data);
464
6.22M
                    }
465
466
                    // Basic checks for invalid Jsonnet code.
467
6.21M
                    if (is_method && plus_sugar) {
468
3
                        throw StaticError(next.location,
469
3
                                          "cannot use +: syntax sugar in a method: " + next.data);
470
3
                    }
471
6.21M
                    if (kind != ObjectField::FIELD_EXPR) {
472
6.06M
                        if (!literal_fields.insert(next.data).second) {
473
31
                            throw StaticError(next.location, "duplicate field: " + next.data);
474
31
                        }
475
6.06M
                    }
476
477
6.21M
                    AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
478
479
6.21M
                    Fodder comma_fodder;
480
6.21M
                    next = pop();
481
6.21M
                    if (next.kind == Token::COMMA) {
482
5.24M
                        comma_fodder = next.fodder;
483
5.24M
                        next = pop();
484
5.24M
                        got_comma = true;
485
5.24M
                    }
486
6.21M
                    fields.emplace_back(kind,
487
6.21M
                                        fodder1,
488
6.21M
                                        fodder2,
489
6.21M
                                        fodder_l,
490
6.21M
                                        fodder_r,
491
6.21M
                                        field_hide,
492
6.21M
                                        plus_sugar,
493
6.21M
                                        is_method,
494
6.21M
                                        expr1,
495
6.21M
                                        id,
496
6.21M
                                        idLocation,
497
6.21M
                                        params,
498
6.21M
                                        meth_comma,
499
6.21M
                                        op.fodder,
500
6.21M
                                        body,
501
6.21M
                                        nullptr,
502
6.21M
                                        comma_fodder);
503
6.21M
                } break;
504
505
181k
                case Token::LOCAL: {
506
181k
                    Fodder local_fodder = next.fodder;
507
181k
                    Token var_id = popExpect(Token::IDENTIFIER);
508
181k
                    auto *id = alloc->makeIdentifier(var_id.data32());
509
510
181k
                    if (binds.find(id) != binds.end()) {
511
5
                        throw StaticError(var_id.location, "duplicate local var: " + var_id.data);
512
5
                    }
513
181k
                    bool is_method = false;
514
181k
                    bool func_comma = false;
515
181k
                    ArgParams params;
516
181k
                    Fodder paren_l_fodder;
517
181k
                    Fodder paren_r_fodder;
518
181k
                    if (peek().kind == Token::PAREN_L) {
519
26.8k
                        Token paren_l = pop();
520
26.8k
                        paren_l_fodder = paren_l.fodder;
521
26.8k
                        is_method = true;
522
26.8k
                        params = parseParams("function parameter", func_comma, paren_r_fodder, current_depth);
523
26.8k
                    }
524
181k
                    Token eq = popExpect(Token::OPERATOR, "=");
525
181k
                    AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
526
181k
                    binds.insert(id);
527
528
181k
                    Fodder comma_fodder;
529
181k
                    next = pop();
530
181k
                    if (next.kind == Token::COMMA) {
531
179k
                        comma_fodder = next.fodder;
532
179k
                        next = pop();
533
179k
                        got_comma = true;
534
179k
                    }
535
181k
                    fields.push_back(ObjectField::Local(local_fodder,
536
181k
                                                        var_id.fodder,
537
181k
                                                        paren_l_fodder,
538
181k
                                                        paren_r_fodder,
539
181k
                                                        is_method,
540
181k
                                                        id,
541
181k
                                                        params,
542
181k
                                                        func_comma,
543
181k
                                                        eq.fodder,
544
181k
                                                        body,
545
181k
                                                        comma_fodder));
546
547
181k
                } break;
548
549
81.6k
                case Token::ASSERT: {
550
81.6k
                    Fodder assert_fodder = next.fodder;
551
81.6k
                    AST *cond = parse(MAX_PRECEDENCE, current_depth + 1);
552
81.6k
                    AST *msg = nullptr;
553
81.6k
                    Fodder colon_fodder;
554
81.6k
                    if (peek().kind == Token::OPERATOR && peek().data == ":") {
555
32.6k
                        Token colon = pop();
556
32.6k
                        colon_fodder = colon.fodder;
557
32.6k
                        msg = parse(MAX_PRECEDENCE, current_depth + 1);
558
32.6k
                    }
559
560
81.6k
                    Fodder comma_fodder;
561
81.6k
                    next = pop();
562
81.6k
                    if (next.kind == Token::COMMA) {
563
72.5k
                        comma_fodder = next.fodder;
564
72.5k
                        next = pop();
565
72.5k
                        got_comma = true;
566
72.5k
                    }
567
81.6k
                    fields.push_back(
568
81.6k
                        ObjectField::Assert(assert_fodder, cond, colon_fodder, msg, comma_fodder));
569
81.6k
                } break;
570
571
218
                default: throw unexpected(next, "parsing field definition");
572
6.48M
            }
573
574
6.48M
        } while (true);
575
1.54M
    }
576
577
    /** Parses for x in expr for y in expr if expr for z in expr ...
578
     *
579
     * \param end The token that ends the comprehension (e.g. ] or }).
580
     * \param for_fodder Fodder before the first 'for'.
581
     * \param specs The comprehension specs to be populated.
582
     * \param current_depth Current recursion depth to prevent stack overflow.
583
     * \returns The closing token.
584
     */
585
    Token parseComprehensionSpecs(Token::Kind end, Fodder for_fodder,
586
                                  std::vector<ComprehensionSpec> &specs,
587
                                  unsigned current_depth)
588
962k
    {
589
962k
        if (current_depth >= MAX_PARSER_DEPTH) {
590
0
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
591
0
        }
592
593
1.05M
        while (true) {
594
1.05M
            LocationRange l;
595
1.05M
            Token id_token = popExpect(Token::IDENTIFIER);
596
1.05M
            const Identifier *id = alloc->makeIdentifier(id_token.data32());
597
1.05M
            Token in_token = popExpect(Token::IN);
598
1.05M
            AST *arr = parse(MAX_PRECEDENCE, current_depth + 1);
599
1.05M
            specs.emplace_back(
600
1.05M
                ComprehensionSpec::FOR, for_fodder, id_token.fodder, id, in_token.fodder, arr);
601
602
1.05M
            Token maybe_if = pop();
603
1.55M
            for (; maybe_if.kind == Token::IF; maybe_if = pop()) {
604
501k
                AST *cond = parse(MAX_PRECEDENCE, current_depth + 1);
605
501k
                specs.emplace_back(
606
501k
                    ComprehensionSpec::IF, maybe_if.fodder, Fodder{}, nullptr, Fodder{}, cond);
607
501k
            }
608
1.05M
            if (maybe_if.kind == end) {
609
959k
                return maybe_if;
610
959k
            }
611
97.2k
            if (maybe_if.kind != Token::FOR) {
612
237
                std::stringstream ss;
613
237
                ss << "expected for, if or " << end << " after for clause, got: " << maybe_if;
614
237
                throw StaticError(maybe_if.location, ss.str());
615
237
            }
616
97.0k
            for_fodder = maybe_if.fodder;
617
97.0k
        }
618
962k
    }
619
620
    /** Parse a terminal (literal, var, import, etc.), an object declaration, unary operator,
621
     * or a parenthesized expression.
622
     *
623
     * \param current_depth Current recursion depth to prevent stack overflow.
624
     * \returns The parsed AST.
625
     */
626
    AST *parseTerminalBracketsOrUnary(unsigned current_depth)
627
119M
    {
628
119M
        if (current_depth >= MAX_PARSER_DEPTH) {
629
0
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
630
0
        }
631
632
119M
        Token tok = pop();
633
119M
        switch (tok.kind) {
634
0
            case Token::ASSERT:
635
31
            case Token::BRACE_R:
636
57
            case Token::BRACKET_R:
637
155
            case Token::COMMA:
638
203
            case Token::DOT:
639
206
            case Token::ELSE:
640
206
            case Token::ERROR:
641
210
            case Token::FOR:
642
210
            case Token::FUNCTION:
643
210
            case Token::IF:
644
225
            case Token::IN:
645
225
            case Token::IMPORT:
646
225
            case Token::IMPORTSTR:
647
225
            case Token::IMPORTBIN:
648
225
            case Token::LOCAL:
649
276
            case Token::PAREN_R:
650
305
            case Token::SEMICOLON:
651
308
            case Token::TAILSTRICT:
652
311
            case Token::THEN: throw unexpected(tok, "parsing terminal");
653
654
2.03k
            case Token::END_OF_FILE: throw StaticError(tok.location, "unexpected end of file.");
655
656
1.77M
            case Token::OPERATOR: {
657
1.77M
                UnaryOp uop;
658
1.77M
                if (!op_is_unary(tok.data, uop)) {
659
618
                    std::stringstream ss;
660
618
                    ss << "not a unary operator: " << tok.data;
661
618
                    throw StaticError(tok.location, ss.str());
662
618
                }
663
1.77M
                AST *expr = parse(UNARY_PRECEDENCE, current_depth + 1);
664
1.77M
                return alloc->make<Unary>(span(tok, expr), tok.fodder, uop, expr);
665
1.77M
            }
666
1.29M
            case Token::BRACE_L: {
667
1.29M
                AST *obj;
668
1.29M
                parseObjectRemainder(obj, tok, current_depth + 1);
669
1.29M
                return obj;
670
1.77M
            }
671
672
3.58M
            case Token::BRACKET_L: {
673
3.58M
                Token next = peek();
674
3.58M
                if (next.kind == Token::BRACKET_R) {
675
589k
                    Token bracket_r = pop();
676
589k
                    return alloc->make<Array>(
677
589k
                        span(tok, next), tok.fodder, Array::Elements{}, false, bracket_r.fodder);
678
589k
                }
679
2.99M
                AST *first = parse(MAX_PRECEDENCE, current_depth + 1);
680
2.99M
                bool got_comma = false;
681
2.99M
                Fodder comma_fodder;
682
2.99M
                next = peek();
683
2.99M
                if (!got_comma && next.kind == Token::COMMA) {
684
460k
                    Token comma = pop();
685
460k
                    comma_fodder = comma.fodder;
686
460k
                    next = peek();
687
460k
                    got_comma = true;
688
460k
                }
689
690
2.99M
                if (next.kind == Token::FOR) {
691
                    // It's a comprehension
692
820k
                    Token for_token = pop();
693
820k
                    std::vector<ComprehensionSpec> specs;
694
820k
                    Token last = parseComprehensionSpecs(Token::BRACKET_R, for_token.fodder, specs, current_depth + 1);
695
820k
                    return alloc->make<ArrayComprehension>(span(tok, last),
696
820k
                                                           tok.fodder,
697
820k
                                                           first,
698
820k
                                                           comma_fodder,
699
820k
                                                           got_comma,
700
820k
                                                           specs,
701
820k
                                                           last.fodder);
702
820k
                }
703
704
                // Not a comprehension: It can have more elements.
705
2.17M
                Array::Elements elements;
706
2.17M
                elements.emplace_back(first, comma_fodder);
707
8.70M
                do {
708
8.70M
                    if (next.kind == Token::BRACKET_R) {
709
2.16M
                        Token bracket_r = pop();
710
2.16M
                        return alloc->make<Array>(
711
2.16M
                            span(tok, next), tok.fodder, elements, got_comma, bracket_r.fodder);
712
2.16M
                    }
713
6.53M
                    if (!got_comma) {
714
779
                        std::stringstream ss;
715
779
                        ss << "expected a comma before next array element.";
716
779
                        throw StaticError(next.location, ss.str());
717
779
                    }
718
6.53M
                    AST *expr = parse(MAX_PRECEDENCE, current_depth + 1);
719
6.53M
                    comma_fodder.clear();
720
6.53M
                    got_comma = false;
721
6.53M
                    next = peek();
722
6.53M
                    if (next.kind == Token::COMMA) {
723
6.12M
                        Token comma = pop();
724
6.12M
                        comma_fodder = comma.fodder;
725
6.12M
                        next = peek();
726
6.12M
                        got_comma = true;
727
6.12M
                    }
728
6.53M
                    elements.emplace_back(expr, comma_fodder);
729
6.53M
                } while (true);
730
2.17M
            }
731
732
1.24M
            case Token::PAREN_L: {
733
1.24M
                auto *inner = parse(MAX_PRECEDENCE, current_depth + 1);
734
1.24M
                Token close = popExpect(Token::PAREN_R);
735
1.24M
                return alloc->make<Parens>(span(tok, close), tok.fodder, inner, close.fodder);
736
2.17M
            }
737
738
            // Literals
739
16.4M
            case Token::NUMBER: return alloc->make<LiteralNumber>(span(tok), tok.fodder, tok.data);
740
741
11.9M
            case Token::STRING_SINGLE:
742
11.9M
                return alloc->make<LiteralString>(
743
11.9M
                    span(tok), tok.fodder, tok.data32(), LiteralString::SINGLE, "", "");
744
205k
            case Token::STRING_DOUBLE:
745
205k
                return alloc->make<LiteralString>(
746
205k
                    span(tok), tok.fodder, tok.data32(), LiteralString::DOUBLE, "", "");
747
7.07k
            case Token::STRING_BLOCK:
748
7.07k
                return alloc->make<LiteralString>(span(tok),
749
7.07k
                                                  tok.fodder,
750
7.07k
                                                  tok.data32(),
751
7.07k
                                                  LiteralString::BLOCK,
752
7.07k
                                                  tok.stringBlockIndent,
753
7.07k
                                                  tok.stringBlockTermIndent);
754
1.77k
            case Token::VERBATIM_STRING_SINGLE:
755
1.77k
                return alloc->make<LiteralString>(
756
1.77k
                    span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_SINGLE, "", "");
757
4.35k
            case Token::VERBATIM_STRING_DOUBLE:
758
4.35k
                return alloc->make<LiteralString>(
759
4.35k
                    span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_DOUBLE, "", "");
760
761
1.25M
            case Token::FALSE: return alloc->make<LiteralBoolean>(span(tok), tok.fodder, false);
762
763
921k
            case Token::TRUE: return alloc->make<LiteralBoolean>(span(tok), tok.fodder, true);
764
765
438k
            case Token::NULL_LIT: return alloc->make<LiteralNull>(span(tok), tok.fodder);
766
767
            // Variables
768
114k
            case Token::DOLLAR: return alloc->make<Dollar>(span(tok), tok.fodder);
769
770
79.7M
            case Token::IDENTIFIER:
771
79.7M
                return alloc->make<Var>(span(tok), tok.fodder, alloc->makeIdentifier(tok.data32()));
772
773
103k
            case Token::SELF: return alloc->make<Self>(span(tok), tok.fodder);
774
775
8.72k
            case Token::SUPER: {
776
8.72k
                Token next = pop();
777
8.72k
                AST *index = nullptr;
778
8.72k
                const Identifier *id = nullptr;
779
8.72k
                Fodder id_fodder;
780
8.72k
                switch (next.kind) {
781
7.58k
                    case Token::DOT: {
782
7.58k
                        Token field_id = popExpect(Token::IDENTIFIER);
783
7.58k
                        id_fodder = field_id.fodder;
784
7.58k
                        id = alloc->makeIdentifier(field_id.data32());
785
7.58k
                    } break;
786
1.12k
                    case Token::BRACKET_L: {
787
1.12k
                        index = parse(MAX_PRECEDENCE, current_depth + 1);
788
1.12k
                        Token bracket_r = popExpect(Token::BRACKET_R);
789
1.12k
                        id_fodder = bracket_r.fodder;  // Not id_fodder, but use the same var.
790
1.12k
                    } break;
791
9
                    default: throw StaticError(tok.location, "expected . or [ after super.");
792
8.72k
                }
793
8.01k
                return alloc->make<SuperIndex>(
794
8.01k
                    span(tok), tok.fodder, next.fodder, index, id_fodder, id);
795
8.72k
            }
796
119M
        }
797
798
0
        std::cerr << "INTERNAL ERROR: Unknown tok kind: " << tok.kind << std::endl;
799
0
        std::abort();
800
0
        return nullptr;  // Quiet, compiler.
801
119M
    }
802
803
    /** If the first token makes it clear that we will be parsing a greedy construct, return the AST.
804
     * Otherwise, return nullptr. Greedy constructs are those that consume as many tokens as possible
805
     * on the right hand side because they have no closing token.
806
     *
807
     * \param current_depth Current recursion depth to prevent stack overflow.
808
     * \returns The parsed AST or nullptr.
809
     */
810
    AST *maybeParseGreedy(unsigned current_depth)
811
136M
    {
812
136M
        if (current_depth >= MAX_PARSER_DEPTH) {
813
13
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
814
13
        }
815
816
        // Allocate this on the heap to control stack growth.
817
136M
        std::unique_ptr<Token> begin_(new Token(peek()));
818
136M
        const Token &begin = *begin_;
819
820
136M
        switch (begin.kind) {
821
            // These cases have effectively MAX_PRECEDENCE as the first
822
            // call to parse will parse them.
823
1.05M
            case Token::ASSERT: {
824
1.05M
                pop();
825
1.05M
                AST *cond = parse(MAX_PRECEDENCE, current_depth + 1);
826
1.05M
                Fodder colonFodder;
827
1.05M
                AST *msg = nullptr;
828
1.05M
                if (peek().kind == Token::OPERATOR && peek().data == ":") {
829
972k
                    Token colon = pop();
830
972k
                    colonFodder = colon.fodder;
831
972k
                    msg = parse(MAX_PRECEDENCE, current_depth + 1);
832
972k
                }
833
1.05M
                Token semicolon = popExpect(Token::SEMICOLON);
834
1.05M
                AST *rest = parse(MAX_PRECEDENCE, current_depth + 1);
835
1.05M
                return alloc->make<Assert>(span(begin, rest),
836
1.05M
                                           begin.fodder,
837
1.05M
                                           cond,
838
1.05M
                                           colonFodder,
839
1.05M
                                           msg,
840
1.05M
                                           semicolon.fodder,
841
1.05M
                                           rest);
842
0
            }
843
844
1.61M
            case Token::ERROR: {
845
1.61M
                pop();
846
1.61M
                AST *expr = parse(MAX_PRECEDENCE, current_depth + 1);
847
1.61M
                return alloc->make<Error>(span(begin, expr), begin.fodder, expr);
848
0
            }
849
850
8.28M
            case Token::IF: {
851
8.28M
                pop();
852
8.28M
                AST *cond = parse(MAX_PRECEDENCE, current_depth + 1);
853
8.28M
                Token then = popExpect(Token::THEN);
854
8.28M
                AST *branch_true = parse(MAX_PRECEDENCE, current_depth + 1);
855
8.28M
                if (peek().kind == Token::ELSE) {
856
8.17M
                    Token else_ = pop();
857
8.17M
                    AST *branch_false = parse(MAX_PRECEDENCE, current_depth + 1);
858
8.17M
                    return alloc->make<Conditional>(span(begin, branch_false),
859
8.17M
                                                    begin.fodder,
860
8.17M
                                                    cond,
861
8.17M
                                                    then.fodder,
862
8.17M
                                                    branch_true,
863
8.17M
                                                    else_.fodder,
864
8.17M
                                                    branch_false);
865
8.17M
                }
866
103k
                return alloc->make<Conditional>(span(begin, branch_true),
867
103k
                                                begin.fodder,
868
103k
                                                cond,
869
103k
                                                then.fodder,
870
103k
                                                branch_true,
871
103k
                                                Fodder{},
872
103k
                                                nullptr);
873
8.28M
            }
874
875
513k
            case Token::FUNCTION: {
876
513k
                pop();  // Still available in 'begin'.
877
513k
                Token paren_l = pop();
878
513k
                if (paren_l.kind == Token::PAREN_L) {
879
513k
                    std::vector<AST *> params_asts;
880
513k
                    bool got_comma;
881
513k
                    Fodder paren_r_fodder;
882
513k
                    ArgParams params = parseParams("function parameter", got_comma, paren_r_fodder, current_depth);
883
513k
                    AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
884
513k
                    return alloc->make<Function>(span(begin, body),
885
513k
                                                 begin.fodder,
886
513k
                                                 paren_l.fodder,
887
513k
                                                 params,
888
513k
                                                 got_comma,
889
513k
                                                 paren_r_fodder,
890
513k
                                                 body);
891
513k
                } else {
892
15
                    std::stringstream ss;
893
15
                    ss << "expected ( but got " << paren_l;
894
15
                    throw StaticError(paren_l.location, ss.str());
895
15
                }
896
513k
            }
897
898
1.46k
            case Token::IMPORT: {
899
1.46k
                pop();
900
1.46k
                AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
901
1.46k
                if (body->type == AST_LITERAL_STRING) {
902
1.09k
                    auto *lit = static_cast<LiteralString *>(body);
903
1.09k
                    if (lit->tokenKind == LiteralString::BLOCK) {
904
3
                        throw StaticError(lit->location,
905
3
                                          "Cannot use text blocks in import statements.");
906
3
                    }
907
1.09k
                    return alloc->make<Import>(span(begin, body), begin.fodder, lit);
908
1.09k
                } else {
909
367
                    std::stringstream ss;
910
367
                    ss << "computed imports are not allowed.";
911
367
                    throw StaticError(body->location, ss.str());
912
367
                }
913
1.46k
            }
914
915
2.98k
            case Token::IMPORTSTR: {
916
2.98k
                pop();
917
2.98k
                AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
918
2.98k
                if (body->type == AST_LITERAL_STRING) {
919
2.63k
                    auto *lit = static_cast<LiteralString *>(body);
920
2.63k
                    if (lit->tokenKind == LiteralString::BLOCK) {
921
2
                        throw StaticError(lit->location,
922
2
                                          "Cannot use text blocks in import statements.");
923
2
                    }
924
2.63k
                    return alloc->make<Importstr>(span(begin, body), begin.fodder, lit);
925
2.63k
                } else {
926
350
                    std::stringstream ss;
927
350
                    ss << "computed imports are not allowed.";
928
350
                    throw StaticError(body->location, ss.str());
929
350
                }
930
2.98k
            }
931
932
1.26k
            case Token::IMPORTBIN: {
933
1.26k
                pop();
934
1.26k
                AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
935
1.26k
                if (body->type == AST_LITERAL_STRING) {
936
1.01k
                    auto *lit = static_cast<LiteralString *>(body);
937
1.01k
                    if (lit->tokenKind == LiteralString::BLOCK) {
938
0
                        throw StaticError(lit->location,
939
0
                                          "Cannot use text blocks in import statements.");
940
0
                    }
941
1.01k
                    return alloc->make<Importbin>(span(begin, body), begin.fodder, lit);
942
1.01k
                } else {
943
252
                    std::stringstream ss;
944
252
                    ss << "computed imports are not allowed.";
945
252
                    throw StaticError(body->location, ss.str());
946
252
                }
947
1.26k
            }
948
949
6.13M
            case Token::LOCAL: {
950
6.13M
                pop();
951
6.13M
                Local::Binds binds;
952
6.47M
                do {
953
6.47M
                    Token delim = parseBind(binds, current_depth + 1);
954
6.47M
                    if (delim.kind != Token::SEMICOLON && delim.kind != Token::COMMA) {
955
48
                        std::stringstream ss;
956
48
                        ss << "expected , or ; but got " << delim;
957
48
                        throw StaticError(delim.location, ss.str());
958
48
                    }
959
6.47M
                    if (delim.kind == Token::SEMICOLON)
960
6.13M
                        break;
961
6.47M
                } while (true);
962
6.13M
                AST *body = parse(MAX_PRECEDENCE, current_depth + 1);
963
6.13M
                return alloc->make<Local>(span(begin, body), begin.fodder, binds, body);
964
6.13M
            }
965
966
119M
            default:
967
119M
            return nullptr;
968
136M
        }
969
136M
    }
970
971
972
    /** Parse a general expression.
973
     *
974
     * Consume infix tokens up to (but not including) max_precedence, then stop.
975
     * \param max_precedence The maximum precedence to consider.
976
     * \param current_depth Current recursion depth to prevent stack overflow.
977
     * \returns The parsed AST.
978
     */
979
    AST *parse(unsigned max_precedence, unsigned current_depth)
980
136M
    {
981
136M
        if (current_depth >= MAX_PARSER_DEPTH) {
982
15
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
983
15
        }
984
985
136M
        AST *ast = maybeParseGreedy(current_depth + 1);
986
        // There cannot be an operator after a greedy parse.
987
136M
        if (ast != nullptr) return ast;
988
989
        // If we get here, we could be parsing an infix construct.
990
991
        // Allocate this on the heap to control stack growth.
992
119M
        std::unique_ptr<Token> begin_(new Token(peek()));
993
119M
        const Token &begin = *begin_;
994
995
119M
        AST *lhs = parseTerminalBracketsOrUnary(current_depth + 1);
996
997
119M
        return parseInfix(lhs, begin, max_precedence, current_depth + 1);
998
136M
    }
999
1000
    /** Parse infix operators (binary operators, indexing, function calls).
1001
     *
1002
     * \param lhs Left-hand side of the operator.
1003
     * \param begin The token representing the beginning of the expression.
1004
     * \param max_precedence The maximum precedence to consider.
1005
     * \param current_depth Current recursion depth to prevent stack overflow.
1006
     * \returns The parsed AST.
1007
     */
1008
    AST *parseInfix(AST *lhs, const Token &begin, unsigned max_precedence, unsigned current_depth)
1009
119M
    {
1010
119M
        if (current_depth >= MAX_PARSER_DEPTH) {
1011
0
            throw StaticError(peek().location, "Exceeded maximum parse depth limit.");
1012
0
        }
1013
1014
184M
        while (true) {
1015
1016
184M
            BinaryOp bop = BOP_PLUS;
1017
184M
            unsigned op_precedence = 0;
1018
1019
184M
            switch (peek().kind) {
1020
                // Logical / arithmetic binary operator.
1021
7.83k
                case Token::IN:
1022
28.4M
                case Token::OPERATOR:
1023
                    // These occur if the outer statement was an assert or array slice.
1024
                    // Either way, we terminate the parsing here.
1025
28.4M
                    if (peek().data == ":" || peek().data == "::") {
1026
2.06M
                        return lhs;
1027
2.06M
                    }
1028
26.3M
                    if (!op_is_binary(peek().data, bop)) {
1029
472
                        std::stringstream ss;
1030
472
                        ss << "not a binary operator: " << peek().data;
1031
472
                        throw StaticError(peek().location, ss.str());
1032
472
                    }
1033
26.3M
                    op_precedence = precedence_map[bop];
1034
26.3M
                    break;
1035
1036
                // Index, Apply
1037
18.2M
                case Token::DOT:
1038
22.6M
                case Token::BRACKET_L:
1039
43.4M
                case Token::PAREN_L:
1040
43.6M
                case Token::BRACE_L:
1041
43.6M
                    op_precedence = APPLY_PRECEDENCE;
1042
43.6M
                    break;
1043
1044
112M
                default:
1045
                    // This happens when we reach EOF or the terminating token of an outer context.
1046
112M
                    return lhs;
1047
184M
            }
1048
1049
            // If higher precedence than the outer recursive call, let that handle it.
1050
70.0M
            if (op_precedence >= max_precedence)
1051
4.20M
                return lhs;
1052
1053
65.8M
            Token op = pop();
1054
1055
65.8M
            switch (op.kind) {
1056
4.38M
                case Token::BRACKET_L: {
1057
4.38M
                    bool is_slice;
1058
4.38M
                    AST *first = nullptr;
1059
4.38M
                    Fodder second_fodder;
1060
4.38M
                    AST *second = nullptr;
1061
4.38M
                    Fodder third_fodder;
1062
4.38M
                    AST *third = nullptr;
1063
1064
4.38M
                    if (peek().kind == Token::BRACKET_R)
1065
5
                        throw unexpected(pop(), "parsing index");
1066
1067
4.38M
                    if (peek().data != ":" && peek().data != "::") {
1068
4.31M
                        first = parse(MAX_PRECEDENCE, current_depth + 1);
1069
4.31M
                    }
1070
1071
4.38M
                    if (peek().kind == Token::OPERATOR && peek().data == "::") {
1072
                        // Handle ::
1073
2.71k
                        is_slice = true;
1074
2.71k
                        Token joined = pop();
1075
2.71k
                        second_fodder = joined.fodder;
1076
1077
2.71k
                        if (peek().kind != Token::BRACKET_R)
1078
2.02k
                            third = parse(MAX_PRECEDENCE, current_depth + 1);
1079
1080
4.38M
                    } else if (peek().kind != Token::BRACKET_R) {
1081
476k
                        is_slice = true;
1082
476k
                        Token delim = pop();
1083
476k
                        if (delim.data != ":")
1084
372
                            throw unexpected(delim, "parsing slice");
1085
1086
476k
                        second_fodder = delim.fodder;
1087
1088
476k
                        if (peek().data != ":" && peek().kind != Token::BRACKET_R)
1089
213k
                            second = parse(MAX_PRECEDENCE, current_depth + 1);
1090
1091
476k
                        if (peek().kind != Token::BRACKET_R) {
1092
30.4k
                            Token delim = pop();
1093
30.4k
                            if (delim.data != ":")
1094
117
                                throw unexpected(delim, "parsing slice");
1095
1096
30.3k
                            third_fodder = delim.fodder;
1097
1098
30.3k
                            if (peek().kind != Token::BRACKET_R)
1099
28.5k
                                third = parse(MAX_PRECEDENCE, current_depth + 1);
1100
30.3k
                        }
1101
3.90M
                    } else {
1102
3.90M
                        is_slice = false;
1103
3.90M
                    }
1104
4.38M
                    Token end = popExpect(Token::BRACKET_R);
1105
4.38M
                    lhs = alloc->make<Index>(span(begin, end),
1106
4.38M
                                             EMPTY_FODDER,
1107
4.38M
                                             lhs,
1108
4.38M
                                             op.fodder,
1109
4.38M
                                             is_slice,
1110
4.38M
                                             first,
1111
4.38M
                                             second_fodder,
1112
4.38M
                                             second,
1113
4.38M
                                             third_fodder,
1114
4.38M
                                             third,
1115
4.38M
                                             end.fodder);
1116
4.38M
                    break;
1117
4.38M
                }
1118
18.2M
                case Token::DOT: {
1119
18.2M
                    Token field_id = popExpect(Token::IDENTIFIER);
1120
18.2M
                    const Identifier *id = alloc->makeIdentifier(field_id.data32());
1121
18.2M
                    lhs = alloc->make<Index>(span(begin, field_id),
1122
18.2M
                                             EMPTY_FODDER,
1123
18.2M
                                             lhs,
1124
18.2M
                                             op.fodder,
1125
18.2M
                                             field_id.fodder,
1126
18.2M
                                             id);
1127
18.2M
                    break;
1128
4.38M
                }
1129
20.7M
                case Token::PAREN_L: {
1130
20.7M
                    ArgParams args;
1131
20.7M
                    bool got_comma;
1132
20.7M
                    Token end = parseArgs(args, "function argument", got_comma, current_depth);
1133
20.7M
                    bool got_named = false;
1134
34.5M
                    for (const auto& arg : args) {
1135
34.5M
                        if (arg.id != nullptr) {
1136
80.2k
                            got_named = true;
1137
34.4M
                        } else {
1138
34.4M
                            if (got_named) {
1139
11
                                throw StaticError(arg.expr->location, "Positional argument after a named argument is not allowed");
1140
11
                            }
1141
34.4M
                        }
1142
34.5M
                    }
1143
20.7M
                    bool tailstrict = false;
1144
20.7M
                    Fodder tailstrict_fodder;
1145
20.7M
                    if (peek().kind == Token::TAILSTRICT) {
1146
1.02M
                        Token tailstrict_token = pop();
1147
1.02M
                        tailstrict_fodder = tailstrict_token.fodder;
1148
1.02M
                        tailstrict = true;
1149
1.02M
                    }
1150
20.7M
                    lhs = alloc->make<Apply>(span(begin, end),
1151
20.7M
                                             EMPTY_FODDER,
1152
20.7M
                                             lhs,
1153
20.7M
                                             op.fodder,
1154
20.7M
                                             args,
1155
20.7M
                                             got_comma,
1156
20.7M
                                             end.fodder,
1157
20.7M
                                             tailstrict_fodder,
1158
20.7M
                                             tailstrict);
1159
20.7M
                    break;
1160
20.7M
                }
1161
250k
                case Token::BRACE_L: {
1162
250k
                    AST *obj;
1163
250k
                    Token end = parseObjectRemainder(obj, op, current_depth + 1);
1164
250k
                    lhs = alloc->make<ApplyBrace>(span(begin, end), EMPTY_FODDER, lhs, obj);
1165
250k
                    break;
1166
20.7M
                }
1167
1168
6.31k
                case Token::IN: {
1169
6.31k
                    if (peek().kind == Token::SUPER) {
1170
558
                        Token super = pop();
1171
558
                        lhs = alloc->make<InSuper>(
1172
558
                            span(begin, super), EMPTY_FODDER, lhs, op.fodder, super.fodder);
1173
5.76k
                    } else {
1174
5.76k
                        AST *rhs = parse(op_precedence, current_depth + 1);
1175
5.76k
                        lhs = alloc->make<Binary>(
1176
5.76k
                            span(begin, rhs), EMPTY_FODDER, lhs, op.fodder, bop, rhs);
1177
5.76k
                    }
1178
6.31k
                    break;
1179
20.7M
                }
1180
1181
22.1M
                case Token::OPERATOR: {
1182
22.1M
                    AST *rhs = parse(op_precedence, current_depth + 1);
1183
22.1M
                    lhs = alloc->make<Binary>(
1184
22.1M
                        span(begin, rhs), EMPTY_FODDER, lhs, op.fodder, bop, rhs);
1185
22.1M
                    break;
1186
20.7M
                }
1187
1188
0
                default: {
1189
0
                    std::cerr << "Should not be here." << std::endl;
1190
0
                    abort();
1191
20.7M
                }
1192
65.8M
            }
1193
65.8M
        }
1194
1195
        // (1 & ((1 + (1 * 1)) + 1)) & 1
1196
        //
1197
        //
1198
1199
/*
1200
        // Allocate this on the heap to control stack growth.
1201
        std::unique_ptr<Token> begin_(new Token(peek()));
1202
        const Token &begin = *begin_;
1203
*/
1204
119M
    }
1205
};
1206
1207
}  // namespace
1208
1209
AST *jsonnet_parse(Allocator *alloc, Tokens &tokens)
1210
48.7k
{
1211
48.7k
    Parser parser(tokens, alloc);
1212
48.7k
    unsigned parse_depth = 0;
1213
48.7k
    AST *expr = parser.parse(MAX_PRECEDENCE, parse_depth);
1214
48.7k
    if (tokens.front().kind != Token::END_OF_FILE) {
1215
681
        std::stringstream ss;
1216
681
        ss << "did not expect: " << tokens.front();
1217
681
        throw StaticError(tokens.front().location, ss.str());
1218
681
    }
1219
1220
48.0k
    return expr;
1221
48.7k
}
1222
1223
}  // namespace jsonnet::internal