-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtag-parser.ml
296 lines (251 loc) · 13.1 KB
/
tag-parser.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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#use "reader.ml";;
#use "pc.ml";;
open PC;;
open Reader;;
type constant =
| Sexpr of sexpr
| Void
type expr =
| Const of constant
| Var of string
| If of expr * expr * expr
| Seq of expr list
| Set of expr * expr
| Def of expr * expr
| Or of expr list
| LambdaSimple of string list * expr
| LambdaOpt of string list * string * expr
| Applic of expr * (expr list);;
let rec expr_eq e1 e2 =
match e1, e2 with
| Const Void, Const Void -> true
| Const(Sexpr s1), Const(Sexpr s2) -> sexpr_eq s1 s2
| Var(v1), Var(v2) -> String.equal v1 v2
| If(t1, th1, el1), If(t2, th2, el2) -> (expr_eq t1 t2) &&
(expr_eq th1 th2) &&
(expr_eq el1 el2)
| (Seq(l1), Seq(l2)
| Or(l1), Or(l2)) -> List.for_all2 expr_eq l1 l2
| (Set(var1, val1), Set(var2, val2)
| Def(var1, val1), Def(var2, val2)) -> (expr_eq var1 var2) &&
(expr_eq val1 val2)
| LambdaSimple(vars1, body1), LambdaSimple(vars2, body2) ->
(List.for_all2 String.equal vars1 vars2) &&
(expr_eq body1 body2)
| LambdaOpt(vars1, var1, body1), LambdaOpt(vars2, var2, body2) ->
(String.equal var1 var2) &&
(List.for_all2 String.equal vars1 vars2) &&
(expr_eq body1 body2)
| Applic(e1, args1), Applic(e2, args2) ->
(expr_eq e1 e2) &&
(List.for_all2 expr_eq args1 args2)
| _ -> false;;
exception X_syntax_error;;
module type TAG_PARSER = sig
val tag_parse_expressions : sexpr list -> expr list
end;; (* signature TAG_PARSER *)
module Tag_Parser : TAG_PARSER = struct
let reserved_word_list =
["and"; "begin"; "cond"; "define"; "else";
"if"; "lambda"; "let"; "let*"; "letrec"; "or";
"quasiquote"; "quote"; "set!"; "pset!"; "unquote";
"unquote-splicing"];;
(* work on the tag parser starts here *)
(* lambda helpers *)
let rec string_list lst =
match lst with
| Pair(Symbol(e),es) -> ((e)::(string_list es))
| Nil -> []
| _ -> raise X_syntax_error;;
let rec string_improper_list lst =
match lst with
| Pair(Symbol(e),Symbol(es)) -> [e]
| Pair(Symbol(e),es) -> ((e)::(string_improper_list es))
| Symbol(x) -> []
| _ -> raise X_syntax_error;;
let rec find_last_item_in_list lst =
match lst with
| Pair(Symbol(e),Symbol(es)) -> es
| Pair(Symbol(e),es) -> (find_last_item_in_list es)
| Symbol(e) -> e
| _ -> raise X_syntax_error;;
let rec lambda_args_type args =
match args with
| Pair(Symbol(e),es) -> (lambda_args_type es)
| Nil -> "simple"
| Symbol(es) -> "opt"
| _ -> raise X_syntax_error;;
let flat_seq exp =
match exp with
| Seq(x) -> x
| y -> [y]
let make_pset_body var_list =
let counter = ref (List.length var_list) in
let plus_c = (fun () -> counter := (!counter - 1)) in
let folded = List.fold_right (fun var rest -> plus_c(); Pair(Pair(Symbol "set!", Pair(var, Pair(Symbol("v%"^(string_of_int !counter)), Nil))), rest)) var_list Nil in
folded;;
let make_pset_ribs exp_list =
let counter = ref (List.length exp_list) in
let plus_c = (fun () -> counter := (!counter - 1)) in
let folded = List.fold_right (fun exp rest -> plus_c(); Pair(Pair(Symbol("v%"^(string_of_int !counter)), Pair(exp, Nil)), rest)) exp_list Nil in
folded;;
let rec tag_parse sexpr =
match sexpr with
| Nil -> Const(Void)
| Number(x) -> Const(Sexpr(Number(x)))
| Bool(x) -> Const(Sexpr(Bool(x)))
| Char(x) -> Const(Sexpr(Char(x)))
| String(x) -> Const(Sexpr(String(x)))
| Pair(Symbol("quote"), Pair(x, Nil)) -> Const(Sexpr(x))
| Pair(Symbol("unquote"), Pair(x, Nil)) -> Const(Sexpr(x))
| Symbol(var) -> if (List.mem var reserved_word_list) then raise X_syntax_error else Var(var)
| Pair(Symbol("if"), Pair(test, Pair(dit, Pair(dif, Nil)))) -> If(tag_parse test, tag_parse dit, tag_parse dif)
| Pair(Symbol("if"), Pair(test, Pair(dit, Nil))) -> If(tag_parse test, tag_parse dit, Const(Void))
| Pair(Symbol "define", Pair(Pair(name, args), Pair(body, Nil))) -> tag_parse (Pair(Symbol("define"), Pair(name, Pair((Pair(Symbol("lambda"), Pair(args, Pair(body, Nil)))), Nil))))
| Pair(Symbol("define"), Pair(name, Pair(exp, Nil))) -> Def(tag_parse name, tag_parse exp)
| Pair(Symbol("set!"), Pair(name, Pair(exp, Nil))) -> Set(tag_parse name, tag_parse exp)
| Pair(Symbol("or"), operands) -> make_or operands
| Pair(Symbol("lambda"), Pair(args, body)) -> (make_lambda args body)
| Pair(Symbol("begin"), exps) -> make_sequence exps
| Pair(Symbol("cond"), ribs) -> make_cond ribs
| Pair(Symbol("let"), Pair(Nil, body)) -> tag_parse (Pair(Pair(Symbol "lambda", Pair(Nil, body)), Nil))
| Pair(Symbol("let"), Pair(Pair(rib, ribs), body)) -> make_let rib ribs body
| Pair(Symbol("let*"), Pair(Nil, body)) -> tag_parse (Pair(Symbol("let"), Pair(Nil, body)))
| Pair(Symbol "let*", Pair(Pair(rib, ribs), body)) -> make_let_star rib ribs body
| Pair(Symbol("letrec"), Pair(Nil, body)) -> tag_parse (Pair(Symbol("let"), Pair(Nil, body)))
| Pair(Symbol("letrec"), Pair(Pair(rib, ribs), body)) -> make_letrec rib ribs body
| Pair(Symbol("and"), operands) -> make_and operands
| Pair(Symbol("pset!"), Pair(Pair(name, Pair(exp, Nil)), Nil)) -> tag_parse (Pair(Symbol("set!"), Pair(name, Pair(exp, Nil))))
| Pair(Symbol("pset!"), (Pair(rib, ribs))) -> make_pset rib ribs
| Pair(Symbol("quasiquote"), Pair(rest, Nil)) -> tag_parse (make_quasi_quote rest)
| Pair(operator, operands) -> Applic(tag_parse operator, make_exp_list operands)
and make_pset rib ribs =
let vars_list = make_let_args_list rib ribs in
let exp_list = make_let_values_list rib ribs in
let body = make_pset_body vars_list in
let ribs = make_pset_ribs exp_list in
tag_parse (Pair(Symbol("let"), Pair(ribs, body)))
and make_let_args_list rib ribs =
let extract_arg =
match rib with
| Pair(arg, Pair(value, Nil)) -> arg
| _ -> raise X_syntax_error in
match ribs with
| Pair(e, rest) -> (extract_arg :: (make_let_args_list e rest))
| Nil -> [extract_arg]
| _ -> raise X_syntax_error
and make_let_values_list rib ribs =
let extract_value =
match rib with
| Pair(arg, Pair(value, Nil)) -> value
| _ -> raise X_syntax_error in
match ribs with
| Pair(e, rest) -> (extract_value :: (make_let_values_list e rest))
| Nil -> [extract_value]
| _ -> raise X_syntax_error
and make_let rib ribs body =
let pack_fun lst = List.fold_right (fun sexp rest -> Pair(sexp, rest)) lst Nil in
let args = pack_fun (make_let_args_list rib ribs) in
let values = pack_fun (make_let_values_list rib ribs) in
tag_parse (Pair(Pair(Symbol "lambda", Pair(args , body)), values))
and make_let_star rib ribs body =
match ribs with
| Nil -> tag_parse (Pair(Symbol "let", Pair(Pair(rib , Nil), body)))
| _ -> tag_parse (Pair(Symbol "let", Pair(Pair(rib, Nil), Pair(Pair(Symbol "let*", Pair(ribs, body)), Nil))))
and make_letrec_args_whatever_list args =
match args with
| Pair(Pair(arg, Pair(value, Nil)),Nil) -> Pair(Pair(arg, Pair(Pair(Symbol "quote", Pair(Symbol "whatever", Nil)), Nil)), Nil)
| Pair(Pair(arg, Pair(value, Nil)),rest) -> Pair(Pair(arg, Pair(Pair(Symbol "quote", Pair(Symbol "whatever", Nil)), Nil)), (make_letrec_args_whatever_list rest))
| _ -> raise X_syntax_error
and make_values_to_sets_and_body args org_body =
match args with
| Pair(Pair(arg, Pair(value, Nil)),Nil) -> Pair(Pair(Symbol "set!", Pair(arg, Pair(value, Nil))), org_body)
| Pair(Pair(arg, Pair(value, Nil)),rest) -> Pair(Pair(Symbol "set!", Pair(arg, Pair(value, Nil))), (make_values_to_sets_and_body rest org_body))
| _ -> raise X_syntax_error
and make_letrec rib ribs body =
let args = make_letrec_args_whatever_list (Pair(rib,ribs)) in
let sets_and_body = make_values_to_sets_and_body (Pair(rib,ribs)) body in
tag_parse (Pair(Symbol "let", Pair(args, sets_and_body)))
and make_cond ribs =
match ribs with
| Pair(Pair(Symbol "else", body), rest) -> tag_parse (Pair(Symbol "begin", body))
| Pair(Pair(q, Pair(Symbol "=>", body)), Nil) -> tag_parse (Pair (Symbol "let", Pair(Pair(Pair(Symbol "value", Pair(q, Nil)), Pair(Pair(Symbol "f", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(Pair(Symbol "begin", body), Nil))), Nil)), Nil)), Pair(Pair(Symbol "if", Pair(Symbol "value", Pair(Pair(Pair(Symbol "f", Nil), Pair(Symbol "value", Nil)), Pair(Pair(Symbol "begin", Pair(Nil, Nil)), Nil)))), Nil))))
| Pair(Pair(q, Pair(Symbol "=>", body)), rest) -> tag_parse (Pair(Symbol "let", Pair(Pair(Pair(Symbol "value", Pair(q, Nil)), Pair(Pair(Symbol "f", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(Pair(Symbol "begin", body), Nil))), Nil)), Pair(Pair(Symbol "rest", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(make_cond_rec rest, Nil))), Nil)), Nil))), Pair(Pair(Symbol "if", Pair(Symbol "value", Pair(Pair(Pair(Symbol "f", Nil), Pair(Symbol "value", Nil)), Pair(Pair(Symbol "rest", Nil), Nil)))), Nil))))
| Pair(Pair(q, body), rest) -> tag_parse (Pair(Symbol "if", Pair(q, Pair(Pair(Symbol "begin", body), Pair(make_cond_rec rest, Nil)))))
| _ -> raise X_syntax_error
and make_cond_rec ribs =
match ribs with
| Nil -> (Pair(Symbol "begin", Pair(Nil,Nil)))
| Pair(Pair(Symbol "else", body), rest) -> (Pair(Symbol "begin", body))
| Pair(Pair(q, Pair(Symbol "=>", body)), Nil) -> (Pair (Symbol "let", Pair(Pair(Pair(Symbol "value", Pair(q, Nil)), Pair(Pair(Symbol "f", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(Pair(Symbol "begin", body), Nil))), Nil)), Nil)), Pair(Pair(Symbol "if", Pair(Symbol "value", Pair(Pair(Pair(Symbol "f", Nil), Pair(Symbol "value", Nil)), Pair(Pair(Symbol "begin", Pair(Nil, Nil)), Nil)))), Nil))))
| Pair(Pair(q, Pair(Symbol "=>", body)), rest) -> (Pair(Symbol "let", Pair(Pair(Pair(Symbol "value", Pair(q, Nil)), Pair(Pair(Symbol "f", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(Pair(Symbol "begin", body), Nil))), Nil)), Pair(Pair(Symbol "rest", Pair(Pair(Symbol "lambda", Pair(Nil, Pair(make_cond_rec rest, Nil))), Nil)), Nil))), Pair(Pair(Symbol "if", Pair(Symbol "value", Pair(Pair(Pair(Symbol "f", Nil), Pair(Symbol "value", Nil)), Pair(Pair(Symbol "rest", Nil), Nil)))), Nil))))
| Pair(Pair(q, body), rest) -> (Pair(Symbol "if", Pair(q, Pair(Pair(Symbol "begin", body), Pair(make_cond_rec rest, Nil)))))
| _ -> raise X_syntax_error
and make_sequence exps =
match exps with
| Nil -> Const(Void)
| Pair(e, Nil) -> tag_parse e
| Pair(Symbol "begin", rest) -> make_sequence rest
| Pair(Symbol(var), rest) -> if (List.mem var reserved_word_list) then
Seq(List.flatten [(flat_seq (tag_parse (Pair((Symbol(var)), rest))))]) else
Seq(sequence_eval_rec (Symbol(var)) rest)
| Pair(primitive, rest) -> Seq(sequence_eval_rec primitive rest)
| _ -> raise X_syntax_error
and sequence_eval_rec primitive rest =
let eval_primitive_to_list =
match primitive with
| Pair(e, rest) -> (List.flatten [(flat_seq (tag_parse (Pair(e,rest))))])
| e -> [(tag_parse e)] in
match rest with
| Pair(e, Nil) -> (List.append eval_primitive_to_list (List.flatten [flat_seq (tag_parse e)]))
| Pair(Symbol(var), rest) -> if (List.mem var reserved_word_list) then
(List.append eval_primitive_to_list (List.flatten [(flat_seq (tag_parse (Pair((Symbol(var)), rest))))])) else
(List.append eval_primitive_to_list (sequence_eval_rec (Symbol(var)) rest))
| Pair(e, rec_rest) -> (List.append eval_primitive_to_list (sequence_eval_rec e rec_rest))
| _ -> raise X_syntax_error
and make_exp_list list =
match list with
| Pair(e,es) -> ((tag_parse e)::(make_exp_list es))
| Nil -> []
| _ -> raise X_syntax_error
and make_exp_list_from_dotted list =
match list with
| Pair(e,es) -> ((tag_parse e)::(make_exp_list es))
| e -> [(tag_parse e)]
and make_or sexp =
match sexp with
| Nil -> tag_parse (Bool(false))
| Pair(one, Nil) -> tag_parse one
| _ -> Or(make_exp_list sexp)
and make_and sexp =
match sexp with
| Nil -> tag_parse (Bool(true))
| Pair(one, Nil) -> tag_parse one
| Pair(first, rest) -> tag_parse (Pair(Symbol "if", Pair(first, Pair(Pair(Symbol("and"), rest), Pair(Bool(false), Nil)))))
| _ -> raise X_syntax_error
and make_lambda args body =
let args_type = (lambda_args_type args) in
match args_type with
| "simple" -> LambdaSimple(string_list args, make_sequence body)
| "opt" -> LambdaOpt(string_improper_list args, find_last_item_in_list args, make_sequence body)
| _ -> raise X_syntax_error
and make_quasi_quote rest =
match rest with
| Pair(Symbol("unquote"), Pair(es, Nil)) -> es
| Pair(Symbol("unquote-splicing"), es) -> raise X_syntax_error
| Nil -> (Pair(Symbol("quote"), Pair(Nil, Nil)))
| Symbol(e) -> (Pair(Symbol("quote"), Pair(Symbol(e), Nil)))
| Pair(a, b) -> quasi_pair a b
| Number(x) -> (Number(x))
| Bool(x) -> (Bool(x))
| Char(x) -> (Char(x))
| String(x) -> (String(x))
and quasi_pair a b =
match a,b with
| Pair(Symbol("unquote-splicing"), Pair(sexp, Nil)), _ -> append sexp (make_quasi_quote b)
| _ , Pair(Symbol("unquote-splicing"), Pair(sexp, Nil)) -> cons (make_quasi_quote a) sexp
| _ , _ -> cons (make_quasi_quote a) (make_quasi_quote b)
and cons a b = Pair(Symbol "cons", Pair(a, Pair(b, Nil)))
and append a b = Pair(Symbol "append", Pair(a, Pair( b, Nil)));;
let tag_parse_expressions sexpr = List.map tag_parse sexpr;;
end;; (* struct Tag_Parser *)