Added predicate primitives.
[scheme.forth.jl.git] / scheme.4th
index 1f02114..1953cf9 100644 (file)
@@ -6,13 +6,14 @@ include defer-is.4th
 
 \ ------ Types ------
 
-0 constant number-type
+0 constant fixnum-type
 1 constant boolean-type
 2 constant character-type
 3 constant string-type
 4 constant nil-type
 5 constant pair-type
 6 constant symbol-type
+7 constant primitive-type
 : istype? ( obj type -- obj bool )
     over = ;
 
@@ -257,8 +258,52 @@ global-env setobj
 
 \ }}}
 
+\ ---- Primitives ---- {{{
+
+: make-primitive ( cfa -- )
+    bl word
+    count
+
+    (create-symbol)
+    drop symbol-type
+    
+    2dup
+
+    symbol-table fetchobj
+    cons
+    symbol-table setobj
+
+    rot primitive-type ( var prim )
+    global-env fetchobj define-var
+;
+
+: arg-count-error
+            bold fg red ." Incorrect argument count." reset-term cr
+            abort
+;
+
+: ensure-arg-count ( args n -- )
+    dup 0= if
+        drop nil objeq? false = if
+            arg-count-error
+        then
+    else
+        -rot 2dup nil objeq? if
+            arg-count-error
+        then
+        
+        cdr rot 1- recurse
+    then
+;
+
+include scheme-primitives.4th
+
+\ }}}
+
 \ ---- Read ---- {{{
 
+defer read
+
 variable parse-idx
 variable stored-parse-idx
 create parse-str 161 allot
@@ -337,10 +382,20 @@ parse-idx-stack parse-idx-sp !
 : minus? ( -- bool )
     nextchar [char] - = ;
 
-: number? ( -- bool )
-    digit? minus? or false = if
-        false
-        exit
+: fixnum? ( -- bool )
+    minus? if
+        inc-parse-idx
+
+        delim? if
+            dec-parse-idx
+            false exit
+        else
+            dec-parse-idx
+        then
+    else
+        digit? false = if
+            false exit
+        then
     then
 
     push-parse-idx
@@ -440,7 +495,7 @@ parse-idx-stack parse-idx-sp !
 
     swap if negate then
 
-    number-type
+    fixnum-type
 ;
 
 : readbool ( -- bool-atom )
@@ -566,8 +621,6 @@ parse-idx-stack parse-idx-sp !
     symbol-table setobj
 ;
 
-defer read
-
 : readpair ( -- pairobj )
     eatspaces
 
@@ -615,7 +668,7 @@ defer read
 
     eatspaces
 
-    number? if
+    fixnum? if
         readnum
         exit
     then
@@ -688,7 +741,7 @@ defer eval
 
 : self-evaluating? ( obj -- obj bool )
     boolean-type istype? if true exit then
-    number-type istype? if true exit then
+    fixnum-type istype? if true exit then
     character-type istype? if true exit then
     string-type istype? if true exit then
     nil-type istype? if true exit then
@@ -784,9 +837,39 @@ defer eval
     then
 ;
 
-: true? ( boolobj -- boolean )
+: true? ( boolobj -- bool )
     false? invert ;
 
+: application? ( obj -- obj bool)
+    pair-type istype? ;
+
+: operator ( obj -- operator )
+    car ;
+
+: operands ( obj -- operands )
+    cdr ;
+
+: nooperands? ( operands -- bool )
+    nil objeq? ;
+
+: first-operand ( operands -- operand )
+    car ;
+
+: rest-operands ( operands -- other-operands )
+    cdr ;
+
+: list-of-vals ( args env -- vals )
+    2swap
+
+    2dup nooperands? if
+        2swap 2drop
+    else
+        2over 2over first-operand 2swap eval
+        -2rot rest-operands 2swap recurse
+        cons
+    then
+;
+
 :noname ( obj env -- result )
     2swap
 
@@ -830,6 +913,22 @@ defer eval
         2swap ['] eval goto
     then
 
+    application? if
+        2over 2over
+        operator 2swap eval
+
+        primitive-type istype? false = if
+            bold fg red ." Object not applicable. Aboring." reset-term cr
+            abort
+        then
+
+        -2rot
+        operands 2swap list-of-vals
+
+        2swap drop execute
+        exit
+    then
+
     bold fg red ." Error evaluating expression - unrecognized type. Aborting." reset-term cr
     abort
 ; is eval
@@ -838,6 +937,8 @@ defer eval
 
 \ ---- Print ---- {{{
 
+defer print
+
 : printnum ( numobj -- ) drop 0 .R ;
 
 : printbool ( numobj -- )
@@ -887,7 +988,6 @@ defer eval
 : printnil ( nilobj -- )
     2drop ." ()" ;
 
-defer print
 : printpair ( pairobj -- )
     2dup
     car print
@@ -897,14 +997,18 @@ defer print
     ."  . " print
 ;
 
+: printprim ( primobj -- )
+    2drop ." <primitive procedure>" ;
+
 :noname ( obj -- )
-    number-type istype? if printnum exit then
+    fixnum-type istype? if printnum exit then
     boolean-type istype? if printbool exit then
     character-type istype? if printchar exit then
     string-type istype? if printstring exit then
     symbol-type istype? if printsymbol exit then
     nil-type istype? if printnil exit then
     pair-type istype? if ." (" printpair ." )" exit then
+    primitive-type istype? if printprim exit then
 
     bold fg red ." Error printing expression - unrecognized type. Aborting" reset-term cr
     abort