From 30e229e040ed28817138bc2161de8d94bcbbb0eb Mon Sep 17 00:00:00 2001 From: Thomas Genin Date: Tue, 10 Jan 2023 23:14:44 -0800 Subject: [PATCH] feat: support for readonly class (#1046) --- src/ast/class.js | 1 + src/ast/declaration.js | 1 + src/parser/class.js | 32 +++- src/parser/statement.js | 1 + test/snapshot/__snapshots__/acid.test.js.snap | 9 + .../__snapshots__/attributes.test.js.snap | 19 +++ .../snapshot/__snapshots__/block.test.js.snap | 3 + test/snapshot/__snapshots__/call.test.js.snap | 6 + .../snapshot/__snapshots__/class.test.js.snap | 154 ++++++++++++++++++ .../__snapshots__/classconstant.test.js.snap | 5 + .../__snapshots__/comment.test.js.snap | 6 + test/snapshot/__snapshots__/enum.test.js.snap | 7 + test/snapshot/__snapshots__/expr.test.js.snap | 1 + .../__snapshots__/function.test.js.snap | 30 +--- .../__snapshots__/graceful.test.js.snap | 5 + .../__snapshots__/heredoc.test.js.snap | 1 + .../__snapshots__/location.test.js.snap | 14 ++ .../__snapshots__/namespace.test.js.snap | 7 + test/snapshot/__snapshots__/new.test.js.snap | 7 + .../__snapshots__/nowdoc.test.js.snap | 1 + test/snapshot/__snapshots__/php5.test.js.snap | 2 + .../__snapshots__/property.test.js.snap | 22 +++ .../propertystatement.test.js.snap | 4 + .../__snapshots__/statement.test.js.snap | 3 + .../traitprecedence.test.js.snap | 1 + test/snapshot/class.test.js | 19 +++ types.d.ts | 1 + 27 files changed, 325 insertions(+), 37 deletions(-) diff --git a/src/ast/class.js b/src/ast/class.js index 7187c786d..637783077 100644 --- a/src/ast/class.js +++ b/src/ast/class.js @@ -19,6 +19,7 @@ const KIND = "class"; * @property {boolean} isAnonymous * @property {boolean} isAbstract * @property {boolean} isFinal + * @property {boolean} isReadonly * @property {AttrGroup[]} attrGroups */ module.exports = Declaration.extends( diff --git a/src/ast/declaration.js b/src/ast/declaration.js index 67a6f8d62..cfc6245fb 100644 --- a/src/ast/declaration.js +++ b/src/ast/declaration.js @@ -39,6 +39,7 @@ const Declaration = Statement.extends( Declaration.prototype.parseFlags = function (flags) { this.isAbstract = flags[2] === 1; this.isFinal = flags[2] === 2; + this.isReadonly = flags[3] === 1; if (this.kind !== "class") { if (flags[0] === -1) { this.visibility = IS_UNDEFINED; diff --git a/src/parser/class.js b/src/parser/class.js index 37dafd2d1..2ee4e13fb 100644 --- a/src/parser/class.js +++ b/src/parser/class.js @@ -36,21 +36,35 @@ module.exports = { }, read_class_modifiers: function () { - return [0, 0, this.read_class_modifier()]; + const modifier = this.read_class_modifier({ + readonly: 0, + final_or_abstract: 0, + }); + return [0, 0, modifier.final_or_abstract, modifier.readonly]; }, - read_class_modifier: function () { - const result = 0; - - if (this.token === this.tok.T_ABSTRACT) { + read_class_modifier: function (memo) { + if (this.token === this.tok.T_READ_ONLY) { + this.next(); + memo.readonly = 1; + memo = this.read_class_modifier(memo); + } else if ( + memo.final_or_abstract === 0 && + this.token === this.tok.T_ABSTRACT + ) { this.next(); - return 1; - } else if (this.token === this.tok.T_FINAL) { + memo.final_or_abstract = 1; + memo = this.read_class_modifier(memo); + } else if ( + memo.final_or_abstract === 0 && + this.token === this.tok.T_FINAL + ) { this.next(); - return 2; + memo.final_or_abstract = 2; + memo = this.read_class_modifier(memo); } - return result; + return memo; }, /* diff --git a/src/parser/statement.js b/src/parser/statement.js index e2d2282e3..ebcf7d1bd 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -47,6 +47,7 @@ module.exports = { // optional flags case this.tok.T_ABSTRACT: case this.tok.T_FINAL: + case this.tok.T_READ_ONLY: case this.tok.T_CLASS: return this.read_class_declaration_statement(attrs); case this.tok.T_INTERFACE: diff --git a/test/snapshot/__snapshots__/acid.test.js.snap b/test/snapshot/__snapshots__/acid.test.js.snap index b6c7b643e..3479658c5 100644 --- a/test/snapshot/__snapshots__/acid.test.js.snap +++ b/test/snapshot/__snapshots__/acid.test.js.snap @@ -1540,6 +1540,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": true, + "isReadonly": false, "isStatic": false, "kind": "method", "leadingComments": [ @@ -1625,6 +1626,7 @@ Program { "isAbstract": true, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "leadingComments": [ CommentBlock { @@ -1713,6 +1715,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -1773,6 +1776,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -1833,6 +1837,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "loc": Location { @@ -2823,6 +2828,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -2936,6 +2942,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -5284,6 +5291,7 @@ next: "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -5343,6 +5351,7 @@ next: "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { diff --git a/test/snapshot/__snapshots__/attributes.test.js.snap b/test/snapshot/__snapshots__/attributes.test.js.snap index 501ab82d5..3ac601a09 100644 --- a/test/snapshot/__snapshots__/attributes.test.js.snap +++ b/test/snapshot/__snapshots__/attributes.test.js.snap @@ -34,6 +34,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -287,6 +288,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -340,6 +342,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -462,6 +465,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -538,6 +542,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -589,6 +594,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -605,6 +611,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -659,6 +666,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -990,6 +998,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1174,6 +1183,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1420,6 +1430,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1525,6 +1536,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1691,6 +1703,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1711,6 +1724,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1731,6 +1745,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1747,6 +1762,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1775,6 +1791,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "leadingComments": [ @@ -1799,6 +1816,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "leadingComments": [ CommentLine { @@ -1968,6 +1986,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/block.test.js.snap b/test/snapshot/__snapshots__/block.test.js.snap index 9720a8d34..6554522b6 100644 --- a/test/snapshot/__snapshots__/block.test.js.snap +++ b/test/snapshot/__snapshots__/block.test.js.snap @@ -88,6 +88,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -667,6 +668,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -683,6 +685,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/call.test.js.snap b/test/snapshot/__snapshots__/call.test.js.snap index e0b687857..3cb9f66b4 100644 --- a/test/snapshot/__snapshots__/call.test.js.snap +++ b/test/snapshot/__snapshots__/call.test.js.snap @@ -1213,6 +1213,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1229,6 +1230,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1339,6 +1341,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1355,6 +1358,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1450,6 +1454,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1466,6 +1471,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/class.test.js.snap b/test/snapshot/__snapshots__/class.test.js.snap index 244842bab..488261ceb 100644 --- a/test/snapshot/__snapshots__/class.test.js.snap +++ b/test/snapshot/__snapshots__/class.test.js.snap @@ -93,6 +93,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": true, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -113,6 +114,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -135,6 +137,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -177,6 +180,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "leadingComments": [ @@ -243,6 +247,7 @@ Program { "byref": false, "isAbstract": true, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -413,6 +418,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "name": Identifier { @@ -429,6 +435,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -476,6 +483,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -560,6 +568,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -607,6 +616,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -674,6 +684,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -690,6 +701,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -751,6 +763,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -901,6 +914,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -917,6 +931,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -984,6 +999,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1000,6 +1016,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1048,6 +1065,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1064,6 +1082,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1103,6 +1122,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1119,6 +1139,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1157,6 +1178,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1196,6 +1218,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1391,6 +1414,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1474,6 +1498,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1532,6 +1557,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1568,6 +1594,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": true, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1725,6 +1752,7 @@ Program { "byref": true, "isAbstract": true, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -1745,6 +1773,7 @@ Program { "isAbstract": true, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1768,6 +1797,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1799,6 +1829,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1822,6 +1853,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1845,6 +1877,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1900,6 +1933,127 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, + "kind": "class", + "name": Identifier { + "kind": "identifier", + "name": "Foo", + }, + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test classes readonly class in PHP8.2 should support abstract readonly 1`] = ` +Program { + "children": [ + Class { + "attrGroups": [], + "body": [], + "extends": null, + "implements": null, + "isAbstract": true, + "isAnonymous": false, + "isFinal": false, + "isReadonly": true, + "kind": "class", + "name": Identifier { + "kind": "identifier", + "name": "Foo", + }, + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test classes readonly class in PHP8.2 should support final readonly 1`] = ` +Program { + "children": [ + Class { + "attrGroups": [], + "body": [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": true, + "isReadonly": true, + "kind": "class", + "name": Identifier { + "kind": "identifier", + "name": "Foo", + }, + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test classes readonly class in PHP8.2 should support readonly 1`] = ` +Program { + "children": [ + Class { + "attrGroups": [], + "body": [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": false, + "isReadonly": true, + "kind": "class", + "name": Identifier { + "kind": "identifier", + "name": "Foo", + }, + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test classes readonly class in PHP8.2 should support readonly abstract 1`] = ` +Program { + "children": [ + Class { + "attrGroups": [], + "body": [], + "extends": null, + "implements": null, + "isAbstract": true, + "isAnonymous": false, + "isFinal": false, + "isReadonly": true, + "kind": "class", + "name": Identifier { + "kind": "identifier", + "name": "Foo", + }, + }, + ], + "errors": [], + "kind": "program", +} +`; + +exports[`Test classes readonly class in PHP8.2 should support readonly final 1`] = ` +Program { + "children": [ + Class { + "attrGroups": [], + "body": [], + "extends": null, + "implements": null, + "isAbstract": false, + "isAnonymous": false, + "isFinal": true, + "isReadonly": true, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/classconstant.test.js.snap b/test/snapshot/__snapshots__/classconstant.test.js.snap index b7603c3ac..0a5018fcb 100644 --- a/test/snapshot/__snapshots__/classconstant.test.js.snap +++ b/test/snapshot/__snapshots__/classconstant.test.js.snap @@ -47,6 +47,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -92,6 +93,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -137,6 +139,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -182,6 +185,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -227,6 +231,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/comment.test.js.snap b/test/snapshot/__snapshots__/comment.test.js.snap index a8f0b9810..0288dac0c 100644 --- a/test/snapshot/__snapshots__/comment.test.js.snap +++ b/test/snapshot/__snapshots__/comment.test.js.snap @@ -688,6 +688,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "leadingComments": [ @@ -726,6 +727,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "leadingComments": [ @@ -772,6 +774,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "leadingComments": [ @@ -797,6 +800,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "leadingComments": [ CommentBlock { @@ -1930,6 +1934,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "leadingComments": [ @@ -1960,6 +1965,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "leadingComments": [ CommentBlock { diff --git a/test/snapshot/__snapshots__/enum.test.js.snap b/test/snapshot/__snapshots__/enum.test.js.snap index d0123d0f4..53b56f638 100644 --- a/test/snapshot/__snapshots__/enum.test.js.snap +++ b/test/snapshot/__snapshots__/enum.test.js.snap @@ -81,6 +81,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -130,6 +131,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": true, "kind": "method", "name": Identifier { @@ -295,6 +297,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -311,6 +314,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -363,6 +367,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -383,6 +388,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -401,6 +407,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/expr.test.js.snap b/test/snapshot/__snapshots__/expr.test.js.snap index 9613bc9aa..ba219eb0d 100644 --- a/test/snapshot/__snapshots__/expr.test.js.snap +++ b/test/snapshot/__snapshots__/expr.test.js.snap @@ -2218,6 +2218,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, diff --git a/test/snapshot/__snapshots__/function.test.js.snap b/test/snapshot/__snapshots__/function.test.js.snap index d7723d4bc..2879e51d4 100644 --- a/test/snapshot/__snapshots__/function.test.js.snap +++ b/test/snapshot/__snapshots__/function.test.js.snap @@ -29,18 +29,6 @@ Program { "nullable": false, "type": null, }, - ExpressionStatement { - "expression": undefined, - "kind": "expressionstatement", - }, - ExpressionStatement { - "expression": Name { - "kind": "name", - "name": "int", - "resolution": "uqn", - }, - "kind": "expressionstatement", - }, ExpressionStatement { "expression": Variable { "curly": false, @@ -98,26 +86,12 @@ Program { "token": "'readonly' (T_READ_ONLY)", }, Error { - "expected": "EXPR", + "expected": 187, "kind": "error", "line": 2, - "message": "Parse Error : syntax error, unexpected 'readonly' (T_READ_ONLY) on line 2", - "token": "'readonly' (T_READ_ONLY)", - }, - Error { - "expected": ";", - "kind": "error", - "line": 2, - "message": "Parse Error : syntax error, unexpected 'int' (T_STRING), expecting ';' on line 2", + "message": "Parse Error : syntax error, unexpected 'int' (T_STRING), expecting T_CLASS on line 2", "token": "'int' (T_STRING)", }, - Error { - "expected": ";", - "kind": "error", - "line": 2, - "message": "Parse Error : syntax error, unexpected '$id' (T_VARIABLE), expecting ';' on line 2", - "token": "'$id' (T_VARIABLE)", - }, Error { "expected": ";", "kind": "error", diff --git a/test/snapshot/__snapshots__/graceful.test.js.snap b/test/snapshot/__snapshots__/graceful.test.js.snap index 7682fd39a..cf45e3329 100644 --- a/test/snapshot/__snapshots__/graceful.test.js.snap +++ b/test/snapshot/__snapshots__/graceful.test.js.snap @@ -324,6 +324,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -467,6 +468,7 @@ Program { "byref": false, "isAbstract": true, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -483,6 +485,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -529,6 +532,7 @@ Program { "byref": false, "isAbstract": true, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -587,6 +591,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { diff --git a/test/snapshot/__snapshots__/heredoc.test.js.snap b/test/snapshot/__snapshots__/heredoc.test.js.snap index c0487a38c..a45680f28 100644 --- a/test/snapshot/__snapshots__/heredoc.test.js.snap +++ b/test/snapshot/__snapshots__/heredoc.test.js.snap @@ -1759,6 +1759,7 @@ FOOBAR", "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/location.test.js.snap b/test/snapshot/__snapshots__/location.test.js.snap index a4d0b8892..24c92943f 100644 --- a/test/snapshot/__snapshots__/location.test.js.snap +++ b/test/snapshot/__snapshots__/location.test.js.snap @@ -854,6 +854,7 @@ Program { "isAbstract": true, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -967,6 +968,7 @@ Program { "isAbstract": true, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -3116,6 +3118,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -3229,6 +3232,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -5683,6 +5687,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": true, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -5796,6 +5801,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": true, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -8378,6 +8384,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -8420,6 +8427,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -8500,6 +8508,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -8542,6 +8551,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -8922,6 +8932,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -12464,6 +12475,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -12779,6 +12791,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -12897,6 +12910,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { diff --git a/test/snapshot/__snapshots__/namespace.test.js.snap b/test/snapshot/__snapshots__/namespace.test.js.snap index f96e736ba..c59e4055c 100644 --- a/test/snapshot/__snapshots__/namespace.test.js.snap +++ b/test/snapshot/__snapshots__/namespace.test.js.snap @@ -282,6 +282,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -444,6 +445,7 @@ Program { "byref": true, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -540,6 +542,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "leadingComments": [ CommentBlock { @@ -816,6 +819,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -978,6 +982,7 @@ Program { "byref": true, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "loc": Location { @@ -1074,6 +1079,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "loc": Location { "end": Position { @@ -1612,6 +1618,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/new.test.js.snap b/test/snapshot/__snapshots__/new.test.js.snap index 5d394d56d..58d7c35f8 100644 --- a/test/snapshot/__snapshots__/new.test.js.snap +++ b/test/snapshot/__snapshots__/new.test.js.snap @@ -52,6 +52,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -93,6 +94,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -145,6 +147,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -181,6 +184,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -209,6 +213,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -242,6 +247,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, @@ -285,6 +291,7 @@ Program { "isAbstract": false, "isAnonymous": true, "isFinal": false, + "isReadonly": false, "kind": "class", "name": null, }, diff --git a/test/snapshot/__snapshots__/nowdoc.test.js.snap b/test/snapshot/__snapshots__/nowdoc.test.js.snap index fdc5d775a..aaed12f60 100644 --- a/test/snapshot/__snapshots__/nowdoc.test.js.snap +++ b/test/snapshot/__snapshots__/nowdoc.test.js.snap @@ -251,6 +251,7 @@ FOOBAR", "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/php5.test.js.snap b/test/snapshot/__snapshots__/php5.test.js.snap index 1512da4de..e8fcd25a5 100644 --- a/test/snapshot/__snapshots__/php5.test.js.snap +++ b/test/snapshot/__snapshots__/php5.test.js.snap @@ -26,6 +26,7 @@ Program { "byref": false, "isAbstract": false, "isFinal": false, + "isReadonly": false, "isStatic": false, "kind": "method", "name": Identifier { @@ -42,6 +43,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/property.test.js.snap b/test/snapshot/__snapshots__/property.test.js.snap index 9d84d45e3..59f1edd5f 100644 --- a/test/snapshot/__snapshots__/property.test.js.snap +++ b/test/snapshot/__snapshots__/property.test.js.snap @@ -31,6 +31,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -77,6 +78,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -120,6 +122,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -166,6 +169,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -209,6 +213,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -252,6 +257,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -298,6 +304,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -344,6 +351,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -387,6 +395,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -433,6 +442,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -503,6 +513,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -563,6 +574,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -617,6 +629,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -664,6 +677,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -711,6 +725,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -760,6 +775,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -825,6 +841,7 @@ EOD", "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -875,6 +892,7 @@ EOD", "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -945,6 +963,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -994,6 +1013,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1040,6 +1060,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -1083,6 +1104,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/propertystatement.test.js.snap b/test/snapshot/__snapshots__/propertystatement.test.js.snap index ec5a17db6..3e3d14d9c 100644 --- a/test/snapshot/__snapshots__/propertystatement.test.js.snap +++ b/test/snapshot/__snapshots__/propertystatement.test.js.snap @@ -55,6 +55,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -122,6 +123,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -165,6 +167,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -208,6 +211,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/statement.test.js.snap b/test/snapshot/__snapshots__/statement.test.js.snap index 4f642af40..e5440f414 100644 --- a/test/snapshot/__snapshots__/statement.test.js.snap +++ b/test/snapshot/__snapshots__/statement.test.js.snap @@ -402,6 +402,7 @@ Program { "isAbstract": true, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -416,6 +417,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": true, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", @@ -430,6 +432,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/__snapshots__/traitprecedence.test.js.snap b/test/snapshot/__snapshots__/traitprecedence.test.js.snap index e12852778..112fc3282 100644 --- a/test/snapshot/__snapshots__/traitprecedence.test.js.snap +++ b/test/snapshot/__snapshots__/traitprecedence.test.js.snap @@ -71,6 +71,7 @@ Program { "isAbstract": false, "isAnonymous": false, "isFinal": false, + "isReadonly": false, "kind": "class", "name": Identifier { "kind": "identifier", diff --git a/test/snapshot/class.test.js b/test/snapshot/class.test.js index 7d2daab06..a4c66f769 100644 --- a/test/snapshot/class.test.js +++ b/test/snapshot/class.test.js @@ -213,6 +213,25 @@ describe("Test classes", function () { expect(ast).toMatchSnapshot(); }); + describe("readonly class in PHP8.2", function () { + [ + "readonly", + "readonly abstract", + "abstract readonly", + "final readonly", + "readonly final", + ].forEach(function (token) { + it("should support " + token, function () { + expect( + parser.parseEval(` + ${token} class Foo { + } + `) + ).toMatchSnapshot(); + }); + }); + }); + it("empty", function () { expect(parser.parseEval("class Foo {}")).toMatchSnapshot(); }); diff --git a/types.d.ts b/types.d.ts index c31816aaf..df53ded31 100644 --- a/types.d.ts +++ b/types.d.ts @@ -148,6 +148,7 @@ declare module "php-parser" { isAnonymous: boolean; isAbstract: boolean; isFinal: boolean; + isReadonly: boolean; attrGroups: AttrGroup[]; } /**