make, swift3: fix parsing empty literal sequences.
[jackhill/mal.git] / ps / step6_file.ps
index 2172942..b1a7dde 100644 (file)
@@ -1,7 +1,13 @@
-(types.ps) run
-(reader.ps) run
+/runlibfile where { pop }{ /runlibfile { run } def } ifelse % 
+(types.ps) runlibfile
+(reader.ps) runlibfile
+(printer.ps) runlibfile
+(env.ps) runlibfile
+(core.ps) runlibfile
 
 % read
+/_readline { print flush (%stdin) (r) file 1024 string readline } def
+
 /READ {
     /str exch def
     str read_str
     %(eval_ast: ) print ast ==
     ast _symbol? { %if symbol
         env ast env_get
-    }{ ast _list? { %elseif list
+    }{ ast _sequential? { %elseif list or vector
         [
-            ast {
+            ast /data get { %forall items
+                env EVAL
+            } forall
+        ] ast _list? { _list_from_array }{ _vector_from_array } ifelse
+    }{ ast _hash_map? { %elseif list or vector
+        <<
+            ast /data get { %forall entries
                 env EVAL
             } forall
-        ]
+        >> _hash_map_from_dict
     }{ % else
         ast
-    } ifelse } ifelse
+    } ifelse } ifelse } ifelse
 end } def
 
 /EVAL { 13 dict begin
@@ -37,67 +49,65 @@ end } def
     ast _list? not { %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
+        /a0 ast 0 _nth def
+        a0 _nil? { %if ()
+            ast
+        }{ /def! a0 eq { %if def!
+            /a1 ast 1 _nth def
+            /a2 ast 2 _nth 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
+            /a1 ast 1 _nth def
+            /a2 ast 2 _nth def
+            /let_env env null null env_new def
+            0 2 a1 _count 1 sub { %for each pair
                 /idx exch def
                 let_env
-                    a1 idx get
-                    a1 idx 1 add get let_env EVAL
+                    a1 idx _nth
+                    a1 idx 1 add _nth let_env EVAL
                     env_set
                     pop % discard the return value
             } for
-            a2 let_env EVAL
+            a2
+            let_env
+            /loop? true def % loop
         }{ /do a0 eq { %if do
-            ast length 2 gt { %if ast has more than 2 elements
-                ast 1 ast length 2 sub getinterval env eval_ast pop
+            ast _count 2 gt { %if ast has more than 2 elements
+                ast 1 ast _count 2 sub _slice env eval_ast pop
             } if
-            ast ast length 1 sub get % last ast becomes new ast
+            ast ast _count 1 sub _nth % last ast becomes new ast
             env
             /loop? true def % loop
         }{ /if a0 eq { %if if
-            /a1 ast 1 get def
+            /a1 ast 1 _nth 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 with a3
-                    ast 3 get env
+                ast _count 3 gt { %if false branch with a3
+                    ast 3 _nth env
                     /loop? true def
                 }{ % else false branch with no a3
                     null
                 } ifelse
             }{ % true branch
-                ast 2 get env
+                ast 2 _nth env
                 /loop? true def
             } ifelse
         }{ /fn* a0 eq { %if fn*
-            /a1 ast 1 get def
-            /a2 ast 2 get def
-            <<
-                /type /_maltype_function % user defined function
-                /params null % close over parameters
-                /ast null    % close over ast
-                /env null    % close over environment
-            >>
-            dup length dict copy % make an actual copy/new instance
-            dup /params a1 put  % insert closed over a1 into position 2
-            dup /ast a2 put  % insert closed over a2 into position 3
-            dup /env env put % insert closed over env into position 4
+            /a1 ast 1 _nth def
+            /a2 ast 2 _nth def
+            a2 env a1 _mal_function
         }{
             /el ast env eval_ast def
-            el _first _mal_function? { % if user defined function
-                el _rest el _first fload % stack: ast new_env
+            el _rest el _first % stack: ast function
+            dup _mal_function? { %if user defined function
+                fload % stack: ast new_env
                 /loop? true def
+            }{ dup _function? { %else if builtin function
+                /data get exec
             }{ %else (regular procedure/function)
-                el _rest el _first exec % apply function to args
-            } ifelse
-        } ifelse } ifelse } ifelse } ifelse } ifelse
+                (cannot apply native proc!\n) print quit
+            } ifelse } ifelse
+        } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse
     } ifelse
 
     loop? not { exit } if
@@ -112,41 +122,36 @@ end } def
 
 
 % repl
-/repl_env null [ ] [ ] env_new def
+/repl_env null null 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
-
-(read-string) { 0 get read_str } _ref
-(eval) { 0 get repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 get slurp } _ref
+% core.ps: defined using postscript
+/_ref { repl_env 3 1 roll env_set pop } def
+core_ns { _function _ref } forall
+(eval) { 0 _nth repl_env EVAL } _function _ref
+(*ARGV*) [ ] _list_from_array _ref
 
+% core.mal: defined using the language itself
 (\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
 (\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
 
-/stdin (%stdin) (r) file def 
-
 userdict /ARGUMENTS known { %if command line arguments
     ARGUMENTS length 0 gt { %if more than 0 arguments
-        ARGUMENTS {
-            (\(load-file ") exch ("\)) concatenate concatenate RE pop
-        } forall
+        (*ARGV*) ARGUMENTS 1 ARGUMENTS length 1 sub getinterval
+        _list_from_array _ref
+        ARGUMENTS 0 get 
+        (\(load-file ") exch ("\)) concatenate concatenate RE pop
         quit
     } if
 } if
-{ % loop
-    (user> ) print flush
-
-    stdin 99 string readline
 
+% repl loop
+{ %loop
+    (user> ) _readline
     not { exit } if  % exit if EOF
 
-    %(\ngot line: ) print dup print (\n) print flush
-
     { %try
         REP print (\n) print
     } stopped {
@@ -155,6 +160,7 @@ userdict /ARGUMENTS known { %if command line arguments
         $error /newerror false put
         $error /errorinfo null put
         clear
+        cleardictstack
     } if
 } bind loop