|
119 | 119 | }
|
120 | 120 |
|
121 | 121 |
|
122 |
| - // The "[", "<", ">" tokens |
| 122 | + // The "&", "[", "<", ">" tokens |
123 | 123 | // are not in basicToken because
|
124 | 124 | // there are two token variants
|
125 |
| - // ("[?", "<=", ">="). This is specially handled |
| 125 | + // ("&&", "[?", "<=", ">="). This is specially handled |
126 | 126 | // below.
|
127 | 127 |
|
128 | 128 | var basicTokens = {
|
|
135 | 135 | "]": "Rbracket",
|
136 | 136 | "(": "Lparen",
|
137 | 137 | ")": "Rparen",
|
138 |
| - "@": "Current", |
139 |
| - "&": "Expref" |
| 138 | + "@": "Current" |
140 | 139 | };
|
141 | 140 |
|
142 | 141 | var identifierStart = {
|
|
231 | 230 | } else if (skipChars[stream[this.current]] !== undefined) {
|
232 | 231 | // Ignore whitespace.
|
233 | 232 | this.current++;
|
| 233 | + } else if (stream[this.current] === "&") { |
| 234 | + start = this.current; |
| 235 | + this.current++; |
| 236 | + if (stream[this.current] === "&") { |
| 237 | + this.current++; |
| 238 | + tokens.push({type: "And", value: "&&", start: start}); |
| 239 | + } else { |
| 240 | + tokens.push({type: "Expref", value: "&", start: start}); |
| 241 | + } |
234 | 242 | } else if (stream[this.current] === "|") {
|
235 | 243 | start = this.current;
|
236 | 244 | this.current++;
|
|
329 | 337 | if (stream[this.current] === "=") {
|
330 | 338 | this.current++;
|
331 | 339 | return {type: "NE", value: "!=", start: start};
|
| 340 | + } else { |
| 341 | + return {type: "Not", value: "!", start: start}; |
332 | 342 | }
|
333 | 343 | } else if (startingChar === "<") {
|
334 | 344 | if (stream[this.current] === "=") {
|
|
419 | 429 | "Current": 0,
|
420 | 430 | "Expref": 0,
|
421 | 431 | "Pipe": 1,
|
422 |
| - "EQ": 2, |
423 |
| - "GT": 2, |
424 |
| - "LT": 2, |
425 |
| - "GTE": 2, |
426 |
| - "LTE": 2, |
427 |
| - "NE": 2, |
428 |
| - "Or": 5, |
429 |
| - "Flatten": 6, |
| 432 | + "Or": 2, |
| 433 | + "And": 3, |
| 434 | + "EQ": 5, |
| 435 | + "GT": 5, |
| 436 | + "LT": 5, |
| 437 | + "GTE": 5, |
| 438 | + "LTE": 5, |
| 439 | + "NE": 5, |
| 440 | + "Flatten": 9, |
430 | 441 | "Star": 20,
|
431 | 442 | "Filter": 20,
|
432 | 443 | "Dot": 40,
|
| 444 | + "Not": 45, |
433 | 445 | "Lbrace": 50,
|
434 | 446 | "Lbracket": 55,
|
435 | 447 | "Lparen": 60
|
|
530 | 542 | }
|
531 | 543 | },
|
532 | 544 |
|
| 545 | + nudNot: function() { |
| 546 | + var right = this.expression(this.bindingPower.Not); |
| 547 | + return {type: "NotExpression", children: [right]}; |
| 548 | + }, |
| 549 | + |
533 | 550 | ledOr: function(left) {
|
534 | 551 | var right = this.expression(this.bindingPower.Or);
|
535 | 552 | return {type: "OrExpression", children: [left, right]};
|
536 | 553 | },
|
537 | 554 |
|
| 555 | + ledAnd: function(left) { |
| 556 | + var right = this.expression(this.bindingPower.And); |
| 557 | + return {type: "AndExpression", children: [left, right]}; |
| 558 | + }, |
| 559 | + |
538 | 560 | ledPipe: function(left) {
|
539 | 561 | var right = this.expression(this.bindingPower.Pipe);
|
540 | 562 | return {type: "Pipe", children: [left, right]};
|
|
717 | 739 | return {type: "Projection", children: [leftNode, rightNode]};
|
718 | 740 | },
|
719 | 741 |
|
| 742 | + nudLparen: function() { |
| 743 | + var args = []; |
| 744 | + var expression; |
| 745 | + while (this.lookahead(0) !== "Rparen") { |
| 746 | + if (this.lookahead(0) === "Current") { |
| 747 | + expression = {type: "Current"}; |
| 748 | + this.advance(); |
| 749 | + } else { |
| 750 | + expression = this.expression(0); |
| 751 | + } |
| 752 | + args.push(expression); |
| 753 | + } |
| 754 | + this.match("Rparen"); |
| 755 | + return args[0]; |
| 756 | + }, |
| 757 | + |
720 | 758 | ledLparen: function(left) {
|
721 | 759 | var name = left.name;
|
722 | 760 | var args = [];
|
|
1085 | 1123 | return matched;
|
1086 | 1124 | },
|
1087 | 1125 |
|
| 1126 | + visitAndExpression: function(node, value) { |
| 1127 | + var first = this.visit(node.children[0], value); |
| 1128 | + |
| 1129 | + if (isFalse(first) === true) { |
| 1130 | + return first; |
| 1131 | + } |
| 1132 | + return this.visit(node.children[1], value); |
| 1133 | + }, |
| 1134 | + |
| 1135 | + visitNotExpression: function(node, value) { |
| 1136 | + var first = this.visit(node.children[0], value); |
| 1137 | + return isFalse(first); |
| 1138 | + }, |
| 1139 | + |
1088 | 1140 | visitLiteral: function(node) {
|
1089 | 1141 | return node.value;
|
1090 | 1142 | },
|
|
1144 | 1196 | length: {
|
1145 | 1197 | func: this.functionLength,
|
1146 | 1198 | signature: [{types: ["string", "array", "object"]}]},
|
| 1199 | + map: { |
| 1200 | + func: this.functionMap, |
| 1201 | + signature: [{types: ["expref"]}, {types: ["array"]}]}, |
1147 | 1202 | max: {
|
1148 | 1203 | func: this.functionMax,
|
1149 | 1204 | signature: [{types: ["array-number", "array-string"]}]},
|
|
1359 | 1414 | }
|
1360 | 1415 | },
|
1361 | 1416 |
|
| 1417 | + functionMap: function(resolvedArgs) { |
| 1418 | + var mapped = []; |
| 1419 | + var interpreter = this.interpreter; |
| 1420 | + var exprefNode = resolvedArgs[0]; |
| 1421 | + var elements = resolvedArgs[1]; |
| 1422 | + for (var i = 0; i < elements.length; i++) { |
| 1423 | + mapped.push(interpreter.visit(exprefNode, elements[i])); |
| 1424 | + } |
| 1425 | + return mapped; |
| 1426 | + }, |
| 1427 | + |
1362 | 1428 | functionMerge: function(resolvedArgs) {
|
1363 | 1429 | var merged = {};
|
1364 | 1430 | for (var i = 0; i < resolvedArgs.length; i++) {
|
|
0 commit comments