diff --git a/src/ast.js b/src/ast.js index adfed614b..bde903025 100644 --- a/src/ast.js +++ b/src/ast.js @@ -149,7 +149,7 @@ AST.precedence = {}; ["<<", ">>"], ["+", "-", "."], ["*", "/", "%"], - ["!"], + ["!", "u-", "u+", "u~"], // u- etc. are unary variants; higher than * so -20*5 parses as (-20)*5 ["instanceof"], ["cast", "silent"], ["**"], @@ -300,7 +300,9 @@ AST.prototype.resolvePrecedence = function (result, parser) { // https://github.com/glayzzle/php-parser/issues/75 if (result.what && !result.what.parenthesizedExpression) { if (result.what.kind === "bin") { - lLevel = AST.precedence[result.type]; + // use the unary-specific precedence (u-, u+, u~) which is higher than binary - and + + lLevel = + AST.precedence["u" + result.type] || AST.precedence[result.type]; rLevel = AST.precedence[result.what.type]; if (lLevel && rLevel && rLevel < lLevel) { buffer = result.what; diff --git a/test/snapshot/__snapshots__/attributes.test.js.snap b/test/snapshot/__snapshots__/attributes.test.js.snap index a109100ae..ddf65c5ff 100644 --- a/test/snapshot/__snapshots__/attributes.test.js.snap +++ b/test/snapshot/__snapshots__/attributes.test.js.snap @@ -1591,74 +1591,74 @@ Program { "attrs": [ Attribute { "args": [ - Unary { - "kind": "unary", - "type": "-", - "what": Bin { + Bin { + "kind": "bin", + "left": Bin { "kind": "bin", "left": Bin { "kind": "bin", "left": Bin { "kind": "bin", - "left": Bin { - "kind": "bin", - "left": Number { + "left": Unary { + "kind": "unary", + "type": "-", + "what": Number { "kind": "number", "value": "20", }, - "right": Unary { + }, + "right": Bin { + "kind": "bin", + "left": Unary { "kind": "unary", - "parenthesizedExpression": true, "type": "+", - "what": Bin { - "kind": "bin", - "left": Number { - "kind": "number", - "value": "10", - }, - "right": Number { - "kind": "number", - "value": "5", - }, - "type": "/", + "what": Number { + "kind": "number", + "value": "10", }, }, - "type": "*", - }, - "right": Number { - "kind": "number", - "value": "2", + "parenthesizedExpression": true, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "/", }, - "type": "%", + "type": "*", }, - "right": Bin { - "kind": "bin", - "left": Number { - "kind": "number", - "value": "8", - }, - "right": Number { - "kind": "number", - "value": "2", - }, - "type": "**", + "right": Number { + "kind": "number", + "value": "2", }, - "type": "+", + "type": "%", }, - "right": Unary { + "right": Bin { + "kind": "bin", + "left": Number { + "kind": "number", + "value": "8", + }, + "right": Number { + "kind": "number", + "value": "2", + }, + "type": "**", + }, + "type": "+", + }, + "right": Unary { + "kind": "unary", + "type": "+", + "what": Unary { "kind": "unary", - "type": "+", - "what": Unary { - "kind": "unary", - "type": "-", - "what": Number { - "kind": "number", - "value": "2", - }, + "type": "-", + "what": Number { + "kind": "number", + "value": "2", }, }, - "type": "-", }, + "type": "-", }, ], "kind": "attribute", diff --git a/test/snapshot/__snapshots__/unary.test.js.snap b/test/snapshot/__snapshots__/unary.test.js.snap index 6013591f7..86a47797e 100644 --- a/test/snapshot/__snapshots__/unary.test.js.snap +++ b/test/snapshot/__snapshots__/unary.test.js.snap @@ -479,6 +479,154 @@ Program { } `; +exports[`Test unary precedence over add 1`] = ` +Program { + "children": [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Unary { + "kind": "unary", + "type": "-", + "what": Number { + "kind": "number", + "value": "20", + }, + }, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "+", + }, + "kind": "expressionstatement", + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test unary precedence over mul 1`] = ` +Program { + "children": [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Unary { + "kind": "unary", + "type": "-", + "what": Number { + "kind": "number", + "value": "20", + }, + }, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "*", + }, + "kind": "expressionstatement", + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test unary precedence over mul and add 1`] = ` +Program { + "children": [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Bin { + "kind": "bin", + "left": Unary { + "kind": "unary", + "type": "-", + "what": Number { + "kind": "number", + "value": "20", + }, + }, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "*", + }, + "right": Number { + "kind": "number", + "value": "10", + }, + "type": "+", + }, + "kind": "expressionstatement", + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test unary precedence with plus 1`] = ` +Program { + "children": [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Unary { + "kind": "unary", + "type": "+", + "what": Number { + "kind": "number", + "value": "20", + }, + }, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "*", + }, + "kind": "expressionstatement", + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test unary precedence with tilde 1`] = ` +Program { + "children": [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Unary { + "kind": "unary", + "type": "~", + "what": Number { + "kind": "number", + "value": "20", + }, + }, + "right": Number { + "kind": "number", + "value": "5", + }, + "type": "*", + }, + "kind": "expressionstatement", + }, + ], + "errors": [], + "kind": "program", +} +`; + exports[`Test unary simple 1`] = ` Program { "children": [ diff --git a/test/snapshot/unary.test.js b/test/snapshot/unary.test.js index d1d992851..c33f8f6d5 100644 --- a/test/snapshot/unary.test.js +++ b/test/snapshot/unary.test.js @@ -28,6 +28,11 @@ describe("Test unary", function () { ["parens (8)", "(~$var);"], ["parens (9)", "(-100);"], ["parens (10)", "-(100);"], + ["precedence over mul", "-20 * 5;"], + ["precedence over add", "-20 + 5;"], + ["precedence over mul and add", "-20 * 5 + 10;"], + ["precedence with plus", "+20 * 5;"], + ["precedence with tilde", "~20 * 5;"], ])("%s", function (_, code) { expect(parser.parseEval(code)).toMatchSnapshot(); });