Skip to content

Commit 980cf46

Browse files
refactor: extends and implements
1 parent 6481747 commit 980cf46

File tree

6 files changed

+182
-27
lines changed

6 files changed

+182
-27
lines changed

src/parser/class.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
* class ::= class_scope? T_CLASS T_STRING (T_EXTENDS NAMESPACE_NAME)? (T_IMPLEMENTS (NAMESPACE_NAME ',')* NAMESPACE_NAME)? '{' CLASS_BODY '}'
1313
* ```
1414
*/
15-
read_class: function() {
15+
read_class_declaration_statement: function() {
1616
const result = this.node("class");
1717
const flag = this.read_class_scope();
1818
// graceful mode : ignore token & go next
@@ -26,14 +26,8 @@ module.exports = {
2626
const name = this.text();
2727
this.next();
2828
propName = propName(name);
29-
let propExtends = null;
30-
if (this.token == this.tok.T_EXTENDS) {
31-
propExtends = this.next().read_namespace_name();
32-
}
33-
let propImplements = null;
34-
if (this.token == this.tok.T_IMPLEMENTS) {
35-
propImplements = this.next().read_name_list();
36-
}
29+
const propExtends = this.read_extends_from();
30+
const propImplements = this.read_implements_list();
3731
this.expect("{");
3832
const body = this.next().read_class_body();
3933
return result(propName, propExtends, propImplements, body, flag);
@@ -278,7 +272,7 @@ module.exports = {
278272
* interface ::= T_INTERFACE T_STRING (T_EXTENDS (NAMESPACE_NAME ',')* NAMESPACE_NAME)? '{' INTERFACE_BODY '}'
279273
* ```
280274
*/
281-
read_interface: function() {
275+
read_interface_declaration_statement: function() {
282276
const result = this.node("interface");
283277
if (this.token !== this.tok.T_INTERFACE) {
284278
this.error(this.tok.T_INTERFACE);
@@ -290,10 +284,7 @@ module.exports = {
290284
const name = this.text();
291285
this.next();
292286
propName = propName(name);
293-
let propExtends = null;
294-
if (this.token === this.tok.T_EXTENDS) {
295-
propExtends = this.next().read_name_list();
296-
}
287+
const propExtends = this.read_interface_extends_list();
297288
this.expect("{");
298289
const body = this.next().read_interface_body();
299290
return result(propName, propExtends, body);

src/parser/expr.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ module.exports = {
456456
// returns variable | scalar
457457
return expr;
458458
},
459+
459460
/**
460461
* ```ebnf
461462
* new_expr ::= T_NEW (namespace_name function_argument_list) | (T_CLASS ... class declaration)
@@ -469,18 +470,12 @@ module.exports = {
469470
if (this.token === this.tok.T_CLASS) {
470471
const what = this.node("class");
471472
// Annonymous class declaration
472-
let propExtends = null,
473-
propImplements = null,
474-
body = null;
475473
if (this.next().token === "(") {
476474
args = this.read_function_argument_list();
477475
}
478-
if (this.token == this.tok.T_EXTENDS) {
479-
propExtends = this.next().read_namespace_name();
480-
}
481-
if (this.token == this.tok.T_IMPLEMENTS) {
482-
propImplements = this.next().read_name_list();
483-
}
476+
const propExtends = this.read_extends_from();
477+
const propImplements = this.read_implements_list();
478+
let body = null;
484479
if (this.expect("{")) {
485480
body = this.next().read_class_body();
486481
}

src/parser/statement.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ module.exports = {
4444
case this.tok.T_ABSTRACT:
4545
case this.tok.T_FINAL:
4646
case this.tok.T_CLASS:
47-
return this.read_class();
47+
return this.read_class_declaration_statement();
4848
case this.tok.T_INTERFACE:
49-
return this.read_interface();
49+
return this.read_interface_declaration_statement();
5050
case this.tok.T_TRAIT:
5151
return this.read_trait();
5252
case this.tok.T_USE:
@@ -157,9 +157,9 @@ module.exports = {
157157
case this.tok.T_ABSTRACT:
158158
case this.tok.T_FINAL:
159159
case this.tok.T_CLASS:
160-
return this.read_class();
160+
return this.read_class_declaration_statement();
161161
case this.tok.T_INTERFACE:
162-
return this.read_interface();
162+
return this.read_interface_declaration_statement();
163163
case this.tok.T_TRAIT:
164164
return this.read_trait();
165165
case this.tok.T_HALT_COMPILER: {

src/parser/utils.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,38 @@ module.exports = {
154154
return variable;
155155
}
156156
}, ",");
157+
},
158+
159+
/*
160+
* Reads class extends
161+
*/
162+
read_extends_from: function() {
163+
if (this.token === this.tok.T_EXTENDS) {
164+
return this.next().read_namespace_name();
165+
}
166+
167+
return null;
168+
},
169+
170+
/*
171+
* Reads interface extends list
172+
*/
173+
read_interface_extends_list: function() {
174+
if (this.token === this.tok.T_EXTENDS) {
175+
return this.next().read_name_list();
176+
}
177+
178+
return null;
179+
},
180+
181+
/*
182+
* Reads implements list
183+
*/
184+
read_implements_list: function() {
185+
if (this.token === this.tok.T_IMPLEMENTS) {
186+
return this.next().read_name_list();
187+
}
188+
189+
return null;
157190
}
158191
};

test/snapshot/__snapshots__/new.test.js.snap

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,133 @@ Program {
6565
}
6666
`;
6767

68+
exports[`new anonymous class #2 1`] = `
69+
Program {
70+
"children": Array [
71+
ExpressionStatement {
72+
"expression": Assign {
73+
"kind": "assign",
74+
"left": Variable {
75+
"curly": false,
76+
"kind": "variable",
77+
"name": "var",
78+
},
79+
"operator": "=",
80+
"right": New {
81+
"arguments": Array [
82+
Variable {
83+
"curly": false,
84+
"kind": "variable",
85+
"name": "var",
86+
},
87+
],
88+
"kind": "new",
89+
"what": Class {
90+
"body": Array [],
91+
"extends": null,
92+
"implements": null,
93+
"isAbstract": false,
94+
"isAnonymous": true,
95+
"isFinal": false,
96+
"kind": "class",
97+
"name": null,
98+
},
99+
},
100+
},
101+
"kind": "expressionstatement",
102+
},
103+
],
104+
"errors": Array [],
105+
"kind": "program",
106+
}
107+
`;
108+
109+
exports[`new anonymous class #3 1`] = `
110+
Program {
111+
"children": Array [
112+
ExpressionStatement {
113+
"expression": Assign {
114+
"kind": "assign",
115+
"left": Variable {
116+
"curly": false,
117+
"kind": "variable",
118+
"name": "var",
119+
},
120+
"operator": "=",
121+
"right": New {
122+
"arguments": Array [
123+
Variable {
124+
"curly": false,
125+
"kind": "variable",
126+
"name": "var",
127+
},
128+
],
129+
"kind": "new",
130+
"what": Class {
131+
"body": Array [],
132+
"extends": ClassReference {
133+
"kind": "classreference",
134+
"name": "SomeClass",
135+
"resolution": "uqn",
136+
},
137+
"implements": Array [
138+
ClassReference {
139+
"kind": "classreference",
140+
"name": "SomeInterface",
141+
"resolution": "uqn",
142+
},
143+
],
144+
"isAbstract": false,
145+
"isAnonymous": true,
146+
"isFinal": false,
147+
"kind": "class",
148+
"name": null,
149+
},
150+
},
151+
},
152+
"kind": "expressionstatement",
153+
},
154+
],
155+
"errors": Array [],
156+
"kind": "program",
157+
}
158+
`;
159+
160+
exports[`new anonymous class 1`] = `
161+
Program {
162+
"children": Array [
163+
ExpressionStatement {
164+
"expression": Assign {
165+
"kind": "assign",
166+
"left": Variable {
167+
"curly": false,
168+
"kind": "variable",
169+
"name": "var",
170+
},
171+
"operator": "=",
172+
"right": New {
173+
"arguments": Array [],
174+
"kind": "new",
175+
"what": Class {
176+
"body": Array [],
177+
"extends": null,
178+
"implements": null,
179+
"isAbstract": false,
180+
"isAnonymous": true,
181+
"isFinal": false,
182+
"kind": "class",
183+
"name": null,
184+
},
185+
},
186+
},
187+
"kind": "expressionstatement",
188+
},
189+
],
190+
"errors": Array [],
191+
"kind": "program",
192+
}
193+
`;
194+
68195
exports[`new anonymous no parens 1`] = `
69196
Program {
70197
"children": Array [

test/snapshot/new.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ describe("new", function() {
4747
it("static", function() {
4848
expect(parser.parseEval('new static();')).toMatchSnapshot();
4949
});
50+
it("anonymous class", function() {
51+
expect(parser.parseEval('$var = new class {};')).toMatchSnapshot();
52+
});
53+
it("anonymous class #2", function() {
54+
expect(parser.parseEval('$var = new class($var) {};')).toMatchSnapshot();
55+
});
56+
it("anonymous class #3", function() {
57+
expect(parser.parseEval('$var = new class($var) extends SomeClass implements SomeInterface {};')).toMatchSnapshot();
58+
});
5059
});

0 commit comments

Comments
 (0)