UNPKG

php-parser

Version:

Parse PHP code from JS and returns its AST

232 lines (225 loc) 6.76 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 namespace declaration block * ```ebnf * namespace ::= T_NAMESPACE namespace_name? '{' * top_statements * '}' * | T_NAMESPACE namespace_name ';' top_statements * ``` * @see http://php.net/manual/en/language.namespaces.php * @return {Namespace} */ read_namespace: function () { const result = this.node("namespace"); let body; this.expect(this.tok.T_NAMESPACE) && this.next(); let name; if (this.token === "{") { name = { name: [""], }; } else { name = this.read_namespace_name(); } this.currentNamespace = name; if (this.token === ";") { this.currentNamespace = name; body = this.next().read_top_statements(); this.expect(this.EOF); return result(name.name, body, false); } else if (this.token === "{") { this.currentNamespace = name; body = this.next().read_top_statements(); this.expect("}") && this.next(); if ( body.length === 0 && this.extractDoc && this._docs.length > this._docIndex ) { body.push(this.node("noop")()); } return result(name.name, body, true); } else { this.error(["{", ";"]); // graceful mode : this.currentNamespace = name; body = this.read_top_statements(); this.expect(this.EOF); return result(name, body, false); } }, /* * Reads a namespace name * ```ebnf * namespace_name ::= T_NS_SEPARATOR? (T_STRING T_NS_SEPARATOR)* T_STRING * ``` * @see http://php.net/manual/en/language.namespaces.rules.php * @return {Reference} */ read_namespace_name: function (resolveReference) { const result = this.node(); let resolution; let name = this.text(); switch (this.token) { case this.tok.T_NAME_RELATIVE: resolution = this.ast.name.RELATIVE_NAME; name = name.replace(/^namespace\\/, ""); break; case this.tok.T_NAME_QUALIFIED: resolution = this.ast.name.QUALIFIED_NAME; break; case this.tok.T_NAME_FULLY_QUALIFIED: resolution = this.ast.name.FULL_QUALIFIED_NAME; break; default: resolution = this.ast.name.UNQUALIFIED_NAME; if (!this.expect(this.tok.T_STRING)) { // graceful mode return result("name", "", this.ast.name.FULL_QUALIFIED_NAME); } } this.next(); if (resolveReference || this.token !== "(") { if (name.toLowerCase() === "parent") { return result("parentreference", name); } else if (name.toLowerCase() === "self") { return result("selfreference", name); } } return result("name", name, resolution); }, /* * Reads a use statement * ```ebnf * use_statement ::= T_USE * use_type? use_declarations | * use_type use_statement '{' use_declarations '}' | * use_statement '{' use_declarations(=>typed) '}' * ';' * ``` * @see http://php.net/manual/en/language.namespaces.importing.php * @return {UseGroup} */ read_use_statement: function () { let result = this.node("usegroup"); let items = []; let name = null; this.expect(this.tok.T_USE) && this.next(); const type = this.read_use_type(); items.push(this.read_use_declaration(false)); if (this.token === ",") { items = items.concat(this.next().read_use_declarations(false)); } else if (this.token === "{") { name = items[0].name; items = this.next().read_use_declarations(type === null); this.expect("}") && this.next(); } result = result(name, type, items); this.expect(";") && this.next(); return result; }, /* * * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1045 */ read_class_name_reference: function () { // resolved as the same return this.read_variable(true, false); }, /* * Reads a use declaration * ```ebnf * use_declaration ::= use_type? namespace_name use_alias * ``` * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L380 * @return {UseItem} */ read_use_declaration: function (typed) { const result = this.node("useitem"); let type = null; if (typed) type = this.read_use_type(); const name = this.read_namespace_name(); const alias = this.read_use_alias(); return result(name.name, alias, type); }, /* * Reads a list of use declarations * ```ebnf * use_declarations ::= use_declaration (',' use_declaration)* * ``` * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L380 * @return {UseItem[]} */ read_use_declarations: function (typed) { const result = [this.read_use_declaration(typed)]; while (this.token === ",") { this.next(); if (typed) { if ( this.token !== this.tok.T_NAME_RELATIVE && this.token !== this.tok.T_NAME_QUALIFIED && this.token !== this.tok.T_NAME_FULLY_QUALIFIED && this.token !== this.tok.T_FUNCTION && this.token !== this.tok.T_CONST && this.token !== this.tok.T_STRING ) { break; } } else if ( this.token !== this.tok.T_NAME_RELATIVE && this.token !== this.tok.T_NAME_QUALIFIED && this.token !== this.tok.T_NAME_FULLY_QUALIFIED && this.token !== this.tok.T_STRING && this.token !== this.tok.T_NS_SEPARATOR ) { break; } result.push(this.read_use_declaration(typed)); } return result; }, /* * Reads a use statement * ```ebnf * use_alias ::= (T_AS T_STRING)? * ``` * @return {String|null} */ read_use_alias: function () { let result = null; if (this.token === this.tok.T_AS) { if (this.next().expect(this.tok.T_STRING)) { const aliasName = this.node("identifier"); const name = this.text(); this.next(); result = aliasName(name); } } return result; }, /* * Reads the namespace type declaration * ```ebnf * use_type ::= (T_FUNCTION | T_CONST)? * ``` * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L335 * @return {String|null} Possible values : function, const */ read_use_type: function () { if (this.token === this.tok.T_FUNCTION) { this.next(); return this.ast.useitem.TYPE_FUNCTION; } else if (this.token === this.tok.T_CONST) { this.next(); return this.ast.useitem.TYPE_CONST; } return null; }, };