diff --git a/ast/ast.go b/ast/ast.go index 6e1b5a5..3ee2b7c 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -8,6 +8,8 @@ import ( "github.com/elliotchance/c2go/util" ) +var TrackPositions bool = false + // Node represents any node in the AST. type Node interface { Address() Address @@ -27,6 +29,9 @@ type Address uint64 // ParseAddress returns the integer representation of the hexadecimal address // (like 0x7f8a1d8ccfd0). If the address cannot be parsed, 0 is returned. func ParseAddress(address string) Address { + if !TrackPositions { + return 0 + } addr, _ := strconv.ParseUint(address, 0, 64) return Address(addr) @@ -318,7 +323,6 @@ func groupsFromRegex(rx, line string) map[string]string { rx = fullRegexp + "[\\s]*$" re := util.GetRegex(rx) - match := re.FindStringSubmatch(line) if len(match) == 0 { panic("could not match regexp with string\n" + rx + "\n" + line + "\n") diff --git a/ast/binary_operator.go b/ast/binary_operator.go index a1d894b..49f750d 100644 --- a/ast/binary_operator.go +++ b/ast/binary_operator.go @@ -20,7 +20,7 @@ func parseBinaryOperator(line string) *BinaryOperator { Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Type: groups["type1"], - Type2: groups["type2"], + //Type2: groups["type2"], Operator: groups["operator"], ChildNodes: []Node{}, } diff --git a/ast/c_style_cast_expr.go b/ast/c_style_cast_expr.go index 49658ea..6519f2c 100644 --- a/ast/c_style_cast_expr.go +++ b/ast/c_style_cast_expr.go @@ -26,7 +26,7 @@ func parseCStyleCastExpr(line string) *CStyleCastExpr { Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Type: groups["type1"], - Type2: groups["type2"], + //Type2: groups["type2"], Kind: groups["kind"], ChildNodes: []Node{}, } diff --git a/ast/enum_constant_decl.go b/ast/enum_constant_decl.go index 03cf79d..8c2b2d4 100644 --- a/ast/enum_constant_decl.go +++ b/ast/enum_constant_decl.go @@ -27,19 +27,19 @@ func parseEnumConstantDecl(line string) *EnumConstantDecl { line, ) - type2 := groups["type2"] + /*type2 := groups["type2"] if type2 != "" { type2 = type2[2 : len(type2)-1] - } + }*/ return &EnumConstantDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: groups["position2"], + //Position2: groups["position2"], Referenced: len(groups["referenced"]) > 0, Name: strings.TrimSpace(groups["name"]), Type: removeQuotes(groups["type"]), - Type2: type2, + //Type2: type2, ChildNodes: []Node{}, } } diff --git a/ast/enum_decl.go b/ast/enum_decl.go index ff8b21e..089db1a 100644 --- a/ast/enum_decl.go +++ b/ast/enum_decl.go @@ -26,18 +26,18 @@ func parseEnumDecl(line string) *EnumDecl { line, ) - type2 := groups["type2"] + /*type2 := groups["type2"] if type2 != "" { type2 = type2[2 : len(type2)-1] - } + }*/ return &EnumDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: groups["position2"], + //Position2: groups["position2"], Name: strings.TrimSpace(groups["name"]), Type: removeQuotes(groups["type"]), - Type2: type2, + //Type2: type2, ChildNodes: []Node{}, } } diff --git a/ast/objc_category_decl.go b/ast/objc_category_decl.go index 336a48b..cff80bf 100644 --- a/ast/objc_category_decl.go +++ b/ast/objc_category_decl.go @@ -26,7 +26,7 @@ func parseObjCCategoryDecl(line string) *ObjCCategoryDecl { return &ObjCCategoryDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), ChildNodes: []Node{}, } diff --git a/ast/objc_interface_decl.go b/ast/objc_interface_decl.go index 82fb6f8..5999fda 100644 --- a/ast/objc_interface_decl.go +++ b/ast/objc_interface_decl.go @@ -25,17 +25,10 @@ func parseObjCInterfaceDecl(line string) *ObjCInterfaceDecl { 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{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), Implicit: len(groups["implicit"])>0, ChildNodes: []Node{}, diff --git a/ast/objc_method_decl.go b/ast/objc_method_decl.go index 9d2cf9e..42e2e7a 100644 --- a/ast/objc_method_decl.go +++ b/ast/objc_method_decl.go @@ -42,13 +42,13 @@ func parseObjCMethodDecl(line string) *ObjCMethodDecl { return &ObjCMethodDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), - Implicit: len(groups["implicit"])>0, + //Position2: strings.TrimSpace(groups["position2"]), + Implicit: len(groups["implicit"]) > 0, ClassMethod: groups["methodtype"] == " +", Name: parts[0], Parameters: params, Type: strings.TrimSpace(groups["type"]), - Type2: strings.TrimSpace(groups["type2"]), + //Type2: strings.TrimSpace(groups["type2"]), Attr: strings.TrimSpace(groups["attr"]), ChildNodes: []Node{}, } diff --git a/ast/objc_property_decl.go b/ast/objc_property_decl.go index 646016e..05c925d 100644 --- a/ast/objc_property_decl.go +++ b/ast/objc_property_decl.go @@ -33,8 +33,8 @@ func parseObjCPropertyDecl(line string) *ObjCPropertyDecl { Pos: NewPositionFromString(groups["position"]), Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), - Type: strings.TrimSpace(groups["type"]), - Type2: strings.TrimSpace(groups["type2"]), + Type: groups["type"], + //Type2: strings.TrimSpace(groups["type2"]), Attr: strings.TrimSpace(groups["attr"]), ChildNodes: []Node{}, } diff --git a/ast/objc_protocol_decl.go b/ast/objc_protocol_decl.go index 9dd957e..746454f 100644 --- a/ast/objc_protocol_decl.go +++ b/ast/objc_protocol_decl.go @@ -25,7 +25,7 @@ func parseObjCProtocolDecl(line string) *ObjCProtocolDecl { return &ObjCProtocolDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), ChildNodes: []Node{}, } diff --git a/ast/objc_type_param_decl.go b/ast/objc_type_param_decl.go index 7dd3111..bd1412d 100644 --- a/ast/objc_type_param_decl.go +++ b/ast/objc_type_param_decl.go @@ -32,10 +32,10 @@ func parseObjCTypeParamDecl(line string) *ObjCTypeParamDecl { line, ) - type2 := groups["type2"] + /*type2 := groups["type2"] if type2 != "" { type2 = type2[2 : len(type2)-1] - } + }*/ if strings.Index(groups["position"], "") > -1 { groups["position"] = "" @@ -45,10 +45,10 @@ func parseObjCTypeParamDecl(line string) *ObjCTypeParamDecl { return &ObjCTypeParamDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), Type: groups["type"], - Type2: type2, + //Type2: type2, IsReferenced: len(groups["referenced"]) > 0, IsCovariant: len(groups["covariant"]) > 0, IsBounded : len(groups["bounded"]) > 0, diff --git a/ast/parm_var_decl.go b/ast/parm_var_decl.go index 3b423ef..bd42b2d 100644 --- a/ast/parm_var_decl.go +++ b/ast/parm_var_decl.go @@ -32,23 +32,23 @@ func parseParmVarDecl(line string) *ParmVarDecl { line, ) - type2 := groups["type2"] + /*type2 := groups["type2"] if type2 != "" { type2 = type2[2 : len(type2)-1] - } + }*/ - if strings.Index(groups["position"], "") > -1 { + /*if strings.Index(groups["position"], "") > -1 { groups["position"] = "" groups["position2"] = "" - } + }*/ return &ParmVarDecl{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Name: strings.TrimSpace(groups["name"]), Type: groups["type"], - Type2: type2, + //Type2: type2, IsUsed: len(groups["used"]) > 0, IsReferenced: len(groups["referenced"]) > 0, IsRegister: len(groups["register"]) > 0, diff --git a/ast/position.go b/ast/position.go index fb7be21..df171d0 100644 --- a/ast/position.go +++ b/ast/position.go @@ -33,6 +33,9 @@ func (p Position) GetSimpleLocation() (loc string) { } func NewPositionFromString(s string) Position { + if !TrackPositions { + return Position{} + } re := util.GetRegex(`||`) if re.MatchString(s) || s == "" { return Position{} diff --git a/ast/unavailable_attr.go b/ast/unavailable_attr.go index d5f5a48..85c7fd4 100644 --- a/ast/unavailable_attr.go +++ b/ast/unavailable_attr.go @@ -25,7 +25,7 @@ func parseUnavailableAttr(line string) *UnavailableAttr { return &UnavailableAttr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Content: strings.TrimSpace(groups["content"]), ChildNodes: []Node{}, } diff --git a/ast/unknown.go b/ast/unknown.go index 63138db..3e33e9b 100644 --- a/ast/unknown.go +++ b/ast/unknown.go @@ -1,7 +1,7 @@ package ast import ( - "strings" + //"strings" ) // Unknown is node represents an unknown node. @@ -30,7 +30,7 @@ func parseUnknown(name, line string) *Unknown { Name: name, Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), - Position2: strings.TrimSpace(groups["position2"]), + //Position2: strings.TrimSpace(groups["position2"]), Content: groups["content"], ChildNodes: []Node{}, } diff --git a/cmd/nswrap/main.go b/cmd/nswrap/main.go index 40919e1..2e73a7e 100644 --- a/cmd/nswrap/main.go +++ b/cmd/nswrap/main.go @@ -3,10 +3,12 @@ package main import ( "fmt" "io/ioutil" + "log" "os" "os/exec" "regexp" "runtime" + "runtime/pprof" "strings" "gopkg.in/yaml.v2" @@ -16,8 +18,10 @@ import ( ) var Debug = false +var Profile = false type conf struct { + Positions bool Package string Inputfiles []string Classes []string @@ -158,9 +162,7 @@ func Start() (err error) { } } - // 2. Preprocess NOT DONE - - // 3. Generate AST + // Generate AST cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump", "-fsyntax-only","-fno-color-diagnostics"} cargs = append(cargs,Config.Inputfiles...) @@ -185,7 +187,12 @@ func Start() (err error) { // Converting to nodes 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 fmt.Printf("Assembling tree\n") @@ -231,6 +238,18 @@ func Start() (err error) { } 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") if err != nil { fmt.Printf("Cannot open config file nswrap.yaml. %s\n",err) @@ -244,4 +263,15 @@ func main() { fmt.Printf("Error: %v\n", err) 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) + } + } } diff --git a/examples/app/main.go b/examples/app/main.go index 55bda4f..3c4a6ea 100644 --- a/examples/app/main.go +++ b/examples/app/main.go @@ -89,7 +89,7 @@ func app() { func main() { //Run our app in an autorelease pool just for fun - go ns.Autorelease(app) + go ns.Autoreleasepool(app) select { } } diff --git a/examples/bluetooth/main.go b/examples/bluetooth/main.go index 2d30d38..a31e8d7 100644 --- a/examples/bluetooth/main.go +++ b/examples/bluetooth/main.go @@ -30,9 +30,12 @@ func updateState(c *ns.CBCentralManager) { func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) { fmt.Printf("Did discover peripheral\n") c.StopScan() + if peripheral != nil { + peripheral.Release() + } peripheral = p peripheral.Retain() - c.ConnectPeripheral(p,nil) + c.ConnectPeripheral(peripheral,nil) } func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) { @@ -106,6 +109,7 @@ func main() { queue := ns.DispatchQueueCreate(ns.CharWithGoString("st.wow.gitlab.ble"),nil) cd = ns.BleDelegateAlloc() + cd.CentralManagerDidUpdateStateCallback(updateState) cd.CentralManagerDidDiscoverPeripheralCallback(discoverPeripheral) cd.CentralManagerDidConnectPeripheralCallback(connectPeripheral) diff --git a/types/combinators.go b/types/combinators.go index 90350f7..ee5e1fd 100644 --- a/types/combinators.go +++ b/types/combinators.go @@ -1,7 +1,6 @@ package types import ( - //"fmt" "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)$") } +//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) -// Adders - -//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 - } -} +// Adders -- add elements to the Node tree //ChildOf takes a node and adds results of a parser to it as a child 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 { return func(s string, n *Node) (string, *Node) { 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 //node. Returns nil and the input string unless the entire sequence succeeds func Seq(ps ...Parser) Parser { @@ -172,7 +135,8 @@ func Seq(ps ...Parser) Parser { 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 { dbg("Nest(%p)\n",ps) p := func(s string, n *Node) (string, *Node) { @@ -212,32 +176,41 @@ func ZeroOrMore(p Parser) Parser { return Children(ret) } +//OneOrMore is ZeroOrMore, but fails (returns nil) if the input parser does +//not match any elements. func OneOrMore(p Parser) Parser { return Seq(p,ZeroOrMore(p)) } +//Parenthesized matches the input parser surrounded by literal parenthesis. func Parenthesized(p Parser) Parser { return Children(Seq(Lit("("),p,Lit(")"))) } +//Bracketed matches the input parser surrounded by literal square brackets. func Bracketed(p Parser) Parser { return Seq(Lit("["),p,Lit("]")) } +//AngBracketed matches the input parser surrounded by literal angled brackets. func AngBracketed(p Parser) Parser { return Children(Seq(Lit("<"),p,Lit(">"))) } +//CurlyBracketed matches the input parser surrounded by literal curly brackets. func CurlyBracketed(p Parser) Parser { 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 { return Lit(f,true) } +//Lit matches a literal string func Lit(f string, ws ...bool) Parser { word := false 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 { f = "^" + f r := regexp.MustCompile(f) diff --git a/types/convert.go b/types/convert.go index d8ec381..254c23e 100644 --- a/types/convert.go +++ b/types/convert.go @@ -33,7 +33,6 @@ var TypeParameters map[string]map[string]string var typedefs map[string]*Type func (t *Type) Typedef() *Type { - //return typedefs[t.BaseType().CType()] return typedefs[t.CType()] } @@ -78,7 +77,6 @@ func AddTypedef(n,t string) { type Type struct { Node *Node Class string - ctype string Variadic bool } @@ -96,7 +94,7 @@ func clean(n *Node,c string) (*Node,bool) { } ret := NewNode(n.Kind,n.Content) ret.Children = n.Children - //fmt.Printf("clean(%s,%s)\n",n.Ctype(),c) + //fmt.Printf("clean(%s,%s)\n",n.CType(),c) recur := false if TypeParameters[c] != nil { for k,v := range TypeParameters[c] { @@ -127,7 +125,7 @@ func NewTypeFromString(t,c string) *Type { } if n2,ok := clean(n, c); ok { //found type parameters, re-parse - return NewTypeFromString(n2.Ctype(),c) + return NewTypeFromString(n2.CType(),c) } return &Type{ Node: n, @@ -216,24 +214,16 @@ func (t *Type) _CType(attrib bool) string { //fmt.Println("nil sent to _CType()") return "" } - //if !attrib && t.ctype != "" { // cache - // return t.ctype - //} var ct string if attrib { ignore := map[string]bool { "GenericList": true } - ct = t.Node._Ctype(ignore) + ct = t.Node._CType(ignore) } else { - ct = t.Node.CtypeSimplified() + ct = t.Node.CTypeSimplified() } ct = r_id.ReplaceAllString(ct,"NSObject*") ct = r_instancename.ReplaceAllString(ct,t.Class) ct = r_instancetype.ReplaceAllString(ct,t.Class + "*") - if attrib { - t._CType(false) - } else { - t.ctype = ct - } return ct } @@ -295,7 +285,7 @@ func (t *Type) IsFunctionPtr() bool { if td := t.Typedef(); td != nil { return td.IsFunctionPtr() } - for pt := t.PointsTo(); pt != nil; pt = pt.PointsTo() { + if pt := t.PointsTo(); pt != nil { return pt.IsFunction() } return false @@ -326,7 +316,8 @@ func (t *Type) IsPointer() bool { 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() { 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 -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 { fmt.Println("nil sent to GoToC") return "" @@ -367,7 +358,7 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string { switch { case pt.Variadic: p = "unsafe.Pointer(&" + p + ")" - case pt.IsPointer(): + case pt.IsPointer() && !fun: p = "unsafe.Pointer(" + pn + ")" default: p = "(" + pt.CGoType() + ")(" + pn + ")" diff --git a/types/cparser.go b/types/cparser.go index cb2a695..4463885 100644 --- a/types/cparser.go +++ b/types/cparser.go @@ -1,85 +1,6 @@ package types -/* Parsers for recognizing type names in C/Objective-C - -type-name: - specifier-qualifier-list abstract-declarator -abstract-declarator: - pointer - pointer direct-abstract-declarator -direct-abstract-declarator: - ( abstract-declarator ) - direct-abstract-declarator [ type-qualifier-list assignment-expression ] - direct-abstract-declarator [ static type-qualifier-list assignment-expression ] - direct-abstract-declarator [ type-qualifier-list static assignment-expression ] - direct-abstract-declarator [ * ] - direct-abstract-declarator ( parameter-type-list ) -pointer: - * type-qualifier-list - * type-qualifier-list 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 -type-qualifier-list: - type-qualifier - type-qualifier-list type-qualifier -specifier-qualifier-list: - type-specifier specifier-qualifier-list - type-qualifier specifier-qualifier-list -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 { 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: constant-expression -identifier: - identifier-non-digit - identifier identifier-nondigit - identifier digit -identifier-nondigit: - nondigit - universal-character-name -nondigit: - _ [a-zA-Z] -digit: - [0-9] -*/ +// A parser to recognize type names in C/Objective-C import ( "regexp" @@ -94,6 +15,7 @@ func init() { return !instancetype.MatchString(s) && !instancename.MatchString(s) } + //memoize the TypeName function for performance cache := map[string]*Node{} TypeName = func(s string, n *Node) (string, *Node) { if n2,ok := cache[s]; ok { @@ -105,6 +27,8 @@ func init() { } return s2,n2 } + //for debug purposes, the following line can be uncommented, which will + //memoization memoization //TypeName = _TypeName } @@ -120,7 +44,6 @@ func AbstractDeclarator(s string, n *Node) (string, *Node) { Opt(Pointer), OneOrMore(DirectAbstractDeclarator)), Pointer, - //Id, Block, )(s,n) } @@ -227,14 +150,6 @@ func NullableAnnotation(s string, n *Node) (string, *Node) { ))(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) { return Seq( NodeNamed("Pointer",Lit("*")), @@ -280,9 +195,7 @@ func TypeSpecifier(s string, n *Node) (string, *Node) { Word("unsigned"), Word("_Bool"), Word("_Complex"), - //StructOrUnionSpecifier, EnumSpecifier, - //TypedefName, ))(s,n) } diff --git a/types/main.go b/types/main.go index c2a4fad..7648586 100644 --- a/types/main.go +++ b/types/main.go @@ -36,15 +36,15 @@ func Parse(s string) (*Node, error) { } //Evaluate a node to determine if it is a pointer or array -func (n *Node) isAbstract(k string) bool { - if n.stripAbstract(k) == nil { +func (n *Node) isIndirect(k string) bool { + if n.stripIndirect(k) == nil { return false } return true } //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 { return nil } @@ -55,14 +55,14 @@ func (n *Node) stripAbstract(k string) *Node { ret := NewNode(n.Kind) cs := append([]*Node{},n.Children...) - dbg("stripAbstract(): i = %d\n",i) + dbg("stripIndirect(): i = %d\n",i) //Scan backwords skipping TypeQualifier and NullableAnnotation tags for ;i > 0 && (cs[i].Kind == "TypeQualifier" || cs[i].Kind == "NullableAnnotation") ; i-- { } 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] return ret } @@ -92,7 +92,7 @@ func (n *Node) stripAbstract(k string) *Node { //pointed to. Otherwise returns nil when called on non-pointer types. func (n *Node) PointsTo() *Node { dbg("PointsTo()\n") - return n.stripAbstract("Pointer") + return n.stripIndirect("Pointer") } //IsPointer returns true if the node is a pointer @@ -108,7 +108,7 @@ func (n *Node) IsPointer() bool { //non-array types. func (n *Node) ArrayOf() *Node { dbg("ArrayOf()\n") - return n.stripAbstract("Array") + return n.stripIndirect("Array") } //IsArray returns true if the node is an array diff --git a/types/node.go b/types/node.go index 9dc714a..8613708 100644 --- a/types/node.go +++ b/types/node.go @@ -13,6 +13,8 @@ type Node struct { 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 { c := "" if len(cs) > 0 { @@ -56,7 +58,6 @@ func (n *Node) AddChild(c *Node) *Node { // Skip literals if c.Kind == "Lit" { return n } - // Do we already have this child? (FIXME: Not needed?) for _,d := range n.Children { if c == d { return n @@ -85,21 +86,21 @@ func (n *Node) renameTypedefs(a,b string) (ret bool) { return } -func (n *Node) CtypeSimplified() string { +func (n *Node) CTypeSimplified() string { ignore := map[string]bool{ "NullableAnnotation": true, "KindQualifier": true, "TypeQualifier": true, "GenericList": true, } - return n._Ctype(ignore) + return n._CType(ignore) } -func (n *Node) Ctype() string { - return n._Ctype(map[string]bool{}) +func (n *Node) CType() string { + 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] { return "" } @@ -108,7 +109,7 @@ func (n *Node) _Ctype(ignore map[string]bool) string { ret := []string{} if n == nil { return ret } for _,c := range n.Children { - if x := c._Ctype(ignore); x != "" { + if x := c._CType(ignore); x != "" { ret = append(ret, x) } } diff --git a/wrap/main.go b/wrap/main.go index 5b6a324..4d57489 100644 --- a/wrap/main.go +++ b/wrap/main.go @@ -659,7 +659,7 @@ func (o *NSAutoreleasePool) Init() *NSAutoreleasePool { return (*NSAutoreleasePool)(unsafe.Pointer(C.NSAutoreleasePool_init(o.Ptr()))) } -func Autorelease(f func()) { +func Autoreleasepool(f func()) { pool := NSAutoreleasePoolAlloc().Init() f() pool.Drain() @@ -777,7 +777,7 @@ func %s%s(%s) %s { `,vn,w.Vaargs,vn,vn)) } w.goCode.WriteString(` ` + - types.GoToC(cname,ns,m.Type,tps) + "\n}\n") + types.GoToC(cname,ns,m.Type,tps,fun) + "\n}\n") cret := "" if !m.isVoid() { @@ -936,7 +936,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { } else { pm := m.Parameters[0] 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 gtypes[i][0] = pm.Type.GoType() if pm.Type.IsPointer() { @@ -948,7 +948,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { for j := 1; j < len(m.Parameters); j++ { pm := m.Parameters[j] 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 gtypes[i][j] = pm.Type.GoType() var getp string @@ -960,7 +960,7 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { getypes[i][j+1] = getp } 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" { grtypes[i] = "" } else {