compile_exports.mx raw

   1  package emit
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/syntax"
   5  	"git.smesh.lol/moxie/pkg/token"
   6  	"git.smesh.lol/moxie/pkg/types"
   7  	"runtime"
   8  	"unsafe"
   9  )
  10  
  11  var irResults []string
  12  var ImportRegistry map[string]*types.TCPackage
  13  
  14  func EnsureImportRegistry() {
  15  	if ImportRegistry == nil {
  16  		ImportRegistry = map[string]*types.TCPackage{}
  17  	}
  18  }
  19  
  20  //export moxie_compile_to_ir
  21  func moxie_compile_to_ir(srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32, triplePtr unsafe.Pointer, tripleLen int32) (n int32) {
  22  	runtime.InitCShared()
  23  	src := unsafe.Slice((*byte)(srcPtr), srcLen)
  24  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  25  	triple := string(unsafe.Slice((*byte)(triplePtr), tripleLen))
  26  
  27  	ir := CompileToIR(src, name, triple)
  28  
  29  	idx := int32(len(irResults))
  30  	irResults = append(irResults, ir)
  31  	return idx
  32  }
  33  
  34  //export moxie_compile_ir_len
  35  func moxie_compile_ir_len(h int32) (n int32) {
  36  	runtime.InitCShared()
  37  	if h < 0 || int32(h) >= len(irResults) {
  38  		return 0
  39  	}
  40  	return int32(len(irResults[h]))
  41  }
  42  
  43  //export moxie_compile_ir_copy
  44  func moxie_compile_ir_copy(h int32, dst unsafe.Pointer, cap int32) (n int32) {
  45  	runtime.InitCShared()
  46  	if h < 0 || int32(h) >= len(irResults) {
  47  		return 0
  48  	}
  49  	ir := irResults[h]
  50  	n = int32(len(ir))
  51  	if n > cap {
  52  		n = cap
  53  	}
  54  	if n > 0 {
  55  		buf := unsafe.Slice((*byte)(dst), n)
  56  		copy(buf, ir[:n])
  57  	}
  58  	return n
  59  }
  60  
  61  //export moxie_compile_ir_free
  62  func moxie_compile_ir_free(h int32) {
  63  	runtime.InitCShared()
  64  	if h >= 0 && int32(h) < len(irResults) {
  65  		irResults[h] = ""
  66  	}
  67  }
  68  
  69  //export moxie_register_package
  70  func moxie_register_package(pathPtr unsafe.Pointer, pathLen int32, namePtr unsafe.Pointer, nameLen int32) {
  71  	runtime.InitCShared()
  72  	EnsureImportRegistry()
  73  	path := string(unsafe.Slice((*byte)(pathPtr), pathLen))
  74  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  75  	ImportRegistry[path] = types.NewTCPackage(path, name)
  76  }
  77  
  78  //export moxie_register_func
  79  func moxie_register_func(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, sigPtr unsafe.Pointer, sigLen int32) {
  80  	runtime.InitCShared()
  81  	EnsureImportRegistry()
  82  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
  83  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  84  	sigDesc := string(unsafe.Slice((*byte)(sigPtr), sigLen))
  85  	pkg := ImportRegistry[pkgPath]
  86  	if pkg == nil {
  87  		return
  88  	}
  89  	old := ParseTypePkgScope
  90  	ParseTypePkgScope = pkg.Scope()
  91  	sig := ParseSignatureDesc(sigDesc)
  92  	ParseTypePkgScope = old
  93  	pkg.Scope().Insert(types.NewTCFunc(pkg, name, sig))
  94  }
  95  
  96  //export moxie_register_var
  97  func moxie_register_var(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, typDescPtr unsafe.Pointer, typDescLen int32) {
  98  	runtime.InitCShared()
  99  	EnsureImportRegistry()
 100  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 101  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 102  	typDesc := string(unsafe.Slice((*byte)(typDescPtr), typDescLen))
 103  	pkg := ImportRegistry[pkgPath]
 104  	if pkg == nil {
 105  		return
 106  	}
 107  	typ := ParseTypeDesc(typDesc)
 108  	pkg.Scope().Insert(types.NewTCVar(pkg, name, typ))
 109  }
 110  
 111  //export moxie_register_const
 112  func moxie_register_const(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, typDescPtr unsafe.Pointer, typDescLen int32, val int64) {
 113  	runtime.InitCShared()
 114  	EnsureImportRegistry()
 115  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 116  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 117  	typDesc := string(unsafe.Slice((*byte)(typDescPtr), typDescLen))
 118  	pkg := ImportRegistry[pkgPath]
 119  	if pkg == nil {
 120  		return
 121  	}
 122  	typ := ParseTypeDesc(typDesc)
 123  	pkg.Scope().Insert(types.NewTCConst(pkg, name, typ, types.NewConstInt(val)))
 124  }
 125  
 126  //export moxie_register_const_string
 127  func moxie_register_const_string(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, valPtr unsafe.Pointer, valLen int32) {
 128  	runtime.InitCShared()
 129  	EnsureImportRegistry()
 130  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 131  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 132  	val := string(unsafe.Slice((*byte)(valPtr), valLen))
 133  	pkg := ImportRegistry[pkgPath]
 134  	if pkg == nil {
 135  		return
 136  	}
 137  	pkg.Scope().Insert(types.NewTCConst(pkg, name, types.Typ[types.UntypedString], types.NewConstStr(val)))
 138  }
 139  
 140  //export moxie_register_iface
 141  func moxie_register_iface(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, methodsPtr unsafe.Pointer, methodsLen int32) {
 142  	runtime.InitCShared()
 143  	EnsureImportRegistry()
 144  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 145  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 146  	methodsDesc := string(unsafe.Slice((*byte)(methodsPtr), methodsLen))
 147  	pkg := ImportRegistry[pkgPath]
 148  	if pkg == nil {
 149  		return
 150  	}
 151  	var methods []*types.IfaceMethod
 152  	if methodsDesc != "" {
 153  		parts := SplitSemicolon(methodsDesc)
 154  		for _, p := range parts {
 155  			eqIdx := -1
 156  			for i := 0; i < len(p); i++ {
 157  				if p[i] == '=' {
 158  					eqIdx = i
 159  					break
 160  				}
 161  			}
 162  			if eqIdx < 0 {
 163  				continue
 164  			}
 165  			mname := p[:eqIdx]
 166  			msig := ParseSignatureDesc(p[eqIdx+1:])
 167  			methods = append(methods, types.NewTCIfaceMethod(mname, msig))
 168  		}
 169  	}
 170  	iface := types.NewTCInterface(methods, nil)
 171  	iface.Complete()
 172  	tn := types.NewTypeName(pkg, name, iface)
 173  	pkg.Scope().Insert(tn)
 174  }
 175  
 176  //export moxie_register_type
 177  func moxie_register_type(pkgPathPtr unsafe.Pointer, pkgPathLen int32, namePtr unsafe.Pointer, nameLen int32, underlyingPtr unsafe.Pointer, underlyingLen int32) {
 178  	runtime.InitCShared()
 179  	EnsureImportRegistry()
 180  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 181  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 182  	pkg := ImportRegistry[pkgPath]
 183  	if pkg == nil {
 184  		return
 185  	}
 186  	var underlying syntax.Type
 187  	if underlyingLen > 0 {
 188  		desc := string(unsafe.Slice((*byte)(underlyingPtr), underlyingLen))
 189  		underlying = ParseTypeDesc(desc)
 190  	} else {
 191  		underlying = types.NewTCStruct(nil, nil)
 192  	}
 193  	tn := types.NewTypeName(pkg, name, nil)
 194  	types.NewNamed(tn, underlying)
 195  	pkg.Scope().Insert(tn)
 196  }
 197  
 198  //export moxie_register_method
 199  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) {
 200  	runtime.InitCShared()
 201  	EnsureImportRegistry()
 202  	pkgPath := string(unsafe.Slice((*byte)(pkgPathPtr), pkgPathLen))
 203  	typeName := string(unsafe.Slice((*byte)(typeNamePtr), typeNameLen))
 204  	methodName := string(unsafe.Slice((*byte)(methodNamePtr), methodNameLen))
 205  	sigDesc := string(unsafe.Slice((*byte)(sigPtr), sigLen))
 206  	pkg := ImportRegistry[pkgPath]
 207  	if pkg == nil {
 208  		return
 209  	}
 210  	obj := pkg.Scope().Lookup(typeName)
 211  	if obj == nil {
 212  		return
 213  	}
 214  	tn, ok := obj.(*types.TypeName)
 215  	if !ok {
 216  		return
 217  	}
 218  	named, ok := tn.Type().(*types.Named)
 219  	if !ok {
 220  		return
 221  	}
 222  	old := ParseTypePkgScope
 223  	ParseTypePkgScope = pkg.Scope()
 224  	sig := ParseSignatureDesc(sigDesc)
 225  	ParseTypePkgScope = old
 226  	var recvType syntax.Type = named
 227  	if ptrRecv != 0 {
 228  		recvType = types.NewPointer(named)
 229  	}
 230  	sig = types.NewSignature(types.NewTCVar(pkg, "", recvType), sig.Params(), sig.Results(), sig.Variadic())
 231  	fn := types.NewTCFunc(pkg, methodName, sig)
 232  	if ptrRecv != 0 {
 233  		fn.SetPtrRecv(true)
 234  	}
 235  	named.AddMethod(fn)
 236  }
 237  
 238  func SplitSemicolon(s string) (ss []string) {
 239  	var parts []string
 240  	start := 0
 241  	for i := 0; i < len(s); i++ {
 242  		if s[i] == ';' {
 243  			parts = append(parts, s[start:i])
 244  			start = i + 1
 245  		}
 246  	}
 247  	parts = append(parts, s[start:])
 248  	return parts
 249  }
 250  
 251  //export moxie_clear_imports
 252  func moxie_clear_imports() {
 253  	runtime.InitCShared()
 254  	EnsureImportRegistry()
 255  	ImportRegistry = map[string]*types.TCPackage{}
 256  }
 257  
 258  var ParseTypePkgScope *types.Scope
 259  
 260  func ParseTypeDesc(desc string) (t syntax.Type) {
 261  	switch desc {
 262  	case "bool":
 263  		return types.Typ[types.Bool]
 264  	case "int8":
 265  		return types.Typ[types.Int8]
 266  	case "int16":
 267  		return types.Typ[types.Int16]
 268  	case "int32", "int32":
 269  		return types.Typ[types.Int32]
 270  	case "int64":
 271  		return types.Typ[types.Int64]
 272  	case "uint8", "byte":
 273  		return types.Typ[types.Uint8]
 274  	case "uint16":
 275  		return types.Typ[types.Uint16]
 276  	case "uint32", "uint32":
 277  		return types.Typ[types.Uint32]
 278  	case "uint64":
 279  		return types.Typ[types.Uint64]
 280  	case "float32":
 281  		return types.Typ[types.Float32]
 282  	case "float64":
 283  		return types.Typ[types.Float64]
 284  	case "string":
 285  		return types.Typ[types.TCString]
 286  	case "ptr":
 287  		return types.Typ[types.UnsafePointer]
 288  	case "error":
 289  		errorSig := types.NewSignature(nil, nil, types.NewTuple(types.NewTCVar(nil, "", types.Typ[types.TCString])), false)
 290  		errorIface := types.NewTCInterface([]*types.IfaceMethod{types.NewTCIfaceMethod("Error", errorSig)}, nil)
 291  		errorIface.Complete()
 292  		return errorIface
 293  	case "struct", "struct{}":
 294  		return types.NewTCStruct(nil, nil)
 295  	case "interface{}":
 296  		emptyIface := types.NewTCInterface(nil, nil)
 297  		emptyIface.Complete()
 298  		return emptyIface
 299  	}
 300  	if len(desc) > 7 && desc[:7] == "struct{" && desc[len(desc)-1] == '}' {
 301  		inner := desc[7 : len(desc)-1]
 302  		if inner == "" {
 303  			return types.NewTCStruct(nil, nil)
 304  		}
 305  		fields := splitCommaBalanced(inner)
 306  		var vars []*types.TCVar
 307  		var tags []string
 308  		for _, f := range fields {
 309  			ci := -1
 310  			for k := 0; k < len(f); k++ {
 311  				if f[k] == ':' {
 312  					ci = k
 313  					break
 314  				}
 315  			}
 316  			if ci < 0 {
 317  				continue
 318  			}
 319  			fname := f[:ci]
 320  			ftype := ParseTypeDesc(f[ci+1:])
 321  			vars = append(vars, types.NewTCVar(nil, fname, ftype))
 322  			tags = append(tags, "")
 323  		}
 324  		return types.NewTCStruct(vars, tags)
 325  	}
 326  	if len(desc) > 2 && desc[0] == '[' && desc[1] == ']' {
 327  		elem := ParseTypeDesc(desc[2:])
 328  		if b, ok := elem.(*types.Basic); ok && b.Kind() == types.Uint8 {
 329  			return types.Typ[types.TCString]
 330  		}
 331  		return types.NewSlice(elem)
 332  	}
 333  	if len(desc) > 2 && desc[0] == '[' && desc[1] != ']' {
 334  		closeBrack := int32(-1)
 335  		for k := int32(1); k < int32(len(desc)); k++ {
 336  			if desc[k] == ']' {
 337  				closeBrack = k
 338  				break
 339  			}
 340  		}
 341  		if closeBrack > 1 {
 342  			n := types.ParseIntLocal(desc[1:closeBrack])
 343  			elem := ParseTypeDesc(desc[closeBrack+1:])
 344  			return types.NewArray(elem, n)
 345  		}
 346  	}
 347  	if len(desc) > 1 && desc[0] == '*' {
 348  		return types.NewPointer(ParseTypeDesc(desc[1:]))
 349  	}
 350  	if len(desc) > 5 && desc[:5] == "chan:" {
 351  		return types.NewTCChan(types.TCSendRecv, ParseTypeDesc(desc[5:]))
 352  	}
 353  	if len(desc) > 7 && desc[:7] == "chan<-:" {
 354  		return types.NewTCChan(types.TCSendOnly, ParseTypeDesc(desc[7:]))
 355  	}
 356  	if len(desc) > 7 && desc[:7] == "<-chan:" {
 357  		return types.NewTCChan(types.TCRecvOnly, ParseTypeDesc(desc[7:]))
 358  	}
 359  	if len(desc) > 4 && desc[:4] == "map[" {
 360  		depth := int32(0)
 361  		closeBrack := int32(-1)
 362  		for k := int32(4); k < int32(len(desc)); k++ {
 363  			if desc[k] == '[' {
 364  				depth++
 365  			} else if desc[k] == ']' {
 366  				if depth == 0 {
 367  					closeBrack = k
 368  					break
 369  				}
 370  				depth--
 371  			}
 372  		}
 373  		if closeBrack > 4 {
 374  			key := ParseTypeDesc(desc[4:closeBrack])
 375  			val := ParseTypeDesc(desc[closeBrack+1:])
 376  			return types.NewTCMap(key, val)
 377  		}
 378  	}
 379  	dotIdx := int32(-1)
 380  	for i := int32(len(desc)) - 1; i >= 0; i-- {
 381  		if desc[i] == '.' {
 382  			dotIdx = i
 383  			break
 384  		}
 385  	}
 386  	if dotIdx > 0 {
 387  		pkgPath := desc[:dotIdx]
 388  		typeName := desc[dotIdx+1:]
 389  		EnsureImportRegistry()
 390  		if extPkg, ok := ImportRegistry[pkgPath]; ok {
 391  			obj := extPkg.Scope().Lookup(typeName)
 392  			if tn, ok := obj.(*types.TypeName); ok && tn.Type() != nil {
 393  				return tn.Type()
 394  			}
 395  		}
 396  	}
 397  	if ParseTypePkgScope != nil {
 398  		obj := ParseTypePkgScope.Lookup(desc)
 399  		if tn, ok := obj.(*types.TypeName); ok && tn.Type() != nil {
 400  			return tn.Type()
 401  		}
 402  	}
 403  	return types.Typ[types.Int32]
 404  }
 405  
 406  func ParseSignatureDesc(desc string) (s *types.Signature) {
 407  	// format: "param1,param2->result1,result2" or "param1,param2" (void) or "->result" (no params)
 408  	arrow := -1
 409  	for i := 0; i < len(desc)-1; i++ {
 410  		if desc[i] == '-' && desc[i+1] == '>' {
 411  			arrow = i
 412  			break
 413  		}
 414  	}
 415  	var paramStr, resultStr string
 416  	if arrow >= 0 {
 417  		paramStr = desc[:arrow]
 418  		resultStr = desc[arrow+2:]
 419  	} else {
 420  		paramStr = desc
 421  	}
 422  	var params []*types.TCVar
 423  	if paramStr != "" {
 424  		parts := splitComma(paramStr)
 425  		for _, p := range parts {
 426  			params = append(params, types.NewTCVar(nil, "", ParseTypeDesc(p)))
 427  		}
 428  	}
 429  	var results []*types.TCVar
 430  	if resultStr != "" {
 431  		parts := splitComma(resultStr)
 432  		for _, r := range parts {
 433  			results = append(results, types.NewTCVar(nil, "", ParseTypeDesc(r)))
 434  		}
 435  	}
 436  	var pTuple, rTuple *types.Tuple
 437  	if len(params) > 0 {
 438  		pTuple = types.NewTuple(params...)
 439  	}
 440  	if len(results) > 0 {
 441  		rTuple = types.NewTuple(results...)
 442  	}
 443  	return types.NewSignature(nil, pTuple, rTuple, false)
 444  }
 445  
 446  func splitCommaBalanced(s string) (ss []string) {
 447  	var parts []string
 448  	start := 0
 449  	depth := 0
 450  	for i := 0; i < len(s); i++ {
 451  		switch s[i] {
 452  		case '{', '[', '(':
 453  			depth++
 454  		case '}', ']', ')':
 455  			depth--
 456  		case ',':
 457  			if depth == 0 {
 458  				parts = append(parts, s[start:i])
 459  				start = i + 1
 460  			}
 461  		}
 462  	}
 463  	parts = append(parts, s[start:])
 464  	return parts
 465  }
 466  
 467  func splitComma(s string) (ss []string) {
 468  	var parts []string
 469  	start := 0
 470  	for i := 0; i < len(s); i++ {
 471  		if s[i] == ',' {
 472  			parts = append(parts, s[start:i])
 473  			start = i + 1
 474  		}
 475  	}
 476  	parts = append(parts, s[start:])
 477  	return parts
 478  }
 479  
 480  func ScanGenericDecls(src []byte, name string) {
 481  	errh := func(err syntax.Error) {}
 482  	file, _ := syntax.ParseBytes(token.NewFileBase(name|".mx"), src, errh, nil, 0)
 483  	if file == nil {
 484  		return
 485  	}
 486  	for _, d := range file.DeclList {
 487  		if fd, ok := d.(*syntax.FuncDecl); ok && fd.Recv == nil && fd.Name.Value != "init" {
 488  			if len(fd.TParamList) > 0 {
 489  				if genericFuncDecls == nil {
 490  					genericFuncDecls = map[string]*syntax.FuncDecl{}
 491  				}
 492  				genericFuncDecls[name|"."|fd.Name.Value] = fd
 493  			}
 494  		}
 495  	}
 496  }
 497  
 498