diff --git a/src/ast.js b/src/ast.js index db93a4744..43200650a 100644 --- a/src/ast.js +++ b/src/ast.js @@ -155,7 +155,7 @@ AST.precedence = {}; ["cast", "silent"], ["**"], // TODO: [ (array) - // TODO: clone, new + // TODO: new ].forEach(function (list, index) { list.forEach(function (operator) { AST.precedence[operator] = index + 1; diff --git a/src/parser/expr.js b/src/parser/expr.js index cbc07bdcc..23b066913 100644 --- a/src/parser/expr.js +++ b/src/parser/expr.js @@ -363,7 +363,8 @@ module.exports = { this.next(); if (this.version >= 805 && this.token === "(") { this.next(); - const what = this.read_expr(); + let what = this.read_variable(false, false); + what = this.handleDereferencable(what); let properties = null; if (this.token === ",") { properties = this.next().read_expr(); @@ -371,7 +372,9 @@ module.exports = { this.expect(")") && this.next(); return node(what, properties); } - return node(this.read_expr(), null); + let what = this.read_variable(false, false); + what = this.handleDereferencable(what); + return node(what, null); } switch (this.token) { diff --git a/test/snapshot/clone.test.js b/test/snapshot/clone.test.js index 157c53918..6a5049402 100644 --- a/test/snapshot/clone.test.js +++ b/test/snapshot/clone.test.js @@ -1,5 +1,32 @@ const parser = require("../main"); +function filterKey(fn, obj) { + if (Array.isArray(obj)) { + return obj.map((e) => filterKey(fn, e)); + } + + if (typeof obj === "object" && obj !== null) { + return Object.keys(obj) + .filter(fn) + .reduce( + (result, key) => ({ + ...result, + [key]: filterKey(fn, obj[key]), + }), + {}, + ); + } + + return obj; +} + +function shouldBeSame(a, b) { + const fn = (key) => key !== "parenthesizedExpression"; + expect(filterKey(fn, parser.parseEval(a))).toEqual( + filterKey(fn, parser.parseEval(b)), + ); +} + describe("clone", function () { it("simple", function () { expect(parser.parseEval("clone $obj;")).toMatchSnapshot(); @@ -20,3 +47,33 @@ describe("clone", function () { ).toMatchSnapshot(); }); }); + +describe("clone precedence comparison", function () { + it("clone $obj + 1 should be same as (clone $obj) + 1", function () { + shouldBeSame("clone $obj + 1", "(clone $obj) + 1"); + }); + it("clone $obj * 2 should be same as (clone $obj) * 2", function () { + shouldBeSame("clone $obj * 2", "(clone $obj) * 2"); + }); + it("clone $obj - 1 should be same as (clone $obj) - 1", function () { + shouldBeSame("clone $obj - 1", "(clone $obj) - 1"); + }); + it("clone $obj / 2 should be same as (clone $obj) / 2", function () { + shouldBeSame("clone $obj / 2", "(clone $obj) / 2"); + }); + it("clone $obj->prop + 1 should be same as (clone $obj->prop) + 1", function () { + shouldBeSame("clone $obj->prop + 1", "(clone $obj->prop) + 1"); + }); + it("clone $obj->method() * 2 should be same as (clone $obj->method()) * 2", function () { + shouldBeSame("clone $obj->method() * 2", "(clone $obj->method()) * 2"); + }); + it("clone $obj[0] + 1 should be same as (clone $obj[0]) + 1", function () { + shouldBeSame("clone $obj[0] + 1", "(clone $obj[0]) + 1"); + }); + it("-clone $obj should be same as -(clone $obj)", function () { + shouldBeSame("-clone $obj", "-(clone $obj)"); + }); + it("!clone $obj should be same as !(clone $obj)", function () { + shouldBeSame("!clone $obj", "!(clone $obj)"); + }); +});