Performance improvements (do not parse addresses or locations unless

location tracking is enabled). Allow profiling option. Add some
comments and clean-ups to types/*.go.
This commit is contained in:
Greg 2019-05-11 23:03:56 -04:00
parent 49fd749fe3
commit 8de87cddb7
24 changed files with 132 additions and 219 deletions

View File

@ -8,6 +8,8 @@ import (
"github.com/elliotchance/c2go/util" "github.com/elliotchance/c2go/util"
) )
var TrackPositions bool = false
// Node represents any node in the AST. // Node represents any node in the AST.
type Node interface { type Node interface {
Address() Address Address() Address
@ -27,6 +29,9 @@ type Address uint64
// ParseAddress returns the integer representation of the hexadecimal address // ParseAddress returns the integer representation of the hexadecimal address
// (like 0x7f8a1d8ccfd0). If the address cannot be parsed, 0 is returned. // (like 0x7f8a1d8ccfd0). If the address cannot be parsed, 0 is returned.
func ParseAddress(address string) Address { func ParseAddress(address string) Address {
if !TrackPositions {
return 0
}
addr, _ := strconv.ParseUint(address, 0, 64) addr, _ := strconv.ParseUint(address, 0, 64)
return Address(addr) return Address(addr)
@ -318,7 +323,6 @@ func groupsFromRegex(rx, line string) map[string]string {
rx = fullRegexp + "[\\s]*$" rx = fullRegexp + "[\\s]*$"
re := util.GetRegex(rx) re := util.GetRegex(rx)
match := re.FindStringSubmatch(line) match := re.FindStringSubmatch(line)
if len(match) == 0 { if len(match) == 0 {
panic("could not match regexp with string\n" + rx + "\n" + line + "\n") panic("could not match regexp with string\n" + rx + "\n" + line + "\n")

View File

@ -20,7 +20,7 @@ func parseBinaryOperator(line string) *BinaryOperator {
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Type: groups["type1"], Type: groups["type1"],
Type2: groups["type2"], //Type2: groups["type2"],
Operator: groups["operator"], Operator: groups["operator"],
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -26,7 +26,7 @@ func parseCStyleCastExpr(line string) *CStyleCastExpr {
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Type: groups["type1"], Type: groups["type1"],
Type2: groups["type2"], //Type2: groups["type2"],
Kind: groups["kind"], Kind: groups["kind"],
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -27,19 +27,19 @@ func parseEnumConstantDecl(line string) *EnumConstantDecl {
line, line,
) )
type2 := groups["type2"] /*type2 := groups["type2"]
if type2 != "" { if type2 != "" {
type2 = type2[2 : len(type2)-1] type2 = type2[2 : len(type2)-1]
} }*/
return &EnumConstantDecl{ return &EnumConstantDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: groups["position2"], //Position2: groups["position2"],
Referenced: len(groups["referenced"]) > 0, Referenced: len(groups["referenced"]) > 0,
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Type: removeQuotes(groups["type"]), Type: removeQuotes(groups["type"]),
Type2: type2, //Type2: type2,
ChildNodes: []Node{}, ChildNodes: []Node{},
} }
} }

View File

@ -26,18 +26,18 @@ func parseEnumDecl(line string) *EnumDecl {
line, line,
) )
type2 := groups["type2"] /*type2 := groups["type2"]
if type2 != "" { if type2 != "" {
type2 = type2[2 : len(type2)-1] type2 = type2[2 : len(type2)-1]
} }*/
return &EnumDecl{ return &EnumDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: groups["position2"], //Position2: groups["position2"],
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Type: removeQuotes(groups["type"]), Type: removeQuotes(groups["type"]),
Type2: type2, //Type2: type2,
ChildNodes: []Node{}, ChildNodes: []Node{},
} }
} }

View File

@ -26,7 +26,7 @@ func parseObjCCategoryDecl(line string) *ObjCCategoryDecl {
return &ObjCCategoryDecl{ return &ObjCCategoryDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -25,17 +25,10 @@ func parseObjCInterfaceDecl(line string) *ObjCInterfaceDecl {
line, line,
) )
/*fmt.Println(line)
fmt.Println("prev = ",groups["prev"])
fmt.Println("position = ",groups["position"])
fmt.Println("position2 = ",groups["position2"])
fmt.Println("implicit = ",len(groups["implicit"])>0)
fmt.Println("name = ",groups["name"])*/
return &ObjCInterfaceDecl{ return &ObjCInterfaceDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Implicit: len(groups["implicit"])>0, Implicit: len(groups["implicit"])>0,
ChildNodes: []Node{}, ChildNodes: []Node{},

View File

@ -42,13 +42,13 @@ func parseObjCMethodDecl(line string) *ObjCMethodDecl {
return &ObjCMethodDecl{ return &ObjCMethodDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Implicit: len(groups["implicit"])>0, Implicit: len(groups["implicit"]) > 0,
ClassMethod: groups["methodtype"] == " +", ClassMethod: groups["methodtype"] == " +",
Name: parts[0], Name: parts[0],
Parameters: params, Parameters: params,
Type: strings.TrimSpace(groups["type"]), Type: strings.TrimSpace(groups["type"]),
Type2: strings.TrimSpace(groups["type2"]), //Type2: strings.TrimSpace(groups["type2"]),
Attr: strings.TrimSpace(groups["attr"]), Attr: strings.TrimSpace(groups["attr"]),
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -33,8 +33,8 @@ func parseObjCPropertyDecl(line string) *ObjCPropertyDecl {
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Type: strings.TrimSpace(groups["type"]), Type: groups["type"],
Type2: strings.TrimSpace(groups["type2"]), //Type2: strings.TrimSpace(groups["type2"]),
Attr: strings.TrimSpace(groups["attr"]), Attr: strings.TrimSpace(groups["attr"]),
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -25,7 +25,7 @@ func parseObjCProtocolDecl(line string) *ObjCProtocolDecl {
return &ObjCProtocolDecl{ return &ObjCProtocolDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -32,10 +32,10 @@ func parseObjCTypeParamDecl(line string) *ObjCTypeParamDecl {
line, line,
) )
type2 := groups["type2"] /*type2 := groups["type2"]
if type2 != "" { if type2 != "" {
type2 = type2[2 : len(type2)-1] type2 = type2[2 : len(type2)-1]
} }*/
if strings.Index(groups["position"], "<invalid sloc>") > -1 { if strings.Index(groups["position"], "<invalid sloc>") > -1 {
groups["position"] = "<invalid sloc>" groups["position"] = "<invalid sloc>"
@ -45,10 +45,10 @@ func parseObjCTypeParamDecl(line string) *ObjCTypeParamDecl {
return &ObjCTypeParamDecl{ return &ObjCTypeParamDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Type: groups["type"], Type: groups["type"],
Type2: type2, //Type2: type2,
IsReferenced: len(groups["referenced"]) > 0, IsReferenced: len(groups["referenced"]) > 0,
IsCovariant: len(groups["covariant"]) > 0, IsCovariant: len(groups["covariant"]) > 0,
IsBounded : len(groups["bounded"]) > 0, IsBounded : len(groups["bounded"]) > 0,

View File

@ -32,23 +32,23 @@ func parseParmVarDecl(line string) *ParmVarDecl {
line, line,
) )
type2 := groups["type2"] /*type2 := groups["type2"]
if type2 != "" { if type2 != "" {
type2 = type2[2 : len(type2)-1] type2 = type2[2 : len(type2)-1]
} }*/
if strings.Index(groups["position"], "<invalid sloc>") > -1 { /*if strings.Index(groups["position"], "<invalid sloc>") > -1 {
groups["position"] = "<invalid sloc>" groups["position"] = "<invalid sloc>"
groups["position2"] = "<invalid sloc>" groups["position2"] = "<invalid sloc>"
} }*/
return &ParmVarDecl{ return &ParmVarDecl{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Name: strings.TrimSpace(groups["name"]), Name: strings.TrimSpace(groups["name"]),
Type: groups["type"], Type: groups["type"],
Type2: type2, //Type2: type2,
IsUsed: len(groups["used"]) > 0, IsUsed: len(groups["used"]) > 0,
IsReferenced: len(groups["referenced"]) > 0, IsReferenced: len(groups["referenced"]) > 0,
IsRegister: len(groups["register"]) > 0, IsRegister: len(groups["register"]) > 0,

View File

@ -33,6 +33,9 @@ func (p Position) GetSimpleLocation() (loc string) {
} }
func NewPositionFromString(s string) Position { func NewPositionFromString(s string) Position {
if !TrackPositions {
return Position{}
}
re := util.GetRegex(`<invalid sloc>|<scratch space>|<built-in>`) re := util.GetRegex(`<invalid sloc>|<scratch space>|<built-in>`)
if re.MatchString(s) || s == "" { if re.MatchString(s) || s == "" {
return Position{} return Position{}

View File

@ -25,7 +25,7 @@ func parseUnavailableAttr(line string) *UnavailableAttr {
return &UnavailableAttr{ return &UnavailableAttr{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Content: strings.TrimSpace(groups["content"]), Content: strings.TrimSpace(groups["content"]),
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -1,7 +1,7 @@
package ast package ast
import ( import (
"strings" //"strings"
) )
// Unknown is node represents an unknown node. // Unknown is node represents an unknown node.
@ -30,7 +30,7 @@ func parseUnknown(name, line string) *Unknown {
Name: name, Name: name,
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]), Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]), //Position2: strings.TrimSpace(groups["position2"]),
Content: groups["content"], Content: groups["content"],
ChildNodes: []Node{}, ChildNodes: []Node{},
} }

View File

@ -3,10 +3,12 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"os/exec" "os/exec"
"regexp" "regexp"
"runtime" "runtime"
"runtime/pprof"
"strings" "strings"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -16,8 +18,10 @@ import (
) )
var Debug = false var Debug = false
var Profile = false
type conf struct { type conf struct {
Positions bool
Package string Package string
Inputfiles []string Inputfiles []string
Classes []string Classes []string
@ -158,9 +162,7 @@ func Start() (err error) {
} }
} }
// 2. Preprocess NOT DONE // Generate AST
// 3. Generate AST
cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump", cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump",
"-fsyntax-only","-fno-color-diagnostics"} "-fsyntax-only","-fno-color-diagnostics"}
cargs = append(cargs,Config.Inputfiles...) cargs = append(cargs,Config.Inputfiles...)
@ -185,7 +187,12 @@ func Start() (err error) {
// Converting to nodes // Converting to nodes
fmt.Printf("Building nodes\n") fmt.Printf("Building nodes\n")
nodes := convertLinesToNodesParallel(lines) if Config.Positions {
ast.TrackPositions = true
}
//NOTE: converting in parallel is slower on my system
//nodes := convertLinesToNodesParallel(lines)
nodes := convertLinesToNodes(lines)
// build tree // build tree
fmt.Printf("Assembling tree\n") fmt.Printf("Assembling tree\n")
@ -231,6 +238,18 @@ func Start() (err error) {
} }
func main() { func main() {
if Profile {
f1, err := os.Create("cpuprofile.pprof")
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f1.Close()
if err := pprof.StartCPUProfile(f1); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}
confbytes, err := ioutil.ReadFile("nswrap.yaml") confbytes, err := ioutil.ReadFile("nswrap.yaml")
if err != nil { if err != nil {
fmt.Printf("Cannot open config file nswrap.yaml. %s\n",err) fmt.Printf("Cannot open config file nswrap.yaml. %s\n",err)
@ -244,4 +263,15 @@ func main() {
fmt.Printf("Error: %v\n", err) fmt.Printf("Error: %v\n", err)
os.Exit(-1) os.Exit(-1)
} }
if Profile {
f2, err := os.Create("memprofile.pprof")
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
defer f2.Close()
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f2); err != nil {
log.Fatal("could not write memory profile: ", err)
}
}
} }

View File

@ -89,7 +89,7 @@ func app() {
func main() { func main() {
//Run our app in an autorelease pool just for fun //Run our app in an autorelease pool just for fun
go ns.Autorelease(app) go ns.Autoreleasepool(app)
select { } select { }
} }

View File

@ -30,9 +30,12 @@ func updateState(c *ns.CBCentralManager) {
func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) { func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) {
fmt.Printf("Did discover peripheral\n") fmt.Printf("Did discover peripheral\n")
c.StopScan() c.StopScan()
if peripheral != nil {
peripheral.Release()
}
peripheral = p peripheral = p
peripheral.Retain() peripheral.Retain()
c.ConnectPeripheral(p,nil) c.ConnectPeripheral(peripheral,nil)
} }
func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) { func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) {
@ -106,6 +109,7 @@ func main() {
queue := ns.DispatchQueueCreate(ns.CharWithGoString("st.wow.gitlab.ble"),nil) queue := ns.DispatchQueueCreate(ns.CharWithGoString("st.wow.gitlab.ble"),nil)
cd = ns.BleDelegateAlloc() cd = ns.BleDelegateAlloc()
cd.CentralManagerDidUpdateStateCallback(updateState) cd.CentralManagerDidUpdateStateCallback(updateState)
cd.CentralManagerDidDiscoverPeripheralCallback(discoverPeripheral) cd.CentralManagerDidDiscoverPeripheralCallback(discoverPeripheral)
cd.CentralManagerDidConnectPeripheralCallback(connectPeripheral) cd.CentralManagerDidConnectPeripheralCallback(connectPeripheral)

View File

@ -1,7 +1,6 @@
package types package types
import ( import (
//"fmt"
"regexp" "regexp"
) )
@ -17,26 +16,12 @@ func init() {
reservedwords = regexp.MustCompile("^(void|char|short|int|long|float|double|signed|unsigned|_Bool|_Complex|const|restrict|volatile|struct|union|enum)$") reservedwords = regexp.MustCompile("^(void|char|short|int|long|float|double|signed|unsigned|_Bool|_Complex|const|restrict|volatile|struct|union|enum)$")
} }
//Parser is a function that takes the string to be parsed plus an input Node
//and returns a new Node and the unparsed remainder string. If the parser fails
//to parse anything in the input, it should return a nil Node.
type Parser func(string, *Node) (string, *Node) type Parser func(string, *Node) (string, *Node)
// Adders // Adders -- add elements to the Node tree
//Child takes a parser and adds its output node (if non-nil) to the tree.
//FIXME -- broken?
func Child(p Parser) Parser {
return func(s string, n *Node) (string, *Node) {
dbg("Child(%s %p)\n",n.Kind,n)
s2,n2 := p(s,n)
if n2 == nil {
return s,nil
}
if n2 != n {
dbg("Child(%p): AddChild()\n",p)
n.AddChild(n2)
}
return s2,n
}
}
//ChildOf takes a node and adds results of a parser to it as a child //ChildOf takes a node and adds results of a parser to it as a child
func ChildOf(ret *Node, p Parser) Parser { func ChildOf(ret *Node, p Parser) Parser {
@ -100,9 +85,10 @@ func NodeNamed(k string, p Parser) Parser {
} }
} }
// Combinators // Combinators -- combine one or more Parsers into a new Parser.
//Opt optionally runs a Parser, returning the input node if it fails //Opt optionally runs a Parser, returning the input Node (instead of nil)
//if it fails
func Opt(p Parser) Parser { func Opt(p Parser) Parser {
return func(s string, n *Node) (string, *Node) { return func(s string, n *Node) (string, *Node) {
s2,n2 := p(s,n) s2,n2 := p(s,n)
@ -127,29 +113,6 @@ func OneOf(ps ...Parser) Parser {
} }
} }
//Doesn't work? May have side effects that do not get unwound.
func Longest(ps ...Parser) Parser {
dbg("Longest(%p)\n",ps)
return func(s string, n *Node) (string, *Node) {
ss := make([]string,len(ps))
ns := make([]*Node,len(ps))
//An arbitrarily large number so I don't have to import "math"
minrem := 10000
mini := 0
for i,p := range ps {
ss[i],ns[i] = p(s,n)
if ns[i] != nil && len(ss[i]) < minrem {
minrem = len(ss[i])
mini = i
}
}
if minrem < 10000 {
return ss[mini],ns[mini]
}
return s,nil
}
}
//Seq applies parsers in sequence, adding results as children to the input //Seq applies parsers in sequence, adding results as children to the input
//node. Returns nil and the input string unless the entire sequence succeeds //node. Returns nil and the input string unless the entire sequence succeeds
func Seq(ps ...Parser) Parser { func Seq(ps ...Parser) Parser {
@ -172,7 +135,8 @@ func Seq(ps ...Parser) Parser {
return Children(p) return Children(p)
} }
//Like Seq but subsequent children are nested inside their earlier siblings. //Nest is like Seq but subsequent children are nested inside their earlier
//siblings.
func Nest(ps ...Parser) Parser { func Nest(ps ...Parser) Parser {
dbg("Nest(%p)\n",ps) dbg("Nest(%p)\n",ps)
p := func(s string, n *Node) (string, *Node) { p := func(s string, n *Node) (string, *Node) {
@ -212,32 +176,41 @@ func ZeroOrMore(p Parser) Parser {
return Children(ret) return Children(ret)
} }
//OneOrMore is ZeroOrMore, but fails (returns nil) if the input parser does
//not match any elements.
func OneOrMore(p Parser) Parser { func OneOrMore(p Parser) Parser {
return Seq(p,ZeroOrMore(p)) return Seq(p,ZeroOrMore(p))
} }
//Parenthesized matches the input parser surrounded by literal parenthesis.
func Parenthesized(p Parser) Parser { func Parenthesized(p Parser) Parser {
return Children(Seq(Lit("("),p,Lit(")"))) return Children(Seq(Lit("("),p,Lit(")")))
} }
//Bracketed matches the input parser surrounded by literal square brackets.
func Bracketed(p Parser) Parser { func Bracketed(p Parser) Parser {
return Seq(Lit("["),p,Lit("]")) return Seq(Lit("["),p,Lit("]"))
} }
//AngBracketed matches the input parser surrounded by literal angled brackets.
func AngBracketed(p Parser) Parser { func AngBracketed(p Parser) Parser {
return Children(Seq(Lit("<"),p,Lit(">"))) return Children(Seq(Lit("<"),p,Lit(">")))
} }
//CurlyBracketed matches the input parser surrounded by literal curly brackets.
func CurlyBracketed(p Parser) Parser { func CurlyBracketed(p Parser) Parser {
return Children(Seq(Lit("{"),p,Lit("}"))) return Children(Seq(Lit("{"),p,Lit("}")))
} }
// Recognizers // Recognizers -- these functions return parsers that match tokens in the input
// stream. There is no separate tokenizer.
//Word matches an element with a word boundary after its end
func Word(f string) Parser { func Word(f string) Parser {
return Lit(f,true) return Lit(f,true)
} }
//Lit matches a literal string
func Lit(f string, ws ...bool) Parser { func Lit(f string, ws ...bool) Parser {
word := false word := false
if len(ws) > 0 { if len(ws) > 0 {
@ -261,6 +234,7 @@ func Lit(f string, ws ...bool) Parser {
} }
} }
//Regexp matches a regular expression at the beginning of the input string
func Regexp(f string) Parser { func Regexp(f string) Parser {
f = "^" + f f = "^" + f
r := regexp.MustCompile(f) r := regexp.MustCompile(f)

View File

@ -33,7 +33,6 @@ var TypeParameters map[string]map[string]string
var typedefs map[string]*Type var typedefs map[string]*Type
func (t *Type) Typedef() *Type { func (t *Type) Typedef() *Type {
//return typedefs[t.BaseType().CType()]
return typedefs[t.CType()] return typedefs[t.CType()]
} }
@ -78,7 +77,6 @@ func AddTypedef(n,t string) {
type Type struct { type Type struct {
Node *Node Node *Node
Class string Class string
ctype string
Variadic bool Variadic bool
} }
@ -96,7 +94,7 @@ func clean(n *Node,c string) (*Node,bool) {
} }
ret := NewNode(n.Kind,n.Content) ret := NewNode(n.Kind,n.Content)
ret.Children = n.Children ret.Children = n.Children
//fmt.Printf("clean(%s,%s)\n",n.Ctype(),c) //fmt.Printf("clean(%s,%s)\n",n.CType(),c)
recur := false recur := false
if TypeParameters[c] != nil { if TypeParameters[c] != nil {
for k,v := range TypeParameters[c] { for k,v := range TypeParameters[c] {
@ -127,7 +125,7 @@ func NewTypeFromString(t,c string) *Type {
} }
if n2,ok := clean(n, c); ok { if n2,ok := clean(n, c); ok {
//found type parameters, re-parse //found type parameters, re-parse
return NewTypeFromString(n2.Ctype(),c) return NewTypeFromString(n2.CType(),c)
} }
return &Type{ return &Type{
Node: n, Node: n,
@ -216,24 +214,16 @@ func (t *Type) _CType(attrib bool) string {
//fmt.Println("nil sent to _CType()") //fmt.Println("nil sent to _CType()")
return "" return ""
} }
//if !attrib && t.ctype != "" { // cache
// return t.ctype
//}
var ct string var ct string
if attrib { if attrib {
ignore := map[string]bool { "GenericList": true } ignore := map[string]bool { "GenericList": true }
ct = t.Node._Ctype(ignore) ct = t.Node._CType(ignore)
} else { } else {
ct = t.Node.CtypeSimplified() ct = t.Node.CTypeSimplified()
} }
ct = r_id.ReplaceAllString(ct,"NSObject*") ct = r_id.ReplaceAllString(ct,"NSObject*")
ct = r_instancename.ReplaceAllString(ct,t.Class) ct = r_instancename.ReplaceAllString(ct,t.Class)
ct = r_instancetype.ReplaceAllString(ct,t.Class + "*") ct = r_instancetype.ReplaceAllString(ct,t.Class + "*")
if attrib {
t._CType(false)
} else {
t.ctype = ct
}
return ct return ct
} }
@ -295,7 +285,7 @@ func (t *Type) IsFunctionPtr() bool {
if td := t.Typedef(); td != nil { if td := t.Typedef(); td != nil {
return td.IsFunctionPtr() return td.IsFunctionPtr()
} }
for pt := t.PointsTo(); pt != nil; pt = pt.PointsTo() { if pt := t.PointsTo(); pt != nil {
return pt.IsFunction() return pt.IsFunction()
} }
return false return false
@ -326,7 +316,8 @@ func (t *Type) IsPointer() bool {
return t.Node.IsPointer() return t.Node.IsPointer()
} }
func (t *Type) CToGo(cval string) string { // cast C value to CGo // cast C value to CGo
func (t *Type) CToGo(cval string) string {
if t.IsPointer() { if t.IsPointer() {
cval = "unsafe.Pointer(" + cval + ")" cval = "unsafe.Pointer(" + cval + ")"
} }
@ -334,7 +325,7 @@ func (t *Type) CToGo(cval string) string { // cast C value to CGo
} }
// Call a C function from Go with a given return type and parameter types // Call a C function from Go with a given return type and parameter types
func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string { func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type, fun bool) string {
if rtype == nil { if rtype == nil {
fmt.Println("nil sent to GoToC") fmt.Println("nil sent to GoToC")
return "" return ""
@ -367,7 +358,7 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string {
switch { switch {
case pt.Variadic: case pt.Variadic:
p = "unsafe.Pointer(&" + p + ")" p = "unsafe.Pointer(&" + p + ")"
case pt.IsPointer(): case pt.IsPointer() && !fun:
p = "unsafe.Pointer(" + pn + ")" p = "unsafe.Pointer(" + pn + ")"
default: default:
p = "(" + pt.CGoType() + ")(" + pn + ")" p = "(" + pt.CGoType() + ")(" + pn + ")"

View File

@ -1,85 +1,6 @@
package types package types
/* Parsers for recognizing type names in C/Objective-C // A parser to recognize type names in C/Objective-C
type-name:
specifier-qualifier-list abstract-declarator<opt>
abstract-declarator:
pointer
pointer<opt> direct-abstract-declarator
direct-abstract-declarator:
( abstract-declarator )
direct-abstract-declarator<opt> [ type-qualifier-list<opt> assignment-expression<opt> ]
direct-abstract-declarator<opt> [ static type-qualifier-list<opt> assignment-expression ]
direct-abstract-declarator<opt> [ type-qualifier-list static assignment-expression ]
direct-abstract-declarator<opt> [ * ]
direct-abstract-declarator<opt> ( parameter-type-list<opt> )
pointer:
* type-qualifier-list<opt>
* type-qualifier-list<opt> pointer
parameter-type-list:
parameter-list
parameter-list , ...
parameter-list:
parameter-declaration
parameter-list , parameter-declaration
parameter-declaration:
declaration-specifiers declarator
declaration-specifiers abstract-declarator<opt>
type-qualifier-list:
type-qualifier
type-qualifier-list type-qualifier
specifier-qualifier-list:
type-specifier specifier-qualifier-list<opt>
type-qualifier specifier-qualifier-list<opt>
type-specifier:
void
char
short
int
long
float
double
signed
unsigned
_Bool
_Complex
struct-or-union-specifier
enum-specifier
typedef-name
type-qualifier:
const
restrict
volatile
struct-or-union-specifier:
// DON'T DO struct-or-union identifier<opt> { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
struct-declarator-list:
struct-declarator
struct-declarator-list , struct-declarator
struct-declarator:
declarator
declarator<opt>: constant-expression
identifier:
identifier-non-digit
identifier identifier-nondigit
identifier digit
identifier-nondigit:
nondigit
universal-character-name
nondigit:
_ [a-zA-Z]
digit:
[0-9]
*/
import ( import (
"regexp" "regexp"
@ -94,6 +15,7 @@ func init() {
return !instancetype.MatchString(s) && !instancename.MatchString(s) return !instancetype.MatchString(s) && !instancename.MatchString(s)
} }
//memoize the TypeName function for performance
cache := map[string]*Node{} cache := map[string]*Node{}
TypeName = func(s string, n *Node) (string, *Node) { TypeName = func(s string, n *Node) (string, *Node) {
if n2,ok := cache[s]; ok { if n2,ok := cache[s]; ok {
@ -105,6 +27,8 @@ func init() {
} }
return s2,n2 return s2,n2
} }
//for debug purposes, the following line can be uncommented, which will
//memoization memoization
//TypeName = _TypeName //TypeName = _TypeName
} }
@ -120,7 +44,6 @@ func AbstractDeclarator(s string, n *Node) (string, *Node) {
Opt(Pointer), Opt(Pointer),
OneOrMore(DirectAbstractDeclarator)), OneOrMore(DirectAbstractDeclarator)),
Pointer, Pointer,
//Id,
Block, Block,
)(s,n) )(s,n)
} }
@ -227,14 +150,6 @@ func NullableAnnotation(s string, n *Node) (string, *Node) {
))(s,n) ))(s,n)
} }
func Id(s string, n *Node) (string, *Node) {
return Seq(
NodeNamed("Id",Lit("id")),
Opt(TypeQualifierList),
Opt(NullableAnnotation),
)(s,n)
}
func Pointer(s string, n *Node) (string, *Node) { func Pointer(s string, n *Node) (string, *Node) {
return Seq( return Seq(
NodeNamed("Pointer",Lit("*")), NodeNamed("Pointer",Lit("*")),
@ -280,9 +195,7 @@ func TypeSpecifier(s string, n *Node) (string, *Node) {
Word("unsigned"), Word("unsigned"),
Word("_Bool"), Word("_Bool"),
Word("_Complex"), Word("_Complex"),
//StructOrUnionSpecifier,
EnumSpecifier, EnumSpecifier,
//TypedefName,
))(s,n) ))(s,n)
} }

View File

@ -36,15 +36,15 @@ func Parse(s string) (*Node, error) {
} }
//Evaluate a node to determine if it is a pointer or array //Evaluate a node to determine if it is a pointer or array
func (n *Node) isAbstract(k string) bool { func (n *Node) isIndirect(k string) bool {
if n.stripAbstract(k) == nil { if n.stripIndirect(k) == nil {
return false return false
} }
return true return true
} }
//Strip one level of pointer or array indirection from a node //Strip one level of pointer or array indirection from a node
func (n *Node) stripAbstract(k string) *Node { func (n *Node) stripIndirect(k string) *Node {
if n == nil { if n == nil {
return nil return nil
} }
@ -55,14 +55,14 @@ func (n *Node) stripAbstract(k string) *Node {
ret := NewNode(n.Kind) ret := NewNode(n.Kind)
cs := append([]*Node{},n.Children...) cs := append([]*Node{},n.Children...)
dbg("stripAbstract(): i = %d\n",i) dbg("stripIndirect(): i = %d\n",i)
//Scan backwords skipping TypeQualifier and NullableAnnotation tags //Scan backwords skipping TypeQualifier and NullableAnnotation tags
for ;i > 0 && for ;i > 0 &&
(cs[i].Kind == "TypeQualifier" || (cs[i].Kind == "TypeQualifier" ||
cs[i].Kind == "NullableAnnotation") ; i-- { } cs[i].Kind == "NullableAnnotation") ; i-- { }
if cs[i].Kind == k { if cs[i].Kind == k {
dbg("stripAbstract(): last node is %s\n",k) dbg("stripIndirect(): last node is %s\n",k)
ret.Children = cs[:i] ret.Children = cs[:i]
return ret return ret
} }
@ -92,7 +92,7 @@ func (n *Node) stripAbstract(k string) *Node {
//pointed to. Otherwise returns nil when called on non-pointer types. //pointed to. Otherwise returns nil when called on non-pointer types.
func (n *Node) PointsTo() *Node { func (n *Node) PointsTo() *Node {
dbg("PointsTo()\n") dbg("PointsTo()\n")
return n.stripAbstract("Pointer") return n.stripIndirect("Pointer")
} }
//IsPointer returns true if the node is a pointer //IsPointer returns true if the node is a pointer
@ -108,7 +108,7 @@ func (n *Node) IsPointer() bool {
//non-array types. //non-array types.
func (n *Node) ArrayOf() *Node { func (n *Node) ArrayOf() *Node {
dbg("ArrayOf()\n") dbg("ArrayOf()\n")
return n.stripAbstract("Array") return n.stripIndirect("Array")
} }
//IsArray returns true if the node is an array //IsArray returns true if the node is an array

View File

@ -13,6 +13,8 @@ type Node struct {
Children []*Node Children []*Node
} }
//NewNode returns a new node of kind k with an optional content string as its
//second parameter.
func NewNode(k string,cs ...string) *Node { func NewNode(k string,cs ...string) *Node {
c := "" c := ""
if len(cs) > 0 { if len(cs) > 0 {
@ -56,7 +58,6 @@ func (n *Node) AddChild(c *Node) *Node {
// Skip literals // Skip literals
if c.Kind == "Lit" { return n } if c.Kind == "Lit" { return n }
// Do we already have this child? (FIXME: Not needed?)
for _,d := range n.Children { for _,d := range n.Children {
if c == d { if c == d {
return n return n
@ -85,21 +86,21 @@ func (n *Node) renameTypedefs(a,b string) (ret bool) {
return return
} }
func (n *Node) CtypeSimplified() string { func (n *Node) CTypeSimplified() string {
ignore := map[string]bool{ ignore := map[string]bool{
"NullableAnnotation": true, "NullableAnnotation": true,
"KindQualifier": true, "KindQualifier": true,
"TypeQualifier": true, "TypeQualifier": true,
"GenericList": true, "GenericList": true,
} }
return n._Ctype(ignore) return n._CType(ignore)
} }
func (n *Node) Ctype() string { func (n *Node) CType() string {
return n._Ctype(map[string]bool{}) return n._CType(map[string]bool{})
} }
func (n *Node) _Ctype(ignore map[string]bool) string { func (n *Node) _CType(ignore map[string]bool) string {
if n == nil || ignore[n.Kind] { if n == nil || ignore[n.Kind] {
return "" return ""
} }
@ -108,7 +109,7 @@ func (n *Node) _Ctype(ignore map[string]bool) string {
ret := []string{} ret := []string{}
if n == nil { return ret } if n == nil { return ret }
for _,c := range n.Children { for _,c := range n.Children {
if x := c._Ctype(ignore); x != "" { if x := c._CType(ignore); x != "" {
ret = append(ret, x) ret = append(ret, x)
} }
} }

View File

@ -659,7 +659,7 @@ func (o *NSAutoreleasePool) Init() *NSAutoreleasePool {
return (*NSAutoreleasePool)(unsafe.Pointer(C.NSAutoreleasePool_init(o.Ptr()))) return (*NSAutoreleasePool)(unsafe.Pointer(C.NSAutoreleasePool_init(o.Ptr())))
} }
func Autorelease(f func()) { func Autoreleasepool(f func()) {
pool := NSAutoreleasePoolAlloc().Init() pool := NSAutoreleasePoolAlloc().Init()
f() f()
pool.Drain() pool.Drain()
@ -777,7 +777,7 @@ func %s%s(%s) %s {
`,vn,w.Vaargs,vn,vn)) `,vn,w.Vaargs,vn,vn))
} }
w.goCode.WriteString(` ` + w.goCode.WriteString(` ` +
types.GoToC(cname,ns,m.Type,tps) + "\n}\n") types.GoToC(cname,ns,m.Type,tps,fun) + "\n}\n")
cret := "" cret := ""
if !m.isVoid() { if !m.isVoid() {
@ -936,7 +936,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
} else { } else {
pm := m.Parameters[0] pm := m.Parameters[0]
w.processType(pm.Type) w.processType(pm.Type)
parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.Ctype(),pm.Vname) parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.CType(),pm.Vname)
vnames[i][1] = pm.Vname vnames[i][1] = pm.Vname
gtypes[i][0] = pm.Type.GoType() gtypes[i][0] = pm.Type.GoType()
if pm.Type.IsPointer() { if pm.Type.IsPointer() {
@ -948,7 +948,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
for j := 1; j < len(m.Parameters); j++ { for j := 1; j < len(m.Parameters); j++ {
pm := m.Parameters[j] pm := m.Parameters[j]
w.processType(pm.Type) w.processType(pm.Type)
parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.Ctype(),pm.Vname) parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.CType(),pm.Vname)
vnames[i][j+1] = pm.Vname vnames[i][j+1] = pm.Vname
gtypes[i][j] = pm.Type.GoType() gtypes[i][j] = pm.Type.GoType()
var getp string var getp string
@ -960,7 +960,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
getypes[i][j+1] = getp getypes[i][j+1] = getp
} }
methprotos[i] = fmt.Sprintf( methprotos[i] = fmt.Sprintf(
`- (%s)%s%s;`,m.Type.Node.Ctype(),m.Name,parms) `- (%s)%s%s;`,m.Type.Node.CType(),m.Name,parms)
if x := m.Type.GoType(); x == "Void" { if x := m.Type.GoType(); x == "Void" {
grtypes[i] = "" grtypes[i] = ""
} else { } else {