2019-04-18 09:38:46 -04:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
Debug bool = false
|
|
|
|
)
|
|
|
|
|
2019-04-18 10:21:03 -04:00
|
|
|
func dbg(f string, xs ...interface{}) {
|
|
|
|
if Debug {
|
|
|
|
fmt.Printf(f,xs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-23 15:48:11 -04:00
|
|
|
func (n *Node) HasFunc() bool {
|
|
|
|
if n == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _,c := range n.Children {
|
|
|
|
if c.Kind == "Function" || c.HasFunc() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2019-04-18 14:04:01 -04:00
|
|
|
|
2019-04-18 14:40:02 -04:00
|
|
|
func Parse(s string) (*Node, error) {
|
|
|
|
s2, n := TypeName(s,NewNode("AST"))
|
2019-04-30 06:59:05 -04:00
|
|
|
//fmt.Printf("%p Parsed %s\n",n,s)
|
2019-04-18 14:40:02 -04:00
|
|
|
if s2 != "" {
|
|
|
|
return n,fmt.Errorf("Parse failed or incomplete. Remainder: %s",s2)
|
|
|
|
}
|
|
|
|
return n, nil
|
2019-04-18 09:38:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
//Evaluate a node to determine if it is a pointer or array
|
|
|
|
func (n *Node) isAbstract(k string) bool {
|
|
|
|
if n.stripAbstract(k) == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
//Strip one level of pointer or array indirection from a node
|
|
|
|
func (n *Node) stripAbstract(k string) *Node {
|
2019-04-18 10:21:03 -04:00
|
|
|
if n == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-04-18 09:38:46 -04:00
|
|
|
i := len(n.Children) - 1
|
|
|
|
if i < 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ret := NewNode(n.Kind)
|
2019-05-03 13:14:30 -04:00
|
|
|
cs := append([]*Node{},n.Children...)
|
2019-04-18 09:38:46 -04:00
|
|
|
|
2019-04-18 10:21:03 -04:00
|
|
|
dbg("stripAbstract(): i = %d\n",i)
|
|
|
|
//Scan backwords skipping TypeQualifier and NullableAnnotation tags
|
|
|
|
for ;i > 0 &&
|
|
|
|
(cs[i].Kind == "TypeQualifier" ||
|
|
|
|
cs[i].Kind == "NullableAnnotation") ; i-- { }
|
2019-04-18 09:38:46 -04:00
|
|
|
|
|
|
|
if cs[i].Kind == k {
|
2019-04-18 10:21:03 -04:00
|
|
|
dbg("stripAbstract(): last node is %s\n",k)
|
2019-04-18 09:38:46 -04:00
|
|
|
ret.Children = cs[:i]
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
if i > 1 && cs[i-1].Kind == "Parenthesized" {
|
|
|
|
j := len(cs[i-1].Children) - 1
|
2019-04-18 10:21:03 -04:00
|
|
|
for ;j > 0 &&
|
|
|
|
(cs[i-1].Children[j].Kind == "TypeQualifier" ||
|
|
|
|
cs[i-1].Children[j].Kind == "NullableAnnotation");
|
|
|
|
j-- { }
|
2019-04-18 09:38:46 -04:00
|
|
|
if cs[i-1].Children[j].Kind != k {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if j == 0 { // strip Parenthesized tag
|
|
|
|
cs[i-1] = cs[i]
|
|
|
|
ret.Children = cs[:i]
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
// strip last child from Parenthesized tag
|
|
|
|
cs[i-1].Children = cs[i-1].Children[:j]
|
|
|
|
ret.Children = cs
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//PointsTo, when called on a pointer node returns a node describing the type
|
|
|
|
//pointed to. Otherwise returns nil when called on non-pointer types.
|
|
|
|
func (n *Node) PointsTo() *Node {
|
2019-04-18 10:21:03 -04:00
|
|
|
dbg("PointsTo()\n")
|
2019-04-18 09:38:46 -04:00
|
|
|
return n.stripAbstract("Pointer")
|
|
|
|
}
|
|
|
|
|
2019-04-23 15:48:11 -04:00
|
|
|
//IsPointer returns true if the node is a pointer
|
|
|
|
func (n *Node) IsPointer() bool {
|
2019-05-03 13:14:30 -04:00
|
|
|
if pt := n.PointsTo(); pt != nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return n.IsInstancetype() || n.IsId()
|
2019-04-23 15:48:11 -04:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:38:46 -04:00
|
|
|
//ArrayOf, when called on an array node returns a node describing the type
|
|
|
|
//of the elements of the array. Otherwise returns nil when called on
|
|
|
|
//non-array types.
|
|
|
|
func (n *Node) ArrayOf() *Node {
|
2019-04-18 10:21:03 -04:00
|
|
|
dbg("ArrayOf()\n")
|
2019-04-18 09:38:46 -04:00
|
|
|
return n.stripAbstract("Array")
|
|
|
|
}
|
|
|
|
|
2019-04-23 15:48:11 -04:00
|
|
|
//IsArray returns true if the node is an array
|
|
|
|
func (n *Node) IsArray() bool {
|
|
|
|
return n.ArrayOf() != nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) IsStruct() bool {
|
|
|
|
if n == nil || len(n.Children) < 1 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return n.Children[0].Kind == "Struct"
|
|
|
|
}
|
|
|
|
|
2019-04-26 10:07:34 -04:00
|
|
|
func (n *Node) IsFunction() bool {
|
|
|
|
if n == nil || len(n.Children) < 1 {
|
|
|
|
return false
|
|
|
|
}
|
2019-05-03 13:14:30 -04:00
|
|
|
if pt := n.PointsTo(); pt != nil {
|
|
|
|
return false
|
|
|
|
}
|
2019-04-26 10:07:34 -04:00
|
|
|
return n.Children[len(n.Children)-1].Kind == "Function"
|
|
|
|
}
|
|
|
|
|
2019-05-01 10:58:29 -04:00
|
|
|
func (n *Node) ReturnType() *Node {
|
|
|
|
if !n.IsFunction() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ret := NewNode(n.Kind)
|
|
|
|
ret.Children = n.Children[:len(n.Children)-1]
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2019-04-26 22:44:30 -04:00
|
|
|
func (n *Node) IsId() bool {
|
|
|
|
if n == nil || len(n.Children) < 1 {
|
|
|
|
return false
|
|
|
|
}
|
2019-05-03 13:14:30 -04:00
|
|
|
return !n.IsFunction() &&
|
|
|
|
n.Children[0].Kind == "TypedefName" &&
|
2019-05-01 10:58:29 -04:00
|
|
|
n.Children[0].Content == "id"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) IsInstancetype() bool {
|
|
|
|
if n == nil || len(n.Children) < 1 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return n.Children[0].Kind == "TypedefName" &&
|
|
|
|
n.Children[0].Content == "instancetype"
|
2019-04-26 22:44:30 -04:00
|
|
|
}
|
|
|
|
|
2019-04-23 15:48:11 -04:00
|
|
|
//BaseType strips off all layers of pointer indirection
|
|
|
|
func (n *Node) BaseType() *Node {
|
|
|
|
if n == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if n2 := n.PointsTo(); n2 == nil {
|
|
|
|
return n
|
|
|
|
} else {
|
|
|
|
return n2.BaseType()
|
|
|
|
}
|
|
|
|
}
|