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