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