Skip to content

Commit 85eb5e6

Browse files
committed
#179 : fix T_DOUBLE_COLON deferencing
1 parent e19fb5f commit 85eb5e6

File tree

4 files changed

+281
-3
lines changed

4 files changed

+281
-3
lines changed

src/parser/expr.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,11 @@ module.exports = {
504504
},
505505
handleDereferencable: function(expr) {
506506
while (this.token !== this.EOF) {
507-
if (this.token === this.tok.T_OBJECT_OPERATOR) {
508-
expr = this.recursive_variable_chain_scan(expr, false);
507+
if (
508+
this.token === this.tok.T_OBJECT_OPERATOR ||
509+
this.token === this.tok.T_DOUBLE_COLON
510+
) {
511+
expr = this.recursive_variable_chain_scan(expr, false, false, true);
509512
} else if (this.token === this.tok.T_CURLY_OPEN || this.token === "[") {
510513
expr = this.read_dereferencable(expr);
511514
} else if (this.token === "(") {

src/parser/variable.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ module.exports = {
9999
return result(what, offset);
100100
},
101101

102-
recursive_variable_chain_scan: function(result, read_only, encapsed) {
102+
recursive_variable_chain_scan: function(
103+
result,
104+
read_only,
105+
encapsed,
106+
dereferencable
107+
) {
103108
let name, node, offset;
104109
recursive_scan_loop: while (this.token != this.EOF) {
105110
switch (this.token) {
@@ -158,6 +163,10 @@ module.exports = {
158163
this.next();
159164
}
160165
result = node(result, offset);
166+
// static lookup dereferencables are limited to staticlookup over functions
167+
if (dereferencable && this.token !== "(") {
168+
this.error("(");
169+
}
161170
break;
162171
case this.tok.T_OBJECT_OPERATOR: {
163172
node = this.node("propertylookup");

test/snapshot/__snapshots__/expr.test.js.snap

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,256 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`Test expressions chaining calls (derefenceable) 1`] = `
4+
Program {
5+
"children": Array [
6+
PropertyLookup {
7+
"kind": "propertylookup",
8+
"offset": ConstRef {
9+
"kind": "constref",
10+
"name": "bar",
11+
},
12+
"what": OffsetLookup {
13+
"kind": "offsetlookup",
14+
"offset": Number {
15+
"kind": "number",
16+
"value": "10",
17+
},
18+
"what": PropertyLookup {
19+
"kind": "propertylookup",
20+
"offset": ConstRef {
21+
"kind": "constref",
22+
"name": "foo",
23+
},
24+
"what": Call {
25+
"arguments": Array [],
26+
"kind": "call",
27+
"what": StaticLookup {
28+
"kind": "staticlookup",
29+
"offset": ConstRef {
30+
"kind": "constref",
31+
"name": "call",
32+
},
33+
"what": PropertyLookup {
34+
"kind": "propertylookup",
35+
"offset": ConstRef {
36+
"kind": "constref",
37+
"name": "b",
38+
},
39+
"parenthesizedExpression": true,
40+
"what": Variable {
41+
"byref": false,
42+
"curly": false,
43+
"kind": "variable",
44+
"name": "a",
45+
},
46+
},
47+
},
48+
},
49+
},
50+
},
51+
},
52+
],
53+
"errors": Array [],
54+
"kind": "program",
55+
}
56+
`;
57+
58+
exports[`Test expressions chaining calls (derefenceable) 2`] = `
59+
Program {
60+
"children": Array [
61+
PropertyLookup {
62+
"kind": "propertylookup",
63+
"offset": ConstRef {
64+
"kind": "constref",
65+
"name": "foo",
66+
},
67+
"what": OffsetLookup {
68+
"kind": "offsetlookup",
69+
"offset": Number {
70+
"kind": "number",
71+
"value": "0",
72+
},
73+
"what": Array {
74+
"items": Array [
75+
Number {
76+
"kind": "number",
77+
"value": "1",
78+
},
79+
Number {
80+
"kind": "number",
81+
"value": "2",
82+
},
83+
Number {
84+
"kind": "number",
85+
"value": "3",
86+
},
87+
],
88+
"kind": "array",
89+
"shortForm": false,
90+
},
91+
},
92+
},
93+
],
94+
"errors": Array [],
95+
"kind": "program",
96+
}
97+
`;
98+
99+
exports[`Test expressions chaining calls (derefenceable) 3`] = `
100+
Program {
101+
"children": Array [
102+
Call {
103+
"arguments": Array [],
104+
"kind": "call",
105+
"what": StaticLookup {
106+
"kind": "staticlookup",
107+
"offset": ConstRef {
108+
"kind": "constref",
109+
"name": "foo",
110+
},
111+
"what": PropertyLookup {
112+
"kind": "propertylookup",
113+
"offset": Encapsed {
114+
"kind": "encapsed",
115+
"type": "offset",
116+
"value": Array [
117+
ConstRef {
118+
"kind": "constref",
119+
"name": "bar",
120+
},
121+
Variable {
122+
"byref": false,
123+
"curly": false,
124+
"kind": "variable",
125+
"name": "baz",
126+
},
127+
],
128+
},
129+
"what": Call {
130+
"arguments": Array [
131+
Variable {
132+
"byref": false,
133+
"curly": false,
134+
"kind": "variable",
135+
"name": "foo",
136+
},
137+
],
138+
"kind": "call",
139+
"what": Post {
140+
"kind": "post",
141+
"parenthesizedExpression": true,
142+
"type": "+",
143+
"what": Variable {
144+
"byref": false,
145+
"curly": false,
146+
"kind": "variable",
147+
"name": "a",
148+
},
149+
},
150+
},
151+
},
152+
},
153+
},
154+
],
155+
"errors": Array [],
156+
"kind": "program",
157+
}
158+
`;
159+
160+
exports[`Test expressions chaining calls (derefenceable) 4`] = `
161+
Program {
162+
"children": Array [
163+
Post {
164+
"kind": "post",
165+
"parenthesizedExpression": true,
166+
"type": "+",
167+
"what": Variable {
168+
"byref": false,
169+
"curly": false,
170+
"kind": "variable",
171+
"name": "a",
172+
},
173+
},
174+
StaticLookup {
175+
"kind": "staticlookup",
176+
"offset": ConstRef {
177+
"kind": "constref",
178+
"name": "baz",
179+
},
180+
"what": StaticLookup {
181+
"kind": "staticlookup",
182+
"offset": ConstRef {
183+
"kind": "constref",
184+
"name": "foo",
185+
},
186+
"what": Identifier {
187+
"kind": "identifier",
188+
"name": "bar",
189+
"resolution": "uqn",
190+
},
191+
},
192+
},
193+
],
194+
"errors": Array [
195+
Error {
196+
"expected": ";",
197+
"kind": "error",
198+
"line": 1,
199+
"message": "Parse Error : syntax error, unexpected 'bar' (T_STRING), expecting ';' on line 1",
200+
"token": "'bar' (T_STRING)",
201+
},
202+
Error {
203+
"expected": undefined,
204+
"kind": "error",
205+
"line": 1,
206+
"message": "Parse Error : syntax error, unexpected '::' (T_DOUBLE_COLON) on line 1",
207+
"token": "'::' (T_DOUBLE_COLON)",
208+
},
209+
],
210+
"kind": "program",
211+
}
212+
`;
213+
214+
exports[`Test expressions chaining calls (derefenceable) 5`] = `
215+
Program {
216+
"children": Array [
217+
Call {
218+
"arguments": Array [],
219+
"kind": "call",
220+
"what": StaticLookup {
221+
"kind": "staticlookup",
222+
"offset": ConstRef {
223+
"kind": "constref",
224+
"name": "baz",
225+
},
226+
"what": Call {
227+
"arguments": Array [],
228+
"kind": "call",
229+
"what": StaticLookup {
230+
"kind": "staticlookup",
231+
"offset": ConstRef {
232+
"kind": "constref",
233+
"name": "foo",
234+
},
235+
"what": Call {
236+
"arguments": Array [],
237+
"kind": "call",
238+
"what": Identifier {
239+
"kind": "identifier",
240+
"name": "bar",
241+
"resolution": "uqn",
242+
},
243+
},
244+
},
245+
},
246+
},
247+
},
248+
],
249+
"errors": Array [],
250+
"kind": "program",
251+
}
252+
`;
253+
3254
exports[`Test expressions should assign class static 1`] = `
4255
Program {
5256
"children": Array [

test/snapshot/expr.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,19 @@ describe("Test expressions", function() {
235235
);
236236
expect(ast).toMatchSnapshot();
237237
});
238+
239+
240+
it("chaining calls (derefenceable)", function() {
241+
expect(parser.parseEval(`($a->b)::call()->foo[10]->bar;`)).toMatchSnapshot();
242+
expect(parser.parseEval(`array(1, 2, 3)[0]->foo;`)).toMatchSnapshot();
243+
expect(parser.parseEval(`($a++)($foo)->bar{$baz}::foo();`)).toMatchSnapshot();
244+
// expect error :
245+
expect(parser.parseEval(`($a++)bar::foo::baz;`, {
246+
parser: {
247+
suppressErrors: true
248+
}
249+
})).toMatchSnapshot();
250+
// should pass
251+
expect(parser.parseEval(`bar()::foo()::baz();`)).toMatchSnapshot();
252+
});
238253
});

0 commit comments

Comments
 (0)