main.go raw
1 package main
2
3 import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "runtime"
8 "unsafe"
9
10 "github.com/ebitengine/purego"
11 )
12
13 func main() {
14 if len(os.Args) < 2 {
15 fmt.Fprintf(os.Stderr, "usage: %s <path-to-typecheck.so>\n", os.Args[0])
16 os.Exit(1)
17 }
18 soPath := os.Args[1]
19 if !filepath.IsAbs(soPath) {
20 wd, _ := os.Getwd()
21 soPath = filepath.Join(wd, soPath)
22 }
23
24 lib, err := purego.Dlopen(soPath, purego.RTLD_NOW|purego.RTLD_GLOBAL)
25 if err != nil {
26 fmt.Fprintf(os.Stderr, "dlopen %s: %v\n", soPath, err)
27 os.Exit(1)
28 }
29
30 var universeOk func() int32
31 purego.RegisterLibFunc(&universeOk, lib, "moxie_tc_universe_ok")
32
33 var parseOnly func(uintptr, int32, uintptr, int32) int32
34 purego.RegisterLibFunc(&parseOnly, lib, "moxie_tc_parse_only")
35
36 var pass1Insert func(uintptr, int32, uintptr, int32) int32
37 purego.RegisterLibFunc(&pass1Insert, lib, "moxie_tc_pass1_insert")
38
39 var checkBytes func(uintptr, int32, uintptr, int32) int32
40 purego.RegisterLibFunc(&checkBytes, lib, "moxie_tc_check_bytes")
41
42 var scopeNameCount func(int32) int32
43 purego.RegisterLibFunc(&scopeNameCount, lib, "moxie_tc_scope_name_count")
44
45 var scopeTypeOf func(int32, uintptr, int32, uintptr, int32) int32
46 purego.RegisterLibFunc(&scopeTypeOf, lib, "moxie_tc_scope_type_of")
47
48 var pkgName func(int32, uintptr, int32) int32
49 purego.RegisterLibFunc(&pkgName, lib, "moxie_tc_pkg_name")
50
51 var pkgPath func(int32, uintptr, int32) int32
52 purego.RegisterLibFunc(&pkgPath, lib, "moxie_tc_pkg_path")
53
54 var tcFree func(int32)
55 purego.RegisterLibFunc(&tcFree, lib, "moxie_tc_free")
56
57 var scopeName func(int32, int32, uintptr, int32) int32
58 purego.RegisterLibFunc(&scopeName, lib, "moxie_tc_scope_name")
59
60 readStr := func(fn func(int32, uintptr, int32) int32, h int32) string {
61 buf := make([]byte, 256)
62 n := fn(h, uintptr(unsafe.Pointer(&buf[0])), 256)
63 return string(buf[:n])
64 }
65
66 pass := 0
67 fail := 0
68 assert := func(name string, cond bool) {
69 if cond {
70 pass++
71 } else {
72 fail++
73 fmt.Fprintf(os.Stderr, "FAIL: %s\n", name)
74 }
75 }
76
77 src1 := []byte(`package mypkg
78
79 var x int32
80
81 func add(a, b int32) int32 {
82 return a + b
83 }
84
85 type Point struct {
86 X int32
87 Y int32
88 }
89 `)
90 name1 := []byte("mypkg")
91
92 uLen := universeOk()
93 fmt.Printf("universe: %d names\n", uLen)
94 assert("universe initialized", uLen > 0)
95
96 h := checkBytes(
97 uintptr(unsafe.Pointer(&src1[0])), int32(len(src1)),
98 uintptr(unsafe.Pointer(&name1[0])), int32(len(name1)),
99 )
100 fmt.Printf("checkBytes: handle = %d\n", h)
101 assert("check returns valid handle", h >= 0)
102
103 if h < 0 {
104 fmt.Printf("%d/%d tests passed\n", pass, pass+fail)
105 os.Exit(1)
106 }
107
108 pName := readStr(pkgName, h)
109 assert("pkg name is mypkg, got "+pName, pName == "mypkg")
110
111 pPath := readStr(pkgPath, h)
112 assert("pkg path is mypkg, got "+pPath, pPath == "mypkg")
113
114 nameCount := scopeNameCount(h)
115 assert(fmt.Sprintf("scope has names (count=%d)", nameCount), nameCount == 3)
116
117 // Verify Names() iteration returns all 3 unique keys
118 expectedNames := map[string]bool{"x": false, "add": false, "Point": false}
119 for i := int32(0); i < nameCount; i++ {
120 nbuf := make([]byte, 256)
121 nn := scopeName(h, i, uintptr(unsafe.Pointer(&nbuf[0])), 256)
122 nm := string(nbuf[:nn])
123 if _, ok := expectedNames[nm]; ok {
124 expectedNames[nm] = true
125 } else {
126 fmt.Fprintf(os.Stderr, "UNEXPECTED name[%d] = %q\n", i, nm)
127 }
128 }
129 for nm, found := range expectedNames {
130 assert(fmt.Sprintf("name %q found via Names() iteration", nm), found)
131 }
132
133 xName := []byte("x")
134 buf := make([]byte, 256)
135 n := scopeTypeOf(h, uintptr(unsafe.Pointer(&xName[0])), int32(len(xName)),
136 uintptr(unsafe.Pointer(&buf[0])), 256)
137 xType := string(buf[:n])
138 assert("x type is int32, got "+xType, xType == "int32")
139
140 addName := []byte("add")
141 n = scopeTypeOf(h, uintptr(unsafe.Pointer(&addName[0])), int32(len(addName)),
142 uintptr(unsafe.Pointer(&buf[0])), 256)
143 addType := string(buf[:n])
144 assert("add has a type string, got "+addType, len(addType) > 0)
145
146 ptName := []byte("Point")
147 n = scopeTypeOf(h, uintptr(unsafe.Pointer(&ptName[0])), int32(len(ptName)),
148 uintptr(unsafe.Pointer(&buf[0])), 256)
149 ptType := string(buf[:n])
150 assert("Point has a type string, got "+ptType, len(ptType) > 0)
151
152 tcFree(h)
153
154 po := parseOnly(
155 uintptr(unsafe.Pointer(&src1[0])), int32(len(src1)),
156 uintptr(unsafe.Pointer(&name1[0])), int32(len(name1)),
157 )
158 fmt.Printf("parseOnly: %d decls\n", po)
159 assert("parse works", po >= 3)
160
161 p1i := pass1Insert(
162 uintptr(unsafe.Pointer(&src1[0])), int32(len(src1)),
163 uintptr(unsafe.Pointer(&name1[0])), int32(len(name1)),
164 )
165 fmt.Printf("pass1Insert: %d names\n", p1i)
166 assert("pass1 insert works", p1i == 3)
167
168 runtime.KeepAlive(src1)
169 runtime.KeepAlive(name1)
170
171 fmt.Printf("%d/%d tests passed\n", pass, pass+fail)
172 if fail > 0 {
173 os.Exit(1)
174 }
175 }
176