tc_exports.mx raw

   1  package main
   2  
   3  import (
   4  	"bytes"
   5  	"runtime"
   6  	"unsafe"
   7  )
   8  
   9  var pkgHandles []*TCPackage
  10  var infoHandles []*Info
  11  
  12  func allocPkgHandle(p *TCPackage) int32 {
  13  	for i, h := range pkgHandles {
  14  		if h == nil {
  15  			pkgHandles[i] = p
  16  			return int32(i)
  17  		}
  18  	}
  19  	pkgHandles = append(pkgHandles, p)
  20  	return int32(len(pkgHandles) - 1)
  21  }
  22  
  23  func getPkg(h int32) *TCPackage {
  24  	if h < 0 || int32(h) >= len(pkgHandles) {
  25  		return nil
  26  	}
  27  	return pkgHandles[h]
  28  }
  29  
  30  func allocInfoHandle(info *Info) int32 {
  31  	for i, h := range infoHandles {
  32  		if h == nil {
  33  			infoHandles[i] = info
  34  			return int32(i)
  35  		}
  36  	}
  37  	infoHandles = append(infoHandles, info)
  38  	return int32(len(infoHandles) - 1)
  39  }
  40  
  41  func getInfo(h int32) *Info {
  42  	if h < 0 || int32(h) >= len(infoHandles) {
  43  		return nil
  44  	}
  45  	return infoHandles[h]
  46  }
  47  
  48  func tcCopyOut(dst unsafe.Pointer, cap int32, src string) int32 {
  49  	n := int32(len(src))
  50  	if n > cap {
  51  		n = cap
  52  	}
  53  	if n > 0 {
  54  		buf := unsafe.Slice((*byte)(dst), n)
  55  		copy(buf, src[:n])
  56  	}
  57  	return n
  58  }
  59  
  60  //export moxie_tc_parse_only
  61  func moxie_tc_parse_only(srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32) int32 {
  62  	runtime.InitCShared()
  63  	src := unsafe.Slice((*byte)(srcPtr), srcLen)
  64  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  65  	r := bytes.NewReader(src)
  66  	f, err := Parse(NewFileBase(name), r, nil, nil, 0)
  67  	if err != nil || f == nil {
  68  		return -1
  69  	}
  70  	return int32(len(f.DeclList))
  71  }
  72  
  73  //export moxie_tc_pass1_insert
  74  func moxie_tc_pass1_insert(srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32) int32 {
  75  	runtime.InitCShared()
  76  	initUniverse()
  77  	src := unsafe.Slice((*byte)(srcPtr), srcLen)
  78  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
  79  	r := bytes.NewReader(src)
  80  	f, err := Parse(NewFileBase(name), r, nil, nil, 0)
  81  	if err != nil || f == nil {
  82  		return -1
  83  	}
  84  	pkg := NewTCPackage(name, packageName([]*File{f}))
  85  	scope := pkg.Scope()
  86  	for _, d := range f.DeclList {
  87  		switch d := d.(type) {
  88  		case *VarDecl:
  89  			for _, n := range d.NameList {
  90  				scope.Insert(NewTCVar(pkg, n.Value, nil))
  91  			}
  92  		case *FuncDecl:
  93  			if d.Recv == nil && d.Name.Value != "init" {
  94  				scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
  95  			}
  96  		case *TypeDecl:
  97  			scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
  98  		case *ConstDecl:
  99  			for _, n := range d.NameList {
 100  				scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
 101  			}
 102  		}
 103  	}
 104  	return int32(len(scope.Names()))
 105  }
 106  
 107  //export moxie_tc_check_bytes
 108  func moxie_tc_check_bytes(srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32) int32 {
 109  	runtime.InitCShared()
 110  	initUniverse()
 111  	src := unsafe.Slice((*byte)(srcPtr), srcLen)
 112  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 113  	r := bytes.NewReader(src)
 114  	f, err := Parse(NewFileBase(name), r, nil, nil, 0)
 115  	if err != nil || f == nil {
 116  		return -1
 117  	}
 118  	pkg := NewTCPackage(name, packageName([]*File{f}))
 119  	scope := pkg.Scope()
 120  	// Pass 1: register all names
 121  	for _, d := range f.DeclList {
 122  		switch d := d.(type) {
 123  		case *VarDecl:
 124  			for _, n := range d.NameList {
 125  				scope.Insert(NewTCVar(pkg, n.Value, nil))
 126  			}
 127  		case *FuncDecl:
 128  			if d.Recv == nil && d.Name.Value != "init" {
 129  				scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
 130  			}
 131  		case *TypeDecl:
 132  			scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
 133  		case *ConstDecl:
 134  			for _, n := range d.NameList {
 135  				scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
 136  			}
 137  		}
 138  	}
 139  	// Pass 2: resolve types
 140  	for _, d := range f.DeclList {
 141  		switch d := d.(type) {
 142  		case *VarDecl:
 143  			typ := tcResolveNameInline(d.Type)
 144  			for _, n := range d.NameList {
 145  				obj := scope.Lookup(n.Value)
 146  				if obj != nil {
 147  					if v, ok := obj.(*TCVar); ok {
 148  						v.typ = typ
 149  					}
 150  				}
 151  			}
 152  		case *FuncDecl:
 153  			if d.Recv == nil && d.Name.Value != "init" {
 154  				sig := tcResolveFuncInline(d.Type)
 155  				obj := scope.Lookup(d.Name.Value)
 156  				if obj != nil {
 157  					if fn, ok := obj.(*TCFunc); ok && sig != nil {
 158  						fn.typ = sig
 159  					}
 160  				}
 161  			}
 162  		case *TypeDecl:
 163  			typ := tcResolveNameInline(d.Type)
 164  			obj := scope.Lookup(d.Name.Value)
 165  			if obj != nil {
 166  				if tn, ok := obj.(*TypeName); ok {
 167  					tn.typ = typ
 168  				}
 169  			}
 170  		}
 171  	}
 172  	ph := allocPkgHandle(pkg)
 173  	return ph
 174  }
 175  
 176  func tcResolveNameInline(e Expr) Type {
 177  	if e == nil {
 178  		return nil
 179  	}
 180  	switch e := e.(type) {
 181  	case *Name:
 182  		_, obj := Universe.LookupParent(e.Value)
 183  		if obj != nil {
 184  			if tn, ok := obj.(*TypeName); ok {
 185  				return tn.typ
 186  			}
 187  		}
 188  	case *Operation:
 189  		if e.Y == nil && e.Op == Mul {
 190  			base := tcResolveNameInline(e.X)
 191  			if base != nil {
 192  				return NewPointer(base)
 193  			}
 194  		}
 195  	case *SliceType:
 196  		elem := tcResolveNameInline(e.Elem)
 197  		if elem != nil {
 198  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
 199  				return Typ[TCString]
 200  			}
 201  			return NewSlice(elem)
 202  		}
 203  	case *ArrayType:
 204  		elem := tcResolveNameInline(e.Elem)
 205  		if elem != nil {
 206  			return NewArray(elem, -1)
 207  		}
 208  	case *MapType:
 209  		key := tcResolveNameInline(e.Key)
 210  		val := tcResolveNameInline(e.Value)
 211  		if key != nil && val != nil {
 212  			return NewTCMap(key, val)
 213  		}
 214  	case *StructType:
 215  		var fields []*TCVar
 216  		var tags []string
 217  		for i, field := range e.FieldList {
 218  			typ := tcResolveNameInline(field.Type)
 219  			fname := ""
 220  			if field.Name != nil {
 221  				fname = field.Name.Value
 222  			} else {
 223  				fname = typeBaseName(typ)
 224  			}
 225  			fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
 226  			tag := ""
 227  			if i < len(e.TagList) && e.TagList[i] != nil {
 228  				tag = e.TagList[i].Value
 229  			}
 230  			tags = append(tags, tag)
 231  		}
 232  		return NewTCStruct(fields, tags)
 233  	case *FuncType:
 234  		return tcResolveFuncInline(e)
 235  	}
 236  	return nil
 237  }
 238  
 239  func tcResolveFuncInline(ft *FuncType) *Signature {
 240  	if ft == nil {
 241  		return nil
 242  	}
 243  	var params []*TCVar
 244  	for _, p := range ft.ParamList {
 245  		typ := tcResolveNameInline(p.Type)
 246  		pname := ""
 247  		if p.Name != nil {
 248  			pname = p.Name.Value
 249  		}
 250  		params = append(params, NewTCVar(nil, pname, typ))
 251  	}
 252  	var results []*TCVar
 253  	for _, r := range ft.ResultList {
 254  		typ := tcResolveNameInline(r.Type)
 255  		rname := ""
 256  		if r.Name != nil {
 257  			rname = r.Name.Value
 258  		}
 259  		results = append(results, NewTCVar(nil, rname, typ))
 260  	}
 261  	variadic := false
 262  	if len(ft.ParamList) > 0 {
 263  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
 264  			variadic = true
 265  		}
 266  	}
 267  	var pTuple *Tuple
 268  	if len(params) > 0 {
 269  		pTuple = NewTuple(params...)
 270  	}
 271  	var rTuple *Tuple
 272  	if len(results) > 0 {
 273  		rTuple = NewTuple(results...)
 274  	}
 275  	return NewSignature(nil, pTuple, rTuple, variadic)
 276  }
 277  
 278  //export moxie_tc_scope_name_count
 279  func moxie_tc_scope_name_count(h int32) int32 {
 280  	runtime.InitCShared()
 281  	names := getCachedNames(h)
 282  	return int32(len(names))
 283  }
 284  
 285  // cachedNames stores a snapshot of Names() per handle so repeated
 286  // index calls return a consistent ordering.
 287  var cachedNames [][]string
 288  
 289  func getCachedNames(h int32) []string {
 290  	for int32(h) >= len(cachedNames) {
 291  		cachedNames = append(cachedNames, nil)
 292  	}
 293  	if cachedNames[h] == nil {
 294  		p := getPkg(h)
 295  		if p == nil || p.Scope() == nil {
 296  			return nil
 297  		}
 298  		cachedNames[h] = p.Scope().Names()
 299  	}
 300  	return cachedNames[h]
 301  }
 302  
 303  //export moxie_tc_scope_name
 304  func moxie_tc_scope_name(h int32, idx int32, out unsafe.Pointer, cap int32) int32 {
 305  	runtime.InitCShared()
 306  	names := getCachedNames(h)
 307  	if idx < 0 || int32(idx) >= len(names) {
 308  		return 0
 309  	}
 310  	return tcCopyOut(out, cap, names[idx])
 311  }
 312  
 313  func isNilType(t Type) bool {
 314  	if t == nil {
 315  		return true
 316  	}
 317  	// Check for typed nil interface (e.g. (*Signature)(nil) stored as Type).
 318  	// An interface is {type_ptr, data_ptr}; data_ptr==0 means nil concrete value.
 319  	iface := (*[2]uintptr)(unsafe.Pointer(&t))
 320  	return iface[1] == 0
 321  }
 322  
 323  //export moxie_tc_scope_type_of
 324  func moxie_tc_scope_type_of(h int32, namePtr unsafe.Pointer, nameLen int32, out unsafe.Pointer, cap int32) int32 {
 325  	runtime.InitCShared()
 326  	p := getPkg(h)
 327  	if p == nil || p.Scope() == nil {
 328  		return 0
 329  	}
 330  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 331  	obj := p.Scope().Lookup(name)
 332  	if obj == nil {
 333  		return 0
 334  	}
 335  	t := obj.Type()
 336  	if isNilType(t) {
 337  		return 0
 338  	}
 339  	return tcCopyOut(out, cap, t.String())
 340  }
 341  
 342  //export moxie_tc_pkg_name
 343  func moxie_tc_pkg_name(h int32, out unsafe.Pointer, cap int32) int32 {
 344  	runtime.InitCShared()
 345  	p := getPkg(h)
 346  	if p == nil {
 347  		return 0
 348  	}
 349  	return tcCopyOut(out, cap, p.Name())
 350  }
 351  
 352  //export moxie_tc_pkg_path
 353  func moxie_tc_pkg_path(h int32, out unsafe.Pointer, cap int32) int32 {
 354  	runtime.InitCShared()
 355  	p := getPkg(h)
 356  	if p == nil {
 357  		return 0
 358  	}
 359  	return tcCopyOut(out, cap, p.Path())
 360  }
 361  
 362  //export moxie_tc_free
 363  func moxie_tc_free(h int32) {
 364  	runtime.InitCShared()
 365  	if h >= 0 && int32(h) < len(pkgHandles) {
 366  		pkgHandles[h] = nil
 367  	}
 368  	if h >= 0 && int32(h) < len(cachedNames) {
 369  		cachedNames[h] = nil
 370  	}
 371  }
 372  
 373  //export moxie_tc_universe_ok
 374  func moxie_tc_universe_ok() int32 {
 375  	runtime.InitCShared()
 376  	initUniverse()
 377  	if Universe == nil {
 378  		return 0
 379  	}
 380  	return int32(Universe.Len())
 381  }
 382  
 383  func main() {}
 384