aboutsummaryrefslogtreecommitdiff
path: root/ps
diff options
context:
space:
mode:
Diffstat (limited to 'ps')
-rw-r--r--ps/reader.ps14
-rw-r--r--ps/step1_read_print.ps16
-rw-r--r--ps/step2_eval.ps19
-rw-r--r--ps/step3_env.ps16
-rw-r--r--ps/types.ps133
5 files changed, 149 insertions, 49 deletions
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