UNPKG

php-parser

Version:

Parse PHP code from JS and returns its AST

204 lines (189 loc) 4.99 kB
/** * Copyright (C) 2018 Glayzzle (BSD3 License) * @authors https://github.com/glayzzle/php-parser/graphs/contributors * @url http://glayzzle.com */ "use strict"; module.exports = { /* * Reads a short form of tokens * @param {Number} token - The ending token * @return {Block} */ read_short_form: function (token) { const body = this.node("block"); const items = []; /* istanbul ignore next */ if (this.expect(":")) this.next(); while (this.token != this.EOF && this.token !== token) { items.push(this.read_inner_statement()); } if ( items.length === 0 && this.extractDoc && this._docs.length > this._docIndex ) { items.push(this.node("noop")()); } /* istanbul ignore next */ if (this.expect(token)) this.next(); this.expectEndOfStatement(); return body(null, items); }, /* * https://wiki.php.net/rfc/trailing-comma-function-calls * @param {*} item * @param {*} separator */ read_function_list: function (item, separator) { const result = []; do { if (this.token == separator && this.version >= 703 && result.length > 0) { result.push(this.node("noop")()); break; } result.push(item.apply(this, [])); if (this.token != separator) { break; } if (this.next().token == ")" && this.version >= 703) { break; } } while (this.token != this.EOF); return result; }, /* * Helper : reads a list of tokens / sample : T_STRING ',' T_STRING ... * ```ebnf * list ::= separator? ( item separator )* item * ``` */ read_list: function (item, separator, preserveFirstSeparator) { const result = []; if (this.token == separator) { if (preserveFirstSeparator) { result.push(typeof item === "function" ? this.node("noop")() : null); } this.next(); } if (typeof item === "function") { do { const itemResult = item.apply(this, []); if (itemResult) { result.push(itemResult); } if (this.token != separator) { break; } } while (this.next().token != this.EOF); } else { if (this.expect(item)) { result.push(this.text()); } else { return []; } while (this.next().token != this.EOF) { if (this.token != separator) break; // trim current separator & check item if (this.next().token != item) break; result.push(this.text()); } } return result; }, /* * Reads a list of names separated by a comma * * ```ebnf * name_list ::= namespace (',' namespace)* * ``` * * Sample code : * ```php * <?php class foo extends bar, baz { } * ``` * * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L726 * @return {Reference[]} */ read_name_list: function () { return this.read_list(this.read_namespace_name, ",", false); }, /* * Reads the byref token and assign it to the specified node * @param {*} cb */ read_byref: function (cb) { let byref = this.node("byref"); this.next(); byref = byref(null); const result = cb(); if (result) { this.ast.swapLocations(result, byref, result, this); result.byref = true; } return result; }, /* * Reads a list of variables declarations * * ```ebnf * variable_declaration ::= T_VARIABLE ('=' expr)?* * variable_declarations ::= variable_declaration (',' variable_declaration)* * ``` * * Sample code : * ```php * <?php static $a = 'hello', $b = 'world'; * ``` * @return {StaticVariable[]} Returns an array composed by a list of variables, or * assign values */ read_variable_declarations: function () { return this.read_list(function () { const node = this.node("staticvariable"); let variable = this.node("variable"); // plain variable name /* istanbul ignore else */ if (this.expect(this.tok.T_VARIABLE)) { const name = this.text().substring(1); this.next(); variable = variable(name, false); } else { variable = variable("#ERR", false); } if (this.token === "=") { return node(variable, this.next().read_expr()); } else { return variable; } }, ","); }, /* * Reads class extends */ read_extends_from: function () { if (this.token === this.tok.T_EXTENDS) { return this.next().read_namespace_name(); } return null; }, /* * Reads interface extends list */ read_interface_extends_list: function () { if (this.token === this.tok.T_EXTENDS) { return this.next().read_name_list(); } return null; }, /* * Reads implements list */ read_implements_list: function () { if (this.token === this.tok.T_IMPLEMENTS) { return this.next().read_name_list(); } return null; }, };