-
Notifications
You must be signed in to change notification settings - Fork 30
/
assemble-open-coded.rkt
156 lines (125 loc) · 5.77 KB
/
assemble-open-coded.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#lang typed/racket/base
(require "assemble-helpers.rkt"
"../compiler/il-structs.rkt"
"../compiler/lexical-structs.rkt"
"../compiler/kernel-primitives.rkt"
racket/string
racket/list)
(provide open-code-kernel-primitive-procedure)
(: open-code-kernel-primitive-procedure (CallKernelPrimitiveProcedure -> String))
(define (open-code-kernel-primitive-procedure op)
(let*: ([operator : KernelPrimitiveName/Inline (CallKernelPrimitiveProcedure-operator op)]
[operands : (Listof String) (map assemble-oparg (CallKernelPrimitiveProcedure-operands op))]
[checked-operands : (Listof String)
(map (lambda: ([dom : OperandDomain]
[pos : Natural]
[rand : String]
[typecheck? : Boolean])
(maybe-typecheck-operand operator dom pos rand typecheck?))
(CallKernelPrimitiveProcedure-expected-operand-types op)
(build-list (length operands) (lambda: ([i : Natural]) i))
operands
(CallKernelPrimitiveProcedure-typechecks? op))])
(case operator
[(+)
(cond [(empty? checked-operands)
"0"]
[else
(string-append "(" (string-join checked-operands " + ") ")")])]
[(-)
(cond [(empty? (rest checked-operands))
(format "(-(~a))" (first checked-operands))]
[else
(string-append "(" (string-join checked-operands "-") ")")])]
[(*)
(cond [(empty? checked-operands)
"1"]
[else
(string-append "(" (string-join checked-operands "*") ")")])]
[(/)
(string-append "(" (string-join checked-operands "/") ")")]
[(add1)
(format "(~a + 1)" (first checked-operands))]
[(sub1)
(format "(~a - 1)" (first checked-operands))]
[(<)
(assemble-chain "<" checked-operands)]
[(<=)
(assemble-chain "<=" checked-operands)]
[(=)
(assemble-chain "===" checked-operands)]
[(>)
(assemble-chain ">" checked-operands)]
[(>=)
(assemble-chain ">=" checked-operands)]
[(cons)
(format "[~a, ~a]" (first checked-operands) (second checked-operands))]
[(car)
(format "(~a)[0]" (first checked-operands))]
[(cdr)
(format "(~a)[1]" (first checked-operands))]
[(list)
(let loop ([checked-operands checked-operands])
(cond
[(empty? checked-operands)
"RUNTIME.NULL"]
[else
(format "[~a,~a]" (first checked-operands) (loop (rest checked-operands)))]))]
[(null?)
(format "(~a === RUNTIME.NULL)" (first checked-operands))]
[(not)
(format "(~a === false)" (first checked-operands))]
[(eq?)
(format "(~a === ~a)" (first checked-operands) (second checked-operands))])))
(: assemble-chain (String (Listof String) -> String))
(define (assemble-chain rator rands)
(string-append "("
(string-join (let: loop : (Listof String) ([rands : (Listof String) rands])
(cond
[(empty? rands)
'()]
[(empty? (rest rands))
'()]
[else
(cons (format "(~a ~a ~a)" (first rands) rator (second rands))
(loop (rest rands)))]))
"&&")
")"))
(: assemble-domain-check (Symbol OperandDomain String Natural -> String))
(define (assemble-domain-check caller domain operand-string pos)
(cond
[(eq? domain 'any)
operand-string]
[else
(let: ([test-string : String
(case domain
[(number)
(format "(typeof(~a) === 'number')"
operand-string)]
[(string)
(format "(typeof(~a) === 'string')"
operand-string)]
[(list)
(format "(~a === [] || (typeof(~a) === 'object' && (~a).length === 2))"
operand-string operand-string operand-string)]
[(pair)
(format "(typeof(~a) === 'object' && (~a).length === 2)"
operand-string operand-string)]
[(box)
(format "(typeof(~a) === 'object' && (~a).length === 1)"
operand-string operand-string)])])
(format "((~a) ? (~a) : RUNTIME.raise(MACHINE, new Error('~a: expected ' + ~s + ' as argument ' + ~s + ' but received ' + ~a)))"
test-string
operand-string
caller
(symbol->string domain)
(add1 pos)
operand-string))]))
(: maybe-typecheck-operand (Symbol OperandDomain Natural String Boolean -> String))
;; Adds typechecks if we can't prove that the operand is of the required type.
(define (maybe-typecheck-operand caller domain-type position operand-string typecheck?)
(cond
[typecheck?
(assemble-domain-check caller domain-type operand-string position)]
[else
operand-string]))