flowquery 1.0.29 → 1.0.30
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.
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/parser.d.ts +12 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +33 -5
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/parsing/parser.py +29 -6
- package/flowquery-py/tests/parsing/test_parser.py +58 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/parsing/parser.ts +37 -6
- package/tests/parsing/parser.test.ts +58 -0
package/package.json
CHANGED
package/src/parsing/parser.ts
CHANGED
|
@@ -798,12 +798,7 @@ class Parser extends BaseParser {
|
|
|
798
798
|
expression.addNode(lookup);
|
|
799
799
|
return true;
|
|
800
800
|
}
|
|
801
|
-
} else if (
|
|
802
|
-
this.token.isLeftParenthesis() &&
|
|
803
|
-
(this.peek()?.isIdentifierOrKeyword() ||
|
|
804
|
-
this.peek()?.isColon() ||
|
|
805
|
-
this.peek()?.isRightParenthesis())
|
|
806
|
-
) {
|
|
801
|
+
} else if (this.token.isLeftParenthesis() && this.looksLikeNodePattern()) {
|
|
807
802
|
// Possible graph pattern expression
|
|
808
803
|
const pattern = this.parsePatternExpression();
|
|
809
804
|
if (pattern !== null) {
|
|
@@ -865,6 +860,42 @@ class Parser extends BaseParser {
|
|
|
865
860
|
return false;
|
|
866
861
|
}
|
|
867
862
|
|
|
863
|
+
/**
|
|
864
|
+
* Peeks ahead from a left parenthesis to determine whether the
|
|
865
|
+
* upcoming tokens form a graph-node pattern (e.g. (n:Label), (n),
|
|
866
|
+
* (:Label), ()) rather than a parenthesised expression (e.g.
|
|
867
|
+
* (variable.property), (a + b)).
|
|
868
|
+
*
|
|
869
|
+
* The heuristic is:
|
|
870
|
+
* • ( followed by `:` or `)` → node pattern
|
|
871
|
+
* • ( identifier, then `:` or `{` or `)` → node pattern
|
|
872
|
+
* • anything else → parenthesised expression
|
|
873
|
+
*/
|
|
874
|
+
private looksLikeNodePattern(): boolean {
|
|
875
|
+
const savedIndex = this.tokenIndex;
|
|
876
|
+
this.setNextToken(); // skip '('
|
|
877
|
+
this.skipWhitespaceAndComments();
|
|
878
|
+
|
|
879
|
+
if (this.token.isColon() || this.token.isRightParenthesis()) {
|
|
880
|
+
this.tokenIndex = savedIndex;
|
|
881
|
+
return true;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (this.token.isIdentifierOrKeyword()) {
|
|
885
|
+
this.setNextToken(); // skip identifier
|
|
886
|
+
this.skipWhitespaceAndComments();
|
|
887
|
+
const result =
|
|
888
|
+
this.token.isColon() ||
|
|
889
|
+
this.token.isOpeningBrace() ||
|
|
890
|
+
this.token.isRightParenthesis();
|
|
891
|
+
this.tokenIndex = savedIndex;
|
|
892
|
+
return result;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
this.tokenIndex = savedIndex;
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
|
|
868
899
|
private parseExpression(): Expression | null {
|
|
869
900
|
const expression = new Expression();
|
|
870
901
|
while (true) {
|
|
@@ -1098,3 +1098,61 @@ test("Test WHERE with NOT ENDS WITH", () => {
|
|
|
1098
1098
|
"--- Reference (s)"
|
|
1099
1099
|
);
|
|
1100
1100
|
});
|
|
1101
|
+
|
|
1102
|
+
test("Test parenthesized expression with addition", () => {
|
|
1103
|
+
const parser = new Parser();
|
|
1104
|
+
const ast = parser.parse("WITH 1 AS n RETURN (n + 2)");
|
|
1105
|
+
// prettier-ignore
|
|
1106
|
+
expect(ast.print()).toBe(
|
|
1107
|
+
"ASTNode\n" +
|
|
1108
|
+
"- With\n" +
|
|
1109
|
+
"-- Expression (n)\n" +
|
|
1110
|
+
"--- Number (1)\n" +
|
|
1111
|
+
"- Return\n" +
|
|
1112
|
+
"-- Expression\n" +
|
|
1113
|
+
"--- Expression\n" +
|
|
1114
|
+
"---- Add\n" +
|
|
1115
|
+
"----- Reference (n)\n" +
|
|
1116
|
+
"----- Number (2)"
|
|
1117
|
+
);
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
test("Test parenthesized expression with property access", () => {
|
|
1121
|
+
const parser = new Parser();
|
|
1122
|
+
const ast = parser.parse("WITH {a: 1} AS obj RETURN (obj.a)");
|
|
1123
|
+
// prettier-ignore
|
|
1124
|
+
expect(ast.print()).toBe(
|
|
1125
|
+
"ASTNode\n" +
|
|
1126
|
+
"- With\n" +
|
|
1127
|
+
"-- Expression (obj)\n" +
|
|
1128
|
+
"--- AssociativeArray\n" +
|
|
1129
|
+
"---- KeyValuePair\n" +
|
|
1130
|
+
"----- String (a)\n" +
|
|
1131
|
+
"----- Expression\n" +
|
|
1132
|
+
"------ Number (1)\n" +
|
|
1133
|
+
"- Return\n" +
|
|
1134
|
+
"-- Expression\n" +
|
|
1135
|
+
"--- Expression\n" +
|
|
1136
|
+
"---- Lookup\n" +
|
|
1137
|
+
"----- Identifier (a)\n" +
|
|
1138
|
+
"----- Reference (obj)"
|
|
1139
|
+
);
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
test("Test parenthesized expression with multiplication", () => {
|
|
1143
|
+
const parser = new Parser();
|
|
1144
|
+
const ast = parser.parse("WITH 5 AS x RETURN (x * 3)");
|
|
1145
|
+
// prettier-ignore
|
|
1146
|
+
expect(ast.print()).toBe(
|
|
1147
|
+
"ASTNode\n" +
|
|
1148
|
+
"- With\n" +
|
|
1149
|
+
"-- Expression (x)\n" +
|
|
1150
|
+
"--- Number (5)\n" +
|
|
1151
|
+
"- Return\n" +
|
|
1152
|
+
"-- Expression\n" +
|
|
1153
|
+
"--- Expression\n" +
|
|
1154
|
+
"---- Multiply\n" +
|
|
1155
|
+
"----- Reference (x)\n" +
|
|
1156
|
+
"----- Number (3)"
|
|
1157
|
+
);
|
|
1158
|
+
});
|