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 || int(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 || int(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  			}
 223  			fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
 224  			tag := ""
 225  			if i < len(e.TagList) && e.TagList[i] != nil {
 226  				tag = e.TagList[i].Value
 227  			}
 228  			tags = append(tags, tag)
 229  		}
 230  		return NewTCStruct(fields, tags)
 231  	case *FuncType:
 232  		return tcResolveFuncInline(e)
 233  	}
 234  	return nil
 235  }
 236  
 237  func tcResolveFuncInline(ft *FuncType) *Signature {
 238  	if ft == nil {
 239  		return nil
 240  	}
 241  	var params []*TCVar
 242  	for _, p := range ft.ParamList {
 243  		typ := tcResolveNameInline(p.Type)
 244  		pname := ""
 245  		if p.Name != nil {
 246  			pname = p.Name.Value
 247  		}
 248  		params = append(params, NewTCVar(nil, pname, typ))
 249  	}
 250  	var results []*TCVar
 251  	for _, r := range ft.ResultList {
 252  		typ := tcResolveNameInline(r.Type)
 253  		rname := ""
 254  		if r.Name != nil {
 255  			rname = r.Name.Value
 256  		}
 257  		results = append(results, NewTCVar(nil, rname, typ))
 258  	}
 259  	variadic := false
 260  	if len(ft.ParamList) > 0 {
 261  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
 262  			variadic = true
 263  		}
 264  	}
 265  	var pTuple *Tuple
 266  	if len(params) > 0 {
 267  		pTuple = NewTuple(params...)
 268  	}
 269  	var rTuple *Tuple
 270  	if len(results) > 0 {
 271  		rTuple = NewTuple(results...)
 272  	}
 273  	return NewSignature(nil, pTuple, rTuple, variadic)
 274  }
 275  
 276  //export moxie_tc_scope_name_count
 277  func moxie_tc_scope_name_count(h int32) int32 {
 278  	runtime.InitCShared()
 279  	names := getCachedNames(h)
 280  	return int32(len(names))
 281  }
 282  
 283  // cachedNames stores a snapshot of Names() per handle so repeated
 284  // index calls return a consistent ordering.
 285  var cachedNames [][]string
 286  
 287  func getCachedNames(h int32) []string {
 288  	for int(h) >= len(cachedNames) {
 289  		cachedNames = append(cachedNames, nil)
 290  	}
 291  	if cachedNames[h] == nil {
 292  		p := getPkg(h)
 293  		if p == nil || p.Scope() == nil {
 294  			return nil
 295  		}
 296  		cachedNames[h] = p.Scope().Names()
 297  	}
 298  	return cachedNames[h]
 299  }
 300  
 301  //export moxie_tc_scope_name
 302  func moxie_tc_scope_name(h int32, idx int32, out unsafe.Pointer, cap int32) int32 {
 303  	runtime.InitCShared()
 304  	names := getCachedNames(h)
 305  	if idx < 0 || int(idx) >= len(names) {
 306  		return 0
 307  	}
 308  	return tcCopyOut(out, cap, names[idx])
 309  }
 310  
 311  func isNilType(t Type) bool {
 312  	if t == nil {
 313  		return true
 314  	}
 315  	// Check for typed nil interface (e.g. (*Signature)(nil) stored as Type).
 316  	// An interface is {type_ptr, data_ptr}; data_ptr==0 means nil concrete value.
 317  	iface := (*[2]uintptr)(unsafe.Pointer(&t))
 318  	return iface[1] == 0
 319  }
 320  
 321  //export moxie_tc_scope_type_of
 322  func moxie_tc_scope_type_of(h int32, namePtr unsafe.Pointer, nameLen int32, out unsafe.Pointer, cap int32) int32 {
 323  	runtime.InitCShared()
 324  	p := getPkg(h)
 325  	if p == nil || p.Scope() == nil {
 326  		return 0
 327  	}
 328  	name := string(unsafe.Slice((*byte)(namePtr), nameLen))
 329  	obj := p.Scope().Lookup(name)
 330  	if obj == nil {
 331  		return 0
 332  	}
 333  	t := obj.Type()
 334  	if isNilType(t) {
 335  		return 0
 336  	}
 337  	return tcCopyOut(out, cap, t.String())
 338  }
 339  
 340  //export moxie_tc_pkg_name
 341  func moxie_tc_pkg_name(h int32, out unsafe.Pointer, cap int32) int32 {
 342  	runtime.InitCShared()
 343  	p := getPkg(h)
 344  	if p == nil {
 345  		return 0
 346  	}
 347  	return tcCopyOut(out, cap, p.Name())
 348  }
 349  
 350  //export moxie_tc_pkg_path
 351  func moxie_tc_pkg_path(h int32, out unsafe.Pointer, cap int32) int32 {
 352  	runtime.InitCShared()
 353  	p := getPkg(h)
 354  	if p == nil {
 355  		return 0
 356  	}
 357  	return tcCopyOut(out, cap, p.Path())
 358  }
 359  
 360  //export moxie_tc_free
 361  func moxie_tc_free(h int32) {
 362  	runtime.InitCShared()
 363  	if h >= 0 && int(h) < len(pkgHandles) {
 364  		pkgHandles[h] = nil
 365  	}
 366  	if h >= 0 && int(h) < len(cachedNames) {
 367  		cachedNames[h] = nil
 368  	}
 369  }
 370  
 371  //export moxie_tc_universe_ok
 372  func moxie_tc_universe_ok() int32 {
 373  	runtime.InitCShared()
 374  	initUniverse()
 375  	if Universe == nil {
 376  		return 0
 377  	}
 378  	return int32(Universe.Len())
 379  }
 380  
 381  func main() {}
 382