Updated BAE.

This commit is contained in:
2025-11-09 17:36:41 -05:00
parent e6deaf6ad6
commit 539973a96e
+34 -19
View File
@@ -10,9 +10,13 @@
| { - <BAE> <BAE> ... }
| { / <BAE> <BAE> ... }
| { = <BAE> <BAE> }
| { <BAE> is <BAE> } -- Sugar.
| { < <BAE> <BAE> }
| { <BAE> is less than <BAE> } -- Sugar.
| { <= <BAE> <BAE> }
| { <BAE> is less than or equal to <BAE> } -- Sugar.
| { with { <id> <BAE> } <BAE> }
| { with <id> as <BAE> <BAE> } -- Sugar.
| { if <BAE> <BAE> <BAE> }
| { if <BAE> then <BAE> else <BAE> } -- Sugar.
| { and <BAE> <BAE> } -- Sugar.
@@ -40,13 +44,14 @@
[Call BAE BAE]
[Id Symbol])
; This is a little strange.
(define-type LambdaContents
[Par Symbol]
[Body BAE])
(define-type Primitive = (U Number Boolean (Listof LambdaContents)))
(define reserved-names (list 'F 'T '+ '* '- '/ '= '< '<= 'with 'if 'then 'else 'lambda 'λ 'of))
(define reserved-names (list 'F 'T '+ '* '- '/ '= 'is '< 'less 'than '<= 'or 'equal 'to 'with 'if 'then 'else 'lambda 'of 'and 'not 'as))
(define pf (Bool #f))
(define pt (Bool #t))
@@ -67,8 +72,12 @@
[(list '- fst args ...) (Sub (parse-sexpr fst) (parse-sexprs args))]
[(list '/ fst args ...) (Div (parse-sexpr fst) (parse-sexprs args))]
[(list '= l r) (Eq (parse-sexpr l) (parse-sexpr r))]
[(list l 'is r) (Eq (parse-sexpr l) (parse-sexpr r))]
[(list '< l r) (Lt (parse-sexpr l) (parse-sexpr r))]
[(list l 'is 'less 'than r) (Lt (parse-sexpr l) (parse-sexpr r))]
[(list '<= l r) (Lte (parse-sexpr l) (parse-sexpr r))]
[(list l 'is 'less 'than 'or 'equal 'to r) (Lte (parse-sexpr l) (parse-sexpr r))]
[(list 'with (symbol: name) 'as val body) (With name (parse-sexpr val) (parse-sexpr body))]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
@@ -77,7 +86,9 @@
[(list 'if p b a) (If (parse-sexpr p) (parse-sexpr b) (parse-sexpr a))]
[(list 'if p 'then b 'else a) (If (parse-sexpr p) (parse-sexpr b) (parse-sexpr a))]
[(list 'and a b) (If (parse-sexpr a) (If (parse-sexpr b) pt pf) pf)]
[(list a 'and b) (If (parse-sexpr a) (If (parse-sexpr b) pt pf) pf)]
[(list 'or a b) (If (parse-sexpr a) pt (If (parse-sexpr b) pt pf))]
[(list a 'or b) (If (parse-sexpr a) pt (If (parse-sexpr b) pt pf))]
[(list 'not a) (If (parse-sexpr a) pf pt)]
[(list 'lambda (symbol: arg) body) (Lambda arg (parse-sexpr body))]
[(list f 'of arg) (Call (parse-sexpr f) (parse-sexpr arg))]
@@ -242,7 +253,10 @@
bound-id
;; see the above `value-bae' helper
(value->bae (eval named-expr)))))]
[(Lambda par body) (list (Par par) (Body body))] ; No lambda primitive, but this branch shouldn't happen anyway. Return dummy value for now.
[(Lambda par body)
(if (member par reserved-names)
(error 'eval "Can't create parameter binding to reserved name '~s'." par)
(list (Par par) (Body body)))]
[(Call f arg) (eval-call (value->bae (eval f)) arg)]
[(Id name) (error 'eval "free identifier: ~s" name)]))
@@ -251,34 +265,31 @@
(define (run str)
(eval (parse str)))
; Because we'ren't writing a lazy language, need to use the Z combinator to delay evaluation of f (otherwise it'd never terminate).
; As we'ren't writing a lazy language, we need to use the Z combinator to delay evaluation of f (otherwise it'd never terminate). This factorial function also isn't tail recursive cause it's hard enough for me to understand already ;-;.
; Z = λf.(λx.(f λv.((x x) v)))(λx.(f λv.((x x) v)))
; factorial = (Y (λself.λn.if (<= n 1) 1 (* n (self (- n 1)))))
(test (run "
{with
{Z {lambda f {
{with Z as {lambda f {
{lambda x {f of {lambda v {{x of x} of v}}}}
of
{lambda x {f of {lambda v {{x of x} of v}}}}
}}}
{with
{factorial {Z of
{lambda self {lambda n
{if {<= n 1} 1 {* n {self of {- n 1}}}}
}
}}}
{factorial of 5}
}}
") => 120)
{with factorial as {Z of
{lambda self {lambda n
{if {n is less than or equal to 1} then 1 else {* n {self of {- n 1}}}}
}
}}
{{{factorial of 4} is 24} and
{{factorial of 5} is 120}}}}") => #t)
(test (run "{{lambda f {f of 1}} of {lambda x {+ x 1}}}") => 2)
(test (run "{{lambda x {+ x 1}} of 2}") => 3)
(test (run "{{lambda + {+ + +}} of 2}") =error> "Can't create parameter binding to reserved name '+'.")
(test (run "{1 of 1}") =error> "eval-call: Expected lambda expression to call, instead got: (Num 1).")
(test (run "{with {x 2} {x of 1}}") =error> "eval-call: Expected lambda expression to call, instead got: (Num 2).")
(test (run "{and T T}") => #t)
(test (run "{and F aaaaaaaaaa}") => #f)
@@ -298,8 +309,10 @@
(test (run "{< 1 2}") => #t)
(test (run "{< 2 2}") => #f)
(test (run "{< 2 1}") => #f)
(test (run "{1 is 2}") => #f)
(test (run "{= 1 2}") => #f)
(test (run "{= 2 2}") => #t)
(test (run "{2 is 2}") => #t)
(test (run "{<= 1 2}") => #t)
(test (run "{<= 2 2}") => #t)
(test (run "{<= 2 1}") => #f)
@@ -322,6 +335,8 @@
(test (run "{/ 3 2 1}") => 3/2)
(test (run "{/ 1 2 3}") => 1/6)
(test (run "{+ x 1}") =error> "eval: free identifier: x")
;; tests (for simple expressions)
(test (run "5") => 5)
(test (run "{+ 5 5}") => 10)