aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-03-29 18:35:22 -0500
committerJoel Martin <github@martintribe.org>2014-03-29 18:35:22 -0500
commit46669c861b0d13e00ab8996e3d6b48b85c959f34 (patch)
tree14d3ce1fa1b21af7d9a068a2ddcfc21d3532f5a2
parent2e05535fa066c279ea915f8eef7bf775b6bf884a (diff)
downloadmal-46669c861b0d13e00ab8996e3d6b48b85c959f34.tar.gz
mal-46669c861b0d13e00ab8996e3d6b48b85c959f34.zip
PS: add step5_tco.
Update step4 function definition to match.
-rw-r--r--ps/step0_repl.ps2
-rw-r--r--ps/step1_read_print.ps1
-rw-r--r--ps/step2_eval.ps1
-rw-r--r--ps/step3_env.ps3
-rw-r--r--ps/step4_if_fn_do.ps23
-rw-r--r--ps/step5_tco.ps160
6 files changed, 174 insertions, 16 deletions
diff --git a/ps/step0_repl.ps b/ps/step0_repl.ps
index 1085525..9dbf107 100644
--- a/ps/step0_repl.ps
+++ b/ps/step0_repl.ps
@@ -31,12 +31,12 @@
{ % loop
(user> ) print flush
- %(%lineedit) (r) file 99 string readline
stdin 99 string readline
not { exit } if % exit if EOF
%(\ngot line: ) print dup print (\n) print flush
+
REP print (\n) print
} bind loop
diff --git a/ps/step1_read_print.ps b/ps/step1_read_print.ps
index 0cd4b5d..bc87226 100644
--- a/ps/step1_read_print.ps
+++ b/ps/step1_read_print.ps
@@ -31,7 +31,6 @@ end } def
{ % loop
(user> ) print flush
- %(%lineedit) (r) file 99 string readline
stdin 99 string readline
not { exit } if % exit if EOF
diff --git a/ps/step2_eval.ps b/ps/step2_eval.ps
index daaf2cb..4328e2f 100644
--- a/ps/step2_eval.ps
+++ b/ps/step2_eval.ps
@@ -68,7 +68,6 @@ end } def
{ % loop
(user> ) print flush
- %(%lineedit) (r) file 99 string readline
stdin 99 string readline
not { exit } if % exit if EOF
diff --git a/ps/step3_env.ps b/ps/step3_env.ps
index 656ca10..02b3e8d 100644
--- a/ps/step3_env.ps
+++ b/ps/step3_env.ps
@@ -26,7 +26,7 @@
} ifelse } ifelse
end } def
-/EVAL { 10 dict begin
+/EVAL { 8 dict begin
/env exch def
/ast exch def
%(EVAL: ) print ast ==
@@ -83,7 +83,6 @@ end } def
{ % loop
(user> ) print flush
- %(%lineedit) (r) file 99 string readline
stdin 99 string readline
not { exit } if % exit if EOF
diff --git a/ps/step4_if_fn_do.ps b/ps/step4_if_fn_do.ps
index 891652e..72dafef 100644
--- a/ps/step4_if_fn_do.ps
+++ b/ps/step4_if_fn_do.ps
@@ -26,7 +26,7 @@
} ifelse } ifelse
end } def
-/EVAL { 10 dict begin
+/EVAL { 9 dict begin
/env exch def
/ast exch def
%(EVAL: ) print ast ==
@@ -68,22 +68,24 @@ end } def
}{ /fn* a0 eq { %if fn*
/a1 ast 1 get def
/a2 ast 2 get def
- { 4 dict begin
- /A1 __a1__ def % close over positino 4
- /A2 __a2__ def % close over position 7
- /ENV __env__ def % close over position 10
- /args exch def
+ { /user_defined % mark this as user defined
+ __PARAMS__ __AST__ __ENV__ % closed over variables
+ 4 dict begin
+ /ENV exch def % closed over above, pos 3
+ /AST exch def % closed over above, pos 2
+ /PARAMS exch def % closed over above, pos 1
+ /args exch def
%(inside fn*:\n) print
%( A1: ) print A1 ==
%( A2: ) print A2 ==
%( ENV: ) print ENV ==
%( args: ) print args ==
- A2 ENV A1 args env_new EVAL
+ AST ENV PARAMS args env_new EVAL
end }
dup length array copy cvx % make an actual copy/new instance
- dup 4 a1 put % insert closed over a1 into position 4
- dup 7 a2 put % insert closed over a1 into position 7
- dup 10 env put % insert closed over a1 into position 10
+ dup 1 a1 put % insert closed over a1 into position 1
+ dup 2 a2 put % insert closed over a2 into position 2
+ dup 3 env put % insert closed over env into position 3
}{
/el ast env eval_ast def
el _rest % args array
@@ -117,7 +119,6 @@ types_ns { _ref } forall
{ % loop
(user> ) print flush
- %(%lineedit) (r) file 99 string readline
stdin 99 string readline
not { exit } if % exit if EOF
diff --git a/ps/step5_tco.ps b/ps/step5_tco.ps
new file mode 100644
index 0000000..5209a14
--- /dev/null
+++ b/ps/step5_tco.ps
@@ -0,0 +1,160 @@
+(types.ps) run
+(reader.ps) run
+
+% read
+/READ {
+ /str exch def
+ str read_str
+} def
+
+
+% eval
+/eval_ast { 2 dict begin
+ /env exch def
+ /ast exch def
+ %(eval_ast: ) print ast ==
+ /nametype ast type eq { %if symbol
+ env ast env_get
+ }{ /arraytype ast type eq { %elseif list
+ [
+ ast {
+ env EVAL
+ } forall
+ ]
+ }{ % else
+ ast
+ } ifelse } ifelse
+end } def
+
+/EVAL { 13 dict begin
+ { %loop (TCO)
+
+ /env exch def
+ /ast exch def
+ /loop? false def
+
+ %(EVAL: ) print ast ==
+ /arraytype ast type ne { %if not a list
+ ast env eval_ast
+ }{ %else apply the list
+ /a0 ast 0 get def
+ /def! a0 eq { %if def!
+ /a1 ast 1 get def
+ /a2 ast 2 get def
+ env a1 a2 env EVAL env_set
+ }{ /let* a0 eq { %if let*
+ /a1 ast 1 get def
+ /a2 ast 2 get def
+ /let_env env [ ] [ ] env_new def
+ 0 2 a1 length 1 sub { %for each pair
+ /idx exch def
+ let_env
+ a1 idx get
+ a1 idx 1 add get let_env EVAL
+ env_set
+ } for
+ a2 let_env EVAL
+ }{ /do a0 eq { %if do
+ ast length 2 ge { %if ast has more than 2 elements
+ ast 1 ast length 1 sub getinterval env eval_ast
+ } if
+ ast ast length 1 sub get % last ast becomes new ast
+ env
+ /loop? true def % loop
+ }{ /if a0 eq { %if if
+ /a1 ast 1 get def
+ /cond a1 env EVAL def
+ cond null eq cond false eq or { % if cond is nil or false
+ ast length 3 gt { %if false branch (a3) provided
+ ast 3 get env % new ast is false branch (a3)
+ /loop? true def
+ }{
+ null
+ } ifelse
+ }{
+ ast 2 get env % new ast is true branch (a2)
+ /loop? true def
+ } ifelse
+ }{ /fn* a0 eq { %if fn*
+ /a1 ast 1 get def
+ /a2 ast 2 get def
+ { /user_defined % mark this as user defined
+ __PARAMS__ __AST__ __ENV__ % closed over variables
+ 4 dict begin
+ /ENV exch def % closed over above, pos 3
+ /AST exch def % closed over above, pos 2
+ /PARAMS exch def % closed over above, pos 1
+ /args exch def
+ %(inside fn*:\n) print
+ %( A1: ) print A1 ==
+ %( A2: ) print A2 ==
+ %( ENV: ) print ENV ==
+ %( args: ) print args ==
+ AST ENV PARAMS args env_new EVAL
+ end }
+ dup length array copy cvx % make an actual copy/new instance
+ dup 1 a1 put % insert closed over a1 into position 1
+ dup 2 a2 put % insert closed over a2 into position 2
+ dup 3 env put % insert closed over env into position 3
+ }{
+ /el ast env eval_ast def
+ el _first 0 get /user_defined eq { %if userdefined function
+ /PARAMS el _first 1 get def
+ /AST el _first 2 get def
+ /ENV el _first 3 get def
+ AST % new ast is one stored in function
+ ENV PARAMS el _rest env_new % new environment
+ /loop? true def
+ }{ %else (regular procedure/function)
+ el _rest % args array
+ el _first cvx % function
+ %(vvv\n) print pstack (^^^\n) print
+ exec % apply function to args
+ } ifelse
+ } ifelse } ifelse } ifelse } ifelse } ifelse
+ } ifelse
+
+ loop? not { exit } if
+ } loop % TCO
+end } def
+
+
+% print
+/PRINT {
+ true _pr_str
+} def
+
+
+% repl
+/repl_env null [ ] [ ] env_new def
+
+/RE { READ repl_env EVAL } def
+/REP { READ repl_env EVAL PRINT } def
+/_ref { repl_env 3 1 roll env_set pop } def
+
+types_ns { _ref } forall
+
+(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
+
+/stdin (%stdin) (r) file def
+
+{ % loop
+ (user> ) print flush
+
+ stdin 99 string readline
+
+ not { exit } if % exit if EOF
+
+ %(\ngot line: ) print dup print (\n) print flush
+
+ { %try
+ REP print (\n) print
+ } stopped {
+ (Error: ) print
+ get_error_data false _pr_str print (\n) print
+ clear
+ } if
+} bind loop
+
+(\n) print % final newline before exit for cleanliness
+quit