diff options
| author | Joel Martin <github@martintribe.org> | 2014-03-29 18:35:22 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-03-29 18:35:22 -0500 |
| commit | 46669c861b0d13e00ab8996e3d6b48b85c959f34 (patch) | |
| tree | 14d3ce1fa1b21af7d9a068a2ddcfc21d3532f5a2 | |
| parent | 2e05535fa066c279ea915f8eef7bf775b6bf884a (diff) | |
| download | mal-46669c861b0d13e00ab8996e3d6b48b85c959f34.tar.gz mal-46669c861b0d13e00ab8996e3d6b48b85c959f34.zip | |
PS: add step5_tco.
Update step4 function definition to match.
| -rw-r--r-- | ps/step0_repl.ps | 2 | ||||
| -rw-r--r-- | ps/step1_read_print.ps | 1 | ||||
| -rw-r--r-- | ps/step2_eval.ps | 1 | ||||
| -rw-r--r-- | ps/step3_env.ps | 3 | ||||
| -rw-r--r-- | ps/step4_if_fn_do.ps | 23 | ||||
| -rw-r--r-- | ps/step5_tco.ps | 160 |
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 |
