Skip to content

Commit 2372443

Browse files
committed
release 2.0.5
1 parent 3c8901f commit 2372443

File tree

6 files changed

+242
-210
lines changed

6 files changed

+242
-210
lines changed

RELEASE.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Releases
22

3+
## 2.0.5 : (2017-07-16)
4+
5+
- Fix precedence between bin, retif, unary
6+
37
## 2.0.4 : (2017-07-09)
48

59
- Fix AST errors on suppressErrors

dist/php-parser.js

+125-105
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! php-parser - BSD3 License - 2017-07-10 */
1+
/*! php-parser - BSD3 License - 2017-07-16 */
22

33
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
44
// shim for using process in browser
@@ -309,6 +309,96 @@ AST.prototype.position = function(parser) {
309309
);
310310
};
311311

312+
313+
// operators in ascending order of precedence
314+
AST.precedence = {};
315+
var binOperatorsPrecedence = [
316+
['or'],
317+
['xor'],
318+
['and'],
319+
// TODO: assignment / not sure that PHP allows this with expressions
320+
['?'],
321+
['??'],
322+
['||'],
323+
['&&'],
324+
['|'],
325+
['^'],
326+
['&'],
327+
['==', '!=', '===', '!==', /* '<>', */ '<=>'],
328+
['<', '<=', '>', '>='],
329+
['<<', '>>'],
330+
['+', '-', '.'],
331+
['*', '/', '%'],
332+
['!'],
333+
['instanceof'],
334+
// TODO: typecasts
335+
// TODO: [ (array)
336+
// TODO: clone, new
337+
].forEach(function (list, index) {
338+
list.forEach(function (operator) {
339+
AST.precedence[operator] = index + 1;
340+
});
341+
});
342+
343+
344+
/**
345+
* Check and fix precence, by default using right
346+
*/
347+
AST.prototype.resolvePrecedence = function(result) {
348+
var buffer;
349+
// handling precendence
350+
if (result.kind === 'bin') {
351+
if (result.right) {
352+
if (result.right.kind === 'bin') {
353+
var lLevel = AST.precedence[result.type];
354+
var rLevel = AST.precedence[result.right.type];
355+
if (lLevel && rLevel && rLevel <= lLevel) {
356+
// https://github.com/glayzzle/php-parser/issues/79
357+
// shift precedence
358+
buffer = result.right;
359+
result.right = result.right.left;
360+
buffer.left = this.resolvePrecedence(result);
361+
result = buffer;
362+
}
363+
} else if (result.right.kind === 'retif') {
364+
var lLevel = AST.precedence[result.type];
365+
var rLevel = AST.precedence['?'];
366+
if (lLevel && rLevel && rLevel <= lLevel) {
367+
buffer = result.right;
368+
result.right = result.right.test;
369+
buffer.test = this.resolvePrecedence(result);
370+
result = buffer;
371+
}
372+
}
373+
}
374+
} else if (result.kind === 'unary') {
375+
// https://github.com/glayzzle/php-parser/issues/75
376+
if (result.what) {
377+
// unary precedence is allways lower
378+
if (result.what.kind === 'bin') {
379+
buffer = result.what;
380+
result.what = result.what.left;
381+
buffer.left = this.resolvePrecedence(result);
382+
result = buffer;
383+
} else if (result.what.kind === 'retif') {
384+
buffer = result.what;
385+
result.what = result.what.test;
386+
buffer.test = this.resolvePrecedence(result);
387+
result = buffer;
388+
}
389+
}
390+
} else if (result.kind === 'retif') {
391+
// https://github.com/glayzzle/php-parser/issues/77
392+
if (result.falseExpr && result.falseExpr.kind === 'retif') {
393+
buffer = result.falseExpr;
394+
result.falseExpr = buffer.test;
395+
buffer.test = this.resolvePrecedence(result);
396+
result = buffer;
397+
}
398+
}
399+
return result;
400+
};
401+
312402
/**
313403
* Prepares an AST node
314404
* @param {String|null} kind - Defines the node type
@@ -357,22 +447,7 @@ AST.prototype.prepare = function(kind, parser) {
357447
}
358448
var result = Object.create(node.prototype);
359449
node.apply(result, args);
360-
if (
361-
result.kind === 'bin' &&
362-
result.right &&
363-
typeof result.right.precedence === 'function'
364-
) {
365-
var out = result.right.precedence(result);
366-
if (out) { // shift with precedence
367-
result = out;
368-
}
369-
} else if (result.kind === 'unary' && result.what) {
370-
var out = result.precedence(result.what);
371-
if (out) { // shift with precedence
372-
result = out;
373-
}
374-
}
375-
return result;
450+
return self.resolvePrecedence(result);
376451
};
377452
};
378453

@@ -556,37 +631,6 @@ module.exports = Assign;
556631

557632
var Operation = require('./operation');
558633
var KIND = 'bin';
559-
560-
// operators in ascending order of precedence
561-
var binOperatorsPrecedence = [
562-
['or'],
563-
['xor'],
564-
['and'],
565-
// TODO: assignment / not sure that PHP allows this with expressions
566-
['retif'],
567-
['??'],
568-
['||'],
569-
['&&'],
570-
['|'],
571-
['^'],
572-
['&'],
573-
['==', '!=', '===', '!==', /* '<>', */ '<=>'],
574-
['<', '<=', '>', '>='],
575-
['<<', '>>'],
576-
['+', '-', '.'],
577-
['*', '/', '%'],
578-
['!'],
579-
['instanceof'],
580-
// TODO: typecasts
581-
// TODO: [ (array)
582-
// TODO: clone, new
583-
];
584-
585-
/*
586-
x OP1 (y OP2 z)
587-
z OP1 (x OP2 y)
588-
z OP2 (x OP1 y)
589-
*/
590634
/**
591635
* Binary operations
592636
* @constructor Bin
@@ -602,25 +646,6 @@ var Bin = Operation.extends(function Bin(type, left, right, location) {
602646
this.right = right;
603647
});
604648

605-
Bin.prototype.precedence = function(node) {
606-
var lLevel = Bin.precedence[node.type];
607-
var rLevel = Bin.precedence[this.type];
608-
if (lLevel && rLevel && rLevel < lLevel) {
609-
// shift precedence
610-
node.right = this.left;
611-
this.left = node;
612-
return this;
613-
}
614-
};
615-
616-
// define nodes shifting
617-
Bin.precedence = {};
618-
binOperatorsPrecedence.forEach(function (list, index) {
619-
list.forEach(function (operator) {
620-
Bin.precedence[operator] = index + 1;
621-
});
622-
});
623-
624649
module.exports = Bin;
625650

626651
},{"./operation":57}],6:[function(require,module,exports){
@@ -2296,8 +2321,6 @@ module.exports = PropertyLookup;
22962321

22972322
var Statement = require('./statement');
22982323
var KIND = 'retif';
2299-
var Bin = require('./bin');
2300-
var PRECEDENCE = Bin.precedence[KIND];
23012324

23022325
/**
23032326
* Defines a short if statement that returns a value
@@ -2314,26 +2337,9 @@ var RetIf = Statement.extends(function RetIf(test, trueExpr, falseExpr, location
23142337
this.falseExpr = falseExpr;
23152338
});
23162339

2317-
/**
2318-
* Handles precedence over items
2319-
*/
2320-
RetIf.prototype.precedence = function(node) {
2321-
var what = node.kind === 'bin' ? node.type : node.kind;
2322-
var lLevel = Bin.precedence[what];
2323-
if (lLevel && PRECEDENCE < lLevel) {
2324-
if (node.kind === 'bin') {
2325-
node.right = this.test;
2326-
this.test = node;
2327-
return this;
2328-
} else {
2329-
throw new Error('@todo ' + node.kind);
2330-
}
2331-
}
2332-
};
2333-
23342340
module.exports = RetIf;
23352341

2336-
},{"./bin":5,"./statement":70}],68:[function(require,module,exports){
2342+
},{"./statement":70}],68:[function(require,module,exports){
23372343
/*!
23382344
* Copyright (C) 2017 Glayzzle (BSD3 License)
23392345
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
@@ -2719,18 +2725,6 @@ var Unary = Operation.extends(function Unary(type, what, location) {
27192725
this.what = what;
27202726
});
27212727

2722-
Unary.prototype.precedence = function(node) {
2723-
if (node.kind === 'bin') {
2724-
this.what = node.left;
2725-
node.left = this;
2726-
return node;
2727-
} else if (node.kind === 'retif') {
2728-
this.what = node.test;
2729-
node.test = this;
2730-
return node;
2731-
}
2732-
};
2733-
27342728
module.exports = Unary;
27352729

27362730
},{"./operation":57}],83:[function(require,module,exports){
@@ -5940,9 +5934,20 @@ module.exports = {
59405934
if (this.is('VARIABLE')) {
59415935
var result = this.node();
59425936
expr = this.read_variable(false, false, false);
5937+
5938+
// https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L877
5939+
// should accept only a variable
5940+
var isConst = (
5941+
expr.kind === 'constref' || (
5942+
expr.kind === 'staticlookup' &&
5943+
expr.offset.kind === 'constref'
5944+
)
5945+
);
5946+
59435947
// VARIABLES SPECIFIC OPERATIONS
59445948
switch(this.token) {
59455949
case '=':
5950+
if (isConst) this.error('VARIABLE');
59465951
var right;
59475952
if (this.next().token == '&') {
59485953
if (this.next().token === this.tok.T_NEW) {
@@ -5957,45 +5962,59 @@ module.exports = {
59575962

59585963
// operations :
59595964
case this.tok.T_PLUS_EQUAL:
5965+
if (isConst) this.error('VARIABLE');
59605966
return result('assign', expr, this.next().read_expr(), '+=');
59615967

59625968
case this.tok.T_MINUS_EQUAL:
5969+
if (isConst) this.error('VARIABLE');
59635970
return result('assign', expr, this.next().read_expr(), '-=');
59645971

59655972
case this.tok.T_MUL_EQUAL:
5973+
if (isConst) this.error('VARIABLE');
59665974
return result('assign', expr, this.next().read_expr(), '*=');
59675975

59685976
case this.tok.T_POW_EQUAL:
5977+
if (isConst) this.error('VARIABLE');
59695978
return result('assign', expr, this.next().read_expr(), '**=');
59705979

59715980
case this.tok.T_DIV_EQUAL:
5981+
if (isConst) this.error('VARIABLE');
59725982
return result('assign', expr, this.next().read_expr(), '/=');
59735983

59745984
case this.tok.T_CONCAT_EQUAL:
5985+
if (isConst) this.error('VARIABLE');
59755986
return result('assign', expr, this.next().read_expr(), '.=');
59765987

59775988
case this.tok.T_MOD_EQUAL:
5989+
if (isConst) this.error('VARIABLE');
59785990
return result('assign', expr, this.next().read_expr(), '%=');
59795991

59805992
case this.tok.T_AND_EQUAL:
5993+
if (isConst) this.error('VARIABLE');
59815994
return result('assign', expr, this.next().read_expr(), '&=');
59825995

59835996
case this.tok.T_OR_EQUAL:
5997+
if (isConst) this.error('VARIABLE');
59845998
return result('assign', expr, this.next().read_expr(), '|=');
59855999

59866000
case this.tok.T_XOR_EQUAL:
6001+
if (isConst) this.error('VARIABLE');
59876002
return result('assign', expr, this.next().read_expr(), '^=');
59886003

59896004
case this.tok.T_SL_EQUAL:
6005+
if (isConst) this.error('VARIABLE');
59906006
return result('assign', expr, this.next().read_expr(), '<<=');
59916007

59926008
case this.tok.T_SR_EQUAL:
6009+
if (isConst) this.error('VARIABLE');
59936010
return result('assign',expr, this.next().read_expr(), '>>=');
59946011

59956012
case this.tok.T_INC:
6013+
if (isConst) this.error('VARIABLE');
59966014
this.next();
59976015
return result('post', '+', expr);
59986016
case this.tok.T_DEC:
6017+
if (isConst) this.error('VARIABLE');
59996018
this.next();
60006019
return result('post', '-', expr);
60016020
}
@@ -7413,18 +7432,19 @@ module.exports = {
74137432
case this.tok.T_STRING:
74147433
var current = [this.token, this.lexer.getState()];
74157434
var label = this.text();
7435+
// AST : https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L457
74167436
if (this.next().token === ':') {
74177437
var result = this.node('label');
74187438
this.next();
74197439
return result(label);
7420-
} else {
7421-
// default fallback expr
7422-
this.lexer.tokens.push(current);
7423-
var expr = this.next().read_expr();
7424-
this.expect([';', this.tok.T_CLOSE_TAG]) && this.nextWithComments();
7425-
return expr;
74267440
}
74277441

7442+
// default fallback expr / T_STRING '::' (etc...)
7443+
this.lexer.tokens.push(current);
7444+
var expr = this.next().read_expr();
7445+
this.expectEndOfStatement();
7446+
return expr;
7447+
74287448
case this.tok.T_GOTO:
74297449
var result = this.node('goto'), label = null;
74307450
if (this.next().expect(this.tok.T_STRING)) {

0 commit comments

Comments
 (0)