Skip to content

Commit

Permalink
#188 - introduce the reference node & rewrite the usage of identifier
Browse files Browse the repository at this point in the history
  • Loading branch information
ichiriac committed Oct 20, 2018
1 parent b142901 commit 1030beb
Show file tree
Hide file tree
Showing 28 changed files with 667 additions and 533 deletions.
1 change: 1 addition & 0 deletions src/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ AST.prototype.prepare = function(kind, docs, parser) {
require("./ast/program"),
require("./ast/property"),
require("./ast/propertylookup"),
require("./ast/reference"),
require("./ast/retif"),
require("./ast/return"),
require("./ast/silent"),
Expand Down
36 changes: 1 addition & 35 deletions src/ast/identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,14 @@ const KIND = "identifier";
* @constructor Identifier
* @extends {Node}
* @property {string} name
* @property {string} resolution
*/
const Identifier = Node.extends(KIND, function Identifier(
name,
isRelative,
docs,
location
) {
Node.apply(this, [KIND, docs, location]);
if (isRelative) {
this.resolution = Identifier.RELATIVE_NAME;
} else if (name.length === 1) {
this.resolution = Identifier.UNQUALIFIED_NAME;
} else if (name[0] === "") {
this.resolution = Identifier.FULL_QUALIFIED_NAME;
} else {
this.resolution = Identifier.QUALIFIED_NAME;
}
this.name = name.join("\\");
this.name = name;
});

/**
* This is an identifier without a namespace separator, such as Foo
* @constant {String} UNQUALIFIED_NAME
*/
Identifier.UNQUALIFIED_NAME = "uqn";
/**
* This is an identifier with a namespace separator, such as Foo\Bar
* @constant {String} QUALIFIED_NAME
*/
Identifier.QUALIFIED_NAME = "qn";
/**
* This is an identifier with a namespace separator that begins with
* a namespace separator, such as \Foo\Bar. The namespace \Foo is also
* a fully qualified name.
* @constant {String} FULL_QUALIFIED_NAME
*/
Identifier.FULL_QUALIFIED_NAME = "fqn";
/**
* This is an identifier starting with namespace, such as namespace\Foo\Bar.
* @constant {String} RELATIVE_NAME
*/
Identifier.RELATIVE_NAME = "rn";

module.exports = Identifier;
60 changes: 60 additions & 0 deletions src/ast/reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Copyright (C) 2018 Glayzzle (BSD3 License)
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
* @url http://glayzzle.com
*/
"use strict";

const Node = require("./node");
const KIND = "reference";

/**
* Defines a reference node
* @constructor Reference
* @extends {Node}
* @property {string} name
* @property {string} resolution
*/
const Reference = Node.extends(KIND, function Reference(
name,
isRelative,
docs,
location
) {
Node.apply(this, [KIND, docs, location]);
if (isRelative) {
this.resolution = Reference.RELATIVE_NAME;
} else if (name.length === 1) {
this.resolution = Reference.UNQUALIFIED_NAME;
} else if (name[0] === "") {
this.resolution = Reference.FULL_QUALIFIED_NAME;
} else {
this.resolution = Reference.QUALIFIED_NAME;
}
this.name = name.join("\\");
});

/**
* This is an identifier without a namespace separator, such as Foo
* @constant {String} UNQUALIFIED_NAME
*/
Reference.UNQUALIFIED_NAME = "uqn";
/**
* This is an identifier with a namespace separator, such as Foo\Bar
* @constant {String} QUALIFIED_NAME
*/
Reference.QUALIFIED_NAME = "qn";
/**
* This is an identifier with a namespace separator that begins with
* a namespace separator, such as \Foo\Bar. The namespace \Foo is also
* a fully qualified name.
* @constant {String} FULL_QUALIFIED_NAME
*/
Reference.FULL_QUALIFIED_NAME = "fqn";
/**
* This is an identifier starting with namespace, such as namespace\Foo\Bar.
* @constant {String} RELATIVE_NAME
*/
Reference.RELATIVE_NAME = "rn";

module.exports = Reference;
Empty file added src/ast/this.js
Empty file.
4 changes: 2 additions & 2 deletions src/parser/expr.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@ module.exports = {
// https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L877
// should accept only a variable
const isConst =
expr.kind === "constref" ||
(expr.kind === "staticlookup" && expr.offset.kind === "constref");
expr.kind === "identifier" ||
(expr.kind === "staticlookup" && expr.offset.kind === "identifier");

// VARIABLES SPECIFIC OPERATIONS
switch (this.token) {
Expand Down
4 changes: 2 additions & 2 deletions src/parser/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module.exports = {
}
this.next();
}
name = nameNode([name], true);
name = nameNode(name);
}
if (this.expect("(")) this.next();
const params = this.read_parameter_list();
Expand Down Expand Up @@ -240,7 +240,7 @@ module.exports = {
* ```
*/
read_type: function() {
const result = this.node("identifier");
const result = this.node("reference");
switch (this.token) {
case this.tok.T_ARRAY:
this.next();
Expand Down
6 changes: 3 additions & 3 deletions src/parser/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module.exports = {
return result(name.name, body, true);
} else if (this.token === "(") {
// resolve ambuiguity between namespace & function call
name.resolution = this.ast.identifier.RELATIVE_NAME;
name.resolution = this.ast.reference.RELATIVE_NAME;
name.name = name.name.substring(1);
return this.node("call")(name, this.read_function_argument_list());
} else {
Expand All @@ -59,10 +59,10 @@ module.exports = {
* namespace_name ::= T_NS_SEPARATOR? (T_STRING T_NS_SEPARATOR)* T_STRING
* ```
* @see http://php.net/manual/en/language.namespaces.rules.php
* @return {Identifier}
* @return {Reference}
*/
read_namespace_name: function() {
const result = this.node("identifier");
const result = this.node("reference");
let relative = false;
if (this.token === this.tok.T_NAMESPACE) {
this.next().expect(this.tok.T_NS_SEPARATOR) && this.next();
Expand Down
2 changes: 1 addition & 1 deletion src/parser/scalar.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ module.exports = {
// https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1239
name = null;
if (this.next().token === this.tok.T_STRING_VARNAME) {
const varName = this.text();
name = this.node("variable");
const varName = this.text();
this.next();
// check if lookup an offset
// https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1243
Expand Down
2 changes: 1 addition & 1 deletion src/parser/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ module.exports = {
* ```
*
* @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L726
* @return {Identifier[]}
* @return {Reference[]}
*/
read_name_list: function() {
return this.read_list(this.read_namespace_name, ",", false);
Expand Down
29 changes: 16 additions & 13 deletions src/parser/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,17 @@ module.exports = {
result = result("boolean", false, name.name);
} else {
// @todo null keyword ?
result = result("constref", name);
result = result("identifier", name);
}
} else {
// @fixme possible #193 bug
result = name;
}
} else if (this.token === this.tok.T_STATIC) {
result = this.node("constref");
result = this.node("identifier");
let name = this.text();
this.next();
result = result("static");
result = result(name);
} else {
this.expect("VARIABLE");
}
Expand All @@ -85,14 +86,14 @@ module.exports = {
this.token === this.tok.T_CLASS ||
(this.php7 && this.is("IDENTIFIER"))
) {
offset = this.node("constref");
offset = this.node("identifier");
name = this.text();
this.next();
offset = offset(name);
} else {
this.error([this.tok.T_VARIABLE, this.tok.T_STRING]);
// graceful mode : set getter as error node and continue
offset = this.node("constref");
offset = this.node("identifier");
name = this.text();
this.next();
offset = offset(name);
Expand Down Expand Up @@ -149,7 +150,7 @@ module.exports = {
this.next().token === this.tok.T_STRING ||
(this.php7 && this.is("IDENTIFIER"))
) {
offset = this.node("constref");
offset = this.node("identifier");
name = this.text();
this.next();
offset = offset(name);
Expand All @@ -159,9 +160,11 @@ module.exports = {
}
} else {
this.error(this.tok.T_STRING);
// fallback on a constref node
offset = this.node("constref")(this.text());
// fallback on an identifier node
offset = this.node("identifier");
name = this.text();
this.next();
offset = offset(name);
}
result = node(result, offset);
// static lookup dereferencables are limited to staticlookup over functions
Expand All @@ -174,7 +177,7 @@ module.exports = {
let what = null;
switch (this.next().token) {
case this.tok.T_STRING:
what = this.node("constref");
what = this.node("identifier");
name = this.text();
this.next();
what = what(name);
Expand Down Expand Up @@ -223,7 +226,7 @@ module.exports = {
default:
this.error([this.tok.T_STRING, this.tok.T_VARIABLE]);
// graceful mode : set what as error mode & continue
what = this.node("constref");
what = this.node("identifier");
name = this.text();
this.next();
what = what(name);
Expand All @@ -246,7 +249,7 @@ module.exports = {
if (this.token === this.tok.T_STRING) {
const text = this.text();
this.next();
offset = offset("constref", text);
offset = offset("identifier", text);
} else if (this.token === this.tok.T_NUM_STRING) {
const num = this.text();
this.next();
Expand All @@ -261,10 +264,10 @@ module.exports = {
this.tok.T_NUM_STRING,
this.tok.T_VARIABLE
]);
// fallback : consider as constref
// fallback : consider as identifier
const text = this.text();
this.next();
offset = offset("constref", text);
offset = offset("identifier", text);
}
return offset;
},
Expand Down
Loading

0 comments on commit 1030beb

Please sign in to comment.