typecheck_inline.mx raw
1 package emit
2
3 import (
4 "bytes"
5 "git.smesh.lol/moxie/pkg/syntax"
6 "git.smesh.lol/moxie/pkg/ssa"
7 "git.smesh.lol/moxie/pkg/token"
8 "git.smesh.lol/moxie/pkg/types"
9 )
10
11 func scanExportPragmas(src []byte) map[string]string {
12 result := map[string]string{}
13 exportPrefix := []byte("//export ")
14 funcPrefix := []byte("func ")
15 commentPrefix := []byte("//")
16 pendingExport := ""
17 i := 0
18 for i < len(src) {
19 nlIdx := bytes.IndexByte(src[i:], '\n')
20 var line []byte
21 var lineEnd int32
22 if nlIdx < 0 {
23 line = src[i:]
24 lineEnd = len(src)
25 } else {
26 line = src[i : i+nlIdx]
27 lineEnd = i + nlIdx + 1
28 }
29 trimmed := bytes.TrimSpace(line)
30 if len(pendingExport) > 0 {
31 if len(trimmed) == 0 || bytes.HasPrefix(trimmed, commentPrefix) {
32 i = lineEnd
33 continue
34 }
35 if bytes.HasPrefix(trimmed, funcPrefix) {
36 rest := trimmed[5:]
37 paren := bytes.IndexByte(rest, '(')
38 if paren > 0 {
39 funcName := string(bytes.TrimSpace(rest[:paren]))
40 result[funcName] = pendingExport
41 }
42 }
43 pendingExport = ""
44 } else if bytes.HasPrefix(trimmed, exportPrefix) {
45 pendingExport = string(bytes.TrimSpace(trimmed[9:]))
46 }
47 i = lineEnd
48 }
49 return result
50 }
51
52 func typeCheckPkg(src []byte, name string) (*types.TCPackage, *syntax.File) {
53 inittypes.Universe()
54 shortName := name
55 for i := len(name) - 1; i >= 0; i-- {
56 if name[i] == '/' {
57 shortName = name[i+1:]
58 break
59 }
60 }
61 pkg := newTCPackageWithUniverse(name, shortName)
62 scope := pkg.Scope()
63
64 src = rewriteSliceMakeLiterals(src)
65 src = rewriteChanMakeLiterals(src)
66 src = stripDuplicatePackageClauses(src)
67
68 if len(src) == 0 {
69 return nil, nil
70 }
71
72 parseErrors = nil
73 constValMap = nil
74 errh := func(err error) {
75 parseErrors = append(parseErrors, err.Error())
76 }
77 tcPkgSrc = src
78 CompileExportMap = scanExportPragmas(src)
79 file, _ := syntax.ParseBytes(token.NewFileBase(name|".mx"), src, errh, nil, 0)
80 if file == nil {
81 return nil, nil
82 }
83 for _, d := range file.DeclList {
84 switch d := d.(type) {
85 case *syntax.ImportDecl:
86 if d.Path == nil {
87 continue
88 }
89 path := d.Path.Value
90 if len(path) >= 2 && path[0] == '"' {
91 path = path[1 : len(path)-1]
92 }
93 EnsureImportRegistry()
94 imported := ImportRegistry[path]
95 if imported == nil {
96 continue
97 }
98 if path == "unsafe" && imported.Scope().Lookup("Pointer") == nil {
99 imported.Scope().Insert(types.NewTypeName(imported, "Pointer", types.Typ[types.UnsafePointer]))
100 }
101 localName := imported.Name()
102 if d.LocalPkgName != nil {
103 localName = d.LocalPkgName.Value
104 }
105 scope.Insert(types.NewPkgName(pkg, localName, imported))
106 case *syntax.VarDecl:
107 for _, n := range d.NameList {
108 scope.Insert(types.NewTCVar(pkg, n.Value, nil))
109 }
110 case *syntax.FuncDecl:
111 if d.Recv == nil && d.Name.Value != "init" {
112 scope.Insert(types.NewTCFunc(pkg, d.Name.Value, nil))
113 }
114 case *syntax.TypeDecl:
115 scope.Insert(types.NewTypeName(pkg, d.Name.Value, nil))
116 case *syntax.ConstDecl:
117 for _, n := range d.NameList {
118 scope.Insert(types.NewTCConst(pkg, n.Value, nil, nil))
119 }
120 }
121 }
122
123 var curConstGroup *Group
124 var prevConstValues syntax.Expr
125 var prevConstType syntax.Expr
126 iotaVal := int64(-1)
127 for _, d := range file.DeclList {
128 if td, ok := d.(*syntax.TypeDecl); ok {
129 obj := scope.Lookup(td.Name.Value)
130 if obj != nil {
131 if tn, ok2 := obj.(*types.TypeName); ok2 {
132 types.NewNamed(tn, nil)
133 }
134 }
135 }
136 }
137 for _, d := range file.DeclList {
138 if cd, ok := d.(*syntax.ConstDecl); ok {
139 if cd.Group == nil || cd.Group != curConstGroup {
140 curConstGroup = cd.Group
141 iotaVal = int64(0)
142 prevConstValues = nil
143 prevConstType = nil
144 } else {
145 iotaVal++
146 }
147 valExpr := cd.Values
148 typeExpr := cd.Type
149 if valExpr == nil {
150 valExpr = prevConstValues
151 if typeExpr == nil {
152 typeExpr = prevConstType
153 }
154 } else {
155 prevConstValues = cd.Values
156 prevConstType = cd.Type
157 }
158 typ := tcResolveNameInline(typeExpr, scope)
159 if typ == nil && valExpr != nil {
160 typ = tcInferTypeFromExpr(valExpr, scope)
161 }
162 var val types.ConstVal
163 if valExpr != nil {
164 val = tcEvalConstExpr(valExpr, scope, iotaVal)
165 }
166 if typ == nil && val != nil {
167 typ = types.UntypedTypeOfCV(val)
168 }
169 for _, n := range cd.NameList {
170 if val != nil {
171 if ci, ok2 := val.(*types.ConstInt); ok2 {
172 if constValMap == nil {
173 constValMap = map[string]int64{}
174 }
175 constValMap[n.Value] = ci.V
176 }
177 }
178 obj := scope.Lookup(n.Value)
179 if obj != nil {
180 if c, ok := obj.(*types.TCConst); ok {
181 c.SetType(typ)
182 c.SetVal(val)
183 }
184 }
185 }
186 }
187 }
188 for _, d := range file.DeclList {
189 if cd, ok := d.(*syntax.ConstDecl); ok {
190 for _, n := range cd.NameList {
191 obj := scope.Lookup(n.Value)
192 if obj == nil {
193 continue
194 }
195 c, ok2 := obj.(*types.TCConst)
196 if !ok2 || c.Val() != nil {
197 continue
198 }
199 valExpr := cd.Values
200 if valExpr == nil {
201 continue
202 }
203 val := tcEvalConstExpr(valExpr, scope, int64(0))
204 if val != nil {
205 c.SetVal(val)
206 if c.Type() == nil {
207 c.SetType(types.UntypedTypeOfCV(val))
208 }
209 }
210 }
211 }
212 }
213 for _, d := range file.DeclList {
214 if td, ok := d.(*syntax.TypeDecl); ok {
215 obj := scope.Lookup(td.Name.Value)
216 if obj != nil {
217 if tn, ok2 := obj.(*types.TypeName); ok2 {
218 named, ok3 := tn.Type().(*types.Named)
219 if ok3 {
220 typ := tcResolveNameInline(td.Type, scope)
221 named.SetUnderlying(typ)
222 }
223 }
224 }
225 }
226 }
227 for _, d := range file.DeclList {
228 switch d := d.(type) {
229 case *syntax.VarDecl:
230 typ := tcResolveNameInline(d.Type, scope)
231 if arr, ok := typ.(*types.Array); ok && arr.Len() < 0 && d.Values != nil {
232 if cl, ok2 := d.Values.(*syntax.CompositeLit); ok2 {
233 typ = types.NewArray(arr.Elem(), int64(len(cl.ElemList)))
234 }
235 }
236 if typ == nil && d.Values != nil {
237 typ = tcInferTypeFromExpr(d.Values, scope)
238 }
239 for _, n := range d.NameList {
240 obj := scope.Lookup(n.Value)
241 if obj != nil {
242 if v, ok := obj.(*types.TCVar); ok {
243 v.SetType(typ)
244 }
245 }
246 }
247 case *syntax.FuncDecl:
248 if d.Recv == nil && d.Name.Value != "init" {
249 if len(d.TParamList) > 0 {
250 if genericFuncDecls == nil {
251 genericFuncDecls = map[string]*syntax.FuncDecl{}
252 }
253 genericFuncDecls[name+"."+d.Name.Value] = d
254 if genericPkgScopes == nil {
255 genericPkgScopes = map[string]*types.Scope{}
256 }
257 genericPkgScopes[name] = pkg.Scope()
258 continue
259 }
260 sig := tcResolveFuncInline(d.Type, scope)
261 obj := scope.Lookup(d.Name.Value)
262 if obj != nil {
263 if fn, ok := obj.(*types.TCFunc); ok && sig != nil {
264 fn.SetType(sig)
265 }
266 }
267 }
268 }
269 }
270 print(" tcpkg-methods\n")
271 for _, d := range file.DeclList {
272 if fd, ok := d.(*syntax.FuncDecl); ok && fd.Recv != nil {
273 recvType := tcResolveRecvType(fd.Recv, scope)
274 if recvType == nil {
275 continue
276 }
277 sig := tcResolveFuncInlineWithRecv(fd.Type, fd.Recv, scope)
278 fn := types.NewTCFunc(pkg, fd.Name.Value, sig)
279 isPtr := false
280 var named *types.Named
281 if pt, ok := recvType.(*types.Pointer); ok {
282 if okv, okok := pt.Elem().(*types.Named); okok {
283 named = okv
284 }
285 isPtr = true
286 } else {
287 if okv, okok := recvType.(*types.Named); okok {
288 named = okv
289 }
290 }
291 if named != nil {
292 if isPtr {
293 fn.SetPtrRecv(true)
294 }
295 named.AddMethod(fn)
296 }
297 }
298 }
299
300 return pkg, file
301 }
302
303 func releasePerPkgState() {
304 parseErrors = nil
305 compileErrors = nil
306 constValMap = nil
307 CompileExportMap = nil
308 tcPkgSrc = nil
309 }
310
311 func TypeCheckOnly(src []byte, name string) {
312 pkg, file := typeCheckPkg(src, name)
313 if pkg != nil && file != nil {
314 registerCompiledExports(pkg)
315 }
316 hasGenerics := pkg != nil && genericPkgScopes != nil && genericPkgScopes[pkg.Path()] != nil
317 if pkg != nil && !hasGenerics {
318 pkg.Release()
319 }
320 if file != nil {
321 file.DeclList = nil
322 }
323 releasePerPkgState()
324 }
325
326 func CompileToIR(src []byte, name string, triple string) string {
327 pkg, file := typeCheckPkg(src, name)
328 if file == nil {
329 out := "; parse error parseErrs=" | simpleItoa(len(parseErrors)) | "\n"
330 for _, pe := range parseErrors {
331 out = out | "; " | pe | "\n"
332 }
333 releasePerPkgState()
334 return out
335 }
336
337 prog := ssa.NewSSAProgram()
338 ssaPkg := prog.CreatePackage(pkg, []*syntax.File{file}, nil)
339 emitter := newIREmitter(ssaPkg, triple)
340 ir := emitter.emit()
341
342 if len(compileErrors) > 0 {
343 out := "; compile error\n"
344 for _, ce := range compileErrors {
345 out = out | "; " | ce | "\n"
346 }
347 emitter.releaseAfterEmit()
348 ssaPkg.release()
349 prog.release()
350 if pkg != nil {
351 pkg.Release()
352 }
353 file.DeclList = nil
354 releasePerPkgState()
355 return out
356 }
357
358 if len(ir) > 0 && ir[0] != ';' {
359 registerCompiledExports(pkg)
360 }
361
362 emitter.releaseAfterEmit()
363 ssaPkg.release()
364 prog.release()
365 hasGenerics := genericPkgScopes != nil && genericPkgScopes[pkg.Path()] != nil
366 if pkg != nil && !hasGenerics {
367 pkg.Release()
368 }
369 file.DeclList = nil
370 releasePerPkgState()
371 return ir
372 }
373
374 func registerCompiledExports(pkg *types.TCPackage) {
375 EnsureImportRegistry()
376 path := pkg.Path()
377 regPkg := types.NewTCPackage(path, pkg.Name())
378 for _, name := range pkg.Scope().Names() {
379 if len(name) == 0 || name[0] < 'A' || name[0] > 'Z' {
380 continue
381 }
382 obj := pkg.Scope().Lookup(name)
383 if obj != nil {
384 regPkg.Scope().Insert(obj)
385 }
386 }
387 ImportRegistry[path] = regPkg
388 }
389
390 func tcInferTypeFromExpr(e syntax.Expr, scope *types.Scope) syntax.Type {
391 switch e := e.(type) {
392 case *syntax.BasicLit:
393 switch e.Kind {
394 case token.StringLit:
395 return types.Typ[types.TCString]
396 case token.IntLit:
397 return types.Typ[types.Int32]
398 case token.FloatLit:
399 return types.Typ[types.Float64]
400 }
401 case *syntax.Name:
402 if e.Value == "true" || e.Value == "false" {
403 return types.Typ[types.Bool]
404 }
405 return tcResolveNameInline(e, scope)
406 case *syntax.CallExpr:
407 ft := tcResolveNameInline(e.Fun, scope)
408 if sig, ok := ft.(*types.Signature); ok && sig != nil {
409 res := sig.Results()
410 if res != nil && res.Len() == 1 {
411 return res.At(0).Type()
412 }
413 if res != nil && res.Len() > 1 {
414 return res
415 }
416 }
417 return ft
418 case *syntax.CompositeLit:
419 t := tcResolveNameInline(e.Type, scope)
420 if arr, ok := t.(*types.Array); ok && arr.Len() < 0 {
421 return types.NewArray(arr.Elem(), int64(len(e.ElemList)))
422 }
423 return t
424 case *syntax.Operation:
425 if e.Y == nil && e.Op == And {
426 return types.NewPointer(tcInferTypeFromExpr(e.X, scope))
427 }
428 }
429 return nil
430 }
431
432 var constValMap map[string]int64
433 var tcPkgSrc []byte
434
435 func resolveArrayLenFromSrc(p token.Pos, cmap map[string]int64) int64 {
436 line := p.Line()
437 col := p.Col()
438 if line == 0 || col == 0 || tcPkgSrc == nil {
439 return -1
440 }
441 off := 0
442 curLine := uint32(1)
443 for off < len(tcPkgSrc) && curLine < line {
444 if tcPkgSrc[off] == '\n' {
445 curLine++
446 }
447 off++
448 }
449 off += int32(col) - 1
450 if off >= len(tcPkgSrc) || tcPkgSrc[off] != '[' {
451 return -1
452 }
453 off++
454 for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
455 off++
456 }
457 start := off
458 for off < len(tcPkgSrc) {
459 c := tcPkgSrc[off]
460 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
461 off++
462 } else {
463 break
464 }
465 }
466 if off == start {
467 return -1
468 }
469 name := string(tcPkgSrc[start:off])
470 if v, ok := cmap[name]; ok {
471 if off < len(tcPkgSrc) && tcPkgSrc[off] == '+' {
472 off++
473 for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
474 off++
475 }
476 numStart := off
477 for off < len(tcPkgSrc) && tcPkgSrc[off] >= '0' && tcPkgSrc[off] <= '9' {
478 off++
479 }
480 if off > numStart {
481 addend := int64(0)
482 for i := numStart; i < off; i++ {
483 addend = addend*10 + int64(tcPkgSrc[i]-'0')
484 }
485 return v + addend
486 }
487 }
488 return v
489 }
490 n := int64(0)
491 isNum := true
492 for i := start; i < off; i++ {
493 c := tcPkgSrc[i]
494 if c >= '0' && c <= '9' {
495 n = n*10 + int64(c-'0')
496 } else {
497 isNum = false
498 break
499 }
500 }
501 if isNum && off > start {
502 return n
503 }
504 return -1
505 }
506
507 func resolveArrayLenFromConstMap(e syntax.Expr, cmap map[string]int64) int64 {
508 line := e.Pos().Line()
509 col := e.Pos().Col()
510 if line == 0 || col == 0 || tcPkgSrc == nil {
511 return -1
512 }
513 curLine := uint32(1)
514 off := 0
515 for off < len(tcPkgSrc) && curLine < line {
516 if tcPkgSrc[off] == '\n' {
517 curLine++
518 }
519 off++
520 }
521 off += int32(col) - 1
522 if off >= len(tcPkgSrc) {
523 return -1
524 }
525 start := off
526 for off < len(tcPkgSrc) {
527 c := tcPkgSrc[off]
528 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
529 off++
530 } else {
531 break
532 }
533 }
534 if off == start {
535 return -1
536 }
537 name := string(tcPkgSrc[start:off])
538 if v, ok := cmap[name]; ok {
539 return v
540 }
541 return -1
542 }
543
544 func tcEvalConstExpr(e syntax.Expr, scope *types.Scope, iotaVal int64) types.ConstVal {
545 if e == nil {
546 return nil
547 }
548 switch e := e.(type) {
549 case *syntax.BasicLit:
550 return types.EvalBasicLitLocal(e)
551 case *syntax.Name:
552 if e.Value == "iota" && iotaVal >= 0 {
553 return &types.ConstInt{V:iotaVal}
554 }
555 if scope != nil {
556 _, obj := scope.LookupParent(e.Value)
557 if c, ok := obj.(*types.TCConst); ok && c.Val() != nil {
558 return c.Val()
559 }
560 }
561 if constValMap != nil {
562 if v, ok := constValMap[e.Value]; ok {
563 return &types.ConstInt{V:v}
564 }
565 }
566 case *syntax.Operation:
567 if e.Y == nil {
568 xr := tcEvalConstExpr(e.X, scope, iotaVal)
569 if xr == nil {
570 return nil
571 }
572 return evalUnaryLocal(e.Op, xr)
573 }
574 xr := tcEvalConstExpr(e.X, scope, iotaVal)
575 yr := tcEvalConstExpr(e.Y, scope, iotaVal)
576 if xr == nil || yr == nil {
577 return nil
578 }
579 return evalBinaryLocal(e.Op, xr, yr)
580 case *syntax.ParenExpr:
581 return tcEvalConstExpr(e.X, scope, iotaVal)
582 case *syntax.CallExpr:
583 if id, ok := e.Fun.(*syntax.Name); ok && id.Value == "len" && len(e.ArgList) == 1 {
584 if lit, ok2 := e.ArgList[0].(*syntax.BasicLit); ok2 && lit.Kind == token.StringLit {
585 lv := types.EvalBasicLitLocal(lit)
586 if cs, ok3 := lv.(*types.ConstStr); ok3 {
587 return &types.ConstInt{V:int64(len(cs.S))}
588 }
589 }
590 inner := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
591 if cs, ok2 := inner.(*types.ConstStr); ok2 {
592 return &types.ConstInt{V:int64(len(cs.S))}
593 }
594 }
595 if sel, ok := e.Fun.(*syntax.SelectorExpr); ok {
596 if pkg, ok2 := sel.X.(*syntax.Name); ok2 && pkg.Value == "unsafe" {
597 switch sel.Sel.Value {
598 case "Sizeof", "Alignof", "Offsetof":
599 return &types.ConstInt{V:8}
600 }
601 }
602 }
603 if len(e.ArgList) != 1 {
604 return nil
605 }
606 inner := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
607 if inner == nil {
608 return nil
609 }
610 targetType := tcResolveNameInline(e.Fun, scope)
611 if targetType == nil {
612 return inner
613 }
614 return convertConstLocal(inner, targetType)
615 case *syntax.SelectorExpr:
616 pkgName, ok := e.X.(*syntax.Name)
617 if !ok {
618 return nil
619 }
620 var imported *types.TCPackage
621 if scope != nil {
622 _, obj := scope.LookupParent(pkgName.Value)
623 if pn, ok2 := obj.(*types.PkgName); ok2 && pn.Imported() != nil {
624 imported = pn.Imported()
625 }
626 }
627 if imported == nil {
628 EnsureImportRegistry()
629 imported = ImportRegistry[pkgName.Value]
630 }
631 if imported == nil {
632 return nil
633 }
634 member := imported.Scope().Lookup(e.Sel.Value)
635 if member == nil {
636 return nil
637 }
638 if k, ok := member.(*types.TCConst); ok && k.Val() != nil {
639 return k.Val()
640 }
641 return nil
642 }
643 return nil
644 }
645
646 func tcResolveNameInline(e syntax.Expr, scope *types.Scope) syntax.Type {
647 if e == nil {
648 return nil
649 }
650 switch e := e.(type) {
651 case *syntax.Name:
652 var obj Object
653 if scope != nil {
654 _, obj = scope.LookupParent(e.Value)
655 } else {
656 _, obj = types.Universe.LookupParent(e.Value)
657 }
658 if obj != nil {
659 if tn, ok := obj.(*types.TypeName); ok {
660 return tn.Type()
661 }
662 if fn, ok := obj.(*types.TCFunc); ok {
663 if sig := fn.Signature(); sig != nil {
664 return sig
665 }
666 }
667 }
668 case *syntax.SelectorExpr:
669 pkgName, ok := e.X.(*syntax.Name)
670 if ok && scope != nil {
671 _, pkgObj := scope.LookupParent(pkgName.Value)
672 if pn, ok2 := pkgObj.(*types.PkgName); ok2 && pn.Imported() != nil {
673 typeObj := pn.Imported().Scope().Lookup(e.Sel.Value)
674 if typeObj != nil {
675 if tn, ok3 := typeObj.(*types.TypeName); ok3 {
676 return tn.Type()
677 }
678 if fn, ok3 := typeObj.(*types.TCFunc); ok3 {
679 if sig := fn.Signature(); sig != nil {
680 return sig
681 }
682 }
683 }
684 }
685 }
686 // Fallback: check ImportRegistry directly for external package types
687 if pkgName, ok := e.X.(*syntax.Name); ok {
688 var irKeys []string
689 for k := range ImportRegistry {
690 irKeys = append(irKeys, k)
691 }
692 for i := 1; i < len(irKeys); i++ {
693 for j := i; j > 0 && irKeys[j] < irKeys[j-1]; j-- {
694 irKeys[j], irKeys[j-1] = irKeys[j-1], irKeys[j]
695 }
696 }
697 for _, k := range irKeys {
698 pkg := ImportRegistry[k]
699 if pkg.Name() == pkgName.Value {
700 typeObj := pkg.Scope().Lookup(e.Sel.Value)
701 if typeObj != nil {
702 if tn, ok2 := typeObj.(*types.TypeName); ok2 {
703 return tn.Type()
704 }
705 }
706 break
707 }
708 }
709 }
710 case *syntax.Operation:
711 if e.Y == nil && e.Op == Mul {
712 base := tcResolveNameInline(e.X, scope)
713 if base == nil {
714 base = types.Typ[types.Int8]
715 }
716 return types.NewPointer(base)
717 }
718 case *types.SliceType:
719 elem := tcResolveNameInline(e.Elem, scope)
720 if elem != nil {
721 if b, ok := elem.(*types.Basic); ok && b.Kind() == Uint8 {
722 return types.Typ[types.TCString]
723 }
724 return types.NewSlice(elem)
725 }
726 case *syntax.ArrayType:
727 elem := tcResolveNameInline(e.Elem, scope)
728 if elem != nil {
729 n := int64(-1)
730 if lit, ok := e.Len.(*syntax.BasicLit); ok {
731 n = irParseInt64(lit.Value)
732 } else if e.Len != nil {
733 cv := tcEvalConstExpr(e.Len, scope, -1)
734 if cv != nil {
735 if ci, ok := cv.(*types.ConstInt); ok {
736 n = ci.V
737 }
738 }
739 if n == -1 && constValMap != nil {
740 n = resolveArrayLenFromSrc(e.pos, constValMap)
741 }
742 }
743 return types.NewArray(elem, n)
744 }
745 case *syntax.MapType:
746 key := tcResolveNameInline(e.Key, scope)
747 val := tcResolveNameInline(e.Value, scope)
748 if key != nil && val != nil {
749 return types.NewTCMap(key, val)
750 }
751 case *syntax.StructType:
752 var fields []*types.TCVar
753 var tags []string
754 for i, field := range e.FieldList {
755 typ := tcResolveNameInline(field.Type, scope)
756 fname := ""
757 if field.Name != nil {
758 fname = field.Name.Value
759 } else {
760 fname = typeBaseName(typ)
761 }
762 fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
763 tag := ""
764 if i < len(e.TagList) && e.TagList[i] != nil {
765 tag = e.TagList[i].Value
766 }
767 tags = append(tags, tag)
768 }
769 return types.NewTCStruct(fields, tags)
770 case *syntax.FuncType:
771 return tcResolveFuncInline(e, scope)
772 case *syntax.InterfaceType:
773 return tcResolveInterfaceInline(e, scope)
774 case *syntax.ChanType:
775 elem := tcResolveNameInline(e.Elem, scope)
776 if elem == nil {
777 elem = types.NewTCStruct(nil, nil)
778 }
779 var dir types.TCChanDir
780 switch e.Dir {
781 case syntax.SendOnly:
782 dir = types.TCSendOnly
783 case syntax.RecvOnly:
784 dir = types.TCRecvOnly
785 default:
786 dir = types.TCSendRecv
787 }
788 return types.NewTCChan(dir, elem)
789 case *syntax.DotsType:
790 elem := tcResolveNameInline(e.Elem, scope)
791 if elem != nil {
792 if b, ok := elem.(*types.Basic); ok && b.Kind() == Uint8 {
793 return types.Typ[types.TCString]
794 }
795 return types.NewSlice(elem)
796 }
797 }
798 return nil
799 }
800
801 func tcResolveInterfaceInline(e *syntax.InterfaceType, scope *types.Scope) *types.TCInterface {
802 var methods []*types.IfaceMethod
803 var embeds []syntax.Type
804 for _, f := range e.MethodList {
805 if f.Name == nil {
806 if f.Type != nil {
807 embed := tcResolveNameInline(f.Type, scope)
808 if embed != nil {
809 embeds = append(embeds, embed)
810 }
811 }
812 continue
813 }
814 ft, ok := f.Type.(*syntax.FuncType)
815 if !ok {
816 continue
817 }
818 sig := tcResolveFuncInline(ft, scope)
819 if sig != nil {
820 methods = append(methods, types.NewTCIfaceMethod(f.Name.Value, sig))
821 }
822 }
823 iface := types.NewTCInterface(methods, embeds)
824 iface.Complete()
825 return iface
826 }
827
828 func stripDuplicatePackageClauses(src []byte) []byte {
829 found := false
830 var out []byte
831 i := 0
832 for i < len(src) {
833 nlIdx := bytes.IndexByte(src[i:], '\n')
834 var line []byte
835 var lineEnd int32
836 if nlIdx < 0 {
837 line = src[i:]
838 lineEnd = len(src)
839 } else {
840 line = src[i : i+nlIdx]
841 lineEnd = i + nlIdx + 1
842 }
843 trimmed := bytes.TrimSpace(line)
844 if bytes.HasPrefix(trimmed, "package ") {
845 if found {
846 if out == nil {
847 out = []byte{:0:len(src)}
848 out = append(out, src[:i]...)
849 }
850 for k := 0; k < len(line); k++ {
851 out = append(out, ' ')
852 }
853 if nlIdx >= 0 {
854 out = append(out, '\n')
855 }
856 i = lineEnd
857 continue
858 }
859 found = true
860 }
861 if out != nil {
862 out = append(out, src[i:lineEnd]...)
863 }
864 i = lineEnd
865 }
866 if out == nil {
867 return src
868 }
869 return out
870 }
871
872 func rewriteSliceMakeLiterals(src []byte) []byte {
873 var out []byte
874 i := 0
875 for i < len(src) {
876 start := bytes.Index(src[i:], []byte("{:"))
877 if start < 0 {
878 out = append(out, src[i:]...)
879 break
880 }
881 start = start + i
882 lbrack := findSliceTypeStart(src, start)
883 if lbrack < 0 {
884 out = append(out, src[i:start+2]...)
885 i = start + 2
886 continue
887 }
888 close := findMatchingBrace(src, start)
889 if close < 0 {
890 out = append(out, src[i:start+2]...)
891 i = start + 2
892 continue
893 }
894 inner := src[start+2 : close]
895 colonIdx := bytes.IndexByte(inner, ':')
896 typeText := src[lbrack:start]
897 out = append(out, src[i:lbrack]...)
898 if colonIdx < 0 {
899 out = append(out, "make("...)
900 out = append(out, typeText...)
901 out = append(out, ", "...)
902 out = append(out, bytes.TrimSpace(inner)...)
903 out = append(out, ')')
904 } else {
905 lenExpr := bytes.TrimSpace(inner[:colonIdx])
906 capExpr := bytes.TrimSpace(inner[colonIdx+1:])
907 out = append(out, "make("...)
908 out = append(out, typeText...)
909 out = append(out, ", "...)
910 out = append(out, lenExpr...)
911 out = append(out, ", "...)
912 out = append(out, capExpr...)
913 out = append(out, ')')
914 }
915 i = close + 1
916 }
917 if out == nil {
918 return src
919 }
920 return out
921 }
922
923 func findSliceTypeStart(src []byte, braceIdx int32) int32 {
924 j := braceIdx - 1
925 for j >= 0 && (src[j] == ' ' || src[j] == '\t' || src[j] == '\n') {
926 j--
927 }
928 if j < 0 {
929 return -1
930 }
931 depth := 0
932 parenDepth := 0
933 candidate := -1
934 for j >= 0 {
935 ch := src[j]
936 if ch == ')' {
937 parenDepth++
938 } else if ch == '(' {
939 if parenDepth == 0 {
940 if candidate >= 0 {
941 return candidate
942 }
943 return -1
944 }
945 parenDepth--
946 } else if parenDepth > 0 {
947 j--
948 continue
949 }
950 if ch == ']' {
951 depth++
952 } else if ch == '[' {
953 depth--
954 if depth == 0 {
955 candidate = j
956 }
957 } else if ch == '{' || ch == ';' {
958 if candidate >= 0 {
959 return candidate
960 }
961 return -1
962 } else if depth == 0 && parenDepth == 0 {
963 if candidate >= 0 {
964 return candidate
965 }
966 if ch == ' ' || ch == '\t' || ch == '\n' || ch == '*' || ch == '(' || ch == ')' {
967 j--
968 continue
969 }
970 if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
971 j--
972 continue
973 }
974 return -1
975 }
976 j--
977 }
978 if candidate >= 0 {
979 return candidate
980 }
981 return -1
982 }
983
984 func findMatchingBrace(src []byte, openIdx int32) int32 {
985 depth := 1
986 for i := openIdx + 1; i < len(src); i++ {
987 if src[i] == '{' {
988 depth++
989 } else if src[i] == '}' {
990 depth--
991 if depth == 0 {
992 return i
993 }
994 }
995 }
996 return -1
997 }
998
999 func rewriteChanMakeLiterals(src []byte) []byte {
1000 chanKw := []byte("chan ")
1001 var out []byte
1002 i := 0
1003 for i < len(src) {
1004 idx := bytes.Index(src[i:], chanKw)
1005 if idx < 0 {
1006 if out != nil {
1007 out = append(out, src[i:]...)
1008 }
1009 break
1010 }
1011 idx = idx + i
1012 j := idx + 5
1013 for j < len(src) && (src[j] == ' ' || src[j] == '\t') {
1014 j++
1015 }
1016 if j >= len(src) {
1017 if out != nil {
1018 out = append(out, src[i:]...)
1019 }
1020 break
1021 }
1022 if src[j] == '<' && j+1 < len(src) && src[j+1] == '-' {
1023 if out != nil {
1024 out = append(out, src[i:j+2]...)
1025 }
1026 i = j + 2
1027 continue
1028 }
1029 for j < len(src) && (src[j] != '{' && src[j] != '\n' && src[j] != ';' && src[j] != '(' && src[j] != ')') {
1030 if src[j] == ' ' || src[j] == '\t' {
1031 break
1032 }
1033 j++
1034 }
1035 if j >= len(src) || src[j] != '{' {
1036 if out == nil {
1037 i = idx + 4
1038 } else {
1039 out = append(out, src[i:idx+4]...)
1040 i = idx + 4
1041 }
1042 continue
1043 }
1044 braceOpen := j
1045 endsStruct := braceOpen >= 6 && string(src[braceOpen-6:braceOpen]) == "struct"
1046 if !endsStruct && braceOpen >= 7 {
1047 k := braceOpen - 1
1048 for k > idx && (src[k] == ' ' || src[k] == '\t') {
1049 k--
1050 }
1051 if k >= 5 && string(src[k-5:k+1]) == "struct" {
1052 endsStruct = true
1053 }
1054 }
1055 if endsStruct {
1056 structClose := findMatchingBrace(src, braceOpen)
1057 if structClose < 0 {
1058 if out == nil {
1059 i = idx + 4
1060 } else {
1061 out = append(out, src[i:idx+4]...)
1062 i = idx + 4
1063 }
1064 continue
1065 }
1066 nj := structClose + 1
1067 if nj >= len(src) || src[nj] != '{' {
1068 if out == nil {
1069 i = structClose + 1
1070 } else {
1071 out = append(out, src[i:structClose+1]...)
1072 i = structClose + 1
1073 }
1074 continue
1075 }
1076 braceOpen = nj
1077 }
1078 close := findMatchingBrace(src, braceOpen)
1079 if close < 0 {
1080 if out == nil {
1081 i = idx + 4
1082 } else {
1083 out = append(out, src[i:idx+4]...)
1084 i = idx + 4
1085 }
1086 continue
1087 }
1088 inner := bytes.TrimSpace(src[braceOpen+1 : close])
1089 chanType := src[idx : braceOpen]
1090 for len(chanType) > 0 && (chanType[len(chanType)-1] == ' ' || chanType[len(chanType)-1] == '\t') {
1091 chanType = chanType[:len(chanType)-1]
1092 }
1093 if out == nil {
1094 out = []byte{:0:len(src)}
1095 out = append(out, src[:idx]...)
1096 } else {
1097 out = append(out, src[i:idx]...)
1098 }
1099 if len(inner) == 0 {
1100 out = append(out, "make("...)
1101 out = append(out, chanType...)
1102 out = append(out, ')')
1103 } else {
1104 out = append(out, "make("...)
1105 out = append(out, chanType...)
1106 out = append(out, ", "...)
1107 out = append(out, inner...)
1108 out = append(out, ')')
1109 }
1110 i = close + 1
1111 }
1112 if out == nil {
1113 return src
1114 }
1115 return out
1116 }
1117
1118 func tcResolveRecvType(recv *syntax.Field, scope *types.Scope) syntax.Type {
1119 if recv == nil {
1120 return nil
1121 }
1122 return tcResolveNameInline(recv.Type, scope)
1123 }
1124
1125 func tcResolveFuncInlineWithRecv(ft *syntax.FuncType, recv *syntax.Field, scope *types.Scope) *types.Signature {
1126 if ft == nil {
1127 return nil
1128 }
1129 var recvVar *types.TCVar
1130 if recv != nil {
1131 recvTyp := tcResolveNameInline(recv.Type, scope)
1132 recvName := ""
1133 if recv.Name != nil {
1134 recvName = recv.Name.Value
1135 }
1136 recvVar = types.NewTCVar(nil, recvName, recvTyp)
1137 }
1138 params := tcResolveFieldList(ft.ParamList, scope)
1139 results := tcResolveFieldList(ft.ResultList, scope)
1140 variadic := false
1141 if len(ft.ParamList) > 0 {
1142 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*syntax.DotsType); ok {
1143 variadic = true
1144 }
1145 }
1146 return types.NewSignature(recvVar, params, results, variadic)
1147 }
1148
1149 func tcResolveFieldList(fields []*syntax.Field, scope *types.Scope) *types.Tuple {
1150 if len(fields) == 0 {
1151 return nil
1152 }
1153 var vars []*types.TCVar
1154 for _, f := range fields {
1155 typ := tcResolveNameInline(f.Type, scope)
1156 pname := ""
1157 if f.Name != nil {
1158 pname = f.Name.Value
1159 }
1160 vars = append(vars, types.NewTCVar(nil, pname, typ))
1161 }
1162 return types.NewTuple(vars...)
1163 }
1164
1165 func tcResolveFuncInline(ft *syntax.FuncType, scope *types.Scope) *types.Signature {
1166 if ft == nil {
1167 return nil
1168 }
1169 var params []*types.TCVar
1170 for _, p := range ft.ParamList {
1171 typ := tcResolveNameInline(p.Type, scope)
1172 pname := ""
1173 if p.Name != nil {
1174 pname = p.Name.Value
1175 }
1176 params = append(params, types.NewTCVar(nil, pname, typ))
1177 }
1178 var results []*types.TCVar
1179 for _, r := range ft.ResultList {
1180 typ := tcResolveNameInline(r.Type, scope)
1181 rname := ""
1182 if r.Name != nil {
1183 rname = r.Name.Value
1184 }
1185 results = append(results, types.NewTCVar(nil, rname, typ))
1186 }
1187 variadic := false
1188 if len(ft.ParamList) > 0 {
1189 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*syntax.DotsType); ok {
1190 variadic = true
1191 }
1192 }
1193 var pTuple *types.Tuple
1194 if len(params) > 0 {
1195 pTuple = types.NewTuple(params...)
1196 }
1197 var rTuple *types.Tuple
1198 if len(results) > 0 {
1199 rTuple = types.NewTuple(results...)
1200 }
1201 return types.NewSignature(nil, pTuple, rTuple, variadic)
1202 }
1203
1204 func (e *irEmitter) instrOperands(instr ssa.SSAInstruction) []ssa.SSAValue {
1205 switch i := instr.(type) {
1206 case *ssa.SSAStore:
1207 return []ssa.SSAValue{i.Addr, i.Val}
1208 case *ssa.SSAUnOp:
1209 return []ssa.SSAValue{i.X}
1210 case *ssa.SSABinOp:
1211 return []ssa.SSAValue{i.X, i.Y}
1212 case *ssa.SSACall:
1213 out := []ssa.SSAValue{i.Call.Value}
1214 for _, a := range i.Call.Args {
1215 out = append(out, a)
1216 }
1217 return out
1218 case *ssa.SSAFieldAddr:
1219 return []ssa.SSAValue{i.X}
1220 case *ssa.SSAIndexAddr:
1221 return []ssa.SSAValue{i.X, i.Index}
1222 case *ssa.SSAExtract:
1223 return []ssa.SSAValue{i.Tuple}
1224 case *ssa.SSAPhi:
1225 return i.Edges
1226 case *ssa.SSAReturn:
1227 var out []ssa.SSAValue
1228 for _, r := range i.Results {
1229 out = append(out, r)
1230 }
1231 return out
1232 case *ssa.SSAIf:
1233 return []ssa.SSAValue{i.Cond}
1234 case *ssa.SSAConvert:
1235 return []ssa.SSAValue{i.X}
1236 case *ssa.SSAChangeType:
1237 return []ssa.SSAValue{i.X}
1238 case *ssa.SSAMakeInterface:
1239 return []ssa.SSAValue{i.X}
1240 case *ssa.SSATypeAssert:
1241 return []ssa.SSAValue{i.X}
1242 case *ssa.SSASlice:
1243 out := []ssa.SSAValue{i.X}
1244 if i.Low != nil { out = append(out, i.Low) }
1245 if i.High != nil { out = append(out, i.High) }
1246 if i.Max != nil { out = append(out, i.Max) }
1247 return out
1248 case *ssa.SSAMapUpdate:
1249 return []ssa.SSAValue{i.Map, i.Key, i.Value}
1250 case *ssa.SSALookup:
1251 return []ssa.SSAValue{i.X, i.Index}
1252 case *ssa.SSARange:
1253 return []ssa.SSAValue{i.X}
1254 case *ssa.SSANext:
1255 return []ssa.SSAValue{i.Iter}
1256 case *ssa.SSASend:
1257 return []ssa.SSAValue{i.Chan, i.X}
1258 case *ssa.SSAMakeSlice:
1259 out := []ssa.SSAValue{i.Len}
1260 if i.Cap != nil { out = append(out, i.Cap) }
1261 if i.Data != nil { out = append(out, i.Data) }
1262 return out
1263 }
1264 return nil
1265 }
1266