Basic: smarter ALLOC. Keywords. Vector fixes.
authorJoel Martin <github@martintribe.org>
Sat, 15 Oct 2016 04:48:03 +0000 (23:48 -0500)
committerJoel Martin <github@martintribe.org>
Sat, 15 Oct 2016 04:48:03 +0000 (23:48 -0500)
- Modify ALLOC to take a type (rather than size) and take default
  values to set for the 1-3 values/pointers. Let alloc do the
  ownership taking of the referred values when appropriate.
- Add FORCE_SEQ_TYPE function to coerce sequence to given type. Fixes
  apply and rest on vector. Simplifies concat.
- Use a double ON GOTO structure for calling the native functions in
  DO_FUNCTION.
- Add some stub core functions.
- Move CHECK_FREE_LIST to debug.in.bas
- All changes together save over 1K

16 files changed:
basic/core.in.bas
basic/debug.in.bas
basic/env.in.bas
basic/printer.in.bas
basic/reader.in.bas
basic/step2_eval.in.bas
basic/step3_env.in.bas
basic/step4_if_fn_do.in.bas
basic/step5_tco.in.bas
basic/step6_file.in.bas
basic/step7_quote.in.bas
basic/step8_macros.in.bas
basic/step9_try.in.bas
basic/stepA_mal.in.bas
basic/types.in.bas
basic/variables.txt

index fcbd6d3..b3dccb6 100644 (file)
@@ -9,24 +9,21 @@ DO_FUNCTION:
   R=Z%(AR,1)+1:GOSUB DEREF_R:AB=R
 
   REM Switch on the function number
-  IF FF>=61 THEN ER=-1:ER$="unknown function"+STR$(FF):RETURN
-  IF FF>=53 THEN DO_53
-  IF FF>=39 THEN DO_39
-  IF FF>=27 THEN DO_27
-  IF FF>=18 THEN DO_18
-  IF FF>=11 THEN DO_11
-
-  ON FF GOTO DO_EQUAL_Q,DO_THROW,DO_NIL_Q,DO_TRUE_Q,DO_FALSE_Q,DO_STRING_Q,DO_SYMBOL,DO_SYMBOL_Q
-  DO_11:
-  ON FF-10 GOTO DO_PR_STR,DO_STR,DO_PRN,DO_PRINTLN,DO_READ_STRING,DO_READLINE,DO_SLURP
-  DO_18:
-  ON FF-17 GOTO DO_LT,DO_LTE,DO_GT,DO_GTE,DO_ADD,DO_SUB,DO_MULT,DO_DIV,DO_TIME_MS
-  DO_27:
-  ON FF-26 GOTO DO_LIST,DO_LIST_Q,DO_VECTOR,DO_VECTOR_Q,DO_HASH_MAP,DO_MAP_Q
-  DO_39:
-  ON FF-38 GOTO DO_SEQUENTIAL_Q,DO_CONS,DO_CONCAT,DO_NTH,DO_FIRST,DO_REST,DO_EMPTY_Q,DO_COUNT,DO_APPLY,DO_MAP
-  DO_53:
-  ON FF-52 GOTO DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_SWAP_BANG,DO_PR_MEMORY,DO_PR_MEMORY_SUMMARY,DO_EVAL
+  IF FF>58 THEN ER=-1:ER$="unknown function"+STR$(FF):RETURN
+  ON FF/10+1 GOTO DO_1_9,DO_10_19,DO_20_29,DO_30_39,DO_40_49,DO_50_59
+
+  DO_1_9:
+  ON FF GOTO DO_EQUAL_Q,DO_THROW,DO_NIL_Q,DO_TRUE_Q,DO_FALSE_Q,DO_STRING_Q,DO_SYMBOL,DO_SYMBOL_Q,DO_KEYWORD
+  DO_10_19:
+  ON FF-9 GOTO DO_KEYWORD_Q,DO_PR_STR,DO_STR,DO_PRN,DO_PRINTLN,DO_READ_STRING,DO_READLINE,DO_SLURP,DO_LT,DO_LTE
+  DO_20_29:
+  ON FF-19 GOTO DO_GT,DO_GTE,DO_ADD,DO_SUB,DO_MULT,DO_DIV,DO_TIME_MS,DO_LIST,DO_LIST_Q,DO_VECTOR
+  DO_30_39:
+  ON FF-29 GOTO DO_VECTOR_Q,DO_HASH_MAP,DO_MAP_Q,DO_THROW,DO_THROW,DO_THROW,DO_THROW,DO_THROW,DO_THROW,DO_SEQUENTIAL_Q
+  DO_40_49:
+  ON FF-39 GOTO DO_CONS,DO_CONCAT,DO_NTH,DO_FIRST,DO_REST,DO_EMPTY_Q,DO_COUNT,DO_APPLY,DO_MAP,DO_THROW
+  DO_50_59:
+  ON FF-49 GOTO DO_THROW,DO_THROW,DO_THROW,DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_SWAP_BANG,DO_EVAL
 
   DO_EQUAL_Q:
     A=AA:B=AB:GOSUB EQUAL_Q
@@ -54,20 +51,33 @@ DO_FUNCTION:
     IF (Z%(AA,0)AND15)=4 THEN R=2
     RETURN
   DO_SYMBOL:
-    R=0
+    T=5:L=Z%(AA,1):GOSUB ALLOC
     RETURN
   DO_SYMBOL_Q:
     R=1
     IF (Z%(AA,0)AND15)=5 THEN R=2
     RETURN
+  DO_KEYWORD:
+    A=Z%(AA,1)
+    AS$=S$(A)
+    IF MID$(AS$,1,1)<>CHR$(127) THEN AS$=CHR$(127)+AS$
+    GOSUB STRING_
+    T=4:L=R:GOSUB ALLOC
+    RETURN
+  DO_KEYWORD_Q:
+    R=1
+    IF (Z%(AA,0)AND15)<>4 THEN RETURN
+    IF MID$(S$(Z%(AA,1)),1,1)<>CHR$(127) THEN RETURN
+    R=2
+    RETURN
 
   DO_PR_STR:
     AZ=AR:PR=1:SE$=" ":GOSUB PR_STR_SEQ
-    AS$=R$:T=4+16:GOSUB STRING
+    AS$=R$:T=4:GOSUB STRING
     RETURN
   DO_STR:
     AZ=AR:PR=0:SE$="":GOSUB PR_STR_SEQ
-    AS$=R$:T=4+16:GOSUB STRING
+    AS$=R$:T=4:GOSUB STRING
     RETURN
   DO_PRN:
     AZ=AR:PR=1:SE$=" ":GOSUB PR_STR_SEQ
@@ -87,7 +97,6 @@ DO_FUNCTION:
     A$=S$(Z%(AA,1)):GOSUB READLINE
     IF EOF=1 THEN EOF=0:R=0:RETURN
     AS$=R$:T=4:GOSUB STRING
-    Z%(R,0)=Z%(R,0)+16
     RETURN
   DO_SLURP:
     R$=""
@@ -104,7 +113,7 @@ DO_FUNCTION:
       GOTO DO_SLURP_LOOP
     DO_SLURP_DONE:
       CLOSE 1
-      AS$=R$:T=4+16:GOSUB STRING
+      AS$=R$:T=4:GOSUB STRING
       RETURN
 
   DO_LT:
@@ -125,24 +134,16 @@ DO_FUNCTION:
     RETURN
 
   DO_ADD:
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=Z%(AA,1)+Z%(AB,1)
+    T=2:L=Z%(AA,1)+Z%(AB,1):GOSUB ALLOC
     RETURN
   DO_SUB:
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=Z%(AA,1)-Z%(AB,1)
+    T=2:L=Z%(AA,1)-Z%(AB,1):GOSUB ALLOC
     RETURN
   DO_MULT:
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=Z%(AA,1)*Z%(AB,1)
+    T=2:L=Z%(AA,1)*Z%(AB,1):GOSUB ALLOC
     RETURN
   DO_DIV:
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=Z%(AA,1)/Z%(AB,1)
+    T=2:L=Z%(AA,1)/Z%(AB,1):GOSUB ALLOC
     RETURN
   DO_TIME_MS:
     R=0
@@ -157,14 +158,14 @@ DO_FUNCTION:
     R=R+1: REM map to mal false/true
     RETURN
   DO_VECTOR:
-    R=0
+    A=AR:T=7:GOSUB FORCE_SEQ_TYPE
     RETURN
   DO_VECTOR_Q:
     R=1
     IF (Z%(AA,0)AND15)=7 THEN R=2
     RETURN
   DO_HASH_MAP:
-    R=0
+    A=AR:T=8:GOSUB FORCE_SEQ_TYPE
     RETURN
   DO_MAP_Q:
     R=1
@@ -176,7 +177,7 @@ DO_FUNCTION:
     IF (Z%(AA,0)AND15)=6 OR (Z%(AA,0)AND15)=7 THEN R=2
     RETURN
   DO_CONS:
-    A=AA:B=AB:GOSUB CONS
+    T=6:L=AB:N=AA:GOSUB ALLOC
     RETURN
   DO_CONCAT:
     REM if empty arguments, return empty list
@@ -184,16 +185,8 @@ DO_FUNCTION:
 
     REM single argument
     IF Z%(Z%(AR,1),1)<>0 THEN GOTO DO_CONCAT_MULT
-      REM if single argument and it's a list, return it
-      IF (Z%(AA,0)AND15)=6 THEN R=AA:Z%(R,0)=Z%(R,0)+16:RETURN
-      REM otherwise, copy first element to turn it into a list
-      B=AA+1:GOSUB DEREF_B: REM value to copy
-      SZ=2:GOSUB ALLOC
-      Z%(R,0)=6+16:Z%(R,1)=Z%(AA,1)
-      Z%(R+1,0)=14:Z%(R+1,1)=B
-      REM inc ref count of trailing list part and of copied value
-      Z%(Z%(AA,1),0)=Z%(Z%(AA,1),0)+16
-      Z%(B,0)=Z%(B,0)+16
+      REM force to list type
+      A=AA:T=6:GOSUB FORCE_SEQ_TYPE
       RETURN
 
     REM multiple arguments
@@ -238,32 +231,35 @@ DO_FUNCTION:
       Z%(R,0)=Z%(R,0)+16
       RETURN
   DO_FIRST:
+    IF AA=0 THEN R=0:RETURN
     IF Z%(AA,1)=0 THEN R=0
     IF Z%(AA,1)<>0 THEN R=AA+1:GOSUB DEREF_R
     IF R<>0 THEN Z%(R,0)=Z%(R,0)+16
     RETURN
   DO_REST:
-    IF Z%(AA,1)=0 THEN R=AA
-    IF Z%(AA,1)<>0 THEN R=Z%(AA,1)
-    Z%(R,0)=Z%(R,0)+16
+    IF AA=0 THEN R=3:Z%(R,0)=Z%(R,0)+16:RETURN
+    IF Z%(AA,1)=0 THEN A=AA
+    IF Z%(AA,1)<>0 THEN A=Z%(AA,1)
+    T=6:GOSUB FORCE_SEQ_TYPE
     RETURN
   DO_EMPTY_Q:
     R=1
     IF Z%(AA,1)=0 THEN R=2
     RETURN
   DO_COUNT:
-    A=AA:GOSUB COUNT:R4=R
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=R4
+    A=AA:GOSUB COUNT
+    T=2:L=R:GOSUB ALLOC
     RETURN
   DO_APPLY:
     F=AA
     AR=Z%(AR,1)
     A=AR:GOSUB COUNT:R4=R
 
+    A=Z%(AR+1,1)
+    REM no intermediate args, but not a list, so convert it first
+    IF R4<=1 AND (Z%(A,0)AND15)<>6 THEN :T=6:GOSUB FORCE_SEQ_TYPE:GOTO DO_APPLY_2
     REM no intermediate args, just call APPLY directly
-    IF R4<=1 THEN AR=Z%(AR+1,1):GOSUB APPLY:RETURN
+    IF R4<=1 THEN AR=A:GOSUB APPLY:RETURN
 
     REM prepend intermediate args to final args element
     A=AR:B=0:C=R4-1:GOSUB SLICE
@@ -273,24 +269,21 @@ DO_FUNCTION:
     Z%(R6,1)=Z%(A+1,1)
     Z%(Z%(A+1,1),0)=Z%(Z%(A+1,1),0)+16
 
-    X=X+1:S%(X)=R: REM push/save new args for release
-    AR=R:GOSUB APPLY
-    AY=S%(X):X=X-1:GOSUB RELEASE: REM pop/release new args
-    RETURN
+    DO_APPLY_2:
+      X=X+1:S%(X)=R: REM push/save new args for release
+      AR=R:GOSUB APPLY
+      AY=S%(X):X=X-1:GOSUB RELEASE: REM pop/release new args
+      RETURN
   DO_MAP:
     F=AA
 
     REM first result list element
-    SZ=2:GOSUB ALLOC
+    T=6:L=0:N=0:GOSUB ALLOC
 
     REM push future return val, prior entry, F and AB
     X=X+4:S%(X-3)=R:S%(X-2)=0:S%(X-1)=F:S%(X)=AB
 
     DO_MAP_LOOP:
-      REM set base values
-      Z%(R,0)=6+16:Z%(R,1)=0
-      Z%(R+1,0)=14:Z%(R+1,1)=0
-
       REM set previous to current if not the first element
       IF S%(X-2)<>0 THEN Z%(S%(X-2),1)=R
       REM update previous reference to current
@@ -299,15 +292,9 @@ DO_FUNCTION:
       IF Z%(AB,1)=0 THEN GOTO DO_MAP_DONE
 
       REM create argument list for apply call
-      SZ=2:GOSUB ALLOC
-      Z%(R,0)=6+16:Z%(R,1)=0
-      Z%(R+1,0)=14:Z%(R+1,1)=0
-      AR=R: REM save end of list temporarily
-      SZ=2:GOSUB ALLOC
-      Z%(R,0)=6+16:Z%(R,1)=AR
+      Z%(3,0)=Z%(3,0)+16
       REM inc ref cnt of referred argument
-      A=Z%(AB+1,1): Z%(A,0)=Z%(A,0)+16
-      Z%(R+1,0)=14:Z%(R+1,1)=A
+      T=6:L=3:N=Z%(AB+1,1):GOSUB ALLOC
 
       REM push argument list
       X=X+1:S%(X)=R
@@ -328,7 +315,7 @@ DO_FUNCTION:
       AB=S%(X)
 
       REM allocate next element
-      SZ=2:GOSUB ALLOC
+      T=6:L=0:N=0:GOSUB ALLOC
 
       GOTO DO_MAP_LOOP
 
@@ -340,10 +327,7 @@ DO_FUNCTION:
       RETURN
 
   DO_ATOM:
-    SZ=1:GOSUB ALLOC
-    Z%(AA,0)=Z%(AA,0)+16: REM inc ref cnt of contained value
-    Z%(R,0)=12+16
-    Z%(R,1)=AA
+    T=12:L=AA:GOSUB ALLOC
     RETURN
   DO_ATOM_Q:
     R=1
@@ -366,7 +350,7 @@ DO_FUNCTION:
     F=AB
 
     REM add atom to front of the args list
-    A=Z%(AA,1):B=Z%(Z%(AR,1),1):GOSUB CONS
+    T=6:L=Z%(Z%(AR,1),1):N=Z%(AA,1):GOSUB ALLOC: REM cons
     AR=R
 
     REM push args for release after
@@ -420,6 +404,8 @@ INIT_CORE_NS:
   K$="string?":A=6:GOSUB INIT_CORE_SET_FUNCTION
   K$="symbol":A=7:GOSUB INIT_CORE_SET_FUNCTION
   K$="symbol?":A=8:GOSUB INIT_CORE_SET_FUNCTION
+  K$="keyword":A=9:GOSUB INIT_CORE_SET_FUNCTION
+  K$="keyword?":A=10:GOSUB INIT_CORE_SET_FUNCTION
 
   K$="pr-str":A=11:GOSUB INIT_CORE_SET_FUNCTION
   K$="str":A=12:GOSUB INIT_CORE_SET_FUNCTION
@@ -445,6 +431,12 @@ INIT_CORE_NS:
   K$="vector?":A=30:GOSUB INIT_CORE_SET_FUNCTION
   K$="hash-map":A=31:GOSUB INIT_CORE_SET_FUNCTION
   K$="map?":A=32:GOSUB INIT_CORE_SET_FUNCTION
+  K$="assoc":A=33:GOSUB INIT_CORE_SET_FUNCTION
+  K$="dissoc":A=34:GOSUB INIT_CORE_SET_FUNCTION
+  K$="get":A=35:GOSUB INIT_CORE_SET_FUNCTION
+  K$="contains?":A=36:GOSUB INIT_CORE_SET_FUNCTION
+  K$="keys":A=37:GOSUB INIT_CORE_SET_FUNCTION
+  K$="vals":A=38:GOSUB INIT_CORE_SET_FUNCTION
 
   K$="sequential?":A=39:GOSUB INIT_CORE_SET_FUNCTION
   K$="cons":A=40:GOSUB INIT_CORE_SET_FUNCTION
@@ -457,14 +449,14 @@ INIT_CORE_NS:
   K$="apply":A=47:GOSUB INIT_CORE_SET_FUNCTION
   K$="map":A=48:GOSUB INIT_CORE_SET_FUNCTION
 
+  K$="with-meta":A=51:GOSUB INIT_CORE_SET_FUNCTION
+  K$="meta":A=52:GOSUB INIT_CORE_SET_FUNCTION
   K$="atom":A=53:GOSUB INIT_CORE_SET_FUNCTION
   K$="atom?":A=54:GOSUB INIT_CORE_SET_FUNCTION
   K$="deref":A=55:GOSUB INIT_CORE_SET_FUNCTION
   K$="reset!":A=56:GOSUB INIT_CORE_SET_FUNCTION
   K$="swap!":A=57:GOSUB INIT_CORE_SET_FUNCTION
 
-  K$="pr-memory":A=58:GOSUB INIT_CORE_SET_FUNCTION
-  K$="pr-memory-summary":A=59:GOSUB INIT_CORE_SET_FUNCTION
-  K$="eval":A=60:GOSUB INIT_CORE_SET_FUNCTION
+  K$="eval":A=58:GOSUB INIT_CORE_SET_FUNCTION
 
   RETURN
index b300fe9..7f43dde 100644 (file)
@@ -1,3 +1,18 @@
+REM CHECK_FREE_LIST
+CHECK_FREE_LIST:
+  REM start and accumulator
+  P1%=ZK
+  P2%=0
+  CHECK_FREE_LIST_LOOP:
+    IF P1%>=ZI THEN GOTO CHECK_FREE_LIST_DONE
+    IF (Z%(P1%,0)AND15)<>15 THEN P2%=-1:GOTO CHECK_FREE_LIST_DONE
+    P2%=P2%+(Z%(P1%,0)AND-16)/16
+    P1%=Z%(P1%,1)
+    GOTO CHECK_FREE_LIST_LOOP
+  CHECK_FREE_LIST_DONE:
+    IF P2%=-1 THEN PRINT "corrupt free list at "+STR$(P1%)
+    RETURN
+
 PR_MEMORY_SUMMARY:
   GOSUB CHECK_FREE_LIST: REM get count in P2%
   PRINT
index 8a278f7..858f09b 100644 (file)
@@ -3,15 +3,11 @@ REM ENV_NEW(O) -> R
 ENV_NEW:
   REM allocate the data hashmap
   GOSUB HASHMAP
-  ET%=R
+  ET=R
 
   REM set the outer and data pointer
-  SZ=2:GOSUB ALLOC
-  Z%(R,0)=13+16
-  Z%(R,1)=ET%
-  Z%(R+1,0)=13
-  Z%(R+1,1)=O
-  IF O<>-1 THEN Z%(O,0)=Z%(O,0)+16
+  T=13:L=R:N=O:GOSUB ALLOC
+  AY=ET:GOSUB RELEASE: REM environment takes ownership
   RETURN
 
 REM see RELEASE types.in.bas for environment cleanup
index bde9ad4..7eb0028 100644 (file)
@@ -5,7 +5,7 @@ PR_STR:
   T=Z%(AZ,0)AND15
   REM PRINT "AZ: "+STR$(AZ)+", T: "+STR$(T)+", V: "+STR$(Z%(AZ,1))
   IF T=0 THEN R$="nil":RETURN
-  ON T GOTO PR_BOOLEAN,PR_INTEGER,PR_UNKNOWN,PR_STRING,PR_SYMBOL,PR_SEQ,PR_SEQ,PR_SEQ,PR_FUNCTION,PR_MAL_FUNCTION,PR_MAL_FUNCTION,PR_ATOM,PR_ENV,PR_RECUR,PR_FREE
+  ON T GOTO PR_BOOLEAN,PR_INTEGER,PR_UNKNOWN,PR_STRING_MAYBE,PR_SYMBOL,PR_SEQ,PR_SEQ,PR_SEQ,PR_FUNCTION,PR_MAL_FUNCTION,PR_MAL_FUNCTION,PR_ATOM,PR_ENV,PR_RECUR,PR_FREE
 
   PR_UNKNOWN:
     R$="#<unknown>"
@@ -24,12 +24,14 @@ PR_STR:
     REM Remove initial space
     R$=RIGHT$(R$, LEN(R$)-1)
     RETURN
+  PR_STRING_MAYBE:
+    R$=S$(Z%(AZ,1))
+    IF LEN(R$)=0 THEN GOTO PR_STRING
+    IF MID$(R$,1,1)=CHR$(127) THEN R$=":"+MID$(R$,2,LEN(R$)-1):RETURN
   PR_STRING:
     IF PR=1 THEN PR_STRING_READABLY
-    R$=S$(Z%(AZ,1))
     RETURN
   PR_STRING_READABLY:
-    R$=S$(Z%(AZ,1))
     S1$=CHR$(92):S2$=CHR$(92)+CHR$(92):GOSUB REPLACE: REM escape backslash
     S1$=CHR$(34):S2$=CHR$(92)+CHR$(34):GOSUB REPLACE: REM escape quotes
     S1$=CHR$(13):S2$=CHR$(92)+"n":GOSUB REPLACE: REM escape newlines
index 9e67c13..f76e7b8 100644 (file)
@@ -59,6 +59,7 @@ READ_FORM:
   IF CH$="-" THEN GOTO READ_SYMBOL_MAYBE
 
   IF CH$=CHR$(34) THEN GOTO READ_STRING
+  IF CH$=":" THEN GOTO READ_KEYWORD
   IF CH$="(" THEN T=6:GOTO READ_SEQ
   IF CH$=")" THEN T=6:GOTO READ_SEQ_END
   IF CH$="[" THEN T=7:GOTO READ_SEQ
@@ -79,9 +80,7 @@ READ_FORM:
     GOTO READ_FORM_DONE
   READ_NUMBER:
     REM PRINT "READ_NUMBER"
-    SZ=1:GOSUB ALLOC
-    Z%(R,0)=2+16
-    Z%(R,1)=VAL(T$)
+    T=2:L=VAL(T$):GOSUB ALLOC
     GOTO READ_FORM_DONE
   READ_MACRO:
     IDX%=IDX%+LEN(T$)
@@ -94,7 +93,9 @@ READ_FORM:
     SD=S%(X-1):B2%=S%(X):X=X-2: REM pop SD, pop symbol into B2%
 
     GOSUB LIST2
-    AY=B1%:GOSUB RELEASE: REM release value, list has ownership
+    REM release values, list has ownership
+    AY=B1%:GOSUB RELEASE
+    AY=B2%:GOSUB RELEASE
 
     T$=""
     GOTO READ_FORM_DONE
@@ -107,14 +108,18 @@ READ_FORM:
     S1$=CHR$(92)+"n":S2$=CHR$(13):GOSUB REPLACE: REM unescape newlines
     S1$=CHR$(92)+CHR$(92):S2$=CHR$(92):GOSUB REPLACE: REM unescape backslashes
     REM intern string value
-    AS$=R$:T=4+16:GOSUB STRING
+    AS$=R$:T=4:GOSUB STRING
+    GOTO READ_FORM_DONE
+  READ_KEYWORD:
+    R$=CHR$(127)+MID$(T$,2,LEN(T$)-1)
+    AS$=R$:T=4:GOSUB STRING
     GOTO READ_FORM_DONE
   READ_SYMBOL_MAYBE:
     CH$=MID$(T$,2,1)
     IF CH$>="0" AND CH$<="9" THEN GOTO READ_NUMBER
   READ_SYMBOL:
     REM PRINT "READ_SYMBOL"
-    AS$=T$:T=5+16:GOSUB STRING
+    AS$=T$:T=5:GOSUB STRING
     GOTO READ_FORM_DONE
 
   READ_SEQ:
@@ -122,17 +127,11 @@ READ_FORM:
     SD=SD+1: REM increase read sequence depth
 
     REM allocate first sequence entry and space for value
-    SZ=2:GOSUB ALLOC
+    L=0:N=0:GOSUB ALLOC: REM T alread set above
 
     REM set reference value/pointer to new embedded sequence
     IF SD>1 THEN Z%(S%(X)+1,1)=R
 
-    REM set the type (with 1 ref cnt) and next pointer to current end
-    Z%(R,0)=T+16
-    Z%(R,1)=0
-    Z%(R+1,0)=14
-    Z%(R+1,1)=0
-
     REM push start ptr on the stack
     X=X+1
     S%(X)=R
@@ -167,7 +166,8 @@ READ_FORM:
     REM PRINT "READ_FORM_DONE next list entry"
 
     REM allocate new sequence entry and space for value
-    SZ=2:GOSUB ALLOC
+    REM set type to previous type, with ref count of 1 (from previous)
+    T=S%(X-1):L=0:N=0:GOSUB ALLOC
 
     REM previous element
     T7=S%(X)
@@ -175,11 +175,6 @@ READ_FORM:
     Z%(T7,1)=R
     REM set the list value pointer
     Z%(T7+1,1)=T8
-    REM set type to previous type, with ref count of 1 (from previous)
-    Z%(R,0)=S%(X-1)+16
-    Z%(R,1)=0: REM current end of sequence
-    Z%(R+1,0)=14
-    Z%(R+1,1)=0
 
     IF T7=S%(X-2) THEN GOTO READ_FORM_SKIP_FIRST
     Z%(T7,1)=R
index 0098e1c..f4aa6ca 100755 (executable)
@@ -40,8 +40,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -55,13 +55,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -91,7 +84,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
@@ -180,9 +174,6 @@ DO_FUNCTION:
   R=AR+1:GOSUB DEREF_R:AA=Z%(R,1)
   R=Z%(AR,1)+1:GOSUB DEREF_R:AB=Z%(R,1)
 
-  REM Allocate the return value
-  SZ=1:GOSUB ALLOC
-
   REM Switch on the function number
   IF FF=1 THEN GOTO DO_ADD
   IF FF=2 THEN GOTO DO_SUB
@@ -191,20 +182,16 @@ DO_FUNCTION:
   ER=-1:ER$="unknown function"+STR$(FF):RETURN
 
   DO_ADD:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA+AB
+    T=2:L=AA+AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_SUB:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA-AB
+    T=2:L=AA-AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_MULT:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA*AB
+    T=2:L=AA*AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_DIV:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA/AB
+    T=2:L=AA/AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
 
   DO_FUNCTION_DONE:
index af94812..231403c 100755 (executable)
@@ -38,8 +38,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -53,13 +53,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -89,7 +82,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
@@ -250,9 +244,6 @@ DO_FUNCTION:
   R=AR+1:GOSUB DEREF_R:AA=Z%(R,1)
   R=Z%(AR,1)+1:GOSUB DEREF_R:AB=Z%(R,1)
 
-  REM Allocate the return value
-  SZ=1:GOSUB ALLOC
-
   REM Switch on the function number
   IF FF=1 THEN GOTO DO_ADD
   IF FF=2 THEN GOTO DO_SUB
@@ -261,20 +252,16 @@ DO_FUNCTION:
   ER=-1:ER$="unknown function"+STR$(FF):RETURN
 
   DO_ADD:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA+AB
+    T=2:L=AA+AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_SUB:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA-AB
+    T=2:L=AA-AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_MULT:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA*AB
+    T=2:L=AA*AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
   DO_DIV:
-    Z%(R,0)=2+16
-    Z%(R,1)=AA/AB
+    T=2:L=AA/AB:GOSUB ALLOC
     GOTO DO_FUNCTION_DONE
 
   DO_FUNCTION_DONE:
index 159e96e..1c8bd37 100755 (executable)
@@ -39,8 +39,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -54,13 +54,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -90,7 +83,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index cc45c43..d28fbd8 100755 (executable)
@@ -39,8 +39,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -54,13 +54,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -90,7 +83,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index 7b1cb41..4241df4 100755 (executable)
@@ -39,8 +39,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -54,13 +54,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -90,7 +83,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index c19f6ed..b6f4548 100755 (executable)
@@ -31,6 +31,7 @@ QUASIQUOTE:
     REM ['quote, ast]
     AS$="quote":T=5:GOSUB STRING
     B2%=R:B1%=A:GOSUB LIST2
+    AY=B2%:GOSUB RELEASE
 
     RETURN
 
@@ -67,6 +68,7 @@ QUASIQUOTE:
       B1%=T6:GOSUB LIST3
       REM release inner quasiquoted since outer list takes ownership
       AY=B1%:GOSUB RELEASE
+      AY=B3%:GOSUB RELEASE
       RETURN
 
   QQ_DEFAULT:
@@ -84,6 +86,7 @@ QUASIQUOTE:
     REM release inner quasiquoted since outer list takes ownership
     AY=B1%:GOSUB RELEASE
     AY=B2%:GOSUB RELEASE
+    AY=B3%:GOSUB RELEASE
     RETURN
 
 
@@ -112,8 +115,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -127,13 +130,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -163,7 +159,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index 9ca0dc3..871d949 100755 (executable)
@@ -31,6 +31,7 @@ QUASIQUOTE:
     REM ['quote, ast]
     AS$="quote":T=5:GOSUB STRING
     B2%=R:B1%=A:GOSUB LIST2
+    AY=B2%:GOSUB RELEASE
 
     RETURN
 
@@ -67,6 +68,7 @@ QUASIQUOTE:
       B1%=T6:GOSUB LIST3
       REM release inner quasiquoted since outer list takes ownership
       AY=B1%:GOSUB RELEASE
+      AY=B3%:GOSUB RELEASE
       RETURN
 
   QQ_DEFAULT:
@@ -84,6 +86,7 @@ QUASIQUOTE:
     REM release inner quasiquoted since outer list takes ownership
     AY=B1%:GOSUB RELEASE
     AY=B2%:GOSUB RELEASE
+    AY=B3%:GOSUB RELEASE
     RETURN
 
 REM MACROEXPAND(A, E) -> A:
@@ -147,8 +150,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -162,13 +165,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -198,7 +194,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index f9a86f3..407d62d 100755 (executable)
@@ -31,6 +31,7 @@ QUASIQUOTE:
     REM ['quote, ast]
     AS$="quote":T=5:GOSUB STRING
     B2%=R:B1%=A:GOSUB LIST2
+    AY=B2%:GOSUB RELEASE
 
     RETURN
 
@@ -67,6 +68,7 @@ QUASIQUOTE:
       B1%=T6:GOSUB LIST3
       REM release inner quasiquoted since outer list takes ownership
       AY=B1%:GOSUB RELEASE
+      AY=B3%:GOSUB RELEASE
       RETURN
 
   QQ_DEFAULT:
@@ -84,6 +86,7 @@ QUASIQUOTE:
     REM release inner quasiquoted since outer list takes ownership
     AY=B1%:GOSUB RELEASE
     AY=B2%:GOSUB RELEASE
+    AY=B3%:GOSUB RELEASE
     RETURN
 
 REM MACROEXPAND(A, E) -> A:
@@ -147,8 +150,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -162,13 +165,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -198,7 +194,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index f2d0eff..ed39522 100755 (executable)
@@ -31,6 +31,7 @@ QUASIQUOTE:
     REM ['quote, ast]
     AS$="quote":T=5:GOSUB STRING
     B2%=R:B1%=A:GOSUB LIST2
+    AY=B2%:GOSUB RELEASE
 
     RETURN
 
@@ -67,6 +68,7 @@ QUASIQUOTE:
       B1%=T6:GOSUB LIST3
       REM release inner quasiquoted since outer list takes ownership
       AY=B1%:GOSUB RELEASE
+      AY=B3%:GOSUB RELEASE
       RETURN
 
   QQ_DEFAULT:
@@ -84,6 +86,7 @@ QUASIQUOTE:
     REM release inner quasiquoted since outer list takes ownership
     AY=B1%:GOSUB RELEASE
     AY=B2%:GOSUB RELEASE
+    AY=B3%:GOSUB RELEASE
     RETURN
 
 REM MACROEXPAND(A, E) -> A:
@@ -147,8 +150,8 @@ EVAL_AST:
     GOTO EVAL_AST_RETURN
 
   EVAL_AST_SEQ:
-    REM allocate the first entry
-    SZ=2:GOSUB ALLOC
+    REM allocate the first entry (T already set above)
+    L=0:N=0:GOSUB ALLOC
 
     REM make space on the stack
     X=X+4
@@ -162,13 +165,6 @@ EVAL_AST:
     S%(X)=R
 
     EVAL_AST_SEQ_LOOP:
-      REM set new sequence entry type (with 1 ref cnt)
-      Z%(R,0)=S%(X-3)+16
-      Z%(R,1)=0
-      REM create value ptr placeholder
-      Z%(R+1,0)=14
-      Z%(R+1,1)=0
-
       REM update index
       S%(X-2)=S%(X-2)+1
 
@@ -198,7 +194,8 @@ EVAL_AST:
       IF ER<>-2 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
 
       REM allocate the next entry
-      SZ=2:GOSUB ALLOC
+      REM same new sequence entry type
+      T=S%(X-3):L=0:N=0:GOSUB ALLOC
 
       REM update previous sequence entry value to point to new entry
       Z%(S%(X),1)=R
index 2c39624..5b49f63 100644 (file)
@@ -6,11 +6,11 @@ REM float              3   ->  ???
 REM string/kw          4   ->  S$ index
 REM symbol             5   ->  S$ index
 REM list next/val      6   ->  next Z% index (0 for last)
-REM                    followed by value (unless empty)
+REM                    followed by 14 and value (unless empty)
 REM vector next/val    7   ->  next Z% index (0 for last)
-REM                    followed by value (unless empty)
+REM                    followed by 14 and value (unless empty)
 REM hashmap next/val   8   ->  next Z% index (0 for last)
-REM                    followed by key or value (alternating)
+REM                    followed by 14 and key/value (alternating)
 REM function           9   ->  function index
 REM mal function       10  ->  body AST Z% index
 REM                    followed by param and env Z% index
@@ -18,7 +18,7 @@ REM macro (same as 10) 11  ->  body AST Z% index
 REM                    followed by param and env Z% index
 REM atom               12  ->  Z% index
 REM environment        13  ->  data/hashmap Z% index
-REM                    followed by 13 and outer Z% index (-1 for none)
+REM                    followed by 14 and outer Z% index (-1 for none)
 REM reference/ptr      14  ->  Z% index / or 0
 REM next free ptr      15  ->  Z% index / or 0
 
@@ -66,11 +66,19 @@ INIT_MEMORY:
   REM PRINT "Interpreter working memory: "+STR$(FRE(0))
   RETURN
 
+
 REM memory functions
 
-REM ALLOC(SZ) -> R
+REM ALLOC(T,L) -> R
+REM ALLOC(T,L,N) -> R
+REM ALLOC(T,L,M,N) -> R
+REM L is default for Z%(R,1)
+REM M is default for Z%(R+1,0), if relevant for T
+REM N is default for Z%(R+1,1), if relevant for T
 ALLOC:
-  REM PRINT "ALLOC SZ: "+STR$(SZ)+", ZK: "+STR$(ZK)
+  SZ=2
+  IF T<6 OR T=9 OR T=12 OR T>13 THEN SZ=1
+  REM PRINT "ALLOC T: "+STR$(T)+", SZ: "+STR$(SZ)+", ZK: "+STR$(ZK)
   U3=ZK
   U4=ZK
   ALLOC_LOOP:
@@ -88,7 +96,7 @@ ALLOC:
     IF U4=ZK THEN ZK=Z%(U4,1)
     REM set previous free to next free
     IF U4<>ZK THEN Z%(U3,1)=Z%(U4,1)
-    RETURN
+    GOTO ALLOC_DONE
   ALLOC_UNUSED:
     REM PRINT "ALLOC_UNUSED ZI: "+STR$(ZI)+", U3: "+STR$(U3)+", U4: "+STR$(U4)
     R=U4
@@ -96,6 +104,22 @@ ALLOC:
     IF U3=U4 THEN ZK=ZI
     REM set previous free to new memory top
     IF U3<>U4 THEN Z%(U3,1)=ZI
+    GOTO ALLOC_DONE
+  ALLOC_DONE:
+    Z%(R,0)=T+16
+    REM set Z%(R,1) to default L
+    IF T>=6 AND T<>9 AND L>0 THEN Z%(L,0)=Z%(L,0)+16
+    Z%(R,1)=L
+
+    IF SZ=1 THEN RETURN
+    Z%(R+1,0)=14: REM default for 6-8, and 13
+
+    REM function/macro sets Z%(R+1,0) to default M
+    IF T=10 OR T=11 THEN Z%(M,0)=Z%(M,0)+16:Z%(R+1,0)=M
+
+    REM seq, function/macro, environment sets Z%(R+1,1) to default N
+    IF N>0 THEN Z%(N,0)=Z%(N,0)+16
+    Z%(R+1,1)=N
     RETURN
 
 REM FREE(AY, SZ) -> nil
@@ -224,20 +248,6 @@ DEREF_B:
   IF (Z%(B,0)AND15)=14 THEN B=Z%(B,1):GOTO DEREF_B
   RETURN
 
-CHECK_FREE_LIST:
-  REM start and accumulator
-  P1%=ZK
-  P2%=0
-  CHECK_FREE_LIST_LOOP:
-    IF P1%>=ZI THEN GOTO CHECK_FREE_LIST_DONE
-    IF (Z%(P1%,0)AND15)<>15 THEN P2%=-1:GOTO CHECK_FREE_LIST_DONE
-    P2%=P2%+(Z%(P1%,0)AND-16)/16
-    P1%=Z%(P1%,1)
-    GOTO CHECK_FREE_LIST_LOOP
-  CHECK_FREE_LIST_DONE:
-    IF P2%=-1 THEN PRINT "corrupt free list at "+STR$(P1%)
-    RETURN
-
 
 REM general functions
 
@@ -247,9 +257,9 @@ EQUAL_Q:
   GOSUB DEREF_B
 
   R=0
-  U1=(Z%(A,0)AND15)
-  U2=(Z%(B,0)AND15)
-  IF NOT ((U1=U2) OR ((U1=6 OR U1=7) AND (U2=6 OR U2=7))) THEN RETURN
+  U1=Z%(A,0)AND15
+  U2=Z%(B,0)AND15
+  IF NOT (U1=U2 OR ((U1=6 OR U1=7) AND (U2=6 OR U2=7))) THEN RETURN
   IF U1=6 THEN GOTO EQUAL_Q_SEQ
   IF U1=7 THEN GOTO EQUAL_Q_SEQ
   IF U1=8 THEN GOTO EQUAL_Q_HM
@@ -297,10 +307,7 @@ REM STRING(AS$, T) -> R
 REM intern string and allocate reference (return Z% index)
 STRING:
   GOSUB STRING_
-  TS%=R
-  SZ=1:GOSUB ALLOC
-  Z%(R,0)=T
-  Z%(R,1)=TS%
+  L=R:GOSUB ALLOC
   RETURN
 
 REM REPLACE(R$, S1$, S2$) -> R$
@@ -317,7 +324,18 @@ REPLACE:
     GOTO REPLACE_LOOP
 
 
-REM list functions
+REM sequence functions
+
+REM FORCE_SEQ_TYPE(A,T) -> R
+FORCE_SEQ_TYPE:
+  REM if it's already the right type, inc ref cnt and return it
+  IF (Z%(A,0)AND15)=T THEN R=A:Z%(R,0)=Z%(R,0)+16:RETURN
+  REM otherwise, copy first element to turn it into correct type
+  B=A+1:GOSUB DEREF_B: REM value to copy
+  L=Z%(A,1):N=B:GOSUB ALLOC: REM T already set
+  IF Z%(A,1)=0 THEN RETURN
+  RETURN
+
 
 REM LIST_Q(A) -> R
 LIST_Q:
@@ -354,19 +372,6 @@ LAST:
     Z%(R,0)=Z%(R,0)+16
     RETURN
 
-REM CONS(A,B) -> R
-CONS:
-  SZ=2:GOSUB ALLOC
-  Z%(R,0)=6+16
-  Z%(R,1)=B
-  Z%(R+1,0)=14
-  Z%(R+1,1)=A
-  REM inc ref cnt of item we are including
-  Z%(A,0)=Z%(A,0)+16
-  REM inc ref cnt of list we are prepending
-  Z%(B,0)=Z%(B,0)+16
-  RETURN
-
 REM SLICE(A,B,C) -> R
 REM make copy of sequence A from index B to C
 REM returns R6 as reference to last element of slice
@@ -377,8 +382,7 @@ SLICE:
   R6=0: REM previous list element
   SLICE_LOOP:
     REM always allocate at least one list element
-    SZ=2:GOSUB ALLOC
-    Z%(R,0)=6+16:Z%(R,1)=0:Z%(R+1,0)=14:Z%(R+1,1)=0
+    T=6:L=0:N=0:GOSUB ALLOC
     IF R5=-1 THEN R5=R
     IF R5<>-1 THEN Z%(R6,1)=R
     REM advance A to position B
@@ -399,76 +403,55 @@ SLICE:
 
 REM LIST2(B2%,B1%) -> R
 LIST2:
-  REM terminator
-  SZ=2:GOSUB ALLOC:TB%=R
-  Z%(R,0)=6+16:Z%(R,1)=0:Z%(R+1,0)=0:Z%(R+1,1)=0
-
-  REM second element is B1%
-  SZ=2:GOSUB ALLOC:TC%=R
-  Z%(R,0)=6+16:Z%(R,1)=TB%:Z%(R+1,0)=14:Z%(R+1,1)=B1%
-  Z%(B1%,0)=Z%(B1%,0)+16
+  REM last element is 3 (empty list), second element is B1%
+  T=6:L=3:N=B1%:GOSUB ALLOC
 
   REM first element is B2%
-  SZ=2:GOSUB ALLOC
-  Z%(R,0)=6+16:Z%(R,1)=TC%:Z%(R+1,0)=14:Z%(R+1,1)=B2%
-  Z%(B2%,0)=Z%(B2%,0)+16
+  T=6:L=R:N=B2%:GOSUB ALLOC
+  AY=L:GOSUB RELEASE: REM new list takes ownership of previous
 
   RETURN
 
 REM LIST3(B3%,B2%,B1%) -> R
 LIST3:
-  GOSUB LIST2:TC%=R
+  GOSUB LIST2
 
   REM first element is B3%
-  SZ=2:GOSUB ALLOC
-  Z%(R,0)=6+16:Z%(R,1)=TC%:Z%(R+1,0)=14:Z%(R+1,1)=B3%
-  Z%(B3%,0)=Z%(B3%,0)+16
+  T=6:L=R:N=B3%:GOSUB ALLOC
+  AY=L:GOSUB RELEASE: REM new list takes ownership of previous
 
   RETURN
 
+
 REM hashmap functions
 
 REM HASHMAP() -> R
 HASHMAP:
-  SZ=2:GOSUB ALLOC
-  Z%(R,0)=8+16
-  Z%(R,1)=0
-  Z%(R+1,0)=14
-  Z%(R+1,1)=0
+  T=8:L=0:N=0:GOSUB ALLOC
   RETURN
 
 REM ASSOC1(H, K, V) -> R
 ASSOC1:
-  REM deref to actual key and value
-  R=K:GOSUB DEREF_R:K=R
+  REM deref K and V
   R=V:GOSUB DEREF_R:V=R
+  R=K:GOSUB DEREF_R:K=R
 
-  REM inc ref count of key and value
-  Z%(K,0)=Z%(K,0)+16
-  Z%(V,0)=Z%(V,0)+16
-  SZ=4:GOSUB ALLOC
-  REM key ptr
-  Z%(R,0)=8+16
-  Z%(R,1)=R+2: REM point to next element (value)
-  Z%(R+1,0)=14
-  Z%(R+1,1)=K
   REM value ptr
-  Z%(R+2,0)=8+16
-  Z%(R+2,1)=H: REM hashmap to assoc onto
-  Z%(R+3,0)=14
-  Z%(R+3,1)=V
+  T=8:L=H:N=V:GOSUB ALLOC
+  AY=L:GOSUB RELEASE: REM we took ownership of previous hashmap
+  REM key ptr
+  T=8:L=R:N=K:GOSUB ALLOC
+  AY=L:GOSUB RELEASE: REM we took ownership of previous hashmap
   RETURN
 
 REM ASSOC1(H, K$, V) -> R
 ASSOC1_S:
-  REM add the key string, then call ASSOC1
-  SZ=1:GOSUB ALLOC
-  K=R
   S$(ZJ)=K$
-  Z%(R,0)=4: REM key ref cnt will be inc'd by ASSOC1
-  Z%(R,1)=ZJ
+  REM add the key string
+  T=4:L=ZJ:GOSUB ALLOC
   ZJ=ZJ+1
-  GOSUB ASSOC1
+  K=R:GOSUB ASSOC1
+  AY=K:GOSUB RELEASE: REM map took ownership of key
   RETURN
 
 REM HASHMAP_GET(H, K) -> R
@@ -498,24 +481,17 @@ HASHMAP_CONTAINS:
   R=T3
   RETURN
 
+
+REM function functions
+
 REM NATIVE_FUNCTION(A) -> R
 NATIVE_FUNCTION:
-  SZ=1:GOSUB ALLOC
-  Z%(R,0)=9+16
-  Z%(R,1)=A
+  T=9:L=A:GOSUB ALLOC
   RETURN
 
 REM MAL_FUNCTION(A, P, E) -> R
 MAL_FUNCTION:
-  SZ=2:GOSUB ALLOC
-  Z%(A,0)=Z%(A,0)+16
-  Z%(P,0)=Z%(P,0)+16
-  Z%(E,0)=Z%(E,0)+16
-
-  Z%(R,0)=10+16
-  Z%(R,1)=A
-  Z%(R+1,0)=P
-  Z%(R+1,1)=E
+  T=10:L=A:M=P:N=E:GOSUB ALLOC
   RETURN
 
 REM APPLY(F, AR) -> R
index c11b7aa..a388602 100644 (file)
@@ -30,6 +30,9 @@ F   : function
 H   : hash map
 K   : hash map key (Z% index)
 K$  : hash map key string
+L   : ALLOC* Z%(R,1) default
+M   : ALLOC* Z%(R+1,0) default
+N   : ALLOC* Z%(R+1,1) default
 O   : outer environment
 P   : MAL_FUNCTION
 R   : common return value