-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompiler.rkt
139 lines (114 loc) · 3.42 KB
/
compiler.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#lang racket/base
(require "compat.rkt")
(require racket/match)
(require json)
;; Symbol handling
(define get-symbol-map
(make-parameter 5))
(define ast
(fn (type . args)
(apply hash 'type type args)))
;; Expressions
(define literal?
(fn (expr)
(or (integer? expr)
(string? expr)
(boolean? expr))))
(define compile-expr
(fn (expr)
(match expr
[(? literal?)
(compile-literal expr)]
[(? symbol?)
(compile-variable expr)]
[(list 'quote (and symbol (? symbol?)))
(compile-symbol symbol)]
[(list 'if condition consequent alternate)
(compile-conditional condition consequent alternate)]
[(list 'fn (list args ...) body)
(compile-fn args body)]
[(list 'record (list ks vs) ...)
(compile-record ks vs)]
[(list 'let (list (list ks vs) ...) body)
(compile-let ks vs body)]
[(list fn args ...)
(compile-funcall fn args)]
)))
(define definition (fn (name value) (ast "VariableDeclaration"
'kind "const"
'declarations (list (ast "VariableDeclarator"
'id name
'init value)))))
(define string->jsidentifier
(fn (name)
(ast "Identifier"
'name name)))
(define identifier
(fn (name)
(string->jsidentifier (symbol->string name))))
(define compile-literal
(fn (value)
(ast "Literal"
'value value
'raw (let ([o (open-output-string)])
(write value o)
(get-output-string o)))))
(define compile-variable
(fn (variable)
(identifier variable)))
(define compile-symbol
(fn (sym)
(ast "Identifier"
'name (hash-ref! (get-symbol-map) sym
(fn () (string-append "__symbol_" (symbol->string sym)))))))
(define compile-conditional
(fn (test consequent alternate)
(ast "ConditionalExpression"
'test test
'consequent consequent
'alternate alternate)))
(define compile-fn
(fn (args body)
(ast "ArrowFunctionExpression"
'params (map identifier args)
'body (compile-expr body))))
(define compile-record
(fn (keys values)
(ast "ObjectExpression"
'properties (for/list ([k keys] [v values]) (ast "Property"
'key (identifier k)
'value (compile-expr v))))))
(define compile-let
(fn (vars values body)
(compile-funcall (list 'fn vars body) values)))
(define compile-funcall
(fn (fn args)
(ast "CallExpression"
'callee (compile-expr fn)
'expression #t
'arguments (map compile-expr args))))
;; Toplevel forms
(define compile-symbol-list
(fn ()
(for/list ([(name id) (get-symbol-map)])
(definition (string->jsidentifier id)
(ast "CallExpression"
'callee (string->jsidentifier "Symbol")
'arguments (list (compile-expr (symbol->string name))))))))
(define compile-toplevel
(fn (form)
(match form
[(list 'define name expr)
(definition (identifier name) (compile-expr expr))]
[_
(compile-expr form)]
)))
(define compile-module
(fn (m)
(parameterize ([get-symbol-map (make-hash)])
(let ([body (map compile-toplevel m)])
(jsexpr->string
(ast "Program"
'sourceType "module"
'body (append (compile-symbol-list) body)))))))
(provide compile-module)