Skip to content

Commit 55c96a7

Browse files
committed
add new lookup nodes & migrate vars (wip)
1 parent cdb9f42 commit 55c96a7

File tree

8 files changed

+171
-23
lines changed

8 files changed

+171
-23
lines changed

docs/AST.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
- [Array](#array)
2121
- [Variable](#variable)
2222
- [ConstRef](#constref)
23+
- [Lookup](#lookup)
24+
- [PropertyLookup](#propertylookup)
25+
- [OffsetLookup](#offsetlookup)
2326
- [Operation](#operation)
2427
- [Coalesce](#coalesce)
2528
- [Pre](#pre)
@@ -644,6 +647,17 @@ Defines the location of the node (with it's source contents as string)
644647
- `start` **[Position](#position)**
645648
- `end` **[Position](#position)**
646649

650+
# Lookup
651+
652+
**Extends Expression**
653+
654+
Lookup on an offset in the specified object
655+
656+
**Properties**
657+
658+
- `what` **[Expression](#expression)**
659+
- `offset` **[Expression](#expression)**
660+
647661
# Magic
648662

649663
**Extends Literal**
@@ -715,6 +729,12 @@ Returns **[Function](#function)**
715729

716730
Defines a numeric value
717731

732+
# OffsetLookup
733+
734+
**Extends Lookup**
735+
736+
Lookup on an offset in an array
737+
718738
# Operation
719739

720740
**Extends Expression**
@@ -802,6 +822,12 @@ Defines a class property
802822
- `visibility` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)**
803823
- `value` **([Node](#node) | null)**
804824

825+
# PropertyLookup
826+
827+
**Extends Lookup**
828+
829+
Lookup to an object property
830+
805831
# RetIf
806832

807833
**Extends Statement**

src/ast.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ var Position = require('./ast/position');
2626
* - [Array](#array)
2727
* - [Variable](#variable)
2828
* - [ConstRef](#constref)
29+
* - [Lookup](#lookup)
30+
* - [PropertyLookup](#propertylookup)
31+
* - [OffsetLookup](#offsetlookup)
2932
* - [Operation](#operation)
3033
* - [Coalesce](#coalesce)
3134
* - [Pre](#pre)
@@ -210,12 +213,14 @@ AST.prototype.prepare = function(kind, parser) {
210213
require('./ast/namespace'),
211214
require('./ast/new'),
212215
require('./ast/number'),
216+
require('./ast/offsetlookup'),
213217
require('./ast/parameter'),
214218
require('./ast/post'),
215219
require('./ast/pre'),
216220
require('./ast/print'),
217221
require('./ast/program'),
218222
require('./ast/property'),
223+
require('./ast/propertylookup'),
219224
require('./ast/retif'),
220225
require('./ast/return'),
221226
require('./ast/shell'),

src/ast/lookup.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*!
2+
* Copyright (C) 2017 Glayzzle (BSD3 License)
3+
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
4+
* @url http://glayzzle.com
5+
*/
6+
7+
var Expr = require('./expression');
8+
var KIND = 'lookup';
9+
10+
/**
11+
* Lookup on an offset in the specified object
12+
* @constructor Lookup
13+
* @extends {Expression}
14+
* @property {Expression} what
15+
* @property {Expression} offset
16+
*/
17+
var Lookup = Expr.extends(function Lookup(kind, what, offset, location) {
18+
Expr.apply(this, [kind || KIND, location]);
19+
this.what = what;
20+
this.offset = offset;
21+
});
22+
23+
module.exports = Lookup;

src/ast/offsetlookup.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*!
2+
* Copyright (C) 2017 Glayzzle (BSD3 License)
3+
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
4+
* @url http://glayzzle.com
5+
*/
6+
"use strict";
7+
var Lookup = require('./lookup');
8+
var KIND = 'offsetlookup';
9+
10+
/**
11+
* Lookup on an offset in an array
12+
* @constructor OffsetLookup
13+
* @extends {Lookup}
14+
*/
15+
var OffsetLookup = Lookup.extends(function OffsetLookup(what, offset, location) {
16+
Lookup.apply(this, [KIND, what, offset, location]);
17+
});
18+
19+
module.exports = OffsetLookup;

src/ast/propertylookup.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*!
2+
* Copyright (C) 2017 Glayzzle (BSD3 License)
3+
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
4+
* @url http://glayzzle.com
5+
*/
6+
"use strict";
7+
var Lookup = require('./lookup');
8+
var KIND = 'propertylookup';
9+
10+
/**
11+
* Lookup to an object property
12+
* @constructor PropertyLookup
13+
* @extends {Lookup}
14+
*/
15+
var PropertyLookup = Lookup.extends(function PropertyLookup(what, offset, location) {
16+
Lookup.apply(this, [KIND, what, offset, location]);
17+
});
18+
19+
module.exports = PropertyLookup;

src/parser/scalar.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,10 @@ module.exports = {
109109
}
110110
// CONSTANT ARRAYS OFFSET : MYCONST[1][0]...
111111
while(this.token === '[') {
112-
result = ['offset', result, this.next().read_expr()];
112+
var node = this.node('offsetlookup');
113+
var offset = this.next().read_expr();
113114
if (this.expect(']')) this.next();
115+
result = node(result, offset);
114116
}
115117
return result;
116118

@@ -131,11 +133,14 @@ module.exports = {
131133
*/
132134
,read_dereferencable: function(expr) {
133135
var result;
136+
var node = this.node('offsetlookup');
134137
if (this.token === '[') {
135-
result = ['offset', expr, this.next().read_expr()];
138+
var offset = this.next().read_expr();
136139
if (this.expect(']')) this.next();
140+
result = node(expr, offset);
137141
} else if (this.token === this.tok.T_DOLLAR_OPEN_CURLY_BRACES) {
138-
result = ['offset', expr, this.read_encapsed_string_item()];
142+
var offset = this.read_encapsed_string_item();
143+
result = node(expr, offset);
139144
}
140145
return result;
141146
}
@@ -158,8 +163,10 @@ module.exports = {
158163
if (this.next().token === this.tok.T_STRING_VARNAME) {
159164
result = ['var', this.text()];
160165
if (this.next().token === '[') {
161-
result = ['offset', result, this.next().read_expr()];
166+
var node = this.node('offsetlookup');
167+
var offset = this.next().read_expr();
162168
if (this.expect(']')) this.next();
169+
result = node(result, offset);
163170
}
164171
} else {
165172
result = this.read_expr();
@@ -169,8 +176,10 @@ module.exports = {
169176
result = this.next().read_variable(false, false, false);
170177
if (this.expect('}')) this.next();
171178
} else if (this.token === '[') {
172-
result = ['offset', result, this.next().read_expr()];
179+
var node = this.node('offsetlookup');
180+
var offset = this.next().read_expr();
173181
if (this.expect(']')) this.next();
182+
result = node(result, offset);
174183
} else if (this.token === this.tok.T_VARIABLE) {
175184
result = this.read_variable(false, true, false);
176185
} else {

src/parser/variable.js

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ module.exports = {
9696
switch(this.token) {
9797
case '(':
9898
if (read_only) {
99+
// @fixme : add more informations & test
99100
return result;
100101
} else {
101102
result = this.node('call')(
@@ -104,6 +105,7 @@ module.exports = {
104105
}
105106
break;
106107
case '[':
108+
var node = this.node('offsetlookup');
107109
this.next();
108110
var offset = false;
109111
if (encapsed) {
@@ -118,29 +120,36 @@ module.exports = {
118120
this.next();
119121
}
120122
}
121-
result = ['offset', result, offset];
123+
result = node(result, offset);
122124
break;
123125
case this.tok.T_OBJECT_OPERATOR:
124-
var what;
126+
var node = this.node('propertylookup');
127+
var what = null;
125128
switch(this.next().token) {
126129
case this.tok.T_STRING:
127-
what = ['string', this.text()];
128-
var tok = this.next().token;
129-
if (tok === this.tok.T_VARIABLE) {
130+
what = this.node('constref');
131+
var name = this.text();
132+
this.next();
133+
what = what(name);
134+
if (this.token === this.tok.T_VARIABLE) {
135+
// @fixme : create encapsed var node
136+
name = this.text().substring(1);
137+
this.next();
130138
// fix $obj->var_$prop
131-
what = ['bin', '.', what, ['var', this.text()]];
132-
} else if (tok === '{') {
139+
what = ['bin', '.', what, ['var', name]];
140+
} else if (this.token === '{') {
133141
// fix $obj->var_{$prop}
134142
what = ['bin', '.', what, this.next().read_expr()];
135143
this.expect('}') && this.next();
136144
}
137145
break;
138146
case this.tok.T_VARIABLE:
139-
what = ['var', this.text()];
147+
what = this.node('variable');
148+
var name = this.text().substring(1);
140149
this.next();
150+
what = what(name, false);
141151
break;
142152
case '$':
143-
144153
this.next().expect(['{', this.tok.T_VARIABLE]);
145154
if (this.token === '{') {
146155
// $obj->${$varname}
@@ -156,12 +165,15 @@ module.exports = {
156165
this.expect('}') && this.next();
157166
break;
158167
default:
159-
what = this.error([this.tok.T_STRING, this.tok.T_VARIABLE]);
168+
this.error([this.tok.T_STRING, this.tok.T_VARIABLE]);
160169
// graceful mode : set what as error mode & continue
170+
what = this.node('constref');
171+
var name = this.text();
161172
this.next();
173+
what = what(name);
162174
break;
163175
}
164-
result = ['prop', result, what];
176+
result = node(result, what);
165177
break;
166178
default:
167179
break recursive_scan_loop;
@@ -178,21 +190,29 @@ module.exports = {
178190
var text = this.text();
179191
var isDblQuote = text[0] === '"';
180192
text = text.substring(1, text.length - 1);
193+
this.next();
181194
offset = offset(
182195
'string', isDblQuote, this.resolve_special_chars(text)
183196
);
184197
} else if (this.token === this.tok.T_NUM_STRING) {
185-
offset = offset('number', this.text());
198+
var num = this.text();
199+
this.next();
200+
offset = offset('number', num);
186201
} else if (this.token === this.tok.T_VARIABLE) {
187-
offset = offset('variable', this.text());
202+
var name = this.text().substring(1);
203+
this.next();
204+
offset = offset('variable', name, false);
188205
} else {
189206
this.expect([
190207
this.tok.T_STRING,
191208
this.tok.T_NUM_STRING,
192209
this.tok.T_VARIABLE
193210
]);
211+
// fallback : consider as text
212+
var text = this.text();
213+
this.next();
214+
offset = offset('string', false, text);
194215
}
195-
this.next();
196216
return offset;
197217
}
198218
/**
@@ -209,17 +229,19 @@ module.exports = {
209229
,read_reference_variable: function(encapsed, byref) {
210230
var result = this.read_simple_variable(byref);
211231
while(this.token != this.EOF) {
232+
var node = this.node();
212233
if (this.token == '[') {
213234
if (encapsed) {
214235
result = this.next().read_encaps_var_offset();
215236
} else {
216237
var offset = this.next().token === ']' ? null : this.read_dim_offset();
217-
result = ['offset', result, offset];
238+
result = node('offsetlookup', result, offset);
218239
}
219240
this.expect(']') && this.next();
220241
} else if (this.token == '{' && !encapsed) {
221-
result = ['offset', result, this.next().read_expr()];
242+
var offset = this.next().read_expr();
222243
this.expect('}') && this.next();
244+
result = node('offsetlookup', result, offset);
223245
} else break;
224246
}
225247
return result;

test/variableTests.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ describe('Test variables', function() {
55
describe('Default variables', function() {
66
var ast = parser.parseEval([
77
'$a = "foo";',
8-
'$b = &$c;'
8+
'$b = &$c;',
9+
'$a->b = true;'
910
].join('\n'));
1011
it('should be $a', function() {
1112
ast.children[0].left.kind.should.be.exactly('variable');
@@ -16,13 +17,33 @@ describe('Test variables', function() {
1617
ast.children[1].right.name.should.be.exactly('c');
1718
ast.children[1].right.byref.should.be.exactly(true);
1819
});
20+
it('should be $a->b', function() {
21+
ast.children[2].left.kind.should.be.exactly('propertylookup');
22+
ast.children[2].left.what.kind.should.be.exactly('variable');
23+
ast.children[2].left.what.name.should.be.exactly('a');
24+
ast.children[2].left.offset.kind.should.be.exactly('constref');
25+
ast.children[2].left.offset.name.should.be.exactly('b');
26+
});
27+
});
28+
29+
describe('Encaps var offset', function() {
30+
var ast = parser.parseEval([
31+
'$a = "{$a[1]}";',
32+
'$a = "{$a["a"]}";',
33+
'$a = "{$a[$b]}";',
34+
].join('\n'));
35+
it('should be $a[1]', function() {
36+
//console.log(ast.children[0].right);
37+
//ast.children[0].left.kind.should.be.exactly('variable');
38+
});
1939
});
2040

2141
describe('Dynamic variables', function() {
2242
var ast = parser.parseEval([
2343
'$$a = "bar";',
2444
'$$$a = "bar";',
25-
'${$a."bar"} = "bar";'
45+
'${$a."bar"} = "bar";',
46+
'$foo{$a."bar"} = "bar";'
2647
].join('\n'));
2748
it('should be $$a', function() {
2849
ast.children[0].left.kind.should.be.exactly('variable');
@@ -43,6 +64,10 @@ describe('Test variables', function() {
4364
ast.children[2].left.name.right.kind.should.be.exactly('string');
4465
ast.children[2].left.name.right.value.should.be.exactly('bar');
4566
});
67+
it('should be $foo{$a."bar"}', function() {
68+
//console.log(ast.children[3]);
69+
//ast.children[3].kind.should.be.exactly('variable');
70+
});
4671
});
4772

4873
describe('Check errors', function() {

0 commit comments

Comments
 (0)