|
1 | 1 | package main |
2 | 2 |
|
| 3 | +// KL-native bindings over the shared bytecode-IR -> Go translator (package |
| 4 | +// codegen). The translator itself lives in codegen/ so other build tools |
| 5 | +// (cmd/yggdrasil-build) can drive it without going through KL. |
| 6 | + |
3 | 7 | import ( |
4 | | - "bytes" |
5 | | - "errors" |
6 | | - "fmt" |
7 | | - "io" |
8 | 8 | "os" |
9 | 9 | "unsafe" |
10 | 10 |
|
| 11 | + "github.com/tiancaiamao/shen-go/codegen" |
11 | 12 | "github.com/tiancaiamao/shen-go/kl" |
12 | 13 | ) |
13 | 14 |
|
14 | 15 | var makeCodeGenerator = kl.MakeNative(func(e *kl.ControlFlow) { |
15 | 16 | // (make-code-generator 'cora) |
16 | | - cg := &codeGenerator{ |
17 | | - declare: make(map[kl.Obj]struct{}), |
18 | | - } |
19 | | - e.Return(kl.MakeRaw(&cg.scmHead)) |
| 17 | + cg := codegen.New() |
| 18 | + e.Return(kl.MakeRaw(&cg.ScmHead)) |
20 | 19 |
|
21 | 20 | }, 0) |
22 | 21 |
|
23 | 22 | var bcToGo = kl.MakeNative(func(e *kl.ControlFlow) { |
24 | 23 | // (let cg (make-code-generator) |
25 | 24 | // (bc->go cg "Main" true "xx.bc" "xx.go")) |
26 | | - cg := (*codeGenerator)(unsafe.Pointer(e.Get(1))) |
| 25 | + cg := (*codegen.CodeGenerator)(unsafe.Pointer(e.Get(1))) |
27 | 26 | exportName := kl.GetString(e.Get(2)) |
28 | 27 | genSym := e.Get(3) |
29 | 28 | inFile := kl.GetString(e.Get(4)) |
@@ -54,354 +53,3 @@ var bcToGo = kl.MakeNative(func(e *kl.ControlFlow) { |
54 | 53 | e.Return(kl.Nil) |
55 | 54 |
|
56 | 55 | }, 5) |
57 | | - |
58 | | -type codeGenerator struct { |
59 | | - scmHead int |
60 | | - declare map[kl.Obj]struct{} |
61 | | -} |
62 | | - |
63 | | -func (cg *codeGenerator) HandleBody(f io.Reader, export string, out io.Writer) error { |
64 | | - fmt.Fprintf(out, "package main\n\n") |
65 | | - fmt.Fprintf(out, "import . \"github.com/tiancaiamao/shen-go/kl\"\n\n") |
66 | | - fmt.Fprintf(out, `var %s = MakeNative(func(__e *ControlFlow) { |
67 | | -`, export) |
68 | | - r := kl.NewSexpReader(f, false) |
69 | | - bc, err := r.Read() |
70 | | - if err != nil { |
71 | | - fmt.Println("read bytecode error", err) |
72 | | - return err |
73 | | - } |
74 | | - if err := cg.generateExpr(out, bc); err != nil { |
75 | | - return err |
76 | | - } |
77 | | - fmt.Fprintf(out, "\n\n") |
78 | | - fmt.Fprintf(out, "}, 0)\n\n") |
79 | | - return nil |
80 | | -} |
81 | | - |
82 | | -func (cg *codeGenerator) HandleSymbol(out io.Writer) { |
83 | | - for sym := range cg.declare { |
84 | | - symStr := kl.GetSymbol(sym) |
85 | | - symVar := "sym" + symbolAsVar(sym) |
86 | | - fmt.Fprintf(out, "var %s = MakeSymbol(\"%s\")\n", symVar, symStr) |
87 | | - } |
88 | | -} |
89 | | - |
90 | | -func symbolAsVar(sym kl.Obj) string { |
91 | | - str := kl.GetSymbol(sym) |
92 | | - var buf bytes.Buffer |
93 | | - for i := 0; i < len(str); i++ { |
94 | | - switch str[i] { |
95 | | - case '_': |
96 | | - buf.WriteString("__") |
97 | | - case '-': |
98 | | - buf.WriteString("_1") |
99 | | - case '?': |
100 | | - buf.WriteString("_2") |
101 | | - case '$': |
102 | | - buf.WriteString("_3") |
103 | | - case '.': |
104 | | - buf.WriteString("_4") |
105 | | - case '<': |
106 | | - buf.WriteString("_5") |
107 | | - case '>': |
108 | | - buf.WriteString("_6") |
109 | | - case '+': |
110 | | - buf.WriteString("_7") |
111 | | - case '@': |
112 | | - buf.WriteString("_8") |
113 | | - case '=': |
114 | | - buf.WriteString("_a") |
115 | | - case '!': |
116 | | - buf.WriteString("_b") |
117 | | - case '/': |
118 | | - buf.WriteString("_c") |
119 | | - case '*': |
120 | | - buf.WriteString("_d") |
121 | | - case '&': |
122 | | - buf.WriteString("_e") |
123 | | - case '%': |
124 | | - buf.WriteString("_f") |
125 | | - case '^': |
126 | | - buf.WriteString("_g") |
127 | | - case ':': |
128 | | - buf.WriteString("_h") |
129 | | - case '{': |
130 | | - buf.WriteString("_i") |
131 | | - case '}': |
132 | | - buf.WriteString("_j") |
133 | | - case ';': |
134 | | - buf.WriteString("_k") |
135 | | - case ',': |
136 | | - buf.WriteString("_l") |
137 | | - default: |
138 | | - buf.WriteByte(str[i]) |
139 | | - } |
140 | | - } |
141 | | - return buf.String() |
142 | | -} |
143 | | - |
144 | | -func (cg *codeGenerator) generateExpr(w io.Writer, sexp kl.Obj) error { |
145 | | - // fmt.Printf("handle %s ..\n", ObjString(sexp)) |
146 | | - if kl.IsSymbol(sexp) { |
147 | | - fmt.Fprintf(w, "%s", symbolAsVar(sexp)) |
148 | | - return nil |
149 | | - } |
150 | | - kind := kl.GetSymbol(kl.Car(sexp)) |
151 | | - switch kind { |
152 | | - case "block": |
153 | | - for cur := kl.Cdr(sexp); cur != kl.Nil; cur = kl.Cdr(cur) { |
154 | | - p := kl.Car(cur) |
155 | | - if err := cg.generateExpr(w, p); err != nil { |
156 | | - return err |
157 | | - } |
158 | | - fmt.Fprintln(w) |
159 | | - } |
160 | | - fmt.Fprintln(w) |
161 | | - case "<-": |
162 | | - // (<- a b) |
163 | | - a := kl.Car(kl.Cdr(sexp)) |
164 | | - b := kl.Car(kl.Cdr(kl.Cdr(sexp))) |
165 | | - fmt.Fprintf(w, "%s = ", symbolAsVar(a)) |
166 | | - cg.generateExpr(w, b) |
167 | | - fmt.Fprintln(w) |
168 | | - case "<=": |
169 | | - a := kl.Car(kl.Cdr(sexp)) |
170 | | - b := kl.Car(kl.Cdr(kl.Cdr(sexp))) |
171 | | - fmt.Fprintf(w, "%s := ", symbolAsVar(a)) |
172 | | - cg.generateExpr(w, b) |
173 | | - fmt.Fprintln(w) |
174 | | - case "$global": |
175 | | - sym := kl.Car(kl.Cdr(sexp)) |
176 | | - cg.declare[sym] = struct{}{} |
177 | | - fmt.Fprintf(w, "PrimFunc(sym%s)", symbolAsVar(sym)) |
178 | | - case "$const": |
179 | | - // (const Number) |
180 | | - // (const ()) |
181 | | - // (const "xxx") |
182 | | - c := kl.Cadr(sexp) |
183 | | - if err := cg.generateConst(w, c); err != nil { |
184 | | - return err |
185 | | - } |
186 | | - case "lambda": |
187 | | - // (lambda (p1 p2 ...) ...) |
188 | | - tmp := kl.Car(kl.Cdr(sexp)) |
189 | | - args := kl.ListToSlice(tmp) |
190 | | - fmt.Fprintf(w, "MakeNative(func(__e *ControlFlow) {\n") |
191 | | - for i, arg := range args { |
192 | | - fmt.Fprintf(w, "%s := __e.Get(%d)\n", symbolAsVar(arg), i+1) |
193 | | - fmt.Fprintf(w, "_ = %s\n", symbolAsVar(arg)) |
194 | | - } |
195 | | - if err := cg.generateExpr(w, kl.Car(kl.Cdr(kl.Cdr(sexp)))); err != nil { |
196 | | - return err |
197 | | - } |
198 | | - fmt.Fprintf(w, "}, %d)", len(args)) |
199 | | - case "if": |
200 | | - // (if a b c) |
201 | | - a := kl.Cadr(sexp) |
202 | | - b := kl.Car(kl.Cdr(kl.Cdr(sexp))) |
203 | | - c := kl.Car(kl.Cdr(kl.Cdr(kl.Cdr(sexp)))) |
204 | | - if err := cg.generateIfExpr(w, a, b, c); err != nil { |
205 | | - return err |
206 | | - } |
207 | | - case "ignore": // (ignore xx) |
208 | | - fmt.Fprintf(w, "_ = ") |
209 | | - exp := kl.Car(kl.Cdr(sexp)) |
210 | | - cg.generateExpr(w, exp) |
211 | | - fmt.Fprintln(w) |
212 | | - case "var": |
213 | | - // (var xxx) |
214 | | - sym := kl.Car(kl.Cdr(sexp)) |
215 | | - fmt.Fprintf(w, "var %s Obj\n", symbolAsVar(sym)) |
216 | | - case "return": |
217 | | - val := kl.Cadr(sexp) |
218 | | - fmt.Fprintf(w, "__e.Return(") |
219 | | - cg.generateExpr(w, val) |
220 | | - fmt.Fprintf(w, ")\nreturn\n") |
221 | | - case "call": |
222 | | - // (call f a b c ...) |
223 | | - ok, err := cg.primitiveCallOptimize(w, sexp, false) |
224 | | - if err != nil { |
225 | | - return err |
226 | | - } |
227 | | - if ok { |
228 | | - return nil |
229 | | - } |
230 | | - |
231 | | - fmt.Fprintf(w, "Call(__e, ") |
232 | | - args := kl.ListToSlice(kl.Cdr(sexp)) |
233 | | - for i, arg := range args { |
234 | | - if i != 0 { |
235 | | - fmt.Fprintf(w, ", ") |
236 | | - } |
237 | | - if kl.IsSymbol(arg) { |
238 | | - fmt.Fprintf(w, "%s", symbolAsVar(arg)) |
239 | | - } else { |
240 | | - if err := cg.generateExpr(w, arg); err != nil { |
241 | | - return err |
242 | | - } |
243 | | - } |
244 | | - } |
245 | | - fmt.Fprintf(w, ")\n") |
246 | | - case "tailapply": |
247 | | - // (tailapply f a b c ...) |
248 | | - ok, err := cg.primitiveCallOptimize(w, sexp, true) |
249 | | - if err != nil { |
250 | | - return err |
251 | | - } |
252 | | - if ok { |
253 | | - return nil |
254 | | - } |
255 | | - |
256 | | - fmt.Fprintf(w, "__e.TailApply(") |
257 | | - args := kl.ListToSlice(kl.Cdr(sexp)) |
258 | | - for i, arg := range args { |
259 | | - if i != 0 { |
260 | | - fmt.Fprintf(w, ", ") |
261 | | - } |
262 | | - if kl.IsSymbol(arg) { |
263 | | - fmt.Fprintf(w, "%s", symbolAsVar(arg)) |
264 | | - } else { |
265 | | - if err := cg.generateExpr(w, arg); err != nil { |
266 | | - return err |
267 | | - } |
268 | | - } |
269 | | - } |
270 | | - fmt.Fprintf(w, ")\nreturn\n") |
271 | | - default: |
272 | | - return fmt.Errorf("unknown instruct: %s", kind) |
273 | | - } |
274 | | - return nil |
275 | | -} |
276 | | - |
277 | | -func (cg *codeGenerator) generateConst(w io.Writer, c kl.Obj) error { |
278 | | - switch { |
279 | | - case kl.IsNumber(c): |
280 | | - fmt.Fprintf(w, "MakeNumber(%d)", kl.GetInteger(c)) |
281 | | - case kl.IsString(c): |
282 | | - str := kl.GetString(c) |
283 | | - fmt.Fprintf(w, "MakeString(%#v)", str) |
284 | | - case kl.IsSymbol(c): |
285 | | - cg.declare[c] = struct{}{} |
286 | | - fmt.Fprintf(w, "sym%s", symbolAsVar(c)) |
287 | | - case c == kl.Nil: |
288 | | - fmt.Fprintf(w, "Nil") |
289 | | - case c == kl.True: |
290 | | - fmt.Fprintf(w, "True") |
291 | | - case c == kl.False: |
292 | | - fmt.Fprintf(w, "False") |
293 | | - default: |
294 | | - return errors.New("unknown $const instruct") |
295 | | - } |
296 | | - return nil |
297 | | -} |
298 | | - |
299 | | -func (cg *codeGenerator) generateIfExpr(w io.Writer, a, b, c kl.Obj) error { |
300 | | - fmt.Fprintf(w, "if True == ") |
301 | | - if err := cg.generateExpr(w, a); err != nil { |
302 | | - return err |
303 | | - } |
304 | | - fmt.Fprintf(w, " {\n") |
305 | | - if err := cg.generateExpr(w, b); err != nil { |
306 | | - return err |
307 | | - } |
308 | | - fmt.Fprintf(w, "} else {\n") |
309 | | - if err := cg.generateExpr(w, c); err != nil { |
310 | | - return err |
311 | | - } |
312 | | - fmt.Fprintf(w, "}\n") |
313 | | - return nil |
314 | | -} |
315 | | - |
316 | | -var symGlobal = kl.MakeSymbol("$global") |
317 | | -var symConst = kl.MakeSymbol("$const") |
318 | | - |
319 | | -func (cg *codeGenerator) primitiveCallOptimize(w io.Writer, sexp kl.Obj, tail bool) (bool, error) { |
320 | | - // (call ($global XX) ...) |
321 | | - // (tailapply ($global XX) ...) |
322 | | - fn := kl.Cadr(sexp) |
323 | | - if kl.PrimIsPair(fn) == kl.False || kl.Car(fn) != symGlobal { |
324 | | - return false, nil |
325 | | - } |
326 | | - global := kl.Cadr(fn) |
327 | | - str := kl.GetSymbol(global) |
328 | | - args := kl.ListToSlice(kl.Cdr(kl.Cdr(sexp))) |
329 | | - prim, ok := shenPrimitive[str] |
330 | | - if !ok || prim.Arity != len(args) { |
331 | | - return false, nil |
332 | | - } |
333 | | - primName := prim.Name |
334 | | - |
335 | | - // ($prim f a b c ...) |
336 | | - if tail { |
337 | | - fmt.Fprintf(w, "__e.Return(") |
338 | | - } |
339 | | - |
340 | | - fmt.Fprintf(w, "%s(", primName) |
341 | | - for i, arg := range args { |
342 | | - if i != 0 { |
343 | | - fmt.Fprintf(w, ", ") |
344 | | - } |
345 | | - if kl.IsSymbol(arg) { |
346 | | - fmt.Fprintf(w, "%s", symbolAsVar(arg)) |
347 | | - } else { |
348 | | - if err := cg.generateExpr(w, arg); err != nil { |
349 | | - return true, err |
350 | | - } |
351 | | - } |
352 | | - } |
353 | | - fmt.Fprintf(w, ")") |
354 | | - |
355 | | - if tail { |
356 | | - fmt.Fprintf(w, ")\nreturn\n") |
357 | | - } |
358 | | - return true, nil |
359 | | -} |
360 | | - |
361 | | -var shenPrimitive = map[string]struct { |
362 | | - Arity int |
363 | | - Name string |
364 | | -}{ |
365 | | - "get-time": {1, "PrimGetTime"}, |
366 | | - "close": {1, "PrimCloseStream"}, |
367 | | - "open": {2, "PrimOpenStream"}, |
368 | | - "read-byte": {1, "PrimReadByte"}, |
369 | | - "write-byte": {2, "PrimWriteByte"}, |
370 | | - "absvector?": {1, "PrimIsVector"}, |
371 | | - "<-address": {2, "PrimVectorGet"}, |
372 | | - "address->": {3, "PrimVectorSet"}, |
373 | | - "absvector": {1, "PrimAbsvector"}, |
374 | | - "str": {1, "PrimStr"}, |
375 | | - "<=": {2, "PrimLessEqual"}, |
376 | | - ">=": {2, "PrimGreatEqual"}, |
377 | | - "<": {2, "PrimLessThan"}, |
378 | | - ">": {2, "PrimGreatThan"}, |
379 | | - "error-to-string": {1, "PrimErrorToString"}, |
380 | | - "simple-error": {1, "PrimSimpleError"}, |
381 | | - "=": {2, "PrimEqual"}, |
382 | | - "-": {2, "PrimNumberSubtract"}, |
383 | | - "*": {2, "PrimNumberMultiply"}, |
384 | | - "/": {2, "PrimNumberDivide"}, |
385 | | - "+": {2, "PrimNumberAdd"}, |
386 | | - "string->n": {1, "PrimStringToNumber"}, |
387 | | - "n->string": {1, "PrimNumberToString"}, |
388 | | - "number?": {1, "PrimIsNumber"}, |
389 | | - "string?": {1, "PrimIsString"}, |
390 | | - "pos": {2, "PrimPos"}, |
391 | | - "tlstr": {1, "PrimTailString"}, |
392 | | - "cn": {2, "PrimStringConcat"}, |
393 | | - "intern": {1, "PrimIntern"}, |
394 | | - "hd": {1, "PrimHead"}, |
395 | | - "tl": {1, "PrimTail"}, |
396 | | - "cons": {2, "PrimCons"}, |
397 | | - "cons?": {1, "PrimIsPair"}, |
398 | | - "value": {1, "PrimValue"}, |
399 | | - "set": {2, "PrimSet"}, |
400 | | - "not": {1, "PrimNot"}, |
401 | | - "if": {3, "PrimIf"}, |
402 | | - "symbol?": {1, "PrimIsSymbol"}, |
403 | | - "read-file-as-bytelist": {1, "PrimReadFileAsByteList"}, |
404 | | - "read-file-as-string": {1, "PrimReadFileAsString"}, |
405 | | - "variable?": {1, "PrimIsVariable"}, |
406 | | - "integer?": {1, "PrimIsInteger"}, |
407 | | -} |
0 commit comments