Subclasses can have new methods in addition to overriding existing
methods (first draft).
This commit is contained in:
		
							parent
							
								
									38c7856b89
								
							
						
					
					
						commit
						34fbcec965
					
				|  | @ -7,7 +7,8 @@ subclasses: | |||
|     ClassThree: | ||||
|         ClassTwo: | ||||
|             - geti1 | ||||
|             - (void)myMethod:int | ||||
|             - -(void)myMethod1:(int)a | ||||
|             - +(const NSObject* _Nonnull)myMethod2:(int)a:(NSDictionary<NSString*,NSObject*> *)options | ||||
| 
 | ||||
| imports: [ simple.h ] | ||||
| frameworks: [ Foundation ] | ||||
|  |  | |||
|  | @ -32,6 +32,26 @@ func init() { | |||
| 	//TypeName = _TypeName
 | ||||
| } | ||||
| 
 | ||||
| func MethodSignature(s string, n *Node) (string, *Node) { | ||||
| 	return ChildOf(NewNode("MethodSignature"),Seq( | ||||
| 		Parenthesized(TypeName), | ||||
| 		Identifier, | ||||
| 		Opt(MethodParameterList), | ||||
| 	))(s,n) | ||||
| } | ||||
| 
 | ||||
| func MethodParameterList(s string, n *Node) (string, *Node) { | ||||
| 	return OneOrMore(MethodParameter)(s,n) | ||||
| } | ||||
| 
 | ||||
| func MethodParameter(s string, n *Node) (string, *Node) { | ||||
| 	return ChildOf(NewNode("MethodParameter"),Seq( | ||||
| 		Lit(":"), | ||||
| 		Parenthesized(TypeName), | ||||
| 		Identifier, | ||||
| 	))(s,n) | ||||
| } | ||||
| 
 | ||||
| func _TypeName(s string, n *Node) (string, *Node) { | ||||
| 	return ChildOf(NewNode("TypeName"),Seq( | ||||
| 		SpecifierQualifierList, | ||||
|  |  | |||
							
								
								
									
										161
									
								
								wrap/main.go
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								wrap/main.go
									
									
									
									
									
								
							|  | @ -23,7 +23,7 @@ type Wrapper struct { | |||
| 	NamedEnums map[string]*Enum | ||||
| 	AnonEnums []*Enum | ||||
| 	Delegates map[string]map[string][]string | ||||
| 	Subclasses map[string]map[string][]string | ||||
| 	Subclasses map[string]*Subclass | ||||
| 	Protocols map[string]*Protocol | ||||
| 
 | ||||
| 	cgoFlags strings.Builder  // put cGo directives here
 | ||||
|  | @ -49,6 +49,7 @@ func NewWrapper(debug bool) *Wrapper { | |||
| 		NamedEnums: map[string]*Enum{}, | ||||
| 		AnonEnums: []*Enum{}, | ||||
| 		Protocols: map[string]*Protocol{}, | ||||
| 		Subclasses: map[string]*Subclass{}, | ||||
| 		ProcessedTypes: map[string]bool{}, | ||||
| 		ProcessedClassMethods: map[string]bool{}, | ||||
| 		Vaargs: 16, | ||||
|  | @ -98,7 +99,39 @@ func (w *Wrapper) Delegate(ds map[string]map[string][]string) { | |||
| } | ||||
| 
 | ||||
| func (w *Wrapper) Subclass(ds map[string]map[string][]string) { | ||||
| 	w.Subclasses = ds | ||||
| 	for k,v := range ds { | ||||
| 		sc := &Subclass{ | ||||
| 			Overrides: []string{}, | ||||
| 			NewMethods: []string{}, | ||||
| 		} | ||||
| 		if len(ds) == 0 { | ||||
| 			fmt.Printf("No superclass specified for subclass %s\n",k) | ||||
| 			os.Exit(-1) | ||||
| 		} | ||||
| 		if len(ds) > 1 { | ||||
| 			fmt.Printf("Multiple inheritance not permitted for subclass %s\n",k) | ||||
| 			os.Exit(-1) | ||||
| 		} | ||||
| 		sc.Name = k | ||||
| 		for x,y := range(v) { | ||||
| 			sc.Super = x | ||||
| 			for _,m := range y { | ||||
| 				switch m[0] { | ||||
| 				case '-','+': | ||||
| 					sc.NewMethods = append(sc.NewMethods,m) | ||||
| 				default: | ||||
| 					sc.Overrides = append(sc.Overrides,m) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		w.Subclasses[sc.Name] = sc | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type Subclass struct { | ||||
| 	Name,Super string | ||||
| 	Overrides []string | ||||
| 	NewMethods []string | ||||
| } | ||||
| 
 | ||||
| type Property struct { | ||||
|  | @ -752,13 +785,13 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) { | |||
| 		return | ||||
| 	} | ||||
| 	w.processType(m.Type) | ||||
| 	//w.processType(m.GoClass) //??
 | ||||
| 	gname := m.Name | ||||
| 	gname = strings.ReplaceAll(gname,"_"," ") | ||||
| 	gname = strings.Title(gname) | ||||
| 	gname = strings.ReplaceAll(gname," ","") | ||||
| 	receiver := "" | ||||
| 	cname := m.Name | ||||
| 	fmt.Printf("Method %s (GoClass %s)\n",cname,m.GoClass) | ||||
| 	switch { | ||||
| 	case !m.ClassMethod: | ||||
| 		if types.IsGoInterface(m.GoClass) { | ||||
|  | @ -943,16 +976,63 @@ type %s %s | |||
| 	w.goConst.WriteString("\n") | ||||
| } | ||||
| 
 | ||||
| func (w *Wrapper) ProcessSubclass(sname string, ps map[string][]string) { | ||||
| 	w._ProcessDelSub(sname,ps,true) | ||||
| func (w *Wrapper) MethodFromSig(sig,class string) *Method { | ||||
| 	ret := &Method{ Parameters: []*Parameter{} } | ||||
| 	if len(sig) == 0 { | ||||
| 		return ret | ||||
| 	} | ||||
| 	if sig[0] == '+' { | ||||
| 		ret.ClassMethod = true | ||||
| 	} | ||||
| 	sig = sig[1:] | ||||
| 	rem,n := types.MethodSignature(sig,types.NewNode("AST")) | ||||
| 	if len(rem) > 0 { | ||||
| 		fmt.Printf("Failed to parse method signature %s (%s)\n",sig,rem) | ||||
| 		os.Exit(-1) | ||||
| 	} | ||||
| 	for _,c := range n.Children { | ||||
| 		switch c.Kind { | ||||
| 		case "TypeName": | ||||
| 			tp := types.NewType(c,class) | ||||
| 			ret.Type = tp | ||||
| 		case "Identifier": | ||||
| 			ret.Name = c.Content | ||||
| 		case "MethodParameter": | ||||
| 			p := &Parameter{} | ||||
| 			for _,d := range c.Children { | ||||
| 				switch d.Kind { | ||||
| 				case "TypeName": | ||||
| 					tp := types.NewType(d,class) | ||||
| 					p.Type = tp | ||||
| 				case "Identifier": | ||||
| 					p.Vname = d.Content | ||||
| 				} | ||||
| 			} | ||||
| 			ret.Parameters = append(ret.Parameters,p) | ||||
| 		} | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func (w *Wrapper) ProcessSubclass(sname string, sc *Subclass) { | ||||
| 	fmt.Printf("Wrapping %s\n",sname) | ||||
| 	types.Wrap(sname) | ||||
| 	types.SetSuper(sname,sc.Super) | ||||
| 	ps := map[string][]string{} | ||||
| 	ps[sc.Super] = sc.Overrides | ||||
| 	nms := make([]*Method,len(sc.NewMethods)) | ||||
| 	for i,sig := range sc.NewMethods { | ||||
| 		nms[i] = w.MethodFromSig(sig,sname) | ||||
| 	} | ||||
| 	w._ProcessDelSub(sname,ps,nms,true) | ||||
| } | ||||
| 
 | ||||
| func (w *Wrapper) ProcessDelegate(dname string, ps map[string][]string) { | ||||
| 	w._ProcessDelSub(dname,ps,false) | ||||
| 	w._ProcessDelSub(dname,ps,nil,false) | ||||
| } | ||||
| 
 | ||||
| //NOTE: The delegate wrapper does not support variadic callback functions.
 | ||||
| func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) { | ||||
| func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string, nms []*Method, sub bool) { | ||||
| 	//To create (per delegate):
 | ||||
| 	//1. ObjC interface
 | ||||
| 	//2. ObjC implementation
 | ||||
|  | @ -972,6 +1052,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 
 | ||||
| 	//set up array of methods for this delegate
 | ||||
| 	methods := []*Method{} | ||||
| 	sms := 0 // the number of methods that have super-methods
 | ||||
| 	gnames := []string{} // go names for methods
 | ||||
| 	pnames := make([]string,len(ps)) | ||||
| 	var supr string | ||||
|  | @ -998,14 +1079,14 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 				if sup := types.Super(s); w.Interfaces[sup] != nil { | ||||
| 					addmeths(sup) | ||||
| 				} | ||||
| 				fmt.Printf("Adding methods for %s\n",s) | ||||
| 				//fmt.Printf("Adding methods for %s\n",s)
 | ||||
| 				for k,v := range w.Interfaces[s].InstanceMethods { | ||||
| 					ms[k] = v | ||||
| 				} | ||||
| 			} | ||||
| 		//for subclasses, add all superclass methods, depth first
 | ||||
| 			addmeths(interf.Name) | ||||
| 		} else { | ||||
| 		} else { // not a subclass
 | ||||
| 			proto := w.Protocols[pname] | ||||
| 			if proto == nil { | ||||
| 				fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname) | ||||
|  | @ -1019,9 +1100,6 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 	//note:we may have capitalized the first character to make a goname,
 | ||||
| 	//but m.Name is not disambiguated for polymorphics...
 | ||||
| 			if !matches(string(m.Name[0])+gname[1:],pats) { | ||||
| 				if sub { | ||||
| 		//Add newly defined methods that don't match anything...
 | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() { | ||||
|  | @ -1029,12 +1107,20 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 			} | ||||
| 			methods = append(methods,m) | ||||
| 			gnames = append(gnames,gname) | ||||
| 			if sub { sms = len(methods) } | ||||
| 		} | ||||
| 	} | ||||
| 	//add new methods being defined for the subclass
 | ||||
| 	if sub { | ||||
| 		for _,m := range nms { | ||||
| 			methods = append(methods,m) | ||||
| 			gnames = append(gnames,strings.Title(m.Name)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	methprotos := make([]string,len(methods)) // objc method prototypes
 | ||||
| 	smethprotos := make([]string,len(methods)) // super method prototypes
 | ||||
| 	sfunprotos := make([]string,len(methods)) // super method prototypes
 | ||||
| 	smethprotos := make([]string,sms) // super method prototypes
 | ||||
| 	sfunprotos := make([]string,sms) // super method prototypes
 | ||||
| 	gname := strings.Title(dname) // go name for this Delegate
 | ||||
| 	vnames := make([][]string,len(methods)) // objc variable names
 | ||||
| 	vpnames := make([][]string,len(methods)) // objc parameter:variable names
 | ||||
|  | @ -1046,11 +1132,10 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 
 | ||||
| 	//1. ObjC interface
 | ||||
| 	if sub { | ||||
| 		fmt.Printf("Subclass ") | ||||
| 		fmt.Printf("Subclass %s <%s>: %d overrides, %d new methods\n",dname,strings.Join(pnames,", "),sms, len(nms)) | ||||
| 	} else { | ||||
| 		fmt.Printf("Delegate ") | ||||
| 		fmt.Printf("Delegate %s <%s>: %d methods\n",dname,strings.Join(pnames,", "),len(methods)) | ||||
| 	} | ||||
| 	fmt.Printf("%s <%s>: %d methods\n",dname,strings.Join(pnames,", "),len(methods)) | ||||
| 	for i,m := range methods { | ||||
| 		w.processType(m.Type) | ||||
| 		vnames[i] = make([]string,len(m.Parameters)+1) | ||||
|  | @ -1100,13 +1185,17 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 		methprotos[i] = fmt.Sprintf( | ||||
| `- (%s)%s%s;`,m.Type.Node.CType(),m.Name,parms) | ||||
| 		ct := m.Type.Node.CType() | ||||
| 		if i < sms { | ||||
| 			smethprotos[i] = fmt.Sprintf( | ||||
| `- (%s)super_%s%s;`,ct,m.Name,parms) | ||||
| 		} | ||||
| 		if ct == "instancetype" { | ||||
| 			ct = gname + "*" | ||||
| 		} | ||||
| 		if i < sms { | ||||
| 			sfunprotos[i] = fmt.Sprintf( | ||||
| `%s %s_super_%s(%s);`,ct,dname,m.Name,cparms) | ||||
| 		} | ||||
| 		if x := m.Type.GoType(); x == "Void" { | ||||
| 			grtypes[i] = "" | ||||
| 		} else { | ||||
|  | @ -1150,8 +1239,11 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 	sfundecls := make([]string,len(methods)) | ||||
| 	for i,mp := range methprotos { | ||||
| 		mp := mp[:len(mp)-1] | ||||
| 		smp := smethprotos[i][:len(smethprotos[i])-1] | ||||
| 		sfp := sfunprotos[i][:len(sfunprotos[i])-1] | ||||
| 		var smp, sfp string | ||||
| 		if sub && i < sms { | ||||
| 			smp = smethprotos[i][:len(smethprotos[i])-1] | ||||
| 			sfp = sfunprotos[i][:len(sfunprotos[i])-1] | ||||
| 		} | ||||
| 		var ret string | ||||
| 		if crtypes[i] != "void" { | ||||
| 			ret = "return " | ||||
|  | @ -1168,7 +1260,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) | |||
| 	%s%s(%s); | ||||
| } | ||||
| `,mp,ret,gname + gnames[i],strings.Join(vnames[i],", ")) | ||||
| 		if sub { | ||||
| 		if sub && i < sms { | ||||
| 			smethdecls[i] = fmt.Sprintf(` | ||||
| %s | ||||
| { | ||||
|  | @ -1207,10 +1299,8 @@ void* | |||
| 
 | ||||
| 	//4. Go type
 | ||||
| 	 | ||||
| 	gotypes.WriteString(fmt.Sprintf(` | ||||
| type %s struct { %s } | ||||
| func (o %s) Ptr() unsafe.Pointer { return o.ptr } | ||||
| `,gname,supr,gname)) | ||||
| 	gotypes.WriteString( | ||||
| 		types.NewTypeFromString(gname,supr).GoInterfaceDecl()) | ||||
| 
 | ||||
| 	//5. Go constructor
 | ||||
| 	gocode.WriteString(fmt.Sprintf(` | ||||
|  | @ -1223,14 +1313,14 @@ func %sAlloc() %s { | |||
| 
 | ||||
| 	//6. Go dispatch database for callbacks
 | ||||
| 	dispitems := make([]string,len(gnames)) | ||||
| 	sdispitems := make([]string,len(gnames)) | ||||
| 	sdispitems := make([]string,sms) | ||||
| 	for i,n := range gnames { | ||||
| 		if !sub { | ||||
| 			gtypes[i] = gtypes[i][1:] | ||||
| 		} | ||||
| 		dispitems[i] = fmt.Sprintf( | ||||
| `	%s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i]) | ||||
| 		if sub { | ||||
| 		if sub && i < sms { | ||||
| 			sdispitems[i] = fmt.Sprintf( | ||||
| `	%s func(%s)%s`,n,strings.Join(gtypes[i][1:],", "),grtypes[i]) | ||||
| 		} | ||||
|  | @ -1259,7 +1349,7 @@ type %sSupermethods struct { | |||
| `,crtypes[i],gname,gnames[i],ctps)) | ||||
| 		//2. Go callback registration functions
 | ||||
| 		gocode.WriteString(fmt.Sprintf(` | ||||
| func (d *%s) %sCallback(f func(%s)%s) { | ||||
| func (d %s) %sCallback(f func(%s)%s) { | ||||
| 	dispatch := %sLookup[d.Ptr()] | ||||
| 	dispatch.%s = f | ||||
| 	%sLookup[d.Ptr()] = dispatch | ||||
|  | @ -1304,16 +1394,19 @@ func (d *%s) %sCallback(f func(%s)%s) { | |||
| 			if cgtypes[i] == "unsafe.Pointer" { | ||||
| 				retn = "return unsafe.Pointer(" | ||||
| 				crtype = " unsafe.Pointer" | ||||
| 				if types.ShouldWrap(m.Type.GoType()) { | ||||
| 					retnparen = ".Ptr()" | ||||
| 				} | ||||
| 			} else { | ||||
| 				retn = "return (" + cgtypes[i] + ")(" | ||||
| 				crtype = " " + cgtypes[i] | ||||
| 			} | ||||
| 			retnparen = ")" | ||||
| 			retnparen = retnparen + ")" | ||||
| 		} | ||||
| 		sdispentries := []string{} | ||||
| 		for _,n := range gnames { | ||||
| 			sdispentries = append(sdispentries,fmt.Sprintf( | ||||
| `		self.Super%s`,n)) | ||||
| 		sdispentries := make([]string,sms) | ||||
| 		for i,_ := range sdispentries { | ||||
| 			sdispentries[i] = fmt.Sprintf( | ||||
| `		self.Super%s`,gnames[i]) | ||||
| 		} | ||||
| 		sper := "" | ||||
| 		if sub && len(gnames) > 0 { | ||||
|  | @ -1338,7 +1431,7 @@ func %s%s(%s)%s { | |||
| } | ||||
| `,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,sper,strings.Join(gargconv,"\n"),retn,strings.Join(garglist,", "),retnparen)) | ||||
| 		//4. Go wrapper functions for superclass methods
 | ||||
| 		if !sub { continue } // for subclasses only
 | ||||
| 		if !sub || i >= sms { continue } // for subclasses only
 | ||||
| 		grtype := m.Type.GoType() | ||||
| 		if grtype == "Void" { | ||||
| 			grtype = "" | ||||
|  | @ -1351,7 +1444,7 @@ func %s%s(%s)%s { | |||
| 		} | ||||
| 		if sub { | ||||
| 			gocode.WriteString(fmt.Sprintf(` | ||||
| func (o *%s) Super%s(%s) %s { | ||||
| func (o %s) Super%s(%s) %s { | ||||
| `,gname,gnames[i],strings.Join(earglist[1:],", "), grtype)) | ||||
| 			ns,tps,_ := w.gpntp(m) | ||||
| 			lparm := len(tps)-1 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user