diff --git a/src/parser/class.js b/src/parser/class.js index 8d98b4b8e..412b59f2c 100644 --- a/src/parser/class.js +++ b/src/parser/class.js @@ -12,9 +12,15 @@ module.exports = { * class ::= class_scope? T_CLASS T_STRING (T_EXTENDS NAMESPACE_NAME)? (T_IMPLEMENTS (NAMESPACE_NAME ',')* NAMESPACE_NAME)? '{' CLASS_BODY '}' * ``` */ - read_class: function(flag) { + read_class: function() { const result = this.node("class"); - this.expect(this.tok.T_CLASS); + const flag = this.read_class_scope(); + // graceful mode : ignore token & go next + if (this.token !== this.tok.T_CLASS) { + this.error(this.tok.T_CLASS); + this.next(); + return null; + } this.next().expect(this.tok.T_STRING); const propName = this.text(); let propExtends = null; diff --git a/src/parser/statement.js b/src/parser/statement.js index 001fee23b..ea91a4f14 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -42,18 +42,9 @@ module.exports = { return this.read_function(false, false); // optional flags case this.tok.T_ABSTRACT: - case this.tok.T_FINAL: { - const flag = this.read_class_scope(); - if (this.token === this.tok.T_CLASS) { - return this.read_class(flag); - } else { - this.error(this.tok.T_CLASS); - this.next(); - return null; - } - } + case this.tok.T_FINAL: case this.tok.T_CLASS: - return this.read_class([0, 0, 0]); + return this.read_class(); case this.tok.T_INTERFACE: return this.read_interface(); case this.tok.T_TRAIT: @@ -155,19 +146,9 @@ module.exports = { return this.read_function(false, false); // optional flags case this.tok.T_ABSTRACT: - case this.tok.T_FINAL: { - const flag = this.read_class_scope(); - if (this.token === this.tok.T_CLASS) { - return this.read_class(flag); - } else { - this.error(this.tok.T_CLASS); - // graceful mode : ignore token & go next - this.next(); - return null; - } - } + case this.tok.T_FINAL: case this.tok.T_CLASS: - return this.read_class([0, 0, 0]); + return this.read_class(); case this.tok.T_INTERFACE: return this.read_interface(); case this.tok.T_TRAIT: @@ -355,13 +336,13 @@ module.exports = { return null; case this.tok.T_STRING: + let result = this.node(); current = [this.token, this.lexer.getState()]; label = this.text(); // AST : https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L457 if (this.next().token === ":") { - result = this.node("label"); this.next(); - return result(label); + return result("label", label); } // default fallback expr / T_STRING '::' (etc...) diff --git a/test/snapshot/__snapshots__/acid.test.js.snap b/test/snapshot/__snapshots__/acid.test.js.snap index 9aa3cc904..7d329fe35 100644 --- a/test/snapshot/__snapshots__/acid.test.js.snap +++ b/test/snapshot/__snapshots__/acid.test.js.snap @@ -1360,7 +1360,7 @@ Program { "line": 47, "offset": 938, }, - "source": "class fooBar implements namespace\\\\fooBaz { + "source": "abstract class fooBar implements namespace\\\\fooBaz { use Line; use foo, bar { foo::baz insteadof bar; @@ -1384,9 +1384,9 @@ Program { } }", "start": Position { - "column": 11, + "column": 2, "line": 25, - "offset": 399, + "offset": 390, }, }, "name": "fooBar", @@ -2776,11 +2776,11 @@ Program { "line": 83, "offset": 1665, }, - "source": ":", + "source": "next:", "start": Position { - "column": 4, + "column": 0, "line": 83, - "offset": 1664, + "offset": 1660, }, }, "name": "next", diff --git a/test/snapshot/__snapshots__/location.test.js.snap b/test/snapshot/__snapshots__/location.test.js.snap index 9a6ba793a..ccbefd5d1 100644 --- a/test/snapshot/__snapshots__/location.test.js.snap +++ b/test/snapshot/__snapshots__/location.test.js.snap @@ -254,6 +254,151 @@ Program { } `; +exports[`Test locations abstract class (inner statement) 1`] = ` +Program { + "children": Array [ + _Function { + "arguments": Array [], + "body": Block { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": true, + "isAnonymous": false, + "isFinal": false, + "kind": "class", + "loc": Location { + "end": Position { + "column": 37, + "line": 1, + "offset": 37, + }, + "source": "abstract class Foo {}", + "start": Position { + "column": 16, + "line": 1, + "offset": 16, + }, + }, + "name": "Foo", + }, + ], + "kind": "block", + "loc": Location { + "end": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + "source": "{ abstract class Foo {} }", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + }, + "byref": false, + "kind": "function", + "loc": Location { + "end": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + "source": "function fn()", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": Identifier { + "kind": "identifier", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "fn", + "start": Position { + "column": 9, + "line": 1, + "offset": 9, + }, + }, + "name": "fn", + }, + "nullable": false, + "type": null, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + "source": "function fn() { abstract class Foo {} }", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations abstract class 1`] = ` +Program { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": true, + "isAnonymous": false, + "isFinal": false, + "kind": "class", + "loc": Location { + "end": Position { + "column": 21, + "line": 1, + "offset": 21, + }, + "source": "abstract class Foo {}", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "Foo", + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 21, + "line": 1, + "offset": 21, + }, + "source": "abstract class Foo {}", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + exports[`Test locations array 1`] = ` Program { "children": Array [ @@ -1071,70 +1216,77 @@ Program { } `; -exports[`Test locations break 1`] = ` +exports[`Test locations bin 2`] = ` Program { "children": Array [ - Break { - "kind": "break", - "level": null, - "loc": Location { - "end": Position { - "column": 6, - "line": 1, - "offset": 6, + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, + "line": 1, + "offset": 4, + }, + "source": "$var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "var", }, - "source": "break;", - "start": Position { - "column": 0, - "line": 1, - "offset": 0, + "loc": Location { + "end": Position { + "column": 12, + "line": 1, + "offset": 12, + }, + "source": "$var + 2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, }, + "right": Number { + "kind": "number", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "2112", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "value": "2112", + }, + "type": "+", }, - }, - ], - "errors": Array [], - "kind": "program", - "loc": Location { - "end": Position { - "column": 6, - "line": 1, - "offset": 6, - }, - "source": "break;", - "start": Position { - "column": 0, - "line": 1, - "offset": 0, - }, - }, -} -`; - -exports[`Test locations class 1`] = ` -Program { - "children": Array [ - Class { - "body": Array [], - "extends": null, - "implements": null, - "isAbstract": false, - "isAnonymous": false, - "isFinal": false, - "kind": "class", + "kind": "expressionstatement", "loc": Location { "end": Position { "column": 12, "line": 1, "offset": 12, }, - "source": "class Foo {}", + "source": "$var + 2112;", "start": Position { "column": 0, "line": 1, "offset": 0, }, }, - "name": "Foo", }, ], "errors": Array [], @@ -1145,7 +1297,7 @@ Program { "line": 1, "offset": 12, }, - "source": "class Foo {}", + "source": "$var + 2112;", "start": Position { "column": 0, "line": 1, @@ -1155,21 +1307,571 @@ Program { } `; -exports[`Test locations clone 1`] = ` +exports[`Test locations bin nested (2) 1`] = ` Program { "children": Array [ ExpressionStatement { - "expression": Clone { - "kind": "clone", - "loc": Location { - "end": Position { - "column": 11, - "line": 1, - "offset": 11, + "expression": Bin { + "kind": "bin", + "left": Bin { + "kind": "bin", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, + "line": 1, + "offset": 4, + }, + "source": "$var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "var", }, - "source": "clone $var;", - "start": Position { - "column": 0, + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "$var + $var + 2112", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "right": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "$var", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "name": "var", + }, + "type": "+", + }, + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var + 2112;", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "right": Number { + "kind": "number", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "2112", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + "value": "2112", + }, + "type": "+", + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var + $var + 2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var + $var + 2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations bin nested 1`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Bin { + "kind": "bin", + "left": Bin { + "kind": "bin", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, + "line": 1, + "offset": 4, + }, + "source": "$var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "var", + }, + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "$var + 2112 + $var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "right": Number { + "kind": "number", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "2112", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "value": "2112", + }, + "type": "+", + }, + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "2112 + $var;", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "right": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "$var", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + "name": "var", + }, + "type": "+", + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var + 2112 + $var;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var + 2112 + $var;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations break 1`] = ` +Program { + "children": Array [ + Break { + "kind": "break", + "level": null, + "loc": Location { + "end": Position { + "column": 6, + "line": 1, + "offset": 6, + }, + "source": "break;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 6, + "line": 1, + "offset": 6, + }, + "source": "break;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations cast 1`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Assign { + "kind": "assign", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, + "line": 1, + "offset": 4, + }, + "source": "$var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "var", + }, + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var = (int) \\"2112\\"", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "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 { + "isDoubleQuote": true, + "kind": "string", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "\\"2112\\"", + "start": Position { + "column": 13, + "line": 1, + "offset": 13, + }, + }, + "raw": "\\"2112\\"", + "unicode": false, + "value": "2112", + }, + }, + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var = (int) \\"2112\\"", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "$var = (int) \\"2112\\"", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations class (inner statement) 1`] = ` +Program { + "children": Array [ + _Function { + "arguments": Array [], + "body": Block { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": false, + "kind": "class", + "loc": Location { + "end": Position { + "column": 28, + "line": 1, + "offset": 28, + }, + "source": "class Foo {}", + "start": Position { + "column": 16, + "line": 1, + "offset": 16, + }, + }, + "name": "Foo", + }, + ], + "kind": "block", + "loc": Location { + "end": Position { + "column": 30, + "line": 1, + "offset": 30, + }, + "source": "{ class Foo {} }", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + }, + "byref": false, + "kind": "function", + "loc": Location { + "end": Position { + "column": 30, + "line": 1, + "offset": 30, + }, + "source": "function fn()", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": Identifier { + "kind": "identifier", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "fn", + "start": Position { + "column": 9, + "line": 1, + "offset": 9, + }, + }, + "name": "fn", + }, + "nullable": false, + "type": null, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 30, + "line": 1, + "offset": 30, + }, + "source": "function fn() { class Foo {} }", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations class 1`] = ` +Program { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": false, + "kind": "class", + "loc": Location { + "end": Position { + "column": 12, + "line": 1, + "offset": 12, + }, + "source": "class Foo {}", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "Foo", + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 12, + "line": 1, + "offset": 12, + }, + "source": "class Foo {}", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations clone 1`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Clone { + "kind": "clone", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "clone $var;", + "start": Position { + "column": 0, "line": 1, "offset": 0, }, @@ -2741,28 +3443,173 @@ Program { "kind": "expressionstatement", "loc": Location { "end": Position { - "column": 8, + "column": 8, + "line": 1, + "offset": 8, + }, + "source": "exit(1);", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + "source": "exit(1);", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations final class (inner statement) 1`] = ` +Program { + "children": Array [ + _Function { + "arguments": Array [], + "body": Block { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": true, + "kind": "class", + "loc": Location { + "end": Position { + "column": 34, + "line": 1, + "offset": 34, + }, + "source": "final class Foo {}", + "start": Position { + "column": 16, + "line": 1, + "offset": 16, + }, + }, + "name": "Foo", + }, + ], + "kind": "block", + "loc": Location { + "end": Position { + "column": 36, + "line": 1, + "offset": 36, + }, + "source": "{ final class Foo {} }", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + }, + "byref": false, + "kind": "function", + "loc": Location { + "end": Position { + "column": 36, + "line": 1, + "offset": 36, + }, + "source": "function fn()", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": Identifier { + "kind": "identifier", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "fn", + "start": Position { + "column": 9, + "line": 1, + "offset": 9, + }, + }, + "name": "fn", + }, + "nullable": false, + "type": null, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 36, + "line": 1, + "offset": 36, + }, + "source": "function fn() { final class Foo {} }", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations final class 1`] = ` +Program { + "children": Array [ + Class { + "body": Array [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": true, + "kind": "class", + "loc": Location { + "end": Position { + "column": 18, "line": 1, - "offset": 8, + "offset": 18, }, - "source": "exit(1);", + "source": "final class Foo {}", "start": Position { "column": 0, "line": 1, "offset": 0, }, }, + "name": "Foo", }, ], "errors": Array [], "kind": "program", "loc": Location { "end": Position { - "column": 8, + "column": 18, "line": 1, - "offset": 8, + "offset": 18, }, - "source": "exit(1);", + "source": "final class Foo {}", "start": Position { "column": 0, "line": 1, @@ -4556,6 +5403,84 @@ Program { } `; +exports[`Test locations label 1`] = ` +Program { + "children": Array [ + Label { + "kind": "label", + "loc": Location { + "end": Position { + "column": 2, + "line": 1, + "offset": 2, + }, + "source": "a:", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "a", + }, + Echo { + "arguments": Array [ + String { + "isDoubleQuote": true, + "kind": "string", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "\\"something\\"", + "start": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + }, + "raw": "\\"something\\"", + "unicode": false, + "value": "something", + }, + ], + "kind": "echo", + "loc": Location { + "end": Position { + "column": 20, + "line": 1, + "offset": 20, + }, + "source": "echo \\"something\\";", + "start": Position { + "column": 3, + "line": 1, + "offset": 3, + }, + }, + "shortForm": false, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 20, + "line": 1, + "offset": 20, + }, + "source": "a: echo \\"something\\";", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + exports[`Test locations list 1`] = ` Program { "children": Array [ @@ -4912,6 +5837,110 @@ Program { } `; +exports[`Test locations method (public) 1`] = ` +Program { + "children": Array [ + Class { + "body": Array [ + Method { + "arguments": Array [], + "body": Block { + "children": Array [], + "kind": "block", + "loc": Location { + "end": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + "source": "{}", + "start": Position { + "column": 37, + "line": 1, + "offset": 37, + }, + }, + }, + "byref": false, + "isAbstract": false, + "isFinal": false, + "isStatic": false, + "kind": "method", + "loc": Location { + "end": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + "source": "function method()", + "start": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + }, + "name": Identifier { + "kind": "identifier", + "loc": Location { + "end": Position { + "column": 34, + "line": 1, + "offset": 34, + }, + "source": "method", + "start": Position { + "column": 28, + "line": 1, + "offset": 28, + }, + }, + "name": "method", + }, + "nullable": false, + "type": null, + "visibility": "public", + }, + ], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": false, + "kind": "class", + "loc": Location { + "end": Position { + "column": 41, + "line": 1, + "offset": 41, + }, + "source": "class Foo { public function method() {} }", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "Foo", + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 41, + "line": 1, + "offset": 41, + }, + "source": "class Foo { public function method() {} }", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + exports[`Test locations method 1`] = ` Program { "children": Array [ @@ -5558,44 +6587,175 @@ Program { "kind": "number", "loc": Location { "end": Position { - "column": 5, + "column": 5, + "line": 1, + "offset": 5, + }, + "source": "2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "value": "2112", + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 5, + "line": 1, + "offset": 5, + }, + "source": "2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 5, + "line": 1, + "offset": 5, + }, + "source": "2112;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations parameter 1`] = ` +Program { + "children": Array [ + _Function { + "arguments": Array [ + Parameter { + "byref": false, + "kind": "parameter", + "loc": Location { + "end": Position { + "column": 28, + "line": 1, + "offset": 28, + }, + "source": "?int $foo = 2112", + "start": Position { + "column": 12, + "line": 1, + "offset": 12, + }, + }, + "name": "foo", + "nullable": true, + "type": TypeReference { + "kind": "typereference", + "loc": Location { + "end": Position { + "column": 16, + "line": 1, + "offset": 16, + }, + "source": "int", + "start": Position { + "column": 13, + "line": 1, + "offset": 13, + }, + }, + "name": "int", + }, + "value": Number { + "kind": "number", + "loc": Location { + "end": Position { + "column": 28, + "line": 1, + "offset": 28, + }, + "source": "2112", + "start": Position { + "column": 24, + "line": 1, + "offset": 24, + }, + }, + "value": "2112", + }, + "variadic": false, + }, + ], + "body": Block { + "children": Array [], + "kind": "block", + "loc": Location { + "end": Position { + "column": 32, "line": 1, - "offset": 5, + "offset": 32, }, - "source": "2112;", + "source": "{}", "start": Position { - "column": 0, + "column": 30, "line": 1, - "offset": 0, + "offset": 30, }, }, - "value": "2112", }, - "kind": "expressionstatement", + "byref": false, + "kind": "function", "loc": Location { "end": Position { - "column": 5, + "column": 32, "line": 1, - "offset": 5, + "offset": 32, }, - "source": "2112;", + "source": "function fn(?int $foo = 2112)", "start": Position { "column": 0, "line": 1, "offset": 0, }, }, + "name": Identifier { + "kind": "identifier", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "fn", + "start": Position { + "column": 9, + "line": 1, + "offset": 9, + }, + }, + "name": "fn", + }, + "nullable": false, + "type": null, }, ], "errors": Array [], "kind": "program", "loc": Location { "end": Position { - "column": 5, + "column": 32, "line": 1, - "offset": 5, + "offset": 32, }, - "source": "2112;", + "source": "function fn(?int $foo = 2112) {}", "start": Position { "column": 0, "line": 1, @@ -5763,44 +6923,495 @@ Program { "kind": "string", "loc": Location { "end": Position { - "column": 17, + "column": 17, + "line": 1, + "offset": 17, + }, + "source": "\\"something\\"", + "start": Position { + "column": 6, + "line": 1, + "offset": 6, + }, + }, + "raw": "\\"something\\"", + "unicode": false, + "value": "something", + }, + "kind": "print", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "print \\"something\\";", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "print \\"something\\";", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "print \\"something\\";", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations retif 1`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Assign { + "kind": "assign", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, + "line": 1, + "offset": 4, + }, + "source": "$var", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "name": "var", + }, + "loc": Location { + "end": Position { + "column": 27, + "line": 1, + "offset": 27, + }, + "source": "$var = $var ? true : false;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + "operator": "=", + "right": RetIf { + "falseExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 26, + "line": 1, + "offset": 26, + }, + "source": "false", + "start": Position { + "column": 21, + "line": 1, + "offset": 21, + }, + }, + "raw": "false", + "value": false, + }, + "kind": "retif", + "loc": Location { + "end": Position { + "column": 26, + "line": 1, + "offset": 26, + }, + "source": "$var ? true : false", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "test": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 11, + "line": 1, + "offset": 11, + }, + "source": "$var", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "name": "var", + }, + "trueExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 18, + "line": 1, + "offset": 18, + }, + "source": "true", + "start": Position { + "column": 14, + "line": 1, + "offset": 14, + }, + }, + "raw": "true", + "value": true, + }, + }, + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 27, + "line": 1, + "offset": 27, + }, + "source": "$var = $var ? true : false;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 27, + "line": 1, + "offset": 27, + }, + "source": "$var = $var ? true : false;", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + +exports[`Test locations retif nested 1`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Assign { + "kind": "assign", + "left": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 4, "line": 1, - "offset": 17, + "offset": 4, }, - "source": "\\"something\\"", + "source": "$var", "start": Position { - "column": 6, + "column": 0, "line": 1, - "offset": 6, + "offset": 0, }, }, - "raw": "\\"something\\"", - "unicode": false, - "value": "something", + "name": "var", }, - "kind": "print", "loc": Location { "end": Position { - "column": 18, + "column": 79, "line": 1, - "offset": 18, + "offset": 79, }, - "source": "print \\"something\\";", + "source": "$var = ($one ? true : false) ? ($two ? true : false) : ($three ? true : false);", "start": Position { "column": 0, "line": 1, "offset": 0, }, }, + "operator": "=", + "right": RetIf { + "falseExpr": RetIf { + "falseExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 77, + "line": 1, + "offset": 77, + }, + "source": "false", + "start": Position { + "column": 72, + "line": 1, + "offset": 72, + }, + }, + "raw": "false", + "value": false, + }, + "kind": "retif", + "loc": Location { + "end": Position { + "column": 77, + "line": 1, + "offset": 77, + }, + "source": "$three ? true : false", + "start": Position { + "column": 56, + "line": 1, + "offset": 56, + }, + }, + "parenthesizedExpression": true, + "test": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 62, + "line": 1, + "offset": 62, + }, + "source": "$three", + "start": Position { + "column": 56, + "line": 1, + "offset": 56, + }, + }, + "name": "three", + }, + "trueExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 69, + "line": 1, + "offset": 69, + }, + "source": "true", + "start": Position { + "column": 65, + "line": 1, + "offset": 65, + }, + }, + "raw": "true", + "value": true, + }, + }, + "kind": "retif", + "loc": Location { + "end": Position { + "column": 78, + "line": 1, + "offset": 78, + }, + "source": "($one ? true : false) ? ($two ? true : false) : ($three ? true : false)", + "start": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + }, + "test": RetIf { + "falseExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 27, + "line": 1, + "offset": 27, + }, + "source": "false", + "start": Position { + "column": 22, + "line": 1, + "offset": 22, + }, + }, + "raw": "false", + "value": false, + }, + "kind": "retif", + "loc": Location { + "end": Position { + "column": 27, + "line": 1, + "offset": 27, + }, + "source": "$one ? true : false", + "start": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + }, + "parenthesizedExpression": true, + "test": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 12, + "line": 1, + "offset": 12, + }, + "source": "$one", + "start": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + }, + "name": "one", + }, + "trueExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 19, + "line": 1, + "offset": 19, + }, + "source": "true", + "start": Position { + "column": 15, + "line": 1, + "offset": 15, + }, + }, + "raw": "true", + "value": true, + }, + }, + "trueExpr": RetIf { + "falseExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 51, + "line": 1, + "offset": 51, + }, + "source": "false", + "start": Position { + "column": 46, + "line": 1, + "offset": 46, + }, + }, + "raw": "false", + "value": false, + }, + "kind": "retif", + "loc": Location { + "end": Position { + "column": 51, + "line": 1, + "offset": 51, + }, + "source": "$two ? true : false", + "start": Position { + "column": 32, + "line": 1, + "offset": 32, + }, + }, + "parenthesizedExpression": true, + "test": Variable { + "byref": false, + "curly": false, + "kind": "variable", + "loc": Location { + "end": Position { + "column": 36, + "line": 1, + "offset": 36, + }, + "source": "$two", + "start": Position { + "column": 32, + "line": 1, + "offset": 32, + }, + }, + "name": "two", + }, + "trueExpr": Boolean { + "kind": "boolean", + "loc": Location { + "end": Position { + "column": 43, + "line": 1, + "offset": 43, + }, + "source": "true", + "start": Position { + "column": 39, + "line": 1, + "offset": 39, + }, + }, + "raw": "true", + "value": true, + }, + }, + }, }, "kind": "expressionstatement", "loc": Location { "end": Position { - "column": 18, + "column": 79, "line": 1, - "offset": 18, + "offset": 79, }, - "source": "print \\"something\\";", + "source": "$var = ($one ? true : false) ? ($two ? true : false) : ($three ? true : false);", "start": Position { "column": 0, "line": 1, @@ -5813,11 +7424,11 @@ Program { "kind": "program", "loc": Location { "end": Position { - "column": 18, + "column": 79, "line": 1, - "offset": 18, + "offset": 79, }, - "source": "print \\"something\\";", + "source": "$var = ($one ? true : false) ? ($two ? true : false) : ($three ? true : false);", "start": Position { "column": 0, "line": 1, @@ -6007,6 +7618,95 @@ Program { } `; +exports[`Test locations silent 2`] = ` +Program { + "children": Array [ + ExpressionStatement { + "expression": Silent { + "expr": Call { + "arguments": Array [], + "kind": "call", + "loc": Location { + "end": Position { + "column": 7, + "line": 1, + "offset": 7, + }, + "source": "()", + "start": Position { + "column": 5, + "line": 1, + "offset": 5, + }, + }, + "what": ClassReference { + "kind": "classreference", + "loc": Location { + "end": Position { + "column": 5, + "line": 1, + "offset": 5, + }, + "source": "call", + "start": Position { + "column": 1, + "line": 1, + "offset": 1, + }, + }, + "name": "call", + "resolution": "uqn", + }, + }, + "kind": "silent", + "loc": Location { + "end": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + "source": "@call();", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + "kind": "expressionstatement", + "loc": Location { + "end": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + "source": "@call();", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, + }, + ], + "errors": Array [], + "kind": "program", + "loc": Location { + "end": Position { + "column": 8, + "line": 1, + "offset": 8, + }, + "source": "@call();", + "start": Position { + "column": 0, + "line": 1, + "offset": 0, + }, + }, +} +`; + exports[`Test locations static 1`] = ` Program { "children": Array [ diff --git a/test/snapshot/location.test.js b/test/snapshot/location.test.js index 58da2696b..c908f0d2b 100644 --- a/test/snapshot/location.test.js +++ b/test/snapshot/location.test.js @@ -326,6 +326,19 @@ describe('Test locations', function() { ) ).toMatchSnapshot(); }); + it('label', function() { + expect( + parser.parseEval( + 'a: echo "something";', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); it('function', function() { expect( parser.parseEval( @@ -352,6 +365,71 @@ describe('Test locations', function() { ) ).toMatchSnapshot(); }); + it('abstract class', function() { + expect( + parser.parseEval( + 'abstract class Foo {}', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('final class', function() { + expect( + parser.parseEval( + 'final class Foo {}', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('class (inner statement)', function() { + expect( + parser.parseEval( + 'function fn() { class Foo {} }', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('abstract class (inner statement)', function() { + expect( + parser.parseEval( + 'function fn() { abstract class Foo {} }', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('final class (inner statement)', function() { + expect( + parser.parseEval( + 'function fn() { final class Foo {} }', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); it('interface', function() { expect( parser.parseEval( @@ -1029,4 +1107,121 @@ string";`, ) ).toMatchSnapshot(); }); + it('method (public)', function() { + expect( + parser.parseEval( + 'class Foo { public function method() {} }', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('cast', function() { + expect( + parser.parseEval( + '$var = (int) "2112"', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('retif', function() { + expect( + parser.parseEval( + '$var = $var ? true : false;', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('retif nested', function() { + expect( + parser.parseEval( + '$var = ($one ? true : false) ? ($two ? true : false) : ($three ? true : false);', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('parameter', function() { + expect( + parser.parseEval( + 'function fn(?int $foo = 2112) {}', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('bin', function() { + expect( + parser.parseEval( + '$var + 2112;', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('bin nested', function() { + expect( + parser.parseEval( + '$var + 2112 + $var;', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('bin nested (2)', function() { + expect( + parser.parseEval( + '$var + $var + 2112;', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); + it('silent', function() { + expect( + parser.parseEval( + '@call();', + { + ast: { + withPositions: true, + withSource: true + } + } + ) + ).toMatchSnapshot(); + }); });