| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // The objc package takes the result of an AST traversal by the
- // importers package and uses the clang command to dump the type
- // information for the referenced ObjC classes and protocols.
- //
- // It is the of go/types for ObjC types and is used by the bind
- // package to generate Go wrappers for ObjC API on iOS.
- package objc
- import (
- "bufio"
- "bytes"
- "fmt"
- "os/exec"
- "strings"
- "unicode"
- "unicode/utf8"
- "golang.org/x/mobile/internal/importers"
- )
- type parser struct {
- sdkPath string
- sc *bufio.Scanner
- decl string
- indent int
- last string
- // Current module as parsed from the AST tree.
- module string
- }
- type TypeKind int
- // Named represents ObjC classes and protocols.
- type Named struct {
- Name string
- GoName string
- Module string
- Funcs []*Func
- Methods []*Func
- AllMethods []*Func
- Supers []Super
- // For deduplication of function or method
- // declarations.
- funcMap map[string]struct{}
- Protocol bool
- // Generated is true if the type is wrapper of a
- // generated Go struct.
- Generated bool
- }
- // Super denotes a super class or protocol.
- type Super struct {
- Name string
- Protocol bool
- }
- // Func is a ObjC method, static functions as well as
- // instance methods.
- type Func struct {
- Sig string
- GoName string
- Params []*Param
- Ret *Type
- Static bool
- // Method whose name start with "init"
- Constructor bool
- }
- type Param struct {
- Name string
- Type *Type
- }
- type Type struct {
- Kind TypeKind
- // For Interface and Protocol types.
- Name string
- // For 'id' types.
- instanceType bool
- // The declared type raw from the AST.
- Decl string
- // Set if the type is a pointer to its kind. For classes
- // Indirect is true if the type is a double pointer, e.g.
- // NSObject **.
- Indirect bool
- }
- const (
- Unknown TypeKind = iota
- Protocol
- Class
- String
- Data
- Int
- Uint
- Short
- Ushort
- Bool
- Char
- Uchar
- Float
- Double
- )
- // Import returns descriptors for a list of references to
- // ObjC protocols and classes.
- //
- // The type information is parsed from the output of clang -cc1
- // -ast-dump.
- func Import(refs *importers.References) ([]*Named, error) {
- var modules []string
- modMap := make(map[string]struct{})
- typeNames := make(map[string][]string)
- typeSet := make(map[string]struct{})
- genMods := make(map[string]struct{})
- for _, emb := range refs.Embedders {
- genMods[initialUpper(emb.Pkg)] = struct{}{}
- }
- for _, ref := range refs.Refs {
- var module, name string
- if idx := strings.Index(ref.Pkg, "/"); idx != -1 {
- // ref is a static method reference.
- module = ref.Pkg[:idx]
- name = ref.Pkg[idx+1:]
- } else {
- // ref is a type name.
- module = ref.Pkg
- name = ref.Name
- }
- if _, exists := typeSet[name]; !exists {
- typeNames[module] = append(typeNames[module], name)
- typeSet[name] = struct{}{}
- }
- if _, exists := modMap[module]; !exists {
- // Include the module only if it is generated.
- if _, exists := genMods[module]; !exists {
- modMap[module] = struct{}{}
- modules = append(modules, module)
- }
- }
- }
- sdkPathOut, err := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-path").CombinedOutput()
- if err != nil {
- return nil, err
- }
- sdkPath := strings.TrimSpace(string(sdkPathOut))
- var allTypes []*Named
- typeMap := make(map[string]*Named)
- for _, module := range modules {
- types, err := importModule(string(sdkPath), module, typeNames[module], typeMap)
- if err != nil {
- return nil, fmt.Errorf("%s: %v", module, err)
- }
- allTypes = append(allTypes, types...)
- }
- // Embedders refer to every exported Go struct that will have its class
- // generated. Allow Go code to reverse bind to those classes by synthesizing
- // their descriptors.
- for _, emb := range refs.Embedders {
- module := initialUpper(emb.Pkg)
- named := &Named{
- Name: module + emb.Name,
- GoName: emb.Name,
- Module: module,
- Generated: true,
- }
- for _, ref := range emb.Refs {
- t, exists := typeMap[ref.Name]
- if !exists {
- return nil, fmt.Errorf("type not found: %q", ref.Name)
- }
- named.Supers = append(named.Supers, Super{
- Name: t.Name,
- Protocol: t.Protocol,
- })
- }
- typeMap[emb.Name] = named
- allTypes = append(allTypes, named)
- }
- initTypes(allTypes, refs, typeMap)
- // Include implicit types that are used in parameter or return values.
- newTypes := allTypes
- for len(newTypes) > 0 {
- var impTypes []*Named
- for _, t := range newTypes {
- for _, funcs := range [][]*Func{t.Funcs, t.AllMethods} {
- for _, f := range funcs {
- types := implicitFuncTypes(f)
- for _, name := range types {
- if _, exists := typeSet[name]; exists {
- continue
- }
- typeSet[name] = struct{}{}
- t, exists := typeMap[name]
- if !exists {
- return nil, fmt.Errorf("implicit type %q not found", name)
- }
- impTypes = append(impTypes, t)
- }
- }
- }
- }
- initTypes(impTypes, refs, typeMap)
- allTypes = append(allTypes, impTypes...)
- newTypes = impTypes
- }
- return allTypes, nil
- }
- func implicitFuncTypes(f *Func) []string {
- var types []string
- if rt := f.Ret; rt != nil && !rt.instanceType && (rt.Kind == Class || rt.Kind == Protocol) {
- types = append(types, rt.Name)
- }
- for _, p := range f.Params {
- if t := p.Type; !t.instanceType && (t.Kind == Class || t.Kind == Protocol) {
- types = append(types, t.Name)
- }
- }
- return types
- }
- func initTypes(types []*Named, refs *importers.References, typeMap map[string]*Named) {
- for _, t := range types {
- fillAllMethods(t, typeMap)
- }
- // Move constructors to functions. They are represented in Go
- // as functions.
- for _, t := range types {
- var methods []*Func
- for _, f := range t.AllMethods {
- if f.Constructor {
- f.Static = true
- t.Funcs = append(t.Funcs, f)
- } else {
- methods = append(methods, f)
- }
- }
- t.AllMethods = methods
- }
- for _, t := range types {
- mangleMethodNames(t.AllMethods)
- mangleMethodNames(t.Funcs)
- }
- filterReferences(types, refs, typeMap)
- for _, t := range types {
- resolveInstanceTypes(t, t.Funcs)
- resolveInstanceTypes(t, t.AllMethods)
- }
- }
- func filterReferences(types []*Named, refs *importers.References, typeMap map[string]*Named) {
- refFuncs := make(map[[2]string]struct{})
- for _, ref := range refs.Refs {
- if sep := strings.Index(ref.Pkg, "/"); sep != -1 {
- pkgName := ref.Pkg[sep+1:]
- n := typeMap[pkgName]
- if n == nil {
- continue
- }
- refFuncs[[...]string{pkgName, ref.Name}] = struct{}{}
- }
- }
- for _, t := range types {
- var filtered []*Func
- for _, f := range t.Funcs {
- if _, exists := refFuncs[[...]string{t.GoName, f.GoName}]; exists {
- filtered = append(filtered, f)
- }
- }
- t.Funcs = filtered
- filtered = nil
- for _, m := range t.Methods {
- if _, exists := refs.Names[m.GoName]; exists {
- filtered = append(filtered, m)
- }
- }
- t.Methods = filtered
- filtered = nil
- for _, m := range t.AllMethods {
- if _, exists := refs.Names[m.GoName]; exists {
- filtered = append(filtered, m)
- }
- }
- t.AllMethods = filtered
- }
- }
- // mangleMethodNames assigns unique Go names to ObjC methods. If a method name is unique
- // within the same method list, its name is used with its first letter in upper case.
- // Multiple methods with the same name have their full signature appended, with : removed.
- func mangleMethodNames(allFuncs []*Func) {
- goName := func(n string, constructor bool) string {
- if constructor {
- n = "new" + n[len("init"):]
- }
- return initialUpper(n)
- }
- overloads := make(map[string][]*Func)
- for i, f := range allFuncs {
- // Copy function so each class can have its own
- // name mangling.
- f := *f
- allFuncs[i] = &f
- f.GoName = goName(f.Sig, f.Constructor)
- if colon := strings.Index(f.GoName, ":"); colon != -1 {
- f.GoName = f.GoName[:colon]
- }
- overloads[f.GoName] = append(overloads[f.GoName], &f)
- }
- fallbacks := make(map[string][]*Func)
- for _, funcs := range overloads {
- if len(funcs) == 1 {
- continue
- }
- for _, f := range funcs {
- sig := f.Sig
- if strings.HasSuffix(sig, ":") {
- sig = sig[:len(sig)-1]
- }
- sigElems := strings.Split(f.Sig, ":")
- for i := 0; i < len(sigElems); i++ {
- sigElems[i] = initialUpper(sigElems[i])
- }
- name := strings.Join(sigElems, "")
- f.GoName = goName(name, f.Constructor)
- fallbacks[f.GoName] = append(fallbacks[f.GoName], f)
- }
- }
- for _, funcs := range fallbacks {
- if len(funcs) == 1 {
- continue
- }
- for _, f := range funcs {
- name := strings.Replace(f.Sig, ":", "_", -1)
- f.GoName = goName(name, f.Constructor)
- }
- }
- }
- func resolveInstanceType(n *Named, t *Type) *Type {
- if !t.instanceType || t.Kind != Protocol {
- return t
- }
- // Copy and update the type name for instancetype types
- ct := *t
- ct.instanceType = false
- ct.Decl = n.Name + " *"
- if n.Name == "NSString" {
- ct.Kind = String
- ct.Name = ""
- } else {
- ct.Kind = Class
- ct.Name = n.Name
- }
- return &ct
- }
- func resolveInstanceTypes(n *Named, funcs []*Func) {
- for _, f := range funcs {
- for _, p := range f.Params {
- p.Type = resolveInstanceType(n, p.Type)
- }
- if f.Ret != nil {
- f.Ret = resolveInstanceType(n, f.Ret)
- }
- }
- }
- func fillAllMethods(n *Named, typeMap map[string]*Named) {
- if len(n.AllMethods) > 0 {
- return
- }
- if len(n.Supers) == 0 {
- n.AllMethods = n.Methods
- return
- }
- for _, sup := range n.Supers {
- super := lookup(sup.Name, sup.Protocol, typeMap)
- fillAllMethods(super, typeMap)
- }
- methods := make(map[string]struct{})
- for _, sup := range n.Supers {
- super := lookup(sup.Name, sup.Protocol, typeMap)
- for _, f := range super.AllMethods {
- if _, exists := methods[f.Sig]; !exists {
- methods[f.Sig] = struct{}{}
- n.AllMethods = append(n.AllMethods, f)
- }
- }
- }
- for _, f := range n.Methods {
- if _, exists := methods[f.Sig]; !exists {
- n.AllMethods = append(n.AllMethods, f)
- }
- }
- }
- const (
- frameworksPath = "/System/Library/Frameworks/"
- )
- // importModule parses ObjC type information with clang -cc1 -ast-dump.
- //
- // TODO: Use module.map files to precisely model the @import Module.Identifier
- // directive. For now, importModules assumes the single umbrella header
- // file Module.framework/Headers/Module.h contains every declaration.
- func importModule(sdkPath, module string, identifiers []string, typeMap map[string]*Named) ([]*Named, error) {
- hFile := fmt.Sprintf(sdkPath+frameworksPath+"%s.framework/Headers/%[1]s.h", module)
- clang := exec.Command("xcrun", "--sdk", "iphonesimulator", "clang", "-cc1", "-triple", "x86_64-apple-ios8.0.0-simulator", "-isysroot", sdkPath, "-ast-dump", "-fblocks", "-fobjc-arc", "-x", "objective-c", hFile)
- out, err := clang.CombinedOutput()
- if err != nil {
- return nil, fmt.Errorf("clang failed to parse module: %v: %s", err, out)
- }
- p := &parser{
- sdkPath: sdkPath,
- sc: bufio.NewScanner(bytes.NewBuffer(out)),
- }
- if err := p.parseModule(module, typeMap); err != nil {
- return nil, err
- }
- var types []*Named
- for _, ident := range identifiers {
- named, exists := typeMap[ident]
- if !exists {
- return nil, fmt.Errorf("no such type: %s", ident)
- }
- types = append(types, named)
- }
- return types, nil
- }
- func (p *parser) scanLine() bool {
- for {
- l := p.last
- if l == "" {
- if !p.sc.Scan() {
- return false
- }
- l = p.sc.Text()
- } else {
- p.last = ""
- }
- indent := (strings.Index(l, "-") + 1) / 2
- switch {
- case indent > p.indent:
- // Skip
- case indent < p.indent:
- p.indent--
- p.last = l
- return false
- case indent == p.indent:
- p.decl = l[p.indent*2:]
- return true
- }
- }
- }
- func (p *parser) parseModule(module string, typeMap map[string]*Named) (err error) {
- defer func() {
- if rerr := recover(); rerr != nil {
- err = rerr.(error)
- }
- }()
- if !p.scanLine() {
- return nil
- }
- // A header file AST starts with
- //
- // TranslationUnitDecl 0x103833ad0 <<invalid sloc>> <invalid sloc>
- if w := p.scanWord(); w != "TranslationUnitDecl" {
- return fmt.Errorf("unexpected AST root: %q", w)
- }
- p.indent++
- for {
- if !p.scanLine() {
- break
- }
- switch w := p.scanWord(); w {
- case "ObjCCategoryDecl":
- // ObjCCategoryDecl 0x103d9bdb8 <line:48:1, line:63:2> line:48:12 NSDateCreation
- // |-ObjCInterface 0x103d9a788 'NSDate'
- // Skip the node address, the source code range, position.
- p.scanWord()
- p.parseLocation()
- catName := p.scanWord()
- p.indent++
- if !p.scanLine() {
- return fmt.Errorf("no interface for category %s", catName)
- }
- if w := p.scanWord(); w != "ObjCInterface" {
- return fmt.Errorf("unexpected declaaration %s for category %s", w, catName)
- }
- p.scanWord()
- clsName := p.scanWord()
- clsName = clsName[1 : len(clsName)-1]
- named := lookup(clsName, false, typeMap)
- if named == nil {
- return fmt.Errorf("category %s references unknown class %s", catName, clsName)
- }
- p.parseInterface(named)
- case "ObjCInterfaceDecl", "ObjCProtocolDecl":
- // ObjCProtocolDecl 0x104116450 <line:15:1, line:47:2> line:15:11 NSObject
- // or
- // ObjCInterfaceDecl 0x1041ca480 <line:17:29, line:64:2> line:17:40 UIResponder
- prot := w == "ObjCProtocolDecl"
- // Skip the node address, the source code range, position.
- p.scanWord()
- if strings.HasPrefix(p.decl, "prev ") {
- p.scanWord()
- p.scanWord()
- }
- p.parseLocation()
- if strings.HasPrefix(p.decl, "implicit ") {
- p.scanWord()
- }
- name := p.decl
- named := p.lookupOrCreate(name, prot, typeMap)
- p.indent++
- p.parseInterface(named)
- default:
- }
- }
- return nil
- }
- func lookup(name string, prot bool, typeMap map[string]*Named) *Named {
- var mangled string
- if prot {
- mangled = name + "P"
- } else {
- mangled = name + "C"
- }
- if n := typeMap[mangled]; n != nil {
- return n
- }
- return typeMap[name]
- }
- // lookupOrCreate looks up the type name in the type map. If it doesn't exist, it creates
- // and returns a new type. If it does exist, it returns the existing type. If there are both
- // a class and a protocol with the same name, their type names are mangled by prefixing
- // 'C' or 'P' and then re-inserted into the type map.
- func (p *parser) lookupOrCreate(name string, prot bool, typeMap map[string]*Named) *Named {
- mangled := name + "C"
- otherMangled := name + "P"
- if prot {
- mangled, otherMangled = otherMangled, mangled
- }
- named, exists := typeMap[mangled]
- if exists {
- return named
- }
- named, exists = typeMap[name]
- if exists {
- if named.Protocol == prot {
- return named
- }
- // Both a class and a protocol exists with the same name.
- delete(typeMap, name)
- named.GoName = otherMangled
- typeMap[otherMangled] = named
- named = &Named{
- GoName: mangled,
- }
- } else {
- named = &Named{
- GoName: name,
- }
- }
- named.Name = name
- named.Protocol = prot
- named.funcMap = make(map[string]struct{})
- named.Module = p.module
- typeMap[named.GoName] = named
- return named
- }
- func (p *parser) parseInterface(n *Named) {
- for {
- more := p.scanLine()
- if !more {
- break
- }
- switch w := p.scanWord(); w {
- case "super":
- if w := p.scanWord(); w != "ObjCInterface" {
- panic(fmt.Errorf("unknown super type: %s", w))
- }
- // Skip node address.
- p.scanWord()
- super := p.scanWord()
- // Remove single quotes
- super = super[1 : len(super)-1]
- n.Supers = append(n.Supers, Super{super, false})
- case "ObjCProtocol":
- p.scanWord()
- super := p.scanWord()
- super = super[1 : len(super)-1]
- n.Supers = append(n.Supers, Super{super, true})
- case "ObjCMethodDecl":
- f := p.parseMethod()
- if f == nil {
- continue
- }
- var key string
- if f.Static {
- key = "+" + f.Sig
- } else {
- key = "-" + f.Sig
- }
- if _, exists := n.funcMap[key]; !exists {
- n.funcMap[key] = struct{}{}
- if f.Static {
- n.Funcs = append(n.Funcs, f)
- } else {
- n.Methods = append(n.Methods, f)
- }
- }
- }
- }
- }
- func (p *parser) parseMethod() *Func {
- // ObjCMethodDecl 0x103bdfb80 <line:17:1, col:27> col:1 - isEqual: 'BOOL':'_Bool'
- // Skip the address, range, position.
- p.scanWord()
- p.parseLocation()
- if strings.HasPrefix(p.decl, "implicit") {
- p.scanWord()
- }
- f := new(Func)
- switch w := p.scanWord(); w {
- case "+":
- f.Static = true
- case "-":
- f.Static = false
- default:
- panic(fmt.Errorf("unknown method type for %q", w))
- }
- f.Sig = p.scanWord()
- if f.Sig == "dealloc" {
- // ARC forbids dealloc
- return nil
- }
- if strings.HasPrefix(f.Sig, "init") {
- f.Constructor = true
- }
- f.Ret = p.parseType()
- p.indent++
- for {
- more := p.scanLine()
- if !more {
- break
- }
- switch p.scanWord() {
- case "UnavailableAttr":
- p.indent--
- return nil
- case "ParmVarDecl":
- f.Params = append(f.Params, p.parseParameter())
- }
- }
- return f
- }
- func (p *parser) parseParameter() *Param {
- // ParmVarDecl 0x1041caca8 <col:70, col:80> col:80 event 'UIEvent * _Nullable':'UIEvent *'
- // Skip address, source range, position.
- p.scanWord()
- p.parseLocation()
- return &Param{Name: p.scanWord(), Type: p.parseType()}
- }
- func (p *parser) parseType() *Type {
- // NSUInteger':'unsigned long'
- s := strings.SplitN(p.decl, ":", 2)
- decl := s[0]
- var canon string
- if len(s) == 2 {
- canon = s[1]
- } else {
- canon = decl
- }
- // unquote the type
- canon = canon[1 : len(canon)-1]
- if canon == "void" {
- return nil
- }
- decl = decl[1 : len(decl)-1]
- instancetype := strings.HasPrefix(decl, "instancetype")
- // Strip modifiers
- mods := []string{"__strong", "__unsafe_unretained", "const", "__strong", "_Nonnull", "_Nullable", "__autoreleasing"}
- for _, mod := range mods {
- if idx := strings.Index(canon, mod); idx != -1 {
- canon = canon[:idx] + canon[idx+len(mod):]
- }
- if idx := strings.Index(decl, mod); idx != -1 {
- decl = decl[:idx] + decl[idx+len(mod):]
- }
- }
- canon = strings.TrimSpace(canon)
- decl = strings.TrimSpace(decl)
- t := &Type{
- Decl: decl,
- instanceType: instancetype,
- }
- switch canon {
- case "int", "long", "long long":
- t.Kind = Int
- case "unsigned int", "unsigned long", "unsigned long long":
- t.Kind = Uint
- case "short":
- t.Kind = Short
- case "unsigned short":
- t.Kind = Ushort
- case "char":
- t.Kind = Char
- case "unsigned char":
- t.Kind = Uchar
- case "float":
- t.Kind = Float
- case "double":
- t.Kind = Double
- case "_Bool":
- t.Kind = Bool
- case "NSString *":
- t.Kind = String
- case "NSData *":
- t.Kind = Data
- default:
- switch {
- case strings.HasPrefix(canon, "enum"):
- t.Kind = Int
- case strings.HasPrefix(canon, "id"):
- _, gen := p.splitGeneric(canon)
- t.Kind = Protocol
- t.Name = gen
- default:
- if ind := strings.Count(canon, "*"); 1 <= ind && ind <= 2 {
- space := strings.Index(canon, " ")
- name := canon[:space]
- name, _ = p.splitGeneric(name)
- t.Kind = Class
- t.Name = name
- t.Indirect = ind > 1
- }
- }
- }
- return t
- }
- func (p *parser) splitGeneric(decl string) (string, string) {
- // NSArray<KeyType>
- if br := strings.Index(decl, "<"); br != -1 {
- return decl[:br], decl[br+1 : len(decl)-1]
- } else {
- return decl, ""
- }
- }
- func (p *parser) parseSrcPos() {
- const invPref = "<invalid sloc>"
- if strings.HasPrefix(p.decl, invPref) {
- p.decl = p.decl[len(invPref):]
- return
- }
- var loc string
- const scrPref = "<scratch space>"
- if strings.HasPrefix(p.decl, scrPref) {
- // <scratch space>:130:1
- p.decl = p.decl[len(scrPref):]
- loc = "line" + p.scanWord()
- } else {
- // line:17:2, col:18 or, a file location:
- // /.../UIKit.framework/Headers/UISelectionFeedbackGenerator.h:16:1
- loc = p.scanWord()
- }
- locs := strings.SplitN(loc, ":", 2)
- if len(locs) != 2 && len(locs) != 3 {
- panic(fmt.Errorf("invalid source position: %q", loc))
- }
- switch loc := locs[0]; loc {
- case "line", "col":
- default:
- if !strings.HasPrefix(loc, p.sdkPath) {
- panic(fmt.Errorf("invalid source position: %q", loc))
- }
- loc = loc[len(p.sdkPath):]
- switch {
- case strings.HasPrefix(loc, "/usr/include/objc/"):
- p.module = "Foundation"
- case strings.HasPrefix(loc, frameworksPath):
- loc = loc[len(frameworksPath):]
- i := strings.Index(loc, ".framework")
- if i == -1 {
- panic(fmt.Errorf("invalid source position: %q", loc))
- }
- p.module = loc[:i]
- // Some types are declared in CoreFoundation.framework
- // even though they belong in Foundation in Objective-C.
- if p.module == "CoreFoundation" {
- p.module = "Foundation"
- }
- default:
- }
- }
- }
- func (p *parser) parseLocation() {
- // Source ranges are on the form: <line:17:29, line:64:2>.
- if !strings.HasPrefix(p.decl, "<") {
- panic(fmt.Errorf("1no source range first in %s", p.decl))
- }
- p.decl = p.decl[1:]
- p.parseSrcPos()
- if strings.HasPrefix(p.decl, ", ") {
- p.decl = p.decl[2:]
- p.parseSrcPos()
- }
- if !strings.HasPrefix(p.decl, "> ") {
- panic(fmt.Errorf("no source range first in %s", p.decl))
- }
- p.decl = p.decl[2:]
- p.parseSrcPos()
- }
- func (p *parser) scanWord() string {
- i := 0
- loop:
- for ; i < len(p.decl); i++ {
- switch p.decl[i] {
- case ' ', '>', ',':
- break loop
- }
- }
- w := p.decl[:i]
- p.decl = p.decl[i:]
- for len(p.decl) > 0 && p.decl[0] == ' ' {
- p.decl = p.decl[1:]
- }
- return w
- }
- func initialUpper(s string) string {
- if s == "" {
- return ""
- }
- r, n := utf8.DecodeRuneInString(s)
- return string(unicode.ToUpper(r)) + s[n:]
- }
- func (t *Named) ObjcType() string {
- if t.Protocol {
- return fmt.Sprintf("id<%s> _Nullable", t.Name)
- } else {
- return t.Name + " * _Nullable"
- }
- }
|