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