1use crate::{
2 ast::Ast,
3 core_forms, eval_unseemly_program_top, expand, grammar,
4 name::{n, Name},
5 runtime::{core_values, eval, eval::Value},
6 ty, type_unseemly_program_top,
7 util::assoc::Assoc,
8};
9use std::cell::RefCell;
10
11thread_local! {
14 pub static ty_env : RefCell<Assoc<Name, Ast>> = RefCell::new(core_values::core_types());
15 pub static val_env : RefCell<Assoc<Name, Value>> = RefCell::new(core_values::core_values());
16}
17
18fn type_unseemly_program(program: &str) -> Result<Ast, String> {
19 let ast = grammar::parse(
20 &core_forms::outermost_form(),
21 core_forms::outermost__parse_context(),
22 program,
23 )
24 .map_err(|e| e.msg)?;
25
26 ty_env.with(|tys| ty::synth_type(&ast, tys.borrow().clone()).map_err(|e| format!("{}", e)))
27}
28
29fn eval_unseemly_program(program: &str) -> Result<Value, String> {
30 let ast: Ast = grammar::parse(
31 &core_forms::outermost_form(),
32 core_forms::outermost__parse_context(),
33 program,
34 )
35 .map_err(|e| e.msg)?;
36
37 let _type = ty_env
38 .with(|tys| ty::synth_type(&ast, tys.borrow().clone()).map_err(|e| format!("{}", e)))?;
39
40 let core_ast = expand::expand(&ast).map_err(|_| "error".to_owned())?;
41
42 val_env.with(|vals| eval::eval(&core_ast, vals.borrow().clone()).map_err(|_| "???".to_string()))
43}
44
45fn assign_variable(name: &str, expr: &str) -> Result<Value, String> {
46 let res = eval_unseemly_program(expr);
47
48 if let Ok(ref v) = res {
49 let ty = type_unseemly_program(expr).unwrap();
50 ty_env.with(|tys| {
51 val_env.with(|vals| {
52 let new_tys = tys.borrow().set(n(name), ty);
53 let new_vals = vals.borrow().set(n(name), v.clone());
54 *tys.borrow_mut() = new_tys;
55 *vals.borrow_mut() = new_vals;
56 })
57 })
58 }
59 res
60}
61
62fn assign_t_var(name: &str, t: &str) -> Result<Ast, String> {
63 let ast = grammar::parse(
64 &grammar::FormPat::Call(n("Type")),
65 core_forms::outermost__parse_context(),
66 t,
67 )
68 .map_err(|e| e.msg)?;
69
70 let res =
71 ty_env.with(|tys| ty::synth_type(&ast, tys.borrow().clone()).map_err(|e| format!("{}", e)));
72
73 if let Ok(ref t) = res {
74 ty_env.with(|tys| {
75 let new_tys = tys.borrow().set(n(name), t.clone());
76 *tys.borrow_mut() = new_tys;
77 })
78 }
79
80 res
81}
82
83fn ignore__this_function() {
84 let _ = eval_unseemly_program_top;
86 let _ = type_unseemly_program_top;
87}
88
89#[test]
94fn end_to_end_int_list_tools() {
95 assert_m!(assign_t_var("IntList", "mu_type IntList . { +[Nil]+ +[Cons Int IntList]+ }"), Ok(_));
96
97 assert_m!(assign_t_var("IntListUF", "{ +[Nil]+ +[Cons Int IntList]+ }"), Ok(_));
98
99 assert_m!(
100 assign_variable("mt_ilist", "fold +[Nil]+ : { +[Nil]+ +[Cons Int IntList]+ } : IntList"),
101 Ok(_)
102 );
103
104 assert_m!(
105 assign_variable("ilist_3", "fold +[Cons three mt_ilist]+ : IntListUF : IntList"),
106 Ok(_)
107 );
108
109 assert_m!(
110 assign_variable("ilist_23", "fold +[Cons two ilist_3]+ : IntListUF : IntList"),
111 Ok(_)
112 );
113
114 assert_m!(
115 assign_variable("ilist_123", "fold +[Cons one ilist_23]+ : IntListUF : IntList"),
116 Ok(_)
117 );
118
119 assert_m!(
120 assign_variable(
121 "sum_int_list",
122 "(fix .[again : [-> [IntList -> Int]] .
123 .[ lst : IntList .
124 match unfold lst {
125 +[Nil]+ => zero +[Cons hd tl]+ => (plus hd ((again) tl))} ]. ]. )"
126 ),
127 Ok(_)
128 );
129
130 assert_eq!(eval_unseemly_program("(sum_int_list ilist_123)"), Ok(val!(i 6)));
131
132 assert_m!(
133 assign_variable(
134 "int_list_len",
135 "(fix .[again : [-> [IntList -> Int]] .
136 .[ lst : IntList .
137 match unfold lst {
138 +[Nil]+ => zero +[Cons hd tl]+ => (plus one ((again) tl))} ]. ].)"
139 ),
140 Ok(_)
141 );
142
143 assert_eq!(eval_unseemly_program("(int_list_len ilist_123)"), Ok(val!(i 3)));
144}
145
146#[test]
147fn end_to_end_list_tools() {
148 assert_m!(
149 assign_t_var("List", "forall T . mu_type List . { +[Nil]+ +[Cons T List<T> ]+ }"),
150 Ok(_)
151 );
152
153 assert_m!(assign_t_var("ListUF", "forall T . { +[Nil]+ +[Cons T List<T> ]+ }"), Ok(_));
154
155 assert_m!(
156 assign_variable(
157 "mt_list",
158 "fold +[Nil]+ : { +[Nil]+ +[Cons Int List<Int> ]+ } : List < Int > "
159 ),
160 Ok(_)
161 );
162
163 assert_m!(
164 assign_variable("list_3", "fold +[Cons three mt_list]+ : ListUF<Int> : List<Int>"),
165 Ok(_)
166 );
167
168 assert_m!(
169 assign_variable("list_23", "fold +[Cons two list_3]+ : ListUF<Int> : List<Int>"),
170 Ok(_)
171 );
172
173 assert_m!(
174 assign_variable("list_123", "fold +[Cons one list_23]+ : ListUF<Int> : List<Int>"),
175 Ok(_)
176 );
177
178 assert_m!(
179 assign_variable(
180 "list_len",
181 "forall S . (fix .[again : [-> [List<S> -> Int]] .
182 .[ lst : List<S> .
183 match unfold lst {
184 +[Nil]+ => zero
185 +[Cons hd tl]+ => (plus one ((again) tl))} ]. ].)"
186 ),
187 Ok(_)
188 );
189
190 assert_eq!(eval_unseemly_program("(list_len list_123)"), Ok(val!(i 3)));
191
192 assert_m!(
193 assign_variable(
194 "map",
195 "forall T S . (fix .[again : [-> [List<T> [T -> S] -> List<S> ]] .
196 .[ lst : List<T> f : [T -> S] .
197 match unfold lst {
198 +[Nil]+ => fold +[Nil]+ : ListUF<S> : List<S>
199 +[Cons hd tl]+ =>
200 fold +[Cons (f hd) ((again) tl f)]+ : ListUF<S> : List<S> } ]. ].)"
201 ),
202 Ok(_)
203 );
204 assert_m!(eval_unseemly_program("(map list_123 .[x : Int . (plus x one)]. )"), Ok(_));
209
210 assert_m!(eval_unseemly_program("(map list_123 .[x : Int . (equal? x two)]. )"), Ok(_));
211}
212
213#[test]
214fn subtyping_direction() {
215 assert_m!(assign_variable("ident", "forall T . .[ a : T . a ]."), Ok(_));
218
219 assert_eq!(eval_unseemly_program("(ident five)"), Ok(val!(i 5)));
220
221 assert_m!(eval_unseemly_program("( .[ a : [Int -> Int] . a]. ident)"), Ok(_));
222
223 assert_m!(eval_unseemly_program("( .[ a : forall T . [T -> T] . a]. .[a : Int . a].)"), Err(_));
224
225 assert_m!(eval_unseemly_program(".[ a : *[]* . a]."), Ok(_));
226
227 assert_m!(
228 eval_unseemly_program("( .[ a : *[normal : Int extra : Int]* . a]. *[normal : one]*)"),
229 Err(_)
230 );
231
232 assert_m!(
233 eval_unseemly_program("( .[ a : *[normal : Int]* . a]. *[normal : one extra : five]*)"),
234 Ok(_)
235 );
236}
237
238#[test]
239fn end_to_end_quotation_advanced() {
240 assert_eq!(
241 eval_unseemly_program(
242 "(.[five_e : Expr < Int >.
243 '[Expr | (plus five ,[five_e],) ]' ].
244 '[Expr | five]')"
245 ),
246 eval_unseemly_program("'[Expr | (plus five five) ]'")
247 );
248
249 assert_m!(
251 type_unseemly_program_top(
252 "(.[five_e : Expr<Int> .
253 '[Expr | (plus five ,[five_e],) ]' ].
254 '[Expr | true]')"
255 ),
256 Err(_)
257 );
258
259 assert_m!(
261 type_unseemly_program_top(
262 "(.[five_e : Expr<Bool> .
263 '[Expr | (plus five ,[five_e],) ]' ].
264 '[Expr | true]')"
265 ),
266 Err(_)
267 );
268
269 assert_m!(
271 type_unseemly_program_top(".[five_e : Expr<Bool> . '[Expr | (plus five ,[five_e],) ]' ]."),
272 Err(_)
273 );
274
275 assert_m!(
276 eval_unseemly_program(
277 "forall T . .[type : Type<T> rhs : Expr<T>
278 . '[Expr | (.[x : ,[Type<T> | type], . eight]. ,[rhs], )]' ]."
279 ),
280 Ok(_)
281 );
282
283 assert_m!(eval_unseemly_program("'[Pat<Nat> | x]'"), Ok(_));
284
285 assert_eq!(
287 eval_unseemly_program(
288 "match '[Expr | (plus one two) ]' {
289 '[Expr<Int> | (plus ,[Expr<Int> | e], two) ]' => e }"
290 ),
291 eval_unseemly_program("'[Expr| one]'")
292 );
293
294 assert_m!(
298 assign_variable(
299 "let",
300 "forall T S . .[binder : Pat<T>
301 type : Type<T>
302 rhs : Expr<T>
303 body : Expr<S> .
304 '[ Expr | (.[x : ,[type],
305 . match x { ,[Pat<T> | binder], => ,[body], } ].
306 ,[rhs],)]' ]."
307 ),
308 Ok(_)
309 );
310
311 without_freshening! {
312 assert_eq!(
313 eval_unseemly_program(
314 "(let '[Pat<Int> | y]'
315 '[Type<Int> | Int]'
316 '[Expr<Int> | eight]'
317 '[Expr<Int> | five]')"),
318 eval_unseemly_program("'[Expr<Int> | (.[x : Int . match x {y => five}]. eight)]'"));
319 }
320
321 }
344
345#[test]
346fn simple_end_to_end_eval() {
347 assert_eq!(eval_unseemly_program_top("(zero? zero)"), Ok(val!(b true)));
348
349 assert_eq!(eval_unseemly_program_top("(plus one one)"), Ok(val!(i 2)));
350
351 assert_eq!(
352 eval_unseemly_program_top("(.[x : Int y : Int . (plus x y)]. one one)"),
353 Ok(val!(i 2))
354 );
355
356 assert_eq!(
357 eval_unseemly_program_top(
358 "((fix .[ again : [ -> [ Int -> Int ]] .
359 .[ n : Int .
360 match (zero? n) {
361 +[True]+ => one
362 +[False]+ => (times n ((again) (minus n one))) } ]. ].) five)"
363 ),
364 Ok(val!(i 120))
365 );
366}
367
368#[test]
369fn end_to_end_quotation_basic() {
370 assert_m!(eval_unseemly_program_top("'[Expr | .[ x : Int . x ]. ]'"), Ok(_));
371
372 assert_m!(eval_unseemly_program_top("'[Expr | (plus five five) ]'"), Ok(_));
373
374 assert_m!(eval_unseemly_program_top("'[Expr | '[Expr | (plus five five) ]' ]'"), Ok(_));
375
376 }
378
379#[test]
380fn language_building() {
381 assert_eq!(
382 eval_unseemly_program_top(
383 r"extend_syntax
384 DefaultSeparator ::= /((?:\s|#[^\n]*)*)/ ;
385 in
386 # Now we have comments! (just not after the last token)
387 five"
388 ),
389 Ok(val!(i 5))
390 );
391
392 let bound_wrong_prog = "extend_syntax
393 Expr ::=also forall T S . '{
394 [
395 lit ,{ DefaultToken }, = 'let'
396 [
397 pat := ( ,{ Pat<S> }, )
398 lit ,{ DefaultToken }, = '='
399 value := ( ,{ Expr<S> }, )
400 lit ,{ DefaultToken }, = ';'
401 ] *
402 lit ,{ DefaultToken }, = 'in'
403 body := ( ,{ Expr<T> }, <-- ...[pat = value]... )
404 ]
405 }' let_macro -> .{
406 '[Expr |
407 match ...[,value, >> ,[value], ]...
408 { ...[,pat, >> ,[pat],]... => ,[body], } ]'
409 }. ;
410 in
411 let x = eight ;
412 y = times ;
413 in (plus x y)";
414 let bound_wrong_ast = grammar::parse(
415 &core_forms::outermost_form(),
416 core_forms::outermost__parse_context(),
417 bound_wrong_prog,
418 )
419 .unwrap();
420
421 assert_m!(
422 ty::synth_type(&bound_wrong_ast, crate::runtime::core_values::core_types()),
423 ty_err_p!(Mismatch(x, y)) => {
424 assert_eq!(x, uty!({Int :}));
425 assert_eq!(y, uty!({fn : [{Int :}; {Int :}] {Int :}}));
426 }
427 );
428
429 let inner_expr_wrong_prog = "extend_syntax
430 Expr ::=also forall T S . '{
431 [
432 lit ,{ DefaultToken }, = 'let'
433 [
434 pat := ( ,{ Pat<S> }, )
435 lit ,{ DefaultToken }, = '='
436 value := ( ,{ Expr<S> }, )
437 lit ,{ DefaultToken }, = ';'
438 ] *
439 lit ,{ DefaultToken }, = 'in'
440 body := ( ,{ Expr< T > }, <-- ...[pat = value]... )
441 ]
442 }' let_macro -> .{
443 '[Expr |
444 match ...[,value, >> ,[value], ]...
445 { ...[,pat, >> ,[pat],]... => ,[body], } ]'
446 }. ;
447 in
448 let x = eight ;
449 y = four ;
450 in (plus x times)";
451 let inner_expr_wrong_ast = grammar::parse(
452 &core_forms::outermost_form(),
453 core_forms::outermost__parse_context(),
454 inner_expr_wrong_prog,
455 )
456 .unwrap();
457
458 assert_m!(
459 ty::synth_type(&inner_expr_wrong_ast, crate::runtime::core_values::core_types()),
460 ty_err_p!(Mismatch(x, times)) => {
461 assert_eq!(x, uty!({Int :}));
462 assert_eq!(times, uty!({fn : [{Int :}; {Int :}] {Int :}}));
463 }
464 );
465
466 let let_macro_prog = "extend_syntax
469 Expr ::=also forall T S . '{
470 [
471 lit ,{ DefaultToken }, = 'let'
472 [
473 pat := ( ,{ Pat<S> }, )
474 lit ,{ DefaultToken }, = '='
475 value := ( ,{ Expr<S> }, )
476 lit ,{ DefaultToken }, = ';'
477 ] *
478 lit ,{ DefaultToken }, = 'in'
479 body := ( ,{ Expr<T> }, <-- ...[pat = value]... )
480 ]
481 }' let_macro -> .{
482 '[Expr |
483 match **[...[,value, >> ,[value], ]... ]**
484 { **[...[,pat, >> ,[pat],]... ]** => ,[body], } ]'
485 }. ;
486 in
487 let x = eight ;
488 y = four ;
489 in (plus y (plus x y))";
490 assert_eq!(eval_unseemly_program_top(let_macro_prog), Ok(val!(i 16)));
491}