jsonata-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
jsonata/parser.py ADDED
@@ -0,0 +1,1397 @@
1
+ #
2
+ # Copyright Robert Yokota
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
+ # Derived from the following code:
17
+ #
18
+ # Project name: jsonata-java
19
+ # Copyright Dashjoin GmbH. https://dashjoin.com
20
+ # Licensed under the Apache License, Version 2.0 (the "License")
21
+ #
22
+ # Project name: JSONata
23
+ # © Copyright IBM Corp. 2016, 2018 All Rights Reserved
24
+ # This project is licensed under the MIT License, see LICENSE
25
+ #
26
+
27
+ import copy
28
+ from typing import Any, MutableSequence, Optional, Sequence
29
+
30
+ from jsonata import jexception, tokenizer, signature, utils
31
+
32
+
33
+ # var parseSignature = require('./signature')
34
+ class Parser:
35
+
36
+ # This parser implements the 'Top down operator precedence' algorithm developed by Vaughan R Pratt; http://dl.acm.org/citation.cfm?id=512931.
37
+ # and builds on the Javascript framework described by Douglas Crockford at http://javascript.crockford.com/tdop/tdop.html
38
+ # and in 'Beautiful Code', edited by Andy Oram and Greg Wilson, Copyright 2007 O'Reilly Media, Inc. 798-0-596-51004-6
39
+
40
+ # var parser = function (source, recover) {
41
+
42
+ def remaining_tokens(self) -> list[tokenizer.Tokenizer.Token]:
43
+ remaining = []
44
+ if self.node.id != "(end)":
45
+ t = tokenizer.Tokenizer.Token(self.node.type, self.node.value, self.node.position)
46
+ remaining.append(t)
47
+ nxt = self.lexer.next(False)
48
+ while nxt is not None:
49
+ remaining.append(nxt)
50
+ nxt = self.lexer.next(False)
51
+ return remaining
52
+
53
+ class Symbol:
54
+ # Symbol s
55
+
56
+ # Procedure:
57
+
58
+ # Infix attributes
59
+ # where rhs = list of Symbol pairs
60
+ # where rhs = list of Symbols
61
+
62
+ # Ternary operator:
63
+
64
+ # processAST error handling
65
+
66
+ # Prefix attributes
67
+
68
+ # Ancestor attributes
69
+
70
+ def nud(self):
71
+ # error - symbol has been invoked as a unary operator
72
+ _err = jexception.JException("S0211", self.position, self.value)
73
+
74
+ if self._outer_instance.recover:
75
+ #
76
+ # err.remaining = remainingTokens()
77
+ # err.type = "error"
78
+ # errors.add(err)
79
+ # return err
80
+ #
81
+ return Parser.Symbol("(error)")
82
+ else:
83
+ raise _err
84
+
85
+ def led(self, left):
86
+ raise NotImplementedError("led not implemented")
87
+
88
+ _outer_instance: 'Parser'
89
+ id: Optional[str]
90
+ type: Optional[str]
91
+ value: Optional[Any]
92
+ bp: int
93
+ lbp: int
94
+ position: int
95
+ keep_array: bool
96
+ descending: bool
97
+ expression: 'Optional[Parser.Symbol]'
98
+ seeking_parent: 'Optional[MutableSequence[Parser.Symbol]]'
99
+ errors: Optional[Sequence[Exception]]
100
+ steps: 'Optional[MutableSequence[Parser.Symbol]]'
101
+ slot: 'Optional[Parser.Symbol]'
102
+ next_function: 'Optional[Parser.Symbol]'
103
+ keep_singleton_array: bool
104
+ consarray: bool
105
+ level: int
106
+ focus: Optional[Any]
107
+ token: Optional[Any]
108
+ thunk: bool
109
+
110
+ # Procedure:
111
+ procedure: 'Optional[Parser.Symbol]'
112
+ arguments: 'Optional[MutableSequence[Parser.Symbol]]'
113
+ body: 'Optional[Parser.Symbol]'
114
+ predicate: 'Optional[MutableSequence[Parser.Symbol]]'
115
+ stages: 'Optional[MutableSequence[Parser.Symbol]]'
116
+ input: Optional[Any]
117
+ # environment: jsonata.Jsonata.Frame | None # creates circular ref
118
+ tuple: Optional[Any]
119
+ expr: Optional[Any]
120
+ group: 'Optional[Parser.Symbol]'
121
+ name: 'Optional[Parser.Symbol]'
122
+
123
+ # Infix attributes
124
+ lhs: 'Optional[Parser.Symbol]'
125
+ rhs: 'Optional[Parser.Symbol]'
126
+
127
+ # where rhs = list of Symbol pairs
128
+ lhs_object: 'Optional[Sequence[Sequence[Parser.Symbol]]]'
129
+ rhs_object: 'Optional[Sequence[Sequence[Parser.Symbol]]]'
130
+
131
+ # where rhs = list of Symbols
132
+ rhs_terms: 'Optional[Sequence[Parser.Symbol]]'
133
+ terms: 'Optional[Sequence[Parser.Symbol]]'
134
+
135
+ # Ternary operator:
136
+ condition: 'Optional[Parser.Symbol]'
137
+ then: 'Optional[Parser.Symbol]'
138
+ _else: 'Optional[Parser.Symbol]'
139
+
140
+ expressions: 'Optional[MutableSequence[Parser.Symbol]]'
141
+
142
+ # processAST error handling
143
+ error: 'Optional[jexception.JException]'
144
+ signature: 'Optional[Any]'
145
+
146
+ # Prefix attributes
147
+ pattern: 'Optional[Parser.Symbol]'
148
+ update: 'Optional[Parser.Symbol]'
149
+ delete: 'Optional[Parser.Symbol]'
150
+
151
+ # Ancestor attributes
152
+ label: Optional[str]
153
+ index: Optional[Any]
154
+ _jsonata_lambda: bool
155
+ ancestor: 'Optional[Parser.Symbol]'
156
+
157
+ def __init__(self, outer_instance, id=None, bp=0):
158
+ self._outer_instance = outer_instance
159
+
160
+ self.id = id
161
+ self.value = id
162
+ self.bp = bp
163
+ # use register(Symbol) ! Otherwise inheritance doesn't work
164
+ # Symbol s = symbolTable.get(id)
165
+ # //bp = bp != 0 ? bp : 0
166
+ # if (s != null) {
167
+ # if (bp >= s.lbp) {
168
+ # s.lbp = bp
169
+ # }
170
+ # } else {
171
+ # s = new Symbol()
172
+ # s.value = s.id = id
173
+ # s.lbp = bp
174
+ # symbolTable.put(id, s)
175
+ # }
176
+ #
177
+ #
178
+ # return s
179
+
180
+ self.type = None
181
+ self.lbp = 0
182
+ self.position = 0
183
+ self.keep_array = False
184
+ self.descending = False
185
+ self.expression = None
186
+ self.seeking_parent = None
187
+ self.errors = None
188
+ self.steps = None
189
+ self.slot = None
190
+ self.next_function = None
191
+ self.keep_singleton_array = False
192
+ self.consarray = False
193
+ self.level = 0
194
+ self.focus = None
195
+ self.token = None
196
+ self.thunk = False
197
+ self.procedure = None
198
+ self.arguments = None
199
+ self.body = None
200
+ self.predicate = None
201
+ self.stages = None
202
+ self.input = None
203
+ self.environment = None
204
+ self.tuple = None
205
+ self.expr = None
206
+ self.group = None
207
+ self.name = None
208
+ self.lhs = None
209
+ self.rhs = None
210
+ self.lhs_object = None
211
+ self.rhs_object = None
212
+ self.rhs_terms = None
213
+ self.terms = None
214
+ self.condition = None
215
+ self.then = None
216
+ self._else = None
217
+ self.expressions = None
218
+ self.error = None
219
+ self.signature = None
220
+ self.pattern = None
221
+ self.update = None
222
+ self.delete = None
223
+ self.label = None
224
+ self.index = None
225
+ self._jsonata_lambda = False
226
+ self.ancestor = None
227
+
228
+ def create(self):
229
+ # We want a shallow clone (do not duplicate outer class!)
230
+ cl = self.clone()
231
+ # System.err.println("cloning "+this+" clone="+cl)
232
+ return cl
233
+
234
+ def clone(self):
235
+ return copy.copy(self)
236
+
237
+ def __repr__(self):
238
+ return str(type(self)) + " " + self.id + " value=" + self.value
239
+
240
+ def register(self, t: Symbol) -> None:
241
+
242
+ # if (t instanceof Infix || t instanceof InfixR) return
243
+
244
+ s = self.symbol_table.get(t.id)
245
+ if s is not None:
246
+ if self.dbg:
247
+ print("Symbol in table " + t.id + " " + str(type(s)) + " -> " + str(type(t)))
248
+ # symbolTable.put(t.id, t)
249
+ if t.bp >= s.lbp:
250
+ if self.dbg:
251
+ print("Symbol in table " + t.id + " lbp=" + str(s.lbp) + " -> " + str(t.bp))
252
+ s.lbp = t.bp
253
+ else:
254
+ s = t.create()
255
+ s.value = s.id = t.id
256
+ s.lbp = t.bp
257
+ self.symbol_table[t.id] = s
258
+
259
+ def handle_error(self, err: jexception.JException) -> Symbol:
260
+ if self.recover:
261
+ err.remaining = self.remaining_tokens()
262
+ self.errors.append(err)
263
+ # Symbol symbol = symbolTable.get("(error)")
264
+ node = Parser.Symbol(self)
265
+ # FIXME node.error = err
266
+ # node.type = "(error)"
267
+ return node
268
+ else:
269
+ raise err
270
+
271
+ # }
272
+
273
+ def advance(self, id: Optional[str] = None, infix: bool = False) -> Symbol:
274
+ if id is not None and self.node.id != id:
275
+ code = None
276
+ if self.node.id == "(end)":
277
+ # unexpected end of buffer
278
+ code = "S0203"
279
+ else:
280
+ code = "S0202"
281
+ err = jexception.JException(code, self.node.position, id, self.node.value)
282
+ return self.handle_error(err)
283
+ next_token = self.lexer.next(infix)
284
+ if self.dbg:
285
+ print("nextToken " + (next_token.type if next_token is not None else None))
286
+ if next_token is None:
287
+ self.node = self.symbol_table["(end)"]
288
+ self.node.position = len(self.source)
289
+ return self.node
290
+ value = next_token.value
291
+ type = next_token.type
292
+ symbol = None
293
+ if type == "name" or type == "variable":
294
+ symbol = self.symbol_table["(name)"]
295
+ elif type == "operator":
296
+ symbol = self.symbol_table[str(value)]
297
+ if symbol is None:
298
+ return self.handle_error(jexception.JException("S0204", next_token.position, value))
299
+ elif type == "string" or type == "number" or type == "value":
300
+ symbol = self.symbol_table["(literal)"]
301
+ elif type == "regex":
302
+ type = "regex"
303
+ symbol = self.symbol_table["(regex)"]
304
+ # istanbul ignore next
305
+ else:
306
+ return self.handle_error(jexception.JException("S0205", next_token.position, value))
307
+
308
+ self.node = symbol.create()
309
+ # Token node = new Token(); //Object.create(symbol)
310
+ self.node.value = value
311
+ self.node.type = type
312
+ self.node.position = next_token.position
313
+ if self.dbg:
314
+ print("advance " + str(self.node))
315
+ return self.node
316
+
317
+ # Pratt's algorithm
318
+ def expression(self, rbp: int) -> Symbol:
319
+ left = None
320
+ t = self.node
321
+ self.advance(None, True)
322
+ left = t.nud()
323
+ while rbp < self.node.lbp:
324
+ t = self.node
325
+ self.advance(None, False)
326
+ if self.dbg:
327
+ print("t=" + str(t) + ", left=" + left.type)
328
+ left = t.led(left)
329
+ return left
330
+
331
+ class Terminal(Symbol):
332
+ _outer_instance: 'Parser'
333
+
334
+ def __init__(self, outer_instance, id):
335
+ super().__init__(outer_instance, id, 0)
336
+ self._outer_instance = outer_instance
337
+
338
+ def nud(self):
339
+ return self
340
+
341
+ #
342
+ # var terminal = function (id) {
343
+ # var s = Parser.Symbol(id, 0)
344
+ # s.nud = function () {
345
+ # return this
346
+ # }
347
+ # }
348
+ #
349
+
350
+ # match infix operators
351
+ # <expression> <operator> <expression>
352
+ # left associative
353
+ class Infix(Symbol):
354
+ _outer_instance: 'Parser'
355
+
356
+ def __init__(self, outer_instance, id, bp=0):
357
+ super().__init__(outer_instance, id,
358
+ bp if bp != 0 else (tokenizer.Tokenizer.operators[id] if id is not None else 0))
359
+ self._outer_instance = outer_instance
360
+
361
+ def led(self, left):
362
+ self.lhs = left
363
+ self.rhs = self._outer_instance.expression(self.bp)
364
+ self.type = "binary"
365
+ return self
366
+
367
+ class InfixAndPrefix(Infix):
368
+ _outer_instance: 'Parser'
369
+ prefix: 'Parser.Prefix'
370
+
371
+ def __init__(self, outer_instance, id, bp=0):
372
+ super().__init__(outer_instance, id, bp)
373
+ self._outer_instance = outer_instance
374
+
375
+ self.prefix = Parser.Prefix(outer_instance, id)
376
+
377
+ def nud(self):
378
+ return self.prefix.nud()
379
+ # expression(70)
380
+ # type="unary"
381
+ # return this
382
+
383
+ def clone(self):
384
+ c = super().clone()
385
+ # IMPORTANT: make sure to allocate a new Prefix!!!
386
+ c.prefix = Parser.Prefix(self._outer_instance, c.id)
387
+ return c
388
+
389
+ # match infix operators
390
+ # <expression> <operator> <expression>
391
+ # right associative
392
+ class InfixR(Symbol):
393
+ _outer_instance: 'Parser'
394
+
395
+ def __init__(self, outer_instance, id, bp):
396
+ super().__init__(outer_instance, id, bp)
397
+ self._outer_instance = outer_instance
398
+
399
+ # abstract Object led()
400
+
401
+ # match prefix operators
402
+ # <operator> <expression>
403
+ class Prefix(Symbol):
404
+
405
+ # public List<Symbol[]> lhs
406
+
407
+ def __init__(self, outer_instance, id):
408
+ super().__init__(outer_instance, id)
409
+ self._outer_instance = outer_instance
410
+ # type = "unary"
411
+
412
+ # Symbol _expression
413
+
414
+ def nud(self):
415
+ self.expression = self._outer_instance.expression(70)
416
+ self.type = "unary"
417
+ return self
418
+
419
+ dbg: bool
420
+ source: Optional[str]
421
+ recover: bool
422
+ node: Optional[Symbol]
423
+ lexer: Optional[tokenizer.Tokenizer]
424
+ symbol_table: dict[str, Symbol]
425
+ errors: MutableSequence[Exception]
426
+ ancestor_label: int
427
+ ancestor_index: int
428
+ ancestry: MutableSequence[Symbol]
429
+
430
+ def __init__(self):
431
+ self.dbg = False
432
+ self.source = None
433
+ self.recover = False
434
+ self.node = None
435
+ self.lexer = None
436
+ self.symbol_table = {}
437
+ self.errors = []
438
+ self.ancestor_label = 0
439
+ self.ancestor_index = 0
440
+ self.ancestry = []
441
+
442
+ self.register(Parser.Terminal(self, "(end)"))
443
+ self.register(Parser.Terminal(self, "(name)"))
444
+ self.register(Parser.Terminal(self, "(literal)"))
445
+ self.register(Parser.Terminal(self, "(regex)"))
446
+ self.register(Parser.Symbol(self, ":"))
447
+ self.register(Parser.Symbol(self, ";"))
448
+ self.register(Parser.Symbol(self, ","))
449
+ self.register(Parser.Symbol(self, ")"))
450
+ self.register(Parser.Symbol(self, "]"))
451
+ self.register(Parser.Symbol(self, "}"))
452
+ self.register(Parser.Symbol(self, "..")) # range operator
453
+ self.register(Parser.Infix(self, ".")) # map operator
454
+ self.register(Parser.Infix(self, "+")) # numeric addition
455
+ self.register(Parser.InfixAndPrefix(self, "-")) # numeric subtraction
456
+ # unary numeric negation
457
+
458
+ self.register(Parser.InfixFieldWildcard(self))
459
+ # numeric multiplication
460
+ self.register(Parser.Infix(self, "/")) # numeric division
461
+ self.register(Parser.InfixParentOperator(self))
462
+ # numeric modulus
463
+ self.register(Parser.Infix(self, "=")) # equality
464
+ self.register(Parser.Infix(self, "<")) # less than
465
+ self.register(Parser.Infix(self, ">")) # greater than
466
+ self.register(Parser.Infix(self, "!=")) # not equal to
467
+ self.register(Parser.Infix(self, "<=")) # less than or equal
468
+ self.register(Parser.Infix(self, ">=")) # greater than or equal
469
+ self.register(Parser.Infix(self, "&")) # string concatenation
470
+
471
+ self.register(Parser.InfixAnd(self))
472
+ # Boolean AND
473
+ self.register(Parser.InfixOr(self))
474
+ # Boolean OR
475
+ self.register(Parser.InfixIn(self))
476
+ # is member of array
477
+ # merged Infix: register(new Terminal("and")); // the 'keywords' can also be used as terminals (field names)
478
+ # merged Infix: register(new Terminal("or")); //
479
+ # merged Infix: register(new Terminal("in")); //
480
+ # merged Infix: register(new Prefix("-")); // unary numeric negation
481
+ self.register(Parser.Infix(self, "~>")) # function application
482
+
483
+ self.register(Parser.InfixRError(self))
484
+
485
+ # field wildcard (single level)
486
+ # merged with Infix *
487
+ # register(new Prefix("*") {
488
+ # @Override Symbol nud() {
489
+ # type = "wildcard"
490
+ # return this
491
+ # }
492
+ # })
493
+
494
+ # descendant wildcard (multi-level)
495
+
496
+ self.register(Parser.PrefixDescendantWildcard(self))
497
+
498
+ # parent operator
499
+ # merged with Infix %
500
+ # register(new Prefix("%") {
501
+ # @Override Symbol nud() {
502
+ # type = "parent"
503
+ # return this
504
+ # }
505
+ # })
506
+
507
+ # function invocation
508
+ self.register(Parser.InfixFunctionInvocation(self, tokenizer.Tokenizer.operators["("]))
509
+
510
+ # array constructor
511
+
512
+ # merged: register(new Prefix("[") {
513
+ self.register(Parser.InfixArrayConstructor(self, tokenizer.Tokenizer.operators["["]))
514
+
515
+ # order-by
516
+ self.register(Parser.InfixOrderBy(self, tokenizer.Tokenizer.operators["^"]))
517
+
518
+ self.register(Parser.InfixObjectConstructor(self, tokenizer.Tokenizer.operators["{"]))
519
+
520
+ # bind variable
521
+ self.register(Parser.InfixRBindVariable(self, tokenizer.Tokenizer.operators[":="]))
522
+
523
+ # focus variable bind
524
+ self.register(Parser.InfixFocusVariableBind(self, tokenizer.Tokenizer.operators["@"]))
525
+
526
+ # index (position) variable bind
527
+ self.register(Parser.InfixIndexVariableBind(self, tokenizer.Tokenizer.operators["#"]))
528
+
529
+ # if/then/else ternary operator ?:
530
+ self.register(Parser.InfixTernaryOperator(self, tokenizer.Tokenizer.operators["?"]))
531
+
532
+ # object transformer
533
+ self.register(Parser.PrefixObjectTransformer(self))
534
+
535
+ class InfixFieldWildcard(Infix):
536
+ _outer_instance: 'Parser'
537
+
538
+ def __init__(self, outer_instance):
539
+ super().__init__(outer_instance, "*")
540
+ self._outer_instance = outer_instance
541
+
542
+ # field wildcard (single level)
543
+ def nud(self):
544
+ self.type = "wildcard"
545
+ return self
546
+
547
+ class InfixParentOperator(Infix):
548
+ _outer_instance: 'Parser'
549
+
550
+ def __init__(self, outer_instance):
551
+ super().__init__(outer_instance, "%")
552
+ self._outer_instance = outer_instance
553
+
554
+ # parent operator
555
+ def nud(self):
556
+ self.type = "parent"
557
+ return self
558
+
559
+ class InfixAnd(Infix):
560
+ _outer_instance: 'Parser'
561
+
562
+ def __init__(self, outer_instance):
563
+ super().__init__(outer_instance, "and")
564
+ self._outer_instance = outer_instance
565
+
566
+ # allow as terminal
567
+ def nud(self):
568
+ return self
569
+
570
+ class InfixOr(Infix):
571
+ _outer_instance: 'Parser'
572
+
573
+ def __init__(self, outer_instance):
574
+ super().__init__(outer_instance, "or")
575
+ self._outer_instance = outer_instance
576
+
577
+ # allow as terminal
578
+ def nud(self):
579
+ return self
580
+
581
+ class InfixIn(Infix):
582
+ _outer_instance: 'Parser'
583
+
584
+ def __init__(self, outer_instance):
585
+ super().__init__(outer_instance, "in")
586
+ self._outer_instance = outer_instance
587
+
588
+ # allow as terminal
589
+ def nud(self):
590
+ return self
591
+
592
+ class InfixRError(Infix):
593
+ _outer_instance: 'Parser'
594
+
595
+ def __init__(self, outer_instance):
596
+ super().__init__(outer_instance, "(error)", 10)
597
+ self._outer_instance = outer_instance
598
+
599
+ def led(self, left):
600
+ raise NotImplementedError("TODO", None)
601
+
602
+ class PrefixDescendantWildcard(Prefix):
603
+ _outer_instance: 'Parser'
604
+
605
+ def __init__(self, outer_instance):
606
+ super().__init__(outer_instance, "**")
607
+ self._outer_instance = outer_instance
608
+
609
+ def nud(self):
610
+ self.type = "descendant"
611
+ return self
612
+
613
+ class InfixFunctionInvocation(Infix):
614
+ _outer_instance: 'Parser'
615
+
616
+ def __init__(self, outer_instance, get):
617
+ super().__init__(outer_instance, "(", get)
618
+ self._outer_instance = outer_instance
619
+
620
+ def led(self, left):
621
+ # left is is what we are trying to invoke
622
+ self.procedure = left
623
+ self.type = "function"
624
+ self.arguments = []
625
+ if self._outer_instance.node.id != ")":
626
+ while True:
627
+ if "operator" == self._outer_instance.node.type and self._outer_instance.node.id == "?":
628
+ # partial function application
629
+ self.type = "partial"
630
+ self.arguments.append(self._outer_instance.node)
631
+ self._outer_instance.advance("?")
632
+ else:
633
+ self.arguments.append(self._outer_instance.expression(0))
634
+ if self._outer_instance.node.id != ",":
635
+ break
636
+ self._outer_instance.advance(",")
637
+ self._outer_instance.advance(")", True)
638
+ # if the name of the function is 'function' or λ, then this is function definition (lambda function)
639
+ if left.type == "name" and (left.value == "function" or left.value == "\u03BB"):
640
+ # all of the args must be VARIABLE tokens
641
+ # int index = 0
642
+ for arg in self.arguments:
643
+ # this.arguments.forEach(function (arg, index) {
644
+ if arg.type != "variable":
645
+ return self._outer_instance.handle_error(
646
+ jexception.JException("S0208", arg.position, arg.value))
647
+ # index++
648
+ self.type = "lambda"
649
+ # is the next token a '<' - if so, parse the function signature
650
+ if self._outer_instance.node.id == "<":
651
+ depth = 1
652
+ sig = "<"
653
+ while depth > 0 and self._outer_instance.node.id != "{" and self._outer_instance.node.id != "(end)":
654
+ tok = self._outer_instance.advance()
655
+ if tok.id == ">":
656
+ depth -= 1
657
+ elif tok.id == "<":
658
+ depth += 1
659
+ sig += tok.value
660
+ self._outer_instance.advance(">")
661
+ self.signature = signature.Signature(sig, "lambda")
662
+ # parse the function body
663
+ self._outer_instance.advance("{")
664
+ self.body = self._outer_instance.expression(0)
665
+ self._outer_instance.advance("}")
666
+ return self
667
+
668
+ # })
669
+
670
+ # parenthesis - block expression
671
+ # Note: in Java both nud and led are in same class!
672
+ # register(new Prefix("(") {
673
+
674
+ def nud(self):
675
+ if self._outer_instance.dbg:
676
+ print("Prefix (")
677
+ expressions = []
678
+ while self._outer_instance.node.id != ")":
679
+ expressions.append(self._outer_instance.expression(0))
680
+ if self._outer_instance.node.id != ";":
681
+ break
682
+ self._outer_instance.advance(";")
683
+ self._outer_instance.advance(")", True)
684
+ self.type = "block"
685
+ self.expressions = expressions
686
+ return self
687
+
688
+ class InfixArrayConstructor(Infix):
689
+ _outer_instance: 'Parser'
690
+
691
+ def __init__(self, outer_instance, get):
692
+ super().__init__(outer_instance, "[", get)
693
+ self._outer_instance = outer_instance
694
+
695
+ def nud(self):
696
+ a = []
697
+ if self._outer_instance.node.id != "]":
698
+ while True:
699
+ item = self._outer_instance.expression(0)
700
+ if self._outer_instance.node.id == "..":
701
+ # range operator
702
+ range = Parser.Symbol(self._outer_instance)
703
+ range.type = "binary"
704
+ range.value = ".."
705
+ range.position = self._outer_instance.node.position
706
+ range.lhs = item
707
+ self._outer_instance.advance("..")
708
+ range.rhs = self._outer_instance.expression(0)
709
+ item = range
710
+ a.append(item)
711
+ if self._outer_instance.node.id != ",":
712
+ break
713
+ self._outer_instance.advance(",")
714
+ self._outer_instance.advance("]", True)
715
+ self.expressions = a
716
+ self.type = "unary"
717
+ return self
718
+
719
+ # })
720
+
721
+ # filter - predicate or array index
722
+ # register(new Infix("[", tokenizer.Tokenizer.operators.get("[")) {
723
+
724
+ def led(self, left):
725
+ if self._outer_instance.node.id == "]":
726
+ # empty predicate means maintain singleton arrays in the output
727
+ step = left
728
+ while step is not None and step.type == "binary" and step.value == "[":
729
+ step = step.lhs
730
+ step.keep_array = True
731
+ self._outer_instance.advance("]")
732
+ return left
733
+ else:
734
+ self.lhs = left
735
+ self.rhs = self._outer_instance.expression(tokenizer.Tokenizer.operators["]"])
736
+ self.type = "binary"
737
+ self._outer_instance.advance("]", True)
738
+ return self
739
+
740
+ class InfixOrderBy(Infix):
741
+ _outer_instance: 'Parser'
742
+
743
+ def __init__(self, outer_instance, get):
744
+ super().__init__(outer_instance, "^", get)
745
+ self._outer_instance = outer_instance
746
+
747
+ def led(self, left):
748
+ self._outer_instance.advance("(")
749
+ terms = []
750
+ while True:
751
+ term = Parser.Symbol(self._outer_instance)
752
+ term.descending = False
753
+
754
+ if self._outer_instance.node.id == "<":
755
+ # ascending sort
756
+ self._outer_instance.advance("<")
757
+ elif self._outer_instance.node.id == ">":
758
+ # descending sort
759
+ term.descending = True
760
+ self._outer_instance.advance(">")
761
+ else:
762
+ # unspecified - default to ascending
763
+ pass
764
+ term.expression = self._outer_instance.expression(0)
765
+ terms.append(term)
766
+ if self._outer_instance.node.id != ",":
767
+ break
768
+ self._outer_instance.advance(",")
769
+ self._outer_instance.advance(")")
770
+ self.lhs = left
771
+ self.rhs_terms = terms
772
+ self.type = "binary"
773
+ return self
774
+
775
+ class InfixObjectConstructor(Infix):
776
+ _outer_instance: 'Parser'
777
+
778
+ def __init__(self, outer_instance, get):
779
+ super().__init__(outer_instance, "{", get)
780
+ self._outer_instance = outer_instance
781
+
782
+ # merged register(new Prefix("{") {
783
+
784
+ def nud(self):
785
+ return self._outer_instance.object_parser(None)
786
+
787
+ # })
788
+
789
+ # register(new Infix("{", tokenizer.Tokenizer.operators.get("{")) {
790
+
791
+ def led(self, left):
792
+ return self._outer_instance.object_parser(left)
793
+
794
+ class InfixRBindVariable(InfixR):
795
+ _outer_instance: 'Parser'
796
+
797
+ def __init__(self, outer_instance, get):
798
+ super().__init__(outer_instance, ":=", get)
799
+ self._outer_instance = outer_instance
800
+
801
+ def led(self, left):
802
+ if left.type != "variable":
803
+ return self._outer_instance.handle_error(jexception.JException("S0212", left.position, left.value))
804
+ self.lhs = left
805
+ self.rhs = self._outer_instance.expression(
806
+ tokenizer.Tokenizer.operators[":="] - 1) # subtract 1 from bindingPower for right associative operators
807
+ self.type = "binary"
808
+ return self
809
+
810
+ class InfixFocusVariableBind(Infix):
811
+ _outer_instance: 'Parser'
812
+
813
+ def __init__(self, outer_instance, get):
814
+ super().__init__(outer_instance, "@", get)
815
+ self._outer_instance = outer_instance
816
+
817
+ def led(self, left):
818
+ self.lhs = left
819
+ self.rhs = self._outer_instance.expression(tokenizer.Tokenizer.operators["@"])
820
+ if self.rhs.type != "variable":
821
+ return self._outer_instance.handle_error(jexception.JException("S0214", self.rhs.position, "@"))
822
+ self.type = "binary"
823
+ return self
824
+
825
+ class InfixIndexVariableBind(Infix):
826
+ _outer_instance: 'Parser'
827
+
828
+ def __init__(self, outer_instance, get):
829
+ super().__init__(outer_instance, "#", get)
830
+ self._outer_instance = outer_instance
831
+
832
+ def led(self, left):
833
+ self.lhs = left
834
+ self.rhs = self._outer_instance.expression(tokenizer.Tokenizer.operators["#"])
835
+ if self.rhs.type != "variable":
836
+ return self._outer_instance.handle_error(jexception.JException("S0214", self.rhs.position, "#"))
837
+ self.type = "binary"
838
+ return self
839
+
840
+ class InfixTernaryOperator(Infix):
841
+ _outer_instance: 'Parser'
842
+
843
+ def __init__(self, outer_instance, get):
844
+ super().__init__(outer_instance, "?", get)
845
+ self._outer_instance = outer_instance
846
+
847
+ def led(self, left):
848
+ self.type = "condition"
849
+ self.condition = left
850
+ self.then = self._outer_instance.expression(0)
851
+ if self._outer_instance.node.id == ":":
852
+ # else condition
853
+ self._outer_instance.advance(":")
854
+ self._else = self._outer_instance.expression(0)
855
+ return self
856
+
857
+ class PrefixObjectTransformer(Prefix):
858
+ _outer_instance: 'Parser'
859
+
860
+ def __init__(self, outer_instance):
861
+ super().__init__(outer_instance, "|")
862
+ self._outer_instance = outer_instance
863
+
864
+ def nud(self):
865
+ self.type = "transform"
866
+ self.pattern = self._outer_instance.expression(0)
867
+ self._outer_instance.advance("|")
868
+ self.update = self._outer_instance.expression(0)
869
+ if self._outer_instance.node.id == ",":
870
+ self._outer_instance.advance(",")
871
+ self.delete = self._outer_instance.expression(0)
872
+ self._outer_instance.advance("|")
873
+ return self
874
+
875
+ # tail call optimization
876
+ # this is invoked by the post parser to analyse lambda functions to see
877
+ # if they make a tail call. If so, it is replaced by a thunk which will
878
+ # be invoked by the trampoline loop during function application.
879
+ # This enables tail-recursive functions to be written without growing the stack
880
+ def tail_call_optimize(self, expr: Symbol) -> Symbol:
881
+ result = None
882
+ if expr.type == "function" and expr.predicate is None:
883
+ thunk = Parser.Symbol(self)
884
+ thunk.type = "lambda"
885
+ thunk.thunk = True
886
+ thunk.arguments = []
887
+ thunk.position = expr.position
888
+ thunk.body = expr
889
+ result = thunk
890
+ elif expr.type == "condition":
891
+ # analyse both branches
892
+ expr.then = self.tail_call_optimize(expr.then)
893
+ if expr._else is not None:
894
+ expr._else = self.tail_call_optimize(expr._else)
895
+ result = expr
896
+ elif expr.type == "block":
897
+ # only the last expression in the block
898
+ length = len(expr.expressions)
899
+ if length > 0:
900
+ if not (isinstance(expr.expressions, list)):
901
+ expr.expressions = [expr.expressions]
902
+ expr.expressions[length - 1] = self.tail_call_optimize(expr.expressions[length - 1])
903
+ result = expr
904
+ else:
905
+ result = expr
906
+ return result
907
+
908
+ def seek_parent(self, node: Symbol, slot: Symbol) -> Symbol:
909
+ if node.type == "name" or node.type == "wildcard":
910
+ slot.level -= 1
911
+ if slot.level == 0:
912
+ if node.ancestor is None:
913
+ node.ancestor = slot
914
+ else:
915
+ # reuse the existing label
916
+ self.ancestry[int(slot.index)].slot.label = node.ancestor.label
917
+ node.ancestor = slot
918
+ node.tuple = True
919
+ elif node.type == "parent":
920
+ slot.level += 1
921
+ elif node.type == "block":
922
+ # look in last expression in the block
923
+ if len(node.expressions) > 0:
924
+ node.tuple = True
925
+ slot = self.seek_parent(node.expressions[-1], slot)
926
+ elif node.type == "path":
927
+ # last step in path
928
+ node.tuple = True
929
+ index = len(node.steps) - 1
930
+ slot = self.seek_parent(node.steps[index], slot)
931
+ index -= 1
932
+ while slot.level > 0 and index >= 0:
933
+ # check previous steps
934
+ slot = self.seek_parent(node.steps[index], slot)
935
+ index -= 1
936
+ else:
937
+ # error - can't derive ancestor
938
+ raise jexception.JException("S0217", node.position, node.type)
939
+ return slot
940
+
941
+ def push_ancestry(self, result: Symbol, value: Optional[Symbol]) -> None:
942
+ if value is None:
943
+ return # Added NPE check
944
+ if value.seeking_parent is not None or value.type == "parent":
945
+ slots = value.seeking_parent if (value.seeking_parent is not None) else []
946
+ if value.type == "parent":
947
+ slots.append(value.slot)
948
+ if result.seeking_parent is None:
949
+ result.seeking_parent = slots
950
+ else:
951
+ result.seeking_parent.extend(slots)
952
+
953
+ def resolve_ancestry(self, path: Symbol) -> None:
954
+ index = len(path.steps) - 1
955
+ laststep = path.steps[index]
956
+ slots = laststep.seeking_parent if (laststep.seeking_parent is not None) else []
957
+ if laststep.type == "parent":
958
+ slots.append(laststep.slot)
959
+ for _, slot in enumerate(slots):
960
+ index = len(path.steps) - 2
961
+ while slot.level > 0:
962
+ if index < 0:
963
+ if path.seeking_parent is None:
964
+ path.seeking_parent = [slot]
965
+ else:
966
+ path.seeking_parent.append(slot)
967
+ break
968
+ # try previous step
969
+ step = path.steps[index]
970
+ index -= 1
971
+ # multiple contiguous steps that bind the focus should be skipped
972
+ while index >= 0 and step.focus is not None and path.steps[index].focus is not None:
973
+ step = path.steps[index]
974
+ index -= 1
975
+ slot = self.seek_parent(step, slot)
976
+
977
+ # post-parse stage
978
+ # the purpose of this is to add as much semantic value to the parse tree as possible
979
+ # in order to simplify the work of the evaluator.
980
+ # This includes flattening the parts of the AST representing location paths,
981
+ # converting them to arrays of steps which in turn may contain arrays of predicates.
982
+ # following this, nodes containing '.' and '[' should be eliminated from the AST.
983
+ def process_ast(self, expr: Optional[Symbol]) -> Optional[Symbol]:
984
+ result = expr
985
+ if expr is None:
986
+ return None
987
+ if self.dbg:
988
+ print(" > processAST type=" + expr.type + " value='" + expr.value + "'")
989
+ type = expr.type if expr.type is not None else "(null)"
990
+ if type == "binary":
991
+ value = str(expr.value)
992
+ if value == ".":
993
+ lstep = self.process_ast(expr.lhs)
994
+
995
+ if lstep.type == "path":
996
+ result = lstep
997
+ else:
998
+ result = Parser.Infix(self, None)
999
+ result.type = "path"
1000
+ result.steps = [lstep]
1001
+ # result = {type: 'path', steps: [lstep]}
1002
+ if lstep.type == "parent":
1003
+ result.seeking_parent = [lstep.slot]
1004
+ rest = self.process_ast(expr.rhs)
1005
+ if (rest.type == "function" and rest.procedure.type == "path" and len(
1006
+ rest.procedure.steps) == 1 and rest.procedure.steps[0].type == "name" and
1007
+ result.steps[-1].type == "function"):
1008
+ # next function in chain of functions - will override a thenable
1009
+ result.steps[-1].next_function = rest.procedure.steps[0].value
1010
+ if rest.type == "path":
1011
+ result.steps.extend(rest.steps)
1012
+ else:
1013
+ if rest.predicate is not None:
1014
+ rest.stages = rest.predicate
1015
+ rest.predicate = None
1016
+ # delete rest.predicate
1017
+ result.steps.append(rest)
1018
+ # any steps within a path that are string literals, should be changed to 'name'
1019
+ for step in result.steps:
1020
+ if step.type == "number" or step.type == "value":
1021
+ # don't allow steps to be numbers or the values true/false/null
1022
+ raise jexception.JException("S0213", step.position, step.value)
1023
+ # System.out.println("step "+step+" type="+step.type)
1024
+ if step.type == "string":
1025
+ step.type = "name"
1026
+ # for (var lit : step.steps) {
1027
+ # System.out.println("step2 "+lit+" type="+lit.type)
1028
+ # lit.type = "name"
1029
+ # }
1030
+
1031
+ # any step that signals keeping a singleton array, should be flagged on the path
1032
+ if len(list(filter(lambda step: step.keep_array, result.steps))) > 0:
1033
+ result.keep_singleton_array = True
1034
+ # if first step is a path constructor, flag it for special handling
1035
+ firststep = result.steps[0]
1036
+ if firststep.type == "unary" and str(firststep.value) == "[":
1037
+ firststep.consarray = True
1038
+ # if the last step is an array constructor, flag it so it doesn't flatten
1039
+ laststep = result.steps[-1]
1040
+ if laststep.type == "unary" and str(laststep.value) == "[":
1041
+ laststep.consarray = True
1042
+ self.resolve_ancestry(result)
1043
+ elif value == "[":
1044
+ if self.dbg:
1045
+ print("binary [")
1046
+ # predicated step
1047
+ # LHS is a step or a predicated step
1048
+ # RHS is the predicate expr
1049
+ result = self.process_ast(expr.lhs)
1050
+ step = result
1051
+ type = "predicate"
1052
+ if result.type == "path":
1053
+ step = result.steps[-1]
1054
+ type = "stages"
1055
+ if step.group is not None:
1056
+ raise jexception.JException("S0209", expr.position)
1057
+ # if (typeof step[type] === 'undefined') {
1058
+ # step[type] = []
1059
+ # }
1060
+ if type == "stages":
1061
+ if step.stages is None:
1062
+ step.stages = []
1063
+ else:
1064
+ if step.predicate is None:
1065
+ step.predicate = []
1066
+
1067
+ predicate = self.process_ast(expr.rhs)
1068
+ if predicate.seeking_parent is not None:
1069
+ _step = step
1070
+ for slot in predicate.seeking_parent:
1071
+ if slot.level == 1:
1072
+ self.seek_parent(_step, slot)
1073
+ else:
1074
+ slot.level -= 1
1075
+ self.push_ancestry(step, predicate)
1076
+ s = Parser.Symbol(self)
1077
+ s.type = "filter"
1078
+ s.expr = predicate
1079
+ s.position = expr.position
1080
+
1081
+ # FIXED:
1082
+ # this logic is required in Java to fix
1083
+ # for example test: flattening case 045
1084
+ # otherwise we lose the keepArray flag
1085
+ if expr.keep_array:
1086
+ step.keep_array = True
1087
+
1088
+ if type == "stages":
1089
+ step.stages.append(s)
1090
+ else:
1091
+ step.predicate.append(s)
1092
+ # step[type].push({type: 'filter', expr: predicate, position: expr.position})
1093
+ elif value == "{":
1094
+ # group-by
1095
+ # LHS is a step or a predicated step
1096
+ # RHS is the object constructor expr
1097
+ result = self.process_ast(expr.lhs)
1098
+ if result.group is not None:
1099
+ raise jexception.JException("S0210", expr.position)
1100
+ # object constructor - process each pair
1101
+ result.group = Parser.Symbol(self)
1102
+ result.group.lhs_object = list(
1103
+ map(lambda pair: [self.process_ast(pair[0]), self.process_ast(pair[1])], expr.rhs_object))
1104
+ result.group.position = expr.position
1105
+
1106
+ elif value == "^":
1107
+ # order-by
1108
+ # LHS is the array to be ordered
1109
+ # RHS defines the terms
1110
+ result = self.process_ast(expr.lhs)
1111
+ if result.type != "path":
1112
+ _res = Parser.Symbol(self)
1113
+ _res.type = "path"
1114
+ _res.steps = []
1115
+ _res.steps.append(result)
1116
+ result = _res
1117
+ sort_step = Parser.Symbol(self)
1118
+ sort_step.type = "sort"
1119
+ sort_step.position = expr.position
1120
+
1121
+ def lambda1(terms):
1122
+ expression = self.process_ast(terms.expression)
1123
+ self.push_ancestry(sort_step, expression)
1124
+ res = Parser.Symbol(self)
1125
+ res.descending = terms.descending
1126
+ res.expression = expression
1127
+ return res
1128
+
1129
+ sort_step.terms = list(map(lambda1, expr.rhs_terms))
1130
+ result.steps.append(sort_step)
1131
+ self.resolve_ancestry(result)
1132
+ elif value == ":=":
1133
+ result = Parser.Symbol(self)
1134
+ result.type = "bind"
1135
+ result.value = expr.value
1136
+ result.position = expr.position
1137
+ result.lhs = self.process_ast(expr.lhs)
1138
+ result.rhs = self.process_ast(expr.rhs)
1139
+ self.push_ancestry(result, result.rhs)
1140
+ elif value == "@":
1141
+ result = self.process_ast(expr.lhs)
1142
+ step = result
1143
+ if result.type == "path":
1144
+ step = result.steps[-1]
1145
+ # throw error if there are any predicates defined at this point
1146
+ # at this point the only type of stages can be predicates
1147
+ if step.stages is not None or step.predicate is not None:
1148
+ raise jexception.JException("S0215", expr.position)
1149
+ # also throw if this is applied after an 'order-by' clause
1150
+ if step.type == "sort":
1151
+ raise jexception.JException("S0216", expr.position)
1152
+ if expr.keep_array:
1153
+ step.keep_array = True
1154
+ step.focus = expr.rhs.value
1155
+ step.tuple = True
1156
+ elif value == "#":
1157
+ result = self.process_ast(expr.lhs)
1158
+ step = result
1159
+ if result.type == "path":
1160
+ step = result.steps[-1]
1161
+ else:
1162
+ _res = Parser.Symbol(self)
1163
+ _res.type = "path"
1164
+ _res.steps = []
1165
+ _res.steps.append(result)
1166
+ result = _res
1167
+ if step.predicate is not None:
1168
+ step.stages = step.predicate
1169
+ step.predicate = None
1170
+ if step.stages is None:
1171
+ step.index = expr.rhs.value # name of index variable = String
1172
+ else:
1173
+ _res = Parser.Symbol(self)
1174
+ _res.type = "index"
1175
+ _res.value = expr.rhs.value
1176
+ _res.position = expr.position
1177
+ step.stages.append(_res)
1178
+ step.tuple = True
1179
+ elif value == "~>":
1180
+ result = Parser.Symbol(self)
1181
+ result.type = "apply"
1182
+ result.value = expr.value
1183
+ result.position = expr.position
1184
+ result.lhs = self.process_ast(expr.lhs)
1185
+ result.rhs = self.process_ast(expr.rhs)
1186
+ else:
1187
+ _result = Parser.Infix(self, None)
1188
+ _result.type = expr.type
1189
+ _result.value = expr.value
1190
+ _result.position = expr.position
1191
+ _result.lhs = self.process_ast(expr.lhs)
1192
+ _result.rhs = self.process_ast(expr.rhs)
1193
+ self.push_ancestry(_result, _result.lhs)
1194
+ self.push_ancestry(_result, _result.rhs)
1195
+ result = _result
1196
+
1197
+ elif type == "unary":
1198
+ result = Parser.Symbol(self)
1199
+ result.type = expr.type
1200
+ result.value = expr.value
1201
+ result.position = expr.position
1202
+ # expr.value might be Character!
1203
+ expr_value = str(expr.value)
1204
+ if expr_value == "[":
1205
+ if self.dbg:
1206
+ print("unary [ " + str(result))
1207
+
1208
+ # array constructor - process each item
1209
+ def lambda2(item):
1210
+ value = self.process_ast(item)
1211
+ self.push_ancestry(result, value)
1212
+ return value
1213
+
1214
+ result.expressions = list(map(lambda2, expr.expressions))
1215
+ elif expr_value == "{":
1216
+ # object constructor - process each pair
1217
+ # throw new Error("processAST {} unimpl")
1218
+ def lambda3(pair):
1219
+ key = self.process_ast(pair[0])
1220
+ self.push_ancestry(result, key)
1221
+ value = self.process_ast(pair[1])
1222
+ self.push_ancestry(result, value)
1223
+ return [key, value]
1224
+
1225
+ result.lhs_object = list(map(lambda3, expr.lhs_object))
1226
+ else:
1227
+ # all other unary expressions - just process the expression
1228
+ result.expression = self.process_ast(expr.expression)
1229
+ # if unary minus on a number, then pre-process
1230
+ if expr_value == "-" and result.expression.type == "number":
1231
+ result = result.expression
1232
+ result.value = utils.Utils.convert_number(-float(result.value))
1233
+ if self.dbg:
1234
+ print("unary - value=" + str(result.value))
1235
+ else:
1236
+ self.push_ancestry(result, result.expression)
1237
+
1238
+ elif type == "function" or type == "partial":
1239
+ result = Parser.Symbol(self)
1240
+ result.type = expr.type
1241
+ result.name = expr.name
1242
+ result.value = expr.value
1243
+ result.position = expr.position
1244
+
1245
+ def lambda4(arg):
1246
+ arg_ast = self.process_ast(arg)
1247
+ self.push_ancestry(result, arg_ast)
1248
+ return arg_ast
1249
+
1250
+ result.arguments = list(map(lambda4, expr.arguments))
1251
+ result.procedure = self.process_ast(expr.procedure)
1252
+ elif type == "lambda":
1253
+ result = Parser.Symbol(self)
1254
+ result.type = expr.type
1255
+ result.arguments = expr.arguments
1256
+ result.signature = expr.signature
1257
+ result.position = expr.position
1258
+ body = self.process_ast(expr.body)
1259
+ result.body = self.tail_call_optimize(body)
1260
+ elif type == "condition":
1261
+ result = Parser.Symbol(self)
1262
+ result.type = expr.type
1263
+ result.position = expr.position
1264
+ result.condition = self.process_ast(expr.condition)
1265
+ self.push_ancestry(result, result.condition)
1266
+ result.then = self.process_ast(expr.then)
1267
+ self.push_ancestry(result, result.then)
1268
+ if expr._else is not None:
1269
+ result._else = self.process_ast(expr._else)
1270
+ self.push_ancestry(result, result._else)
1271
+ elif type == "transform":
1272
+ result = Parser.Symbol(self)
1273
+ result.type = expr.type
1274
+ result.position = expr.position
1275
+ result.pattern = self.process_ast(expr.pattern)
1276
+ result.update = self.process_ast(expr.update)
1277
+ if expr.delete is not None:
1278
+ result.delete = self.process_ast(expr.delete)
1279
+ elif type == "block":
1280
+ result = Parser.Symbol(self)
1281
+ result.type = expr.type
1282
+ result.position = expr.position
1283
+
1284
+ # array of expressions - process each one
1285
+ def lambda5(item):
1286
+ part = self.process_ast(item)
1287
+ self.push_ancestry(result, part)
1288
+ if part.consarray or (part.type == "path" and part.steps[0].consarray):
1289
+ result.consarray = True
1290
+ return part
1291
+
1292
+ result.expressions = list(map(lambda5, expr.expressions))
1293
+ # TODO scan the array of expressions to see if any of them assign variables
1294
+ # if so, need to mark the block as one that needs to create a new frame
1295
+ elif type == "name":
1296
+ result = Parser.Symbol(self)
1297
+ result.type = "path"
1298
+ result.steps = []
1299
+ result.steps.append(expr)
1300
+ if expr.keep_array:
1301
+ result.keep_singleton_array = True
1302
+ elif type == "parent":
1303
+ result = Parser.Symbol(self)
1304
+ result.type = "parent"
1305
+ result.slot = Parser.Symbol(self)
1306
+ result.slot.label = "!" + str(self.ancestor_label)
1307
+ self.ancestor_label += 1
1308
+ result.slot.level = 1
1309
+ result.slot.index = self.ancestor_index
1310
+ self.ancestor_index += 1
1311
+ # slot: { label: '!' + ancestorLabel++, level: 1, index: ancestorIndex++ } }
1312
+ self.ancestry.append(result)
1313
+ elif (type == "string" or type == "number" or type == "value" or type == "wildcard" or type == "descendant" or
1314
+ type == "variable" or type == "regex"):
1315
+ result = expr
1316
+ elif type == "operator":
1317
+ # the tokens 'and' and 'or' might have been used as a name rather than an operator
1318
+ if expr.value == "and" or expr.value == "or" or expr.value == "in":
1319
+ expr.type = "name"
1320
+ result = self.process_ast(expr)
1321
+ elif str(expr.value) == "?":
1322
+ # partial application
1323
+ result = expr
1324
+ else:
1325
+ raise jexception.JException("S0201", expr.position, expr.value)
1326
+ elif type == "error":
1327
+ result = expr
1328
+ if expr.lhs is not None:
1329
+ result = self.process_ast(expr.lhs)
1330
+ else:
1331
+ code = "S0206"
1332
+ # istanbul ignore else
1333
+ if expr.id == "(end)":
1334
+ code = "S0207"
1335
+ err = jexception.JException(code, expr.position, expr.value)
1336
+ if self.recover:
1337
+ self.errors.append(err)
1338
+ ret = Parser.Symbol(self)
1339
+ ret.type = "error"
1340
+ ret.error = err
1341
+ return ret
1342
+ else:
1343
+ # err.stack = (new Error()).stack
1344
+ raise err
1345
+ if expr.keep_array:
1346
+ result.keep_array = True
1347
+ return result
1348
+
1349
+ def object_parser(self, left: Optional[Symbol]) -> Symbol:
1350
+
1351
+ res = Parser.Infix(self, "{") if left is not None else Parser.Prefix(self, "{")
1352
+
1353
+ a = []
1354
+ if self.node.id != "}":
1355
+ while True:
1356
+ n = self.expression(0)
1357
+ self.advance(":")
1358
+ v = self.expression(0)
1359
+ pair = [n, v]
1360
+ a.append(pair) # holds an array of name/value expression pairs
1361
+ if self.node.id != ",":
1362
+ break
1363
+ self.advance(",")
1364
+ self.advance("}", True)
1365
+ if left is None:
1366
+ # NUD - unary prefix form
1367
+ res.lhs_object = a
1368
+ res.type = "unary"
1369
+ else:
1370
+ # LED - binary infix form
1371
+ res.lhs = left
1372
+ res.rhs_object = a
1373
+ res.type = "binary"
1374
+ return res
1375
+
1376
+ def parse(self, jsonata: Optional[str]) -> Symbol:
1377
+ self.source = jsonata
1378
+
1379
+ # now invoke the tokenizer and the parser and return the syntax tree
1380
+ self.lexer = tokenizer.Tokenizer(self.source)
1381
+ self.advance()
1382
+ # parse the tokens
1383
+ expr = self.expression(0)
1384
+ if self.node.id != "(end)":
1385
+ err = jexception.JException("S0201", self.node.position, self.node.value)
1386
+ self.handle_error(err)
1387
+
1388
+ expr = self.process_ast(expr)
1389
+
1390
+ if expr.type == "parent" or expr.seeking_parent is not None:
1391
+ # error - trying to derive ancestor at top level
1392
+ raise jexception.JException("S0217", expr.position, expr.type)
1393
+
1394
+ if len(self.errors) > 0:
1395
+ expr.errors = self.errors
1396
+
1397
+ return expr