diff options
| author | Joel Martin <github@martintribe.org> | 2014-03-29 17:35:53 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-03-29 17:35:53 -0500 |
| commit | aef93ea3969feee92e68358395d5750ebe83f57d (patch) | |
| tree | 9e38fae1432ac26f2c4915f3f38d8ae6ccfe54f8 | |
| parent | 04517bc8265b6930e96735dd5d12b7aac7d86217 (diff) | |
| download | mal-aef93ea3969feee92e68358395d5750ebe83f57d.tar.gz mal-aef93ea3969feee92e68358395d5750ebe83f57d.zip | |
PS: error handling, throw, print excpetions without dying.
| -rw-r--r-- | docs/TODO | 1 | ||||
| -rw-r--r-- | docs/step_notes.txt | 9 | ||||
| -rw-r--r-- | ps/reader.ps | 14 | ||||
| -rw-r--r-- | ps/step1_read_print.ps | 16 | ||||
| -rw-r--r-- | ps/step2_eval.ps | 19 | ||||
| -rw-r--r-- | ps/step3_env.ps | 16 | ||||
| -rw-r--r-- | ps/types.ps | 133 | ||||
| -rw-r--r-- | python/step2_eval.py | 5 | ||||
| -rw-r--r-- | tests/step1_read_print.mal | 11 | ||||
| -rw-r--r-- | tests/step2_eval.mal | 3 |
10 files changed, 173 insertions, 54 deletions
@@ -17,6 +17,7 @@ All: - Print full exception when test gets EOF from expect - Note that bash 4, Java 1.7, php 5.3 required - Break out language eval into step0.5 + - regular expression matching in runtest --------------------------------------------- diff --git a/docs/step_notes.txt b/docs/step_notes.txt index 703d855..c0cd35a 100644 --- a/docs/step_notes.txt +++ b/docs/step_notes.txt @@ -36,6 +36,11 @@ Step Notes: - read_atom - return scalar boxed type: - nil, true, false, symbol, integer, string + - repl loop + - catch errors, print them and continue + - impls without exception handling will need to have a global + variable with checks for it at the beginning of critical + code sections - vectors - Basically: two array types that retain their boxed types, can be @@ -103,7 +108,9 @@ Step Notes: - if: - fn*: - simple if language supports closures - - define not using rep() + - otherwise needs a way of representing functions that can + have associated metadata + - define "not" using REP/RE - metadata diff --git a/ps/reader.ps b/ps/reader.ps index 0fa4c02..8575d64 100644 --- a/ps/reader.ps +++ b/ps/reader.ps @@ -63,8 +63,8 @@ /cnt 0 def { % loop idx str length ge { %if EOF - (Error: unexpected EOF reading string\n) print - error + (unexpected EOF reading string) + throw } if /ch str idx get def % current character /idx idx 1 add def @@ -119,8 +119,8 @@ { % loop str idx read_spaces /idx exch def pop str length idx le { %if EOF - (Error: unexpected EOF reading list\n) print - error + (unexpected EOF reading list) + throw } if /ch str idx get def % current character ch 41 eq { exit } if % ')' is end of list @@ -159,9 +159,13 @@ /ch str idx get def % current character ch 40 eq { %if ( str idx read_list + }{ ch 91 eq { %elseif [ + (unexpected '[') throw + }{ ch 93 eq { %elseif ] + (unexpected ']') throw }{ % else str idx read_atom - } ifelse + } ifelse } ifelse } ifelse %(stack vvv\n) print %pstack diff --git a/ps/step1_read_print.ps b/ps/step1_read_print.ps index d08579c..e03c8cc 100644 --- a/ps/step1_read_print.ps +++ b/ps/step1_read_print.ps @@ -9,19 +9,17 @@ % eval -/EVAL { +/EVAL { 2 dict begin % just "return" the "ast" /env exch def /ast exch def ast -} def +end } def % print /PRINT { - /exp exch def - %(printing: ) print exp == - exp pr_str + pr_str } def @@ -39,7 +37,13 @@ not { exit } if % exit if EOF %(\ngot line: ) print dup print (\n) print flush - REP print (\n) print + { %try + REP print (\n) print + } stopped { + (Error: ) print + get_error_data pr_str print (\n) print + clear + } if } bind loop (\n) print % final newline before exit for cleanliness diff --git a/ps/step2_eval.ps b/ps/step2_eval.ps index 72a91fa..dec403c 100644 --- a/ps/step2_eval.ps +++ b/ps/step2_eval.ps @@ -14,7 +14,12 @@ /ast exch def %(eval_ast: ) print ast == /nametype ast type eq { %if symbol - env ast get + env ast known { + env ast get + }{ + (') ast pr_str (' not found) + concatenate concatenate throw + } ifelse }{ /arraytype ast type eq { %elseif list [ ast { @@ -44,9 +49,7 @@ end } def % print /PRINT { - /exp exch def - %(printing: ) print exp == - exp pr_str + pr_str } def @@ -71,7 +74,13 @@ end } def not { exit } if % exit if EOF %(\ngot line: ) print dup print (\n) print flush - REP print (\n) print + { %try + REP print (\n) print + } stopped { + (Error: ) print + get_error_data pr_str print (\n) print + clear + } if } bind loop (\n) print % final newline before exit for cleanliness diff --git a/ps/step3_env.ps b/ps/step3_env.ps index c2e65cb..908ff43 100644 --- a/ps/step3_env.ps +++ b/ps/step3_env.ps @@ -41,7 +41,7 @@ end } def }{ /let* a0 eq { %if let* /a1 ast 1 get def /a2 ast 2 get def - /let_env env env_new def + /let_env env [ ] [ ] env_new def 0 2 a1 length 1 sub { %for each pair /idx exch def let_env @@ -63,14 +63,12 @@ end } def % print /PRINT { - /exp exch def - %(printing: ) print exp == - exp pr_str + pr_str } def % repl -/repl_env null env_new def +/repl_env null [ ] [ ] env_new def /REP { READ repl_env EVAL PRINT } def /_ref { repl_env 3 1 roll env_set pop } def @@ -91,7 +89,13 @@ end } def not { exit } if % exit if EOF %(\ngot line: ) print dup print (\n) print flush - REP print (\n) print + { %try + REP print (\n) print + } stopped { + (Error: ) print + get_error_data pr_str print (\n) print + clear + } if } bind loop (\n) print % final newline before exit for cleanliness diff --git a/ps/types.ps b/ps/types.ps index 5028c58..8843841 100644 --- a/ps/types.ps +++ b/ps/types.ps @@ -28,29 +28,29 @@ aload % push array onto stack length -1 0 { 1 roll } for % reverse ] -} def +} bind def -/pr_str { - %(in pr_str\n) print - /obj exch def +/_pr_str { 4 dict begin + /print_readably exch def + dup + /func? exch xcheck def % executable function + /obj exch cvlit def /arraytype obj type eq { % if list % accumulate an array of strings - (\() - obj length 0 gt { %if any elements - [ - obj { - pr_str - } forall - ] - { concatenate ( ) concatenate } forall - dup length 1 sub 0 exch getinterval % strip off final space - } if - (\)) concatenate + func? { (<fn* { ) }{ (\() } ifelse + obj ( ) print_readably _pr_str_args + concatenate + func? { ( } >) }{ (\)) } ifelse + concatenate }{ /integertype obj type eq { % if number /slen obj 10 idiv 1 add def obj 10 slen string cvrs }{ /stringtype obj type eq { % if string - (") obj (") concatenate concatenate + print_readably { + (") obj (") concatenate concatenate + }{ + obj + } ifelse }{ null obj eq { % if nil (nil) }{ true obj eq { % if true @@ -58,18 +58,79 @@ }{ false obj eq { % if false (false) }{ /nametype obj type eq { % if symbol - obj obj length string cvs + obj dup length string cvs }{ (<unknown>) } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse +end } def + +% array delim print_readably -> _pr_str_args -> new_string +/_pr_str_args { 3 dict begin + /print_readably exch def + /delim exch def + /args exch def + () + args length 0 gt { %if any elements + [ + args { %foreach argument in array + print_readably _pr_str + } forall + ] + { concatenate delim concatenate } forall + dup length delim length sub 0 exch getinterval % strip off final delim + } if +} def + + +% +% errors/exceptions +% + +% data -> throw -> +% Takes an arbitrary data and puts it in $error:/errorinfo. Then calls +% stop to transfer control to end of nearest stopped context. +/throw { + $error exch /errorinfo exch put + $error /command /throw put + stop +} def - %(pr_str2 stack vvv\n) print - %pstack - %(pr_str2 stack ^^^\n) print +/errorinfo? { + $error /errorinfo known { % if set + $error /errorinfo get null ne { + true + }{ + false + } ifelse + }{ + false + } ifelse } def +/get_error_data { + errorinfo? { %if + $error /errorinfo get + }{ + $error /errorname get 255 string cvs + (: ) + $error /command get 99 string cvs + ( at ) + $error /position get 10 99 string cvrs + concatenate + concatenate + concatenate + concatenate + } ifelse +} def + + +% % list operations +% +/_list? { + dup xcheck not exch type /arraytype eq and +} def /_first { 0 get } def /_rest { dup length 1 sub 1 exch getinterval } def /_nth { get } def @@ -78,10 +139,24 @@ % % Env implementation % -/env_new { 1 dict begin +% outer binds exprs -> env_new -> new_env +/env_new { 3 dict begin + %(in env_new\n) print + /exprs exch def + /binds exch def /outer exch def << /__outer__ outer + 0 1 binds length 1 sub { + /idx exch def + binds idx get (&) eq { %if & + binds idx 1 add get % key + exprs idx exprs length idx sub getinterval % value + exit + } if + binds idx get % key + exprs idx get % value + } for >> end } def @@ -97,13 +172,14 @@ end } def } ifelse } ifelse end } def -/env_set { 3 dict begin - /func dup xcheck def +/env_set { 4 dict begin + dup + /func? exch xcheck def % executable function /val exch cvlit def /key exch def /env exch def - env key val func { cvx } if put - val func { cvx } if + env key val func? { cvx } if put + val func? { cvx } if end } def /env_get { 2 dict begin @@ -111,8 +187,11 @@ end } def /env exch def env key env_find dup null eq { - (Error: ') print key 99 string cvs print (' not found\n) print - error + (') + key 99 string cvs + (' not found) + concatenate concatenate + throw }{ key get } ifelse diff --git a/python/step2_eval.py b/python/step2_eval.py index bb5d6f8..65972a2 100644 --- a/python/step2_eval.py +++ b/python/step2_eval.py @@ -12,7 +12,10 @@ def READ(str): # eval def eval_ast(ast, env): if symbol_Q(ast): - return env[ast] + try: + return env[ast] + except: + raise Exception("'" + ast + "' not found") elif list_Q(ast): return new_list(*map(lambda a: EVAL(a, env), ast)) elif vector_Q(ast): diff --git a/tests/step1_read_print.mal b/tests/step1_read_print.mal index f0d7a9a..de7fcc1 100644 --- a/tests/step1_read_print.mal +++ b/tests/step1_read_print.mal @@ -60,7 +60,6 @@ abc-def ( + 1 (+ 2 3 ) ) ;=>(+ 1 (+ 2 3)) - ;; Testing read of vectors [+ 1 2] ;=>[+ 1 2] @@ -71,7 +70,6 @@ abc-def [ + 1 [+ 2 3 ] ] ;=>[+ 1 [+ 2 3]] - ;; Testing read of hash maps {"abc" 1} ;=>{"abc" 1} @@ -109,4 +107,11 @@ abc-def @a ;=>(deref a) - +;; +;; Testing reader errors +(1 2 +; expected ')', got EOF +[1 2 +; expected ']', got EOF +"abc +; expected '"', got EOF diff --git a/tests/step2_eval.mal b/tests/step2_eval.mal index 33c7b17..b24af93 100644 --- a/tests/step2_eval.mal +++ b/tests/step2_eval.mal @@ -11,6 +11,9 @@ (/ (- (+ 5 (* 2 3)) 3) 4) ;=>2 +(abc 1 2 3) +; .*\'abc\' not found.* + ;; Testing evaluation within collection literals [1 2 (+ 1 2)] ;=>[1 2 3] |
