diff --git a/frontend/main.js b/frontend/main.js
index 34dab50..3053bb2 100644
--- a/frontend/main.js
+++ b/frontend/main.js
@@ -231,8 +231,10 @@ function renderAST (json) {
return renderNode(ast);
}
+const NODE_TYPE_LIST = 8;
+
function renderNode (node) {
- return `${node.id || ''}${Array.isArray(node.children) ? `
${node.children.map(c => `- ${renderNode(c)}
`).join('')}
` : ''}`;
+ return `${node.id || (node.type === NODE_TYPE_LIST ? "LIST" : '')}${Array.isArray(node.children) ? `${node.children.map(c => `- ${renderNode(c)}
`).join('')}
` : ''}`;
}
function getSuggestions () {
diff --git a/src/parser.js b/src/parser.js
index 429f870..c21dd82 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -541,7 +541,7 @@ function parseFromTokenList (tokenList, source="") {
const nodes = [];
- while (!end()) {
+ while (!end() && !peek(TOKEN_TYPES.BRACKET, ")")) {
try {
nodes.push(descendNode());
} catch (e) {
@@ -569,71 +569,68 @@ function parseFromTokenList (tokenList, source="") {
throw Error("Expecting an operator");
}
- index++;
+ // // Unary prefix
+ // if (t.value === "NOT") {}
- const left = nodes[index];
+ let left = nodes[++index];
if (left.type === NODE_TYPES.OPERATOR) {
- root.children[0] = assembleExpressionTree(nodes)
- } else {
- root.children[0] = left;
+ left = assembleExpressionTree(nodes);
+ } else if (left.type === NODE_TYPES.LIST) {
+ // If we have a list here it's not actually a list
+ // it's really a subexpression in brackets.
+ // That subexpression has already been correctly parsed.
+ left = left.children[0];
+ }
+
+ root.children[0] = left;
+
+ // Unary postfix
+ if (root.id === "IS NULL" ||
+ root.id === "IS NOT NULL")
+ {
+ return root;
}
- index++;
+ let right = nodes[++index];
+
+ if (root.id === "BETWEEN" && right.id === "AND") {
+ // skip ahead then we have two more nodes to add
- const right = nodes[index];
+ right = nodes[++index];
+ }
if (right.type === NODE_TYPES.OPERATOR) {
- root.children[1] = assembleExpressionTree(nodes)
- } else {
- root.children[1] = right;
+ right = assembleExpressionTree(nodes);
+ } else if (right.type === NODE_TYPES.LIST && (root.id !== "IN" && root.id !== "NOT IN")) {
+ // Most of the time 'LISTs' are just bracketed sub-expressions
+ // but the IN operators can take a list
+ right = right.children[0];
+ }
+
+ root.children[1] = right;
+
+ if (root.id === "BETWEEN") {
+ // Between has a third child node
+ let farRight = nodes[++index];
+
+ if (farRight.type === NODE_TYPES.OPERATOR) {
+ farRight = assembleExpressionTree(nodes);
+ } else if (farRight.type === NODE_TYPES.LIST) {
+ farRight = farRight.children[0];
+ }
+
+ root.children[2] = farRight;
}
return root;
}
- return assembleExpressionTree(nodes);
-
-
- // const t = next();
-
-
- // let right;
-
- // // Unary prefix
- // if (t.value === "NOT") {}
- // // Unary postfix
- // if (t.value === "IS NULL" ||
- // t.value === "IS NOT NULL")
- // {
- // op.children.push(left);
- // root = op;
- // }
- // else {
- // right = descendExpression(getPrecedence(op));
-
- // if (right.type === NODE_TYPES.OPERATOR) {
- // // if child operator is weaker than me
- // if (getPrecedence(right) < getPrecedence(op)) {
- // // Steal left child
- // const leftChild = right.children[0];
- // op.children.push(left, leftChild);
- // right.children[0] = op;
- // root = right;
- // } else {
- // op.children.push(left, right);
- // root = op;
- // }
- // } else {
- // op.children.push(left, right);
- // root = op;
- // }
- // }
- // }
-
- // root.source = source.substring(start, current() && current().start).trim();
-
- // return root;
+ const root = assembleExpressionTree(nodes);
+
+ root.source = source.substring(start, current() && current().start).trim();
+
+ return root;
}
/**
diff --git a/test/expr.test.js b/test/expr.test.js
index fbcfc43..28a7827 100644
--- a/test/expr.test.js
+++ b/test/expr.test.js
@@ -102,63 +102,65 @@ describe("Maths", () => {
});
});
- test("Order of Operations: +-", () => {
- return runQuery("SELECT 14 + 28 - 18").then(r => {
- expect(r[1][0]).toBe(24);
+ describe("Order of Operations", () => {
+ test("+-", () => {
+ return runQuery("SELECT 14 + 28 - 18").then(r => {
+ expect(r[1][0]).toBe(24);
+ });
});
- });
- test("Order of Operations: -+", () => {
- return runQuery("SELECT 14 - 8 + 26").then(r => {
- expect(r[1][0]).toBe(32);
+ test("-+", () => {
+ return runQuery("SELECT 14 - 8 + 26").then(r => {
+ expect(r[1][0]).toBe(32);
+ });
});
- });
- test("Order of Operations: *+", () => {
- return runQuery("SELECT 14 * 2 + 7").then(r => {
- expect(r[1][0]).toBe(35);
+ test("*+", () => {
+ return runQuery("SELECT 14 * 2 + 7").then(r => {
+ expect(r[1][0]).toBe(35);
+ });
});
- });
- test("Order of Operations: *-", () => {
- return runQuery("SELECT 14 * 2 - 7").then(r => {
- expect(r[1][0]).toBe(21);
+ test("*-", () => {
+ return runQuery("SELECT 14 * 2 - 7").then(r => {
+ expect(r[1][0]).toBe(21);
+ });
});
- });
- test("Order of Operations: +*", () => {
- return runQuery("SELECT 14 + 7 * 2").then(r => {
- expect(r[1][0]).toBe(28);
+ test("+*", () => {
+ return runQuery("SELECT 14 + 7 * 2").then(r => {
+ expect(r[1][0]).toBe(28);
+ });
});
- });
- test("Order of Operations: -*", () => {
- return runQuery("SELECT 42 - 7 * 3").then(r => {
- expect(r[1][0]).toBe(21);
+ test("-*", () => {
+ return runQuery("SELECT 42 - 7 * 3").then(r => {
+ expect(r[1][0]).toBe(21);
+ });
});
- });
- test("Order of Operations: +*+", () => {
- return runQuery("SELECT 14 + 7 * 2 + 1").then(r => {
- expect(r[1][0]).toBe(29);
+ test("+*+", () => {
+ return runQuery("SELECT 14 + 7 * 2 + 1").then(r => {
+ expect(r[1][0]).toBe(29);
+ });
});
- });
- test("Order of Operations: +*-", () => {
- return runQuery("SELECT 14 + 7 * 5 - 1").then(r => {
- expect(r[1][0]).toBe(48);
+ test("+*-", () => {
+ return runQuery("SELECT 14 + 7 * 5 - 1").then(r => {
+ expect(r[1][0]).toBe(48);
+ });
});
- });
- test("Order of Operations: *+*", () => {
- return runQuery("SELECT 14 * 2 + 7 * 2").then(r => {
- expect(r[1][0]).toBe(42);
+ test("*+*", () => {
+ return runQuery("SELECT 14 * 2 + 7 * 2").then(r => {
+ expect(r[1][0]).toBe(42);
+ });
});
- });
- test("Order of Operations: *-*", () => {
- return runQuery("SELECT 14 * 3 - 7 * 5").then(r => {
- expect(r[1][0]).toBe(7);
+ test("*-*", () => {
+ return runQuery("SELECT 14 * 3 - 7 * 5").then(r => {
+ expect(r[1][0]).toBe(7);
+ });
});
});
});
@@ -180,7 +182,39 @@ test("Coalesce operator (??)", () => {
expect(r[1][0]).toBe(0);
}),
]);
-})
+});
+
+describe("Brackets", () => {
+ test("(+)*", () => {
+ return runQuery("SELECT (5 + 2) * 3").then(r => {
+ expect(r[1][0]).toBe(21);
+ });
+ });
+
+ test("+(*)", () => {
+ return runQuery("SELECT 5 + (2 * 3)").then(r => {
+ expect(r[1][0]).toBe(11);
+ });
+ });
+
+ test("* (-) *", () => {
+ return runQuery("SELECT 2 * (10 - 6) * 3").then(r => {
+ expect(r[1][0]).toBe(24);
+ });
+ });
+
+ test("+ (-) *", () => {
+ return runQuery("SELECT 2 + (10 - 4) * 3").then(r => {
+ expect(r[1][0]).toBe(20);
+ });
+ });
+
+ test("(+) IN", () => {
+ return runQuery("SELECT (3 + 4) IN (5, 6, 7, 8)").then(r => {
+ expect(r[1][0]).toBe(true);
+ });
+ });
+});
describe("Nested Functions", () => {
test("Function -> Expression", () => {