Source file Scheme_syntax.ml
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
open Scheme
exception Error of string * Sexpr.span
let fail (x : Sexpr.t) fmt = Printf.ksprintf (fun msg -> raise (Error (msg, x.span))) fmt
let rec datum (x : Sexpr.t) : Scheme.t =
match x.datum with
| Int n -> Int n
| Float f -> Real f
| Str s -> Str s
| Sym s -> Sym s
| Char c -> Char c
| Bool b -> Bool b
| List (xs, tail) -> List.fold_right (fun x rest -> Pair (datum x, rest)) xs (match tail with Some t -> datum t | None -> Nil)
| Vector xs -> Vector (Array.of_list (List.map datum xs))
let mk (desc : desc) (span : Sexpr.span) : expr = { desc; span }
let quote v span = mk (Quote v) span
let prim (name : string) (span : Sexpr.span) : expr = quote (Proc (Prim name)) span
let name_of (x : Sexpr.t) (what : string) : string = match x.datum with Sym s -> s | _ -> fail x "%s: expected a name, but found %s" what (Sexpr.to_string x)
let parts (x : Sexpr.t) : Sexpr.t list = match x.datum with List (xs, None) -> xs | _ -> fail x "bad syntax: %s" (Sexpr.to_string x)
let is_define (x : Sexpr.t) : bool = match x.datum with List ({ datum = Sym "define"; _ } :: _, None) -> true | _ -> false
let rec expr (x : Sexpr.t) : expr =
let sp = x.span in
match x.datum with
| Int _ | Float _ | Str _ | Char _ | Bool _ | Vector _ -> quote (datum x) sp
| Sym s -> mk (Var s) sp
| List ([], None) -> fail x "(): expected a function after the open parenthesis, but nothing's there"
| List (_, Some _) -> fail x "bad syntax: a dotted list is not an expression"
| List (({ datum = Sym head; _ } as h) :: args, None) -> form x h head args
| List (f :: args, None) -> mk (App (expr f, List.map expr args)) sp
and form (x : Sexpr.t) (h : Sexpr.t) (head : string) (args : Sexpr.t list) : expr =
let sp = x.span in
match (head, args) with
| "quote", [ d ] -> quote (datum d) sp
| "quote", _ -> fail x "quote: expected one thing after quote"
| "quasiquote", [ d ] -> quasi d
| ("lambda" | "λ"), formals :: body -> mk (Lambda (lambda x "" formals body)) sp
| ("lambda" | "λ"), [] -> fail x "lambda: expected the variables, then the body"
| "if", [ c; a; b ] -> mk (If (expr c, expr a, expr b)) sp
| "if", [ c; a ] -> mk (If (expr c, expr a, quote Void sp)) sp
| "if", _ -> fail x "if: expected a question and two answers, but found %d parts" (List.length args)
| "set!", [ v; e ] -> mk (Set (name_of v "set!", expr e)) sp
| "set!", _ -> fail x "set!: expected a variable and an expression"
| "begin", [] -> quote Void sp
| "begin", es -> mk (Seq (List.map expr es)) sp
| "let", { datum = Sym name; _ } :: bindings :: body ->
let vars, inits = bind_list bindings in
let loop = { params = vars; rest = None; locals = []; body = []; name } in
let loop = mk (Lambda (body_of x { loop with body = [] } body)) sp in
let f = mk (Lambda { params = []; rest = None; locals = [ name ]; body = [ mk (Set (name, loop)) sp; mk (Var name) sp ]; name = "" }) sp in
mk (App (mk (App (f, [])) sp, inits)) sp
| "let", bindings :: body ->
let vars, inits = bind_list bindings in
mk (App (mk (Lambda (body_of x { params = vars; rest = None; locals = []; body = []; name = "" } body)) sp, inits)) sp
| "let*", bindings :: body -> (
match parts bindings with
| [] | [ _ ] -> form x h "let" args
| b :: more -> form x h "let" [ Sexpr.make (List ([ b ], None)) bindings.span; Sexpr.make (List (Sexpr.sym "let*" h.span :: Sexpr.make (List (more, None)) bindings.span :: body, None)) sp ])
| "letrec", bindings :: body | "letrec*", bindings :: body ->
let defs = List.map (fun b -> match parts b with [ v; e ] -> Sexpr.make (List ([ Sexpr.sym "define" b.span; v; e ], None)) b.span | _ -> fail b "letrec: expected [name expression]") (parts bindings) in
mk (App (mk (Lambda (body_of x { params = []; rest = None; locals = []; body = []; name = "" } (defs @ body))) sp, [])) sp
| ("let" | "let*" | "letrec"), [] -> fail x "%s: expected the bindings, then the body" head
| "and", [] -> quote (Bool true) sp
| "and", [ a ] -> expr a
| "and", a :: rest -> mk (If (expr a, form x h "and" rest, quote (Bool false) sp)) sp
| "or", [] -> quote (Bool false) sp
| "or", [ a ] -> expr a
| "or", a :: rest ->
let t = mk (Var " t") sp in
mk (App (mk (Lambda { params = [ " t" ]; rest = None; locals = []; body = [ mk (If (t, t, form x h "or" rest)) sp ]; name = "" }) sp, [ expr a ])) sp
| "cond", clauses -> cond x clauses
| "when", c :: body -> mk (If (expr c, mk (Seq (List.map expr body)) sp, quote Void sp)) sp
| "unless", c :: body -> mk (If (expr c, quote Void sp, mk (Seq (List.map expr body)) sp)) sp
| "case", key :: clauses ->
let t = mk (Var " t") sp in
let rec go cs =
match cs with
| [] -> quote Void sp
| c :: rest -> (
match parts c with
| { datum = Sym "else"; _ } :: body -> mk (Seq (List.map expr body)) c.span
| ds :: body -> mk (If (mk (App (prim "memv" c.span, [ t; quote (datum ds) ds.span ])) c.span, mk (Seq (List.map expr body)) c.span, go rest)) c.span
| [] -> fail c "case: expected a clause")
in
mk (App (mk (Lambda { params = [ " t" ]; rest = None; locals = []; body = [ go clauses ]; name = "" }) sp, [ expr key ])) sp
| "big-bang", w :: clauses ->
let clause c = match parts c with [ { datum = Sym name; _ }; e ] -> (name, expr e) | _ -> fail c "big-bang: expected a clause such as [on-tick f]" in
mk (Big_bang (expr w, List.map clause clauses)) sp
| ("define" | "define-struct"), _ -> fail x "%s: found a definition that is not at the top level" head
| _ -> mk (App (expr h, List.map expr args)) sp
and bind_list (bindings : Sexpr.t) : string list * expr list =
List.split (List.map (fun b -> match parts b with [ v; e ] -> (name_of v "let", expr e) | _ -> fail b "let: expected a variable and an expression") (parts bindings))
and lambda (x : Sexpr.t) (name : string) (formals : Sexpr.t) (body : Sexpr.t list) : lambda =
let params, rest =
match formals.datum with
| Sym r -> ([], Some r)
| List (ps, tail) -> (List.map (fun p -> name_of p "lambda") ps, Option.map (fun t -> name_of t "lambda") tail)
| _ -> fail formals "lambda: expected the variables, but found %s" (Sexpr.to_string formals)
in
body_of x { params; rest; locals = []; body = []; name } body
and body_of (x : Sexpr.t) (l : lambda) (forms : Sexpr.t list) : lambda =
if List.for_all is_define forms then fail x "expected an expression for the body, but nothing's there";
let one (f : Sexpr.t) : string list * expr =
if is_define f then
match definition f with
| { desc = Define (name, e); span } -> ([ name ], mk (Set (name, e)) span)
| _ -> fail f "define: bad syntax"
else ([], expr f)
in
let locals, body = List.split (List.map one forms) in
{ l with locals = List.concat locals; body }
and cond (x : Sexpr.t) (clauses : Sexpr.t list) : expr =
match clauses with
| [] ->
mk (App (prim "cond-fell-through" x.span, [])) x.span
| c :: rest -> (
match parts c with
| [ { datum = Sym "else"; _ } ] -> fail c "cond: expected an answer after else"
| { datum = Sym "else"; _ } :: body -> mk (Seq (List.map expr body)) c.span
| [ q ] ->
let t = mk (Var " t") c.span in
mk (App (mk (Lambda { params = [ " t" ]; rest = None; locals = []; body = [ mk (If (t, t, cond x rest)) c.span ]; name = "" }) c.span, [ expr q ])) c.span
| q :: body -> mk (If (expr q, mk (Seq (List.map expr body)) c.span, cond x rest)) c.span
| [] -> fail c "cond: expected a clause with a question and an answer, but found an empty part")
and quasi (d : Sexpr.t) : expr =
let sp = d.span in
match d.datum with
| List ([ { datum = Sym "unquote"; _ }; e ], None) -> expr e
| List (xs, tail) ->
let last = match tail with Some t -> quasi t | None -> quote Nil sp in
List.fold_right
(fun (x : Sexpr.t) rest ->
match x.datum with
| List ([ { datum = Sym "unquote-splicing"; _ }; e ], None) -> mk (App (prim "append" x.span, [ expr e; rest ])) x.span
| _ -> mk (App (prim "cons" x.span, [ quasi x; rest ])) x.span)
xs last
| _ -> quote (datum d) sp
and definition (x : Sexpr.t) : expr =
match parts x with
| [ _; { datum = Sym name; _ }; e ] -> mk (Define (name, match expr e with { desc = Lambda l; span } -> { desc = Lambda { l with name }; span } | e -> e)) x.span
| _ :: ({ datum = List (({ datum = Sym name; _ }) :: params, tail); _ } as ) :: body ->
if body = [] then fail x "define: expected an expression for the function's body, but nothing's there";
let formals = Sexpr.make (List (params, tail)) header.span in
mk (Define (name, mk (Lambda (lambda x name formals body)) x.span)) x.span
| [ _; v ] -> fail x "define: expected an expression after the name %s, but nothing's there" (Sexpr.to_string v)
| _ -> fail x "define: expected a name, or a name and its arguments in parentheses"
let top (x : Sexpr.t) : expr =
match x.datum with
| List ({ datum = Sym "define"; _ } :: _, None) -> definition x
| List ([ { datum = Sym "define-struct"; _ }; name; fields ], None) ->
mk (Define_struct (name_of name "define-struct", List.map (fun f -> name_of f "define-struct") (parts fields))) x.span
| List ({ datum = Sym "define-struct"; _ } :: _, None) -> fail x "define-struct: expected a name and the fields in parentheses"
| _ -> expr x