diff --git a/src/ast.js b/src/ast.js index 967a66988..45c7ab266 100644 --- a/src/ast.js +++ b/src/ast.js @@ -163,8 +163,7 @@ AST.precedence = {}; ["*", "/", "%"], ["!"], ["instanceof"], - ["cast"] - // TODO: typecasts + ["cast", "silent"] // TODO: [ (array) // TODO: clone, new ].forEach(function(list, index) { @@ -254,22 +253,22 @@ AST.prototype.resolvePrecedence = function(result, parser) { } } } else if ( - result.kind === "cast" && - result.what && - !result.what.parenthesizedExpression + (result.kind === "silent" || result.kind === "cast") && + result.expr && + !result.expr.parenthesizedExpression ) { // https://github.com/glayzzle/php-parser/issues/172 - if (result.what.kind === "bin") { - buffer = result.what; - result.what = result.what.left; - this.swapLocations(result, result, result.what, parser); + if (result.expr.kind === "bin") { + buffer = result.expr; + result.expr = result.expr.left; + this.swapLocations(result, result, result.expr, parser); buffer.left = this.resolvePrecedence(result, parser); this.swapLocations(buffer, buffer.left, buffer.right, parser); result = buffer; - } else if (result.what.kind === "retif") { - buffer = result.what; - result.what = result.what.test; - this.swapLocations(result, result, result.what, parser); + } else if (result.expr.kind === "retif") { + buffer = result.expr; + result.expr = result.expr.test; + this.swapLocations(result, result, result.expr, parser); buffer.test = this.resolvePrecedence(result, parser); this.swapLocations(buffer, buffer.test, buffer.falseExpr, parser); result = buffer; @@ -285,13 +284,6 @@ AST.prototype.resolvePrecedence = function(result, parser) { buffer.left = this.resolvePrecedence(result, parser); this.swapLocations(buffer, buffer.left, buffer.right, parser); result = buffer; - } else if (result.what.kind === "retif") { - buffer = result.what; - result.what = result.what.test; - this.swapLocations(result, result, result.what, parser); - buffer.test = this.resolvePrecedence(result, parser); - this.swapLocations(buffer, buffer.test, buffer.falseExpr, parser); - result = buffer; } } } else if (result.kind === "retif") { @@ -326,16 +318,6 @@ AST.prototype.resolvePrecedence = function(result, parser) { result = buffer; } } - } else if (result.kind === "silent" && !result.expr.parenthesizedExpression) { - if (result.expr.kind === "assign") return result; - // overall least precedence - if (result.expr.right) { - buffer = result.expr; - result.expr = buffer.left; - buffer.left = result; - this.swapLocations(buffer, buffer.left, buffer.right, parser); - result = buffer; - } } else if (result.kind === "expressionstatement") { this.swapLocations(result, result.expression, result, parser); } diff --git a/src/ast/cast.js b/src/ast/cast.js index 9c2ca33c0..c34701e5f 100644 --- a/src/ast/cast.js +++ b/src/ast/cast.js @@ -14,17 +14,17 @@ const KIND = "cast"; * @extends {Operation} * @property {String} type * @property {String} raw - * @property {Expression} what + * @property {Expression} expr */ module.exports = Operation.extends(KIND, function Cast( type, raw, - what, + expr, docs, location ) { Operation.apply(this, [KIND, docs, location]); this.type = type; this.raw = raw; - this.what = what; + this.expr = expr; }); diff --git a/test/precedence.test.js b/test/precedence.test.js index dd3606289..5166541d0 100644 --- a/test/precedence.test.js +++ b/test/precedence.test.js @@ -3,45 +3,39 @@ var parser = require("./main"); /** * Check precedence by using parenthesis on node B */ -var checkPrecedence = function(a, b) { - if (!a && !b) - return false; - for (let k in b) { - if (k === 'parenthesizedExpression') continue; - if (b.hasOwnProperty(k)) { - if (!a.hasOwnProperty(k)) - return expect(a).toHaveProperty(k, b[k]); - if (typeof b[k] === "object" && b[k] !== null) { - checkPrecedence(a[k], b[k]); - } else { - expect(a[k]).toEqual(b[k]); - } - } +function filterKey(fn, obj) { + if (Array.isArray(obj)) { + return obj.map(e => filterKey(fn, e)); } - for (let k in a) { - if (k === 'parenthesizedExpression') continue; - if (a.hasOwnProperty(k)) { - if (!b.hasOwnProperty(k)) - return expect(b).toHaveProperty(k, a[k]); - } - } - return true; -}; -var shouldBeSame = function(a, b) { - var ast = parser.parseEval([ - a + ";", - b + ";" - ].join("\n")); - let result = checkPrecedence(ast.children[0], ast.children[1]); - if (!result) { - console.log("Parsed :", ast.children[0]); - console.log("Expected :", ast.children[1]); + if (typeof(obj) === "object" && obj !== null) { + return Object.keys(obj) + .filter(fn) + .reduce((result, key) => ({ + ...result, + [key]: filterKey(fn, obj[key]) + }), {}); } - expect(result).toBeTruthy(); + + return obj +} + +function shouldBeSame(a, b) { + const fn = key => key !== "parenthesizedExpression"; + expect(filterKey(fn, parser.parseEval(a))).toEqual(filterKey(fn, parser.parseEval(b))) }; // START TESTS HERE + +describe("Test infrastructure", function() { + it("should filter parenthesizedExpression prop", function() { + const fn = key => key !== "parenthesizedExpression"; + expect(filterKey(fn, {foo: "bar", parenthesizedExpression: true})).toEqual({foo: "bar"}); + expect(filterKey(fn, {x: {foo: "bar", parenthesizedExpression: true}})).toEqual({x: {foo: "bar"}}); + expect(filterKey(fn, [{foo: "bar", parenthesizedExpression: true}])).toEqual([{foo: "bar"}]); + }); +}); + describe("Test precedence", function() { it("test *", function() { shouldBeSame("5 * 3 - 2", "(5 * 3) - 2"); @@ -135,6 +129,9 @@ describe("Test precedence", function() { it("test silent node / div", function() { shouldBeSame("@$i / 0;", "@($i) / 0;"); }); + it("test silent node / retif", function() { + shouldBeSame("@$var ? 1 : 2;", "(@$var) ? 1 : 2;"); + }); it("test silent node / ret if", function() { shouldBeSame("@$i == true ? @$foo : @$bar;", "@($i) == true ? @($foo) : @($bar);"); }); diff --git a/test/snapshot/__snapshots__/acid.test.js.snap b/test/snapshot/__snapshots__/acid.test.js.snap index ca41881bf..a5917499c 100644 --- a/test/snapshot/__snapshots__/acid.test.js.snap +++ b/test/snapshot/__snapshots__/acid.test.js.snap @@ -3737,23 +3737,7 @@ Program { "test": Bin { "kind": "bin", "left": Cast { - "kind": "cast", - "loc": Location { - "end": Position { - "column": 19, - "line": 90, - "offset": 1817, - }, - "source": "(int)$index", - "start": Position { - "column": 8, - "line": 90, - "offset": 1806, - }, - }, - "raw": "(int)", - "type": "int", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "loc": Location { @@ -3771,6 +3755,22 @@ Program { }, "name": "index", }, + "kind": "cast", + "loc": Location { + "end": Position { + "column": 19, + "line": 90, + "offset": 1817, + }, + "source": "(int)$index", + "start": Position { + "column": 8, + "line": 90, + "offset": 1806, + }, + }, + "raw": "(int)", + "type": "int", }, "loc": Location { "end": Position { @@ -6177,23 +6177,7 @@ next: "test": Bin { "kind": "bin", "left": Cast { - "kind": "cast", - "loc": Location { - "end": Position { - "column": 41, - "line": 99, - "offset": 2047, - }, - "source": "(int)calculateMeaningOfLife()", - "start": Position { - "column": 12, - "line": 99, - "offset": 2018, - }, - }, - "raw": "(int)", - "type": "int", - "what": Call { + "expr": Call { "arguments": Array [], "kind": "call", "loc": Location { @@ -6228,6 +6212,22 @@ next: "resolution": "uqn", }, }, + "kind": "cast", + "loc": Location { + "end": Position { + "column": 41, + "line": 99, + "offset": 2047, + }, + "source": "(int)calculateMeaningOfLife()", + "start": Position { + "column": 12, + "line": 99, + "offset": 2018, + }, + }, + "raw": "(int)", + "type": "int", }, "loc": Location { "end": Position { diff --git a/test/snapshot/__snapshots__/expr.test.js.snap b/test/snapshot/__snapshots__/expr.test.js.snap index 926e67660..aa44104c2 100644 --- a/test/snapshot/__snapshots__/expr.test.js.snap +++ b/test/snapshot/__snapshots__/expr.test.js.snap @@ -965,157 +965,157 @@ Program { "children": Array [ ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(int)", - "type": "int", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(int)", + "type": "int", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(integer)", - "type": "int", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(integer)", + "type": "int", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(bool)", - "type": "bool", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(bool)", + "type": "bool", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(boolean)", - "type": "bool", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(boolean)", + "type": "bool", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(float)", - "type": "float", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(float)", + "type": "float", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(double)", - "type": "float", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(double)", + "type": "float", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(real)", - "type": "float", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(real)", + "type": "float", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(string)", - "type": "string", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(string)", + "type": "string", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(binary)", - "type": "binary", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(binary)", + "type": "binary", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(array)", - "type": "array", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(array)", + "type": "array", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(object)", - "type": "object", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(object)", + "type": "object", }, "kind": "expressionstatement", }, ExpressionStatement { "expression": Cast { - "kind": "cast", - "raw": "(unset)", - "type": "unset", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "name": "var", }, + "kind": "cast", + "raw": "(unset)", + "type": "unset", }, "kind": "expressionstatement", }, diff --git a/test/snapshot/__snapshots__/location.test.js.snap b/test/snapshot/__snapshots__/location.test.js.snap index 37d9e48b7..154e3bd23 100644 --- a/test/snapshot/__snapshots__/location.test.js.snap +++ b/test/snapshot/__snapshots__/location.test.js.snap @@ -541,23 +541,7 @@ Program { "expression": Bin { "kind": "bin", "left": Cast { - "kind": "cast", - "loc": Location { - "end": Position { - "column": 13, - "line": 1, - "offset": 13, - }, - "source": "(string)$var1", - "start": Position { - "column": 0, - "line": 1, - "offset": 0, - }, - }, - "raw": "(string)", - "type": "string", - "what": Variable { + "expr": Variable { "curly": false, "kind": "variable", "loc": Location { @@ -575,6 +559,22 @@ Program { }, "name": "var1", }, + "kind": "cast", + "loc": Location { + "end": Position { + "column": 13, + "line": 1, + "offset": 13, + }, + "source": "(string)$var1", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "raw": "(string)", + "type": "string", }, "loc": Location { "end": Position { @@ -3025,23 +3025,7 @@ Program { }, "operator": "=", "right": Cast { - "kind": "cast", - "loc": Location { - "end": Position { - "column": 19, - "line": 1, - "offset": 19, - }, - "source": "(int) \\"2112\\"", - "start": Position { - "column": 7, - "line": 1, - "offset": 7, - }, - }, - "raw": "(int)", - "type": "int", - "what": String { + "expr": String { "isDoubleQuote": true, "kind": "string", "loc": Location { @@ -3061,6 +3045,22 @@ Program { "unicode": false, "value": "2112", }, + "kind": "cast", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "(int) \\"2112\\"", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "raw": "(int)", + "type": "int", }, }, "kind": "expressionstatement",