jsonata-python 0.5.2__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,1393 @@
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 node.expressions:
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 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 [step for step in result.steps if step.keep_array]:
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
+ for slot in predicate.seeking_parent:
1070
+ if slot.level == 1:
1071
+ self.seek_parent(step, slot)
1072
+ else:
1073
+ slot.level -= 1
1074
+ self.push_ancestry(step, predicate)
1075
+ s = Parser.Symbol(self)
1076
+ s.type = "filter"
1077
+ s.expr = predicate
1078
+ s.position = expr.position
1079
+
1080
+ # FIXED:
1081
+ # this logic is required in Java to fix
1082
+ # for example test: flattening case 045
1083
+ # otherwise we lose the keepArray flag
1084
+ if expr.keep_array:
1085
+ step.keep_array = True
1086
+
1087
+ if type == "stages":
1088
+ step.stages.append(s)
1089
+ else:
1090
+ step.predicate.append(s)
1091
+ # step[type].push({type: 'filter', expr: predicate, position: expr.position})
1092
+ elif value == "{":
1093
+ # group-by
1094
+ # LHS is a step or a predicated step
1095
+ # RHS is the object constructor expr
1096
+ result = self.process_ast(expr.lhs)
1097
+ if result.group is not None:
1098
+ raise jexception.JException("S0210", expr.position)
1099
+ # object constructor - process each pair
1100
+ result.group = Parser.Symbol(self)
1101
+ result.group.lhs_object = [[self.process_ast(pair[0]), self.process_ast(pair[1])]
1102
+ for pair in expr.rhs_object]
1103
+ result.group.position = expr.position
1104
+
1105
+ elif value == "^":
1106
+ # order-by
1107
+ # LHS is the array to be ordered
1108
+ # RHS defines the terms
1109
+ result = self.process_ast(expr.lhs)
1110
+ if result.type != "path":
1111
+ _res = Parser.Symbol(self)
1112
+ _res.type = "path"
1113
+ _res.steps = [result]
1114
+ result = _res
1115
+ sort_step = Parser.Symbol(self)
1116
+ sort_step.type = "sort"
1117
+ sort_step.position = expr.position
1118
+
1119
+ def lambda1(terms):
1120
+ expression = self.process_ast(terms.expression)
1121
+ self.push_ancestry(sort_step, expression)
1122
+ res = Parser.Symbol(self)
1123
+ res.descending = terms.descending
1124
+ res.expression = expression
1125
+ return res
1126
+
1127
+ sort_step.terms = [lambda1(x) for x in expr.rhs_terms]
1128
+ result.steps.append(sort_step)
1129
+ self.resolve_ancestry(result)
1130
+ elif value == ":=":
1131
+ result = Parser.Symbol(self)
1132
+ result.type = "bind"
1133
+ result.value = expr.value
1134
+ result.position = expr.position
1135
+ result.lhs = self.process_ast(expr.lhs)
1136
+ result.rhs = self.process_ast(expr.rhs)
1137
+ self.push_ancestry(result, result.rhs)
1138
+ elif value == "@":
1139
+ result = self.process_ast(expr.lhs)
1140
+ step = result
1141
+ if result.type == "path":
1142
+ step = result.steps[-1]
1143
+ # throw error if there are any predicates defined at this point
1144
+ # at this point the only type of stages can be predicates
1145
+ if step.stages is not None or step.predicate is not None:
1146
+ raise jexception.JException("S0215", expr.position)
1147
+ # also throw if this is applied after an 'order-by' clause
1148
+ if step.type == "sort":
1149
+ raise jexception.JException("S0216", expr.position)
1150
+ if expr.keep_array:
1151
+ step.keep_array = True
1152
+ step.focus = expr.rhs.value
1153
+ step.tuple = True
1154
+ elif value == "#":
1155
+ result = self.process_ast(expr.lhs)
1156
+ step = result
1157
+ if result.type == "path":
1158
+ step = result.steps[-1]
1159
+ else:
1160
+ _res = Parser.Symbol(self)
1161
+ _res.type = "path"
1162
+ _res.steps = [result]
1163
+ result = _res
1164
+ if step.predicate is not None:
1165
+ step.stages = step.predicate
1166
+ step.predicate = None
1167
+ if step.stages is None:
1168
+ step.index = expr.rhs.value # name of index variable = String
1169
+ else:
1170
+ _res = Parser.Symbol(self)
1171
+ _res.type = "index"
1172
+ _res.value = expr.rhs.value
1173
+ _res.position = expr.position
1174
+ step.stages.append(_res)
1175
+ step.tuple = True
1176
+ elif value == "~>":
1177
+ result = Parser.Symbol(self)
1178
+ result.type = "apply"
1179
+ result.value = expr.value
1180
+ result.position = expr.position
1181
+ result.lhs = self.process_ast(expr.lhs)
1182
+ result.rhs = self.process_ast(expr.rhs)
1183
+ result.keep_array = result.lhs.keep_array or result.rhs.keep_array
1184
+ else:
1185
+ result = Parser.Infix(self, None)
1186
+ result.type = expr.type
1187
+ result.value = expr.value
1188
+ result.position = expr.position
1189
+ result.lhs = self.process_ast(expr.lhs)
1190
+ result.rhs = self.process_ast(expr.rhs)
1191
+ self.push_ancestry(result, result.lhs)
1192
+ self.push_ancestry(result, result.rhs)
1193
+
1194
+ elif type == "unary":
1195
+ result = Parser.Symbol(self)
1196
+ result.type = expr.type
1197
+ result.value = expr.value
1198
+ result.position = expr.position
1199
+ # expr.value might be Character!
1200
+ expr_value = str(expr.value)
1201
+ if expr_value == "[":
1202
+ if self.dbg:
1203
+ print("unary [ " + str(result))
1204
+
1205
+ # array constructor - process each item
1206
+ def lambda2(item):
1207
+ value = self.process_ast(item)
1208
+ self.push_ancestry(result, value)
1209
+ return value
1210
+
1211
+ result.expressions = [lambda2(x) for x in expr.expressions]
1212
+ elif expr_value == "{":
1213
+ # object constructor - process each pair
1214
+ # throw new Error("processAST {} unimpl")
1215
+ def lambda3(pair):
1216
+ key = self.process_ast(pair[0])
1217
+ self.push_ancestry(result, key)
1218
+ value = self.process_ast(pair[1])
1219
+ self.push_ancestry(result, value)
1220
+ return [key, value]
1221
+
1222
+ result.lhs_object = [lambda3(x) for x in expr.lhs_object]
1223
+ else:
1224
+ # all other unary expressions - just process the expression
1225
+ result.expression = self.process_ast(expr.expression)
1226
+ # if unary minus on a number, then pre-process
1227
+ if expr_value == "-" and result.expression.type == "number":
1228
+ result = result.expression
1229
+ result.value = utils.Utils.convert_number(-float(result.value))
1230
+ if self.dbg:
1231
+ print("unary - value=" + str(result.value))
1232
+ else:
1233
+ self.push_ancestry(result, result.expression)
1234
+
1235
+ elif type == "function" or type == "partial":
1236
+ result = Parser.Symbol(self)
1237
+ result.type = expr.type
1238
+ result.name = expr.name
1239
+ result.value = expr.value
1240
+ result.position = expr.position
1241
+
1242
+ def lambda4(arg):
1243
+ arg_ast = self.process_ast(arg)
1244
+ self.push_ancestry(result, arg_ast)
1245
+ return arg_ast
1246
+
1247
+ result.arguments = [lambda4(x) for x in expr.arguments]
1248
+ result.procedure = self.process_ast(expr.procedure)
1249
+ elif type == "lambda":
1250
+ result = Parser.Symbol(self)
1251
+ result.type = expr.type
1252
+ result.arguments = expr.arguments
1253
+ result.signature = expr.signature
1254
+ result.position = expr.position
1255
+ body = self.process_ast(expr.body)
1256
+ result.body = self.tail_call_optimize(body)
1257
+ elif type == "condition":
1258
+ result = Parser.Symbol(self)
1259
+ result.type = expr.type
1260
+ result.position = expr.position
1261
+ result.condition = self.process_ast(expr.condition)
1262
+ self.push_ancestry(result, result.condition)
1263
+ result.then = self.process_ast(expr.then)
1264
+ self.push_ancestry(result, result.then)
1265
+ if expr._else is not None:
1266
+ result._else = self.process_ast(expr._else)
1267
+ self.push_ancestry(result, result._else)
1268
+ elif type == "transform":
1269
+ result = Parser.Symbol(self)
1270
+ result.type = expr.type
1271
+ result.position = expr.position
1272
+ result.pattern = self.process_ast(expr.pattern)
1273
+ result.update = self.process_ast(expr.update)
1274
+ if expr.delete is not None:
1275
+ result.delete = self.process_ast(expr.delete)
1276
+ elif type == "block":
1277
+ result = Parser.Symbol(self)
1278
+ result.type = expr.type
1279
+ result.position = expr.position
1280
+
1281
+ # array of expressions - process each one
1282
+ def lambda5(item):
1283
+ part = self.process_ast(item)
1284
+ self.push_ancestry(result, part)
1285
+ if part.consarray or (part.type == "path" and part.steps[0].consarray):
1286
+ result.consarray = True
1287
+ return part
1288
+
1289
+ result.expressions = [lambda5(x) for x in expr.expressions]
1290
+ # TODO scan the array of expressions to see if any of them assign variables
1291
+ # if so, need to mark the block as one that needs to create a new frame
1292
+ elif type == "name":
1293
+ result = Parser.Symbol(self)
1294
+ result.type = "path"
1295
+ result.steps = [expr]
1296
+ if expr.keep_array:
1297
+ result.keep_singleton_array = True
1298
+ elif type == "parent":
1299
+ result = Parser.Symbol(self)
1300
+ result.type = "parent"
1301
+ result.slot = Parser.Symbol(self)
1302
+ result.slot.label = "!" + str(self.ancestor_label)
1303
+ self.ancestor_label += 1
1304
+ result.slot.level = 1
1305
+ result.slot.index = self.ancestor_index
1306
+ self.ancestor_index += 1
1307
+ # slot: { label: '!' + ancestorLabel++, level: 1, index: ancestorIndex++ } }
1308
+ self.ancestry.append(result)
1309
+ elif (type == "string" or type == "number" or type == "value" or type == "wildcard" or type == "descendant" or
1310
+ type == "variable" or type == "regex"):
1311
+ result = expr
1312
+ elif type == "operator":
1313
+ # the tokens 'and' and 'or' might have been used as a name rather than an operator
1314
+ if expr.value == "and" or expr.value == "or" or expr.value == "in":
1315
+ expr.type = "name"
1316
+ result = self.process_ast(expr)
1317
+ elif str(expr.value) == "?":
1318
+ # partial application
1319
+ result = expr
1320
+ else:
1321
+ raise jexception.JException("S0201", expr.position, expr.value)
1322
+ elif type == "error":
1323
+ result = expr
1324
+ if expr.lhs is not None:
1325
+ result = self.process_ast(expr.lhs)
1326
+ else:
1327
+ code = "S0206"
1328
+ # istanbul ignore else
1329
+ if expr.id == "(end)":
1330
+ code = "S0207"
1331
+ err = jexception.JException(code, expr.position, expr.value)
1332
+ if self.recover:
1333
+ self.errors.append(err)
1334
+ ret = Parser.Symbol(self)
1335
+ ret.type = "error"
1336
+ ret.error = err
1337
+ return ret
1338
+ else:
1339
+ # err.stack = (new Error()).stack
1340
+ raise err
1341
+ if expr.keep_array:
1342
+ result.keep_array = True
1343
+ return result
1344
+
1345
+ def object_parser(self, left: Optional[Symbol]) -> Symbol:
1346
+
1347
+ res = Parser.Infix(self, "{") if left is not None else Parser.Prefix(self, "{")
1348
+
1349
+ a = []
1350
+ if self.node.id != "}":
1351
+ while True:
1352
+ n = self.expression(0)
1353
+ self.advance(":")
1354
+ v = self.expression(0)
1355
+ pair = [n, v]
1356
+ a.append(pair) # holds an array of name/value expression pairs
1357
+ if self.node.id != ",":
1358
+ break
1359
+ self.advance(",")
1360
+ self.advance("}", True)
1361
+ if left is None:
1362
+ # NUD - unary prefix form
1363
+ res.lhs_object = a
1364
+ res.type = "unary"
1365
+ else:
1366
+ # LED - binary infix form
1367
+ res.lhs = left
1368
+ res.rhs_object = a
1369
+ res.type = "binary"
1370
+ return res
1371
+
1372
+ def parse(self, jsonata: Optional[str]) -> Symbol:
1373
+ self.source = jsonata
1374
+
1375
+ # now invoke the tokenizer and the parser and return the syntax tree
1376
+ self.lexer = tokenizer.Tokenizer(self.source)
1377
+ self.advance()
1378
+ # parse the tokens
1379
+ expr = self.expression(0)
1380
+ if self.node.id != "(end)":
1381
+ err = jexception.JException("S0201", self.node.position, self.node.value)
1382
+ self.handle_error(err)
1383
+
1384
+ expr = self.process_ast(expr)
1385
+
1386
+ if expr.type == "parent" or expr.seeking_parent is not None:
1387
+ # error - trying to derive ancestor at top level
1388
+ raise jexception.JException("S0217", expr.position, expr.type)
1389
+
1390
+ if self.errors:
1391
+ expr.errors = self.errors
1392
+
1393
+ return expr