compile_exports.mx raw

   1  package main
   2  
   3  import (
   4  	"runtime"
   5  	"unsafe"
   6  )
   7  
   8  var irResults []string
   9  var importRegistry map[string]*TCPackage
  10  
  11  func ensureImportRegistry() {
  12  	if importRegistry == nil {
  13  		importRegistry = map[string]*TCPackage{}
  14  	}
  15  }
  16  
  17  //export moxie_compile_to_ir
  18  func moxie_compile_to_ir(srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32, triplePtr unsafe.Pointer, tripleLen int32) int32 {
  19  	runtime.InitCShared()
  20  	src := unsafe.Slice((*byte)(srcPtr), srcLen)
  21  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  22  	triple := string(unsafe.Slice((*byte)(triplePtr), tripleLen))
  23  
  24  	ir := CompileToIR(src, name, triple)
  25  
  26  	idx := int32(len(irResults))
  27  	irResults = append(irResults, ir)
  28  	return idx
  29  }
  30  
  31  //export moxie_compile_ir_len
  32  func moxie_compile_ir_len(h int32) int32 {
  33  	runtime.InitCShared()
  34  	if h < 0 || int32(h) >= len(irResults) {
  35  		return 0
  36  	}
  37  	return int32(len(irResults[h]))
  38  }
  39  
  40  //export moxie_compile_ir_copy
  41  func moxie_compile_ir_copy(h int32, dst unsafe.Pointer, cap int32) int32 {
  42  	runtime.InitCShared()
  43  	if h < 0 || int32(h) >= len(irResults) {
  44  		return 0
  45  	}
  46  	ir := irResults[h]
  47  	n := int32(len(ir))
  48  	if n > cap {
  49  		n = cap
  50  	}
  51  	if n > 0 {
  52  		buf := unsafe.Slice((*byte)(dst), n)
  53  		copy(buf, ir[:n])
  54  	}
  55  	return n
  56  }
  57  
  58  //export moxie_compile_ir_free
  59  func moxie_compile_ir_free(h int32) {
  60  	runtime.InitCShared()
  61  	if h >= 0 && int32(h) < len(irResults) {
  62  		irResults[h] = ""
  63  	}
  64  }
  65  
  66  //export moxie_register_package
  67  func moxie_register_package(pathPtr unsafe.Pointer, pathLen int32, namePtr unsafe.Pointer, nameLen int32) {
  68  	runtime.InitCShared()
  69  	ensureImportRegistry()
  70  	path := string(unsafe.Slice((*byte)(pathPtr), pathLen))
  71  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  72  	importRegistry[path] = NewTCPackage(path, name)
  73  }
  74  
  75  //export moxie_register_func
  76  func moxie_register_func(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, sigPtr unsafe.Pointer, sigLen int32) {
  77  	runtime.InitCShared()
  78  	ensureImportRegistry()
  79  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
  80  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  81  	sigDesc := string(unsafe.Slice((*byte)(sigPtr), sigLen))
  82  	pkg := importRegistry[pkgPath]
  83  	if pkg == nil {
  84  		return
  85  	}
  86  	sig := parseSignatureDesc(sigDesc)
  87  	pkg.Scope().Insert(NewTCFunc(pkg, name, sig))
  88  }
  89  
  90  //export moxie_register_var
  91  func moxie_register_var(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, typDescPtr unsafe.Pointer, typDescLen int32) {
  92  	runtime.InitCShared()
  93  	ensureImportRegistry()
  94  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
  95  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  96  	typDesc := string(unsafe.Slice((*byte)(typDescPtr), typDescLen))
  97  	pkg := importRegistry[pkgPath]
  98  	if pkg == nil {
  99  		return
 100  	}
 101  	typ := parseTypeDesc(typDesc)
 102  	pkg.Scope().Insert(NewTCVar(pkg, name, typ))
 103  }
 104  
 105  //export moxie_register_const
 106  func moxie_register_const(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, typDescPtr unsafe.Pointer, typDescLen int32, val int32) {
 107  	runtime.InitCShared()
 108  	ensureImportRegistry()
 109  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 110  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 111  	typDesc := string(unsafe.Slice((*byte)(typDescPtr), typDescLen))
 112  	pkg := importRegistry[pkgPath]
 113  	if pkg == nil {
 114  		return
 115  	}
 116  	typ := parseTypeDesc(typDesc)
 117  	pkg.Scope().Insert(NewTCConst(pkg, name, typ, constInt{val}))
 118  }
 119  
 120  //export moxie_register_const_string
 121  func moxie_register_const_string(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, valPtr unsafe.Pointer, valLen int32) {
 122  	runtime.InitCShared()
 123  	ensureImportRegistry()
 124  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 125  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 126  	val := string(unsafe.Slice((*byte)(valPtr), valLen))
 127  	pkg := importRegistry[pkgPath]
 128  	if pkg == nil {
 129  		return
 130  	}
 131  	pkg.Scope().Insert(NewTCConst(pkg, name, Typ[UntypedString], constStr{val}))
 132  }
 133  
 134  //export moxie_register_iface
 135  func moxie_register_iface(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, methodsPtr unsafe.Pointer, methodsLen int32) {
 136  	runtime.InitCShared()
 137  	ensureImportRegistry()
 138  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 139  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 140  	methodsDesc := string(unsafe.Slice((*byte)(methodsPtr), methodsLen))
 141  	pkg := importRegistry[pkgPath]
 142  	if pkg == nil {
 143  		return
 144  	}
 145  	var methods []*IfaceMethod
 146  	if methodsDesc != "" {
 147  		parts := splitSemicolon(methodsDesc)
 148  		for _, p := range parts {
 149  			eqIdx := -1
 150  			for i := 0; i < len(p); i++ {
 151  				if p[i] == '=' {
 152  					eqIdx = i
 153  					break
 154  				}
 155  			}
 156  			if eqIdx < 0 {
 157  				continue
 158  			}
 159  			mname := p[:eqIdx]
 160  			msig := parseSignatureDesc(p[eqIdx+1:])
 161  			methods = append(methods, NewTCIfaceMethod(mname, msig))
 162  		}
 163  	}
 164  	iface := NewTCInterface(methods, nil)
 165  	iface.Complete()
 166  	tn := NewTypeName(pkg, name, iface)
 167  	pkg.Scope().Insert(tn)
 168  }
 169  
 170  //export moxie_register_type
 171  func moxie_register_type(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, underlyingPtr unsafe.Pointer, underlyingLen int32) {
 172  	runtime.InitCShared()
 173  	ensureImportRegistry()
 174  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 175  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 176  	pkg := importRegistry[pkgPath]
 177  	if pkg == nil {
 178  		return
 179  	}
 180  	var underlying Type
 181  	if underlyingLen > 0 {
 182  		desc := string(unsafe.Slice((*byte)(underlyingPtr), underlyingLen))
 183  		underlying = parseTypeDesc(desc)
 184  	} else {
 185  		underlying = NewTCStruct(nil, nil)
 186  	}
 187  	tn := NewTypeName(pkg, name, nil)
 188  	NewNamed(tn, underlying)
 189  	pkg.Scope().Insert(tn)
 190  }
 191  
 192  //export moxie_register_method
 193  func moxie_register_method(pkgPathPtr unsafe.Pointer, pkgPathLen int32, typeNamePtr unsafe.Pointer, typeNameLen int32, methodNamePtr unsafe.Pointer, methodNameLen int32, sigPtr unsafe.Pointer, sigLen int32, ptrRecv int32) {
 194  	runtime.InitCShared()
 195  	ensureImportRegistry()
 196  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 197  	typeName := string(unsafe.Slice((*byte)(typeNamePtr), typeNameLen))
 198  	methodName := string(unsafe.Slice((*byte)(methodNamePtr), methodNameLen))
 199  	sigDesc := string(unsafe.Slice((*byte)(sigPtr), sigLen))
 200  	pkg := importRegistry[pkgPath]
 201  	if pkg == nil {
 202  		return
 203  	}
 204  	obj := pkg.Scope().Lookup(typeName)
 205  	if obj == nil {
 206  		return
 207  	}
 208  	tn, ok := obj.(*TypeName)
 209  	if !ok {
 210  		return
 211  	}
 212  	named, ok := tn.typ.(*Named)
 213  	if !ok {
 214  		return
 215  	}
 216  	sig := parseSignatureDesc(sigDesc)
 217  	fn := NewTCFunc(pkg, methodName, sig)
 218  	if ptrRecv != 0 {
 219  		fn.hasPtrRecv = true
 220  	}
 221  	named.AddMethod(fn)
 222  }
 223  
 224  func splitSemicolon(s string) []string {
 225  	var parts []string
 226  	start := 0
 227  	for i := 0; i < len(s); i++ {
 228  		if s[i] == ';' {
 229  			parts = append(parts, s[start:i])
 230  			start = i + 1
 231  		}
 232  	}
 233  	parts = append(parts, s[start:])
 234  	return parts
 235  }
 236  
 237  //export moxie_clear_imports
 238  func moxie_clear_imports() {
 239  	runtime.InitCShared()
 240  	ensureImportRegistry()
 241  	importRegistry = map[string]*TCPackage{}
 242  }
 243  
 244  func parseTypeDesc(desc string) Type {
 245  	switch desc {
 246  	case "bool":
 247  		return Typ[Bool]
 248  	case "int8":
 249  		return Typ[Int8]
 250  	case "int16":
 251  		return Typ[Int16]
 252  	case "int32", "int32":
 253  		return Typ[Int32]
 254  	case "int32":
 255  		return Typ[Int64]
 256  	case "uint8", "byte":
 257  		return Typ[Uint8]
 258  	case "uint16":
 259  		return Typ[Uint16]
 260  	case "uint32", "uint32":
 261  		return Typ[Uint32]
 262  	case "uint32":
 263  		return Typ[Uint64]
 264  	case "float32":
 265  		return Typ[Float32]
 266  	case "float64":
 267  		return Typ[Float64]
 268  	case "string":
 269  		return Typ[TCString]
 270  	case "ptr":
 271  		return Typ[UnsafePointer]
 272  	case "error":
 273  		errorSig := NewSignature(nil, nil, NewTuple(NewTCVar(nil, "", Typ[TCString])), false)
 274  		errorIface := NewTCInterface([]*IfaceMethod{NewTCIfaceMethod("Error", errorSig)}, nil)
 275  		errorIface.Complete()
 276  		return errorIface
 277  	case "interface{}":
 278  		emptyIface := NewTCInterface(nil, nil)
 279  		emptyIface.Complete()
 280  		return emptyIface
 281  	}
 282  	if len(desc) > 2 && desc[0] == '[' && desc[1] == ']' {
 283  		elem := parseTypeDesc(desc[2:])
 284  		if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
 285  			return Typ[TCString]
 286  		}
 287  		return NewSlice(elem)
 288  	}
 289  	if len(desc) > 1 && desc[0] == '*' {
 290  		return NewPointer(parseTypeDesc(desc[1:]))
 291  	}
 292  	return Typ[Int32]
 293  }
 294  
 295  func parseSignatureDesc(desc string) *Signature {
 296  	// format: "param1,param2->result1,result2" or "param1,param2" (void) or "->result" (no params)
 297  	arrow := -1
 298  	for i := 0; i < len(desc)-1; i++ {
 299  		if desc[i] == '-' && desc[i+1] == '>' {
 300  			arrow = i
 301  			break
 302  		}
 303  	}
 304  	var paramStr, resultStr string
 305  	if arrow >= 0 {
 306  		paramStr = desc[:arrow]
 307  		resultStr = desc[arrow+2:]
 308  	} else {
 309  		paramStr = desc
 310  	}
 311  	var params []*TCVar
 312  	if paramStr != "" {
 313  		parts := splitComma(paramStr)
 314  		for _, p := range parts {
 315  			params = append(params, NewTCVar(nil, "", parseTypeDesc(p)))
 316  		}
 317  	}
 318  	var results []*TCVar
 319  	if resultStr != "" {
 320  		parts := splitComma(resultStr)
 321  		for _, r := range parts {
 322  			results = append(results, NewTCVar(nil, "", parseTypeDesc(r)))
 323  		}
 324  	}
 325  	var pTuple, rTuple *Tuple
 326  	if len(params) > 0 {
 327  		pTuple = NewTuple(params...)
 328  	}
 329  	if len(results) > 0 {
 330  		rTuple = NewTuple(results...)
 331  	}
 332  	return NewSignature(nil, pTuple, rTuple, false)
 333  }
 334  
 335  func splitComma(s string) []string {
 336  	var parts []string
 337  	start := 0
 338  	for i := 0; i < len(s); i++ {
 339  		if s[i] == ',' {
 340  			parts = append(parts, s[start:i])
 341  			start = i + 1
 342  		}
 343  	}
 344  	parts = append(parts, s[start:])
 345  	return parts
 346  }
 347  
 348