alias resolving

This commit is contained in:
z7zmey 2018-02-26 20:21:11 +02:00
parent 90f451293d
commit fbeffe7d29
2 changed files with 99 additions and 27 deletions

View File

@ -42,6 +42,8 @@ func main() {
nsResolver := visitor.NewNsResolver() nsResolver := visitor.NewNsResolver()
nodes.Walk(nsResolver) nodes.Walk(nsResolver)
fmt.Printf("%+v \n", nsResolver.ResolvedNames)
dumper := visitor.Dumper{ dumper := visitor.Dumper{
Indent: " | ", Indent: " | ",
Comments: comments, Comments: comments,

View File

@ -2,6 +2,7 @@
package visitor package visitor
import ( import (
"errors"
"strings" "strings"
"github.com/z7zmey/php-parser/node" "github.com/z7zmey/php-parser/node"
@ -10,6 +11,22 @@ import (
"github.com/z7zmey/php-parser/walker" "github.com/z7zmey/php-parser/walker"
) )
func concatNameParts(parts ...[]node.Node) string {
str := ""
for _, p := range parts {
for _, n := range p {
if str == "" {
str = n.(*name.NamePart).Value
} else {
str = str + "\\" + n.(*name.NamePart).Value
}
}
}
return str
}
type Namespace struct { type Namespace struct {
Namespace string Namespace string
Aliases map[string]map[string]string Aliases map[string]map[string]string
@ -17,7 +34,7 @@ type Namespace struct {
func NewNamespace(NSName string) *Namespace { func NewNamespace(NSName string) *Namespace {
return &Namespace{ return &Namespace{
Namespace: "", Namespace: NSName,
Aliases: map[string]map[string]string{ Aliases: map[string]map[string]string{
"": {}, "": {},
"const": {}, "const": {},
@ -36,6 +53,53 @@ func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string)
} }
} }
func (ns *Namespace) resolveName(nameNode node.Node, aliasType string) string {
switch n := nameNode.(type) {
case *name.FullyQualified:
return concatNameParts(n.Parts)
case *name.Relative:
return ns.Namespace + "\\" + concatNameParts(n.Parts)
case *name.Name:
aliasName, err := ns.resolveAlias(nameNode, aliasType)
if err != nil {
return ns.Namespace + "\\" + concatNameParts(n.Parts)
}
if len(n.Parts) > 1 {
return aliasName + "\\" + concatNameParts(n.Parts[1:])
}
return aliasName
}
panic("invalid nameNode variable type")
}
func (ns *Namespace) resolveAlias(nameNode node.Node, aliasType string) (string, error) {
aliasType = strings.ToLower(aliasType)
nameParts := nameNode.(*name.Name).Parts
firstPartStr := nameParts[0].(*name.NamePart).Value
if len(nameParts) > 1 { // resolve aliases for qualified names, always against class alias table
firstPartStr = strings.ToLower(firstPartStr)
aliasType = ""
} else {
if aliasType != "const" { // constans are case-sensitive
firstPartStr = strings.ToLower(firstPartStr)
}
}
aliasName, ok := ns.Aliases[aliasType][firstPartStr]
if !ok {
return "", errors.New("Not found")
}
return aliasName, nil
}
type NsResolver struct { type NsResolver struct {
Namespace *Namespace Namespace *Namespace
ResolvedNames map[node.Node]string ResolvedNames map[node.Node]string
@ -86,11 +150,36 @@ func (nsr *NsResolver) EnterNode(w walker.Walkable) bool {
// no reason to iterate into depth // no reason to iterate into depth
return false return false
case *stmt.Class:
if n.Extends != nil {
nsr.resolveName(n.Extends, "")
}
for _, _ = range n.Implements {
// todo resolve inteface name
}
nsr.addNamespacedName(n, n.ClassName.(*node.Identifier).Value)
} }
return true return true
} }
// GetChildrenVisitor is invoked at every node parameter that contains children nodes
func (nsr *NsResolver) GetChildrenVisitor(key string) walker.Visitor {
return nsr
}
// LeaveNode is invoked after node process
func (nsr *NsResolver) LeaveNode(w walker.Walkable) {
switch n := w.(type) {
case *stmt.Namespace:
if n.Stmts != nil {
nsr.Namespace = NewNamespace("")
}
}
}
func (nsr *NsResolver) AddAlias(useType string, nn node.Node, prefix []node.Node) { func (nsr *NsResolver) AddAlias(useType string, nn node.Node, prefix []node.Node) {
switch use := nn.(type) { switch use := nn.(type) {
case *stmt.Use: case *stmt.Use:
@ -110,33 +199,14 @@ func (nsr *NsResolver) AddAlias(useType string, nn node.Node, prefix []node.Node
} }
} }
// GetChildrenVisitor is invoked at every node parameter that contains children nodes func (nsr *NsResolver) addNamespacedName(nn node.Node, nodeName string) {
func (nsr *NsResolver) GetChildrenVisitor(key string) walker.Visitor { if nsr.Namespace.Namespace == "" {
return nsr nsr.ResolvedNames[nn] = nodeName
}
// LeaveNode is invoked after node process
func (nsr *NsResolver) LeaveNode(w walker.Walkable) {
switch n := w.(type) {
case *stmt.Namespace:
if n.Stmts != nil {
nsr.Namespace = NewNamespace("")
}
}
}
func concatNameParts(parts ...[]node.Node) string {
str := ""
for _, p := range parts {
for _, n := range p {
if str == "" {
str = n.(*name.NamePart).Value
} else { } else {
str = str + "\\" + n.(*name.NamePart).Value nsr.ResolvedNames[nn] = nsr.Namespace.Namespace + "\\" + nodeName
}
} }
} }
return str func (nsr *NsResolver) resolveName(nameNode node.Node, aliasType string) {
nsr.ResolvedNames[nameNode] = nsr.Namespace.resolveName(nameNode, aliasType)
} }