stext = text
text = re.sub(r"(THEN) %s\b" % a, r"THEN %s" % b, stext)
#text = re.sub(r"(THEN)%s\b" % a, r"THEN%s" % b, stext)
- text = re.sub(r"(ON [^:]* GOTO [^:\n]*)\b%s\b" % a, r"\g<1>%s" % b, text)
- text = re.sub(r"(ON [^:]* GOSUB [^:\n]*)\b%s\b" % a, r"\g<2>%s" % b, text)
+ text = re.sub(r"(ON [^:\n]* GOTO [^:\n]*)\b%s\b" % a, r"\g<1>%s" % b, text)
+ text = re.sub(r"(ON [^:\n]* GOSUB [^:\n]*)\b%s\b" % a, r"\g<2>%s" % b, text)
text = re.sub(r"(GOSUB) %s\b" % a, r"\1 %s" % b, text)
text = re.sub(r"(GOTO) %s\b" % a, r"\1 %s" % b, text)
#text = re.sub(r"(GOTO)%s\b" % a, r"\1%s" % b, text)
+REM APPLY should really be in types.in.bas but it is here because it
+REM has return labels into DO_TCO_FUNCTION so it will cause syntax
+REM errors for steps1-3 if it is in types.in.bas because there are
+REM unresolved labels.
+
+REM APPLY(F, AR) -> R
+REM - restores E
+REM - call using GOTO and with return label/address on the stack
+APPLY:
+ REM if metadata, get the actual object
+ IF (Z%(F,0)AND31)>=16 THEN F=Z%(F,1)
+
+ IF (Z%(F,0)AND31)=9 THEN GOTO APPLY_FUNCTION
+ IF (Z%(F,0)AND31)=10 THEN GOTO APPLY_MAL_FUNCTION
+ IF (Z%(F,0)AND31)=11 THEN GOTO APPLY_MAL_FUNCTION
+
+ APPLY_FUNCTION:
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_APPLY
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=1:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_APPLY:
+ GOTO APPLY_DONE
+
+ APPLY_MAL_FUNCTION:
+ X=X+1:X%(X)=E: REM save the current environment
+
+ REM create new environ using env and params stored in the
+ REM function and bind the params to the apply arguments
+ O=Z%(F+1,1):BI=Z%(F+1,0):EX=AR:GOSUB ENV_NEW_BINDS
+
+ A=Z%(F,1):E=R:GOSUB EVAL
+
+ AY=E:GOSUB RELEASE: REM release the new environment
+
+ E=X%(X):X=X-1: REM pop/restore the saved environment
+
+ APPLY_DONE:
+ REM pop APPLY return label/address
+ RN=X%(X):X=X-1
+ ON RN GOTO APPLY_RETURN_1,APPLY_RETURN_2,APPLY_RETURN_MAP,APPLY_RETURN_SWAP,APPLY_RETURN_MACROEXPAND
+
+
+REM DO_TCO_FUNCTION(F, AR)
+REM - similar to DO_FUNCTION but non-GOSUB version for potentially
+REM recursive function (apply, map, swap!)
+DO_TCO_FUNCTION:
+ FF=Z%(F,1)
+
+ REM Get argument values
+ R=AR+1:GOSUB DEREF_R:AA=R
+ R=Z%(AR,1)+1:GOSUB DEREF_R:AB=R
+
+ ON FF-60 GOTO DO_APPLY,DO_MAP,DO_SWAP_BANG
+
+ 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)AND31)<>6 THEN T=6:GOSUB FORCE_SEQ_TYPE:GOTO DO_APPLY_2
+ REM no intermediate args, just call APPLY directly
+ IF R4<=1 THEN GOTO DO_APPLY_1
+
+ REM prepend intermediate args to final args element
+ A=AR:B=0:C=R4-1:GOSUB SLICE
+ REM release the terminator of new list (we skip over it)
+ AY=Z%(R6,1):GOSUB RELEASE
+ REM attach end of slice to final args element
+ Z%(R6,1)=Z%(A+1,1)
+ Z%(Z%(A+1,1),0)=Z%(Z%(A+1,1),0)+32
+
+ GOTO DO_APPLY_2
+
+ DO_APPLY_1:
+ X=X+1:X%(X)=1: REM push APPLY return label/address
+ AR=A:GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_1:
+
+ GOTO DO_TCO_FUNCTION_RETURN
+
+ DO_APPLY_2:
+ X=X+1:X%(X)=R: REM push/save new args for release
+
+ X=X+1:X%(X)=2: REM push APPLY return label/address
+ AR=R:GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_2:
+
+ AY=X%(X):X=X-1:GOSUB RELEASE: REM pop/release new args
+ GOTO DO_TCO_FUNCTION_RETURN
+
+ DO_MAP:
+ F=AA
+
+ REM first result list element
+ T=6:L=0:N=0:GOSUB ALLOC
+
+ REM push future return val, prior entry, F and AB
+ X=X+4:X%(X-3)=R:X%(X-2)=0:X%(X-1)=F:X%(X)=AB
+
+ DO_MAP_LOOP:
+ REM set previous to current if not the first element
+ IF X%(X-2)<>0 THEN Z%(X%(X-2),1)=R
+ REM update previous reference to current
+ X%(X-2)=R
+
+ IF Z%(AB,1)=0 THEN GOTO DO_MAP_DONE
+
+ REM create argument list for apply call
+ Z%(3,0)=Z%(3,0)+32
+ REM inc ref cnt of referred argument
+ T=6:L=3:N=Z%(AB+1,1):GOSUB ALLOC
+
+ REM push argument list
+ X=X+1:X%(X)=R
+
+ X=X+1:X%(X)=3: REM push APPLY return label/address
+ AR=R:GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_MAP:
+
+ REM pop apply args are release them
+ AY=X%(X):X=X-1:GOSUB RELEASE
+
+ REM set the result value
+ Z%(X%(X-2)+1,1)=R
+
+ REM restore F
+ F=X%(X-1)
+
+ REM update AB to next source element
+ X%(X)=Z%(X%(X),1)
+ AB=X%(X)
+
+ REM allocate next element
+ T=6:L=0:N=0:GOSUB ALLOC
+
+ GOTO DO_MAP_LOOP
+
+ DO_MAP_DONE:
+ REM get return val
+ R=X%(X-3)
+ REM pop everything off stack
+ X=X-4
+ GOTO DO_TCO_FUNCTION_RETURN
+
+
+ DO_SWAP_BANG:
+ F=AB
+
+ REM add atom to front of the args list
+ T=6:L=Z%(Z%(AR,1),1):N=Z%(AA,1):GOSUB ALLOC: REM cons
+ AR=R
+
+ REM push args for release after
+ X=X+1:X%(X)=AR
+
+ REM push atom
+ X=X+1:X%(X)=AA
+
+ X=X+1:X%(X)=4: REM push APPLY return label/address
+ GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_SWAP:
+
+ REM pop atom
+ AA=X%(X):X=X-1
+
+ REM pop and release args
+ AY=X%(X):X=X-1:GOSUB RELEASE
+
+ REM use reset to update the value
+ AB=R:GOSUB DO_RESET_BANG
+
+ REM but decrease ref cnt of return by 1 (not sure why)
+ AY=R:GOSUB RELEASE
+
+ GOTO DO_TCO_FUNCTION_RETURN
+
+ DO_TCO_FUNCTION_RETURN:
+ REM pop EVAL AST return label/address
+ RN=X%(X):X=X-1
+ ON RN GOTO DO_TCO_FUNCTION_RETURN_APPLY,DO_TCO_FUNCTION_RETURN_EVAL
+
REM DO_FUNCTION(F, AR)
DO_FUNCTION:
REM Switch on the function number
IF FF>59 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
+ ON FF/10+1 GOTO DO_1_9,DO_10_19,DO_20_29,DO_30_39,DO_40_49,DO_50_56
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_30_39:
ON FF-29 GOTO DO_VECTOR_Q,DO_HASH_MAP,DO_MAP_Q,DO_ASSOC,DO_THROW,DO_GET,DO_CONTAINS,DO_KEYS,DO_VALS,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_WITH_META,DO_META,DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_SWAP_BANG,DO_EVAL,DO_READ_FILE
+ ON FF-39 GOTO DO_CONS,DO_CONCAT,DO_NTH,DO_FIRST,DO_REST,DO_EMPTY_Q,DO_COUNT,DO_THROW,DO_THROW,DO_WITH_META
+ DO_50_56:
+ ON FF-49 GOTO DO_META,DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_EVAL,DO_READ_FILE
DO_EQUAL_Q:
A=AA:B=AB:GOSUB EQUAL_Q
T=2:L=Z%(AA,1)/Z%(AB,1):GOSUB ALLOC
RETURN
DO_TIME_MS:
- R=0
+ T=2:L=INT((TI-BT)*16.667):GOSUB ALLOC
RETURN
DO_LIST:
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)AND31)<>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=A:GOSUB APPLY:RETURN
-
- REM prepend intermediate args to final args element
- A=AR:B=0:C=R4-1:GOSUB SLICE
- REM release the terminator of new list (we skip over it)
- AY=Z%(R6,1):GOSUB RELEASE
- REM attach end of slice to final args element
- Z%(R6,1)=Z%(A+1,1)
- Z%(Z%(A+1,1),0)=Z%(Z%(A+1,1),0)+32
-
- DO_APPLY_2:
- X=X+1:X%(X)=R: REM push/save new args for release
- AR=R:GOSUB APPLY
- AY=X%(X):X=X-1:GOSUB RELEASE: REM pop/release new args
- RETURN
- DO_MAP:
- F=AA
-
- REM first result list element
- T=6:L=0:N=0:GOSUB ALLOC
-
- REM push future return val, prior entry, F and AB
- X=X+4:X%(X-3)=R:X%(X-2)=0:X%(X-1)=F:X%(X)=AB
-
- DO_MAP_LOOP:
- REM set previous to current if not the first element
- IF X%(X-2)<>0 THEN Z%(X%(X-2),1)=R
- REM update previous reference to current
- X%(X-2)=R
-
- IF Z%(AB,1)=0 THEN GOTO DO_MAP_DONE
-
- REM create argument list for apply call
- Z%(3,0)=Z%(3,0)+32
- REM inc ref cnt of referred argument
- T=6:L=3:N=Z%(AB+1,1):GOSUB ALLOC
-
- REM push argument list
- X=X+1:X%(X)=R
-
- AR=R:GOSUB APPLY
-
- REM pop apply args are release them
- AY=X%(X):X=X-1:GOSUB RELEASE
-
- REM set the result value
- Z%(X%(X-2)+1,1)=R
-
- REM restore F
- F=X%(X-1)
-
- REM update AB to next source element
- X%(X)=Z%(X%(X),1)
- AB=X%(X)
-
- REM allocate next element
- T=6:L=0:N=0:GOSUB ALLOC
-
- GOTO DO_MAP_LOOP
-
- DO_MAP_DONE:
- REM get return val
- R=X%(X-3)
- REM pop everything off stack
- X=X-4
- RETURN
DO_WITH_META:
T=Z%(AA,0)AND31
REM update value
Z%(AA,1)=R
RETURN
- DO_SWAP_BANG:
- F=AB
-
- REM add atom to front of the args list
- T=6:L=Z%(Z%(AR,1),1):N=Z%(AA,1):GOSUB ALLOC: REM cons
- AR=R
-
- REM push args for release after
- X=X+1:X%(X)=AR
-
- REM push atom
- X=X+1:X%(X)=AA
-
- GOSUB APPLY
-
- REM pop atom
- AA=X%(X):X=X-1
-
- REM pop and release args
- AY=X%(X):X=X-1:GOSUB RELEASE
-
- REM use reset to update the value
- AB=R:GOSUB DO_RESET_BANG
-
- REM but decrease ref cnt of return by 1 (not sure why)
- AY=R:GOSUB RELEASE
-
- RETURN
- DO_PR_MEMORY:
- P1=ZT:P2=-1:GOSUB PR_MEMORY
- RETURN
- DO_PR_MEMORY_SUMMARY:
- GOSUB PR_MEMORY_SUMMARY
- RETURN
+ REM DO_PR_MEMORY:
+ REM P1=ZT:P2=-1:GOSUB PR_MEMORY
+ REM RETURN
+ REM DO_PR_MEMORY_SUMMARY:
+ REM GOSUB PR_MEMORY_SUMMARY
+ REM RETURN
DO_EVAL:
A=AA:E=D:GOSUB EVAL
K$="rest":A=44:GOSUB INIT_CORE_SET_FUNCTION
K$="empty?":A=45:GOSUB INIT_CORE_SET_FUNCTION
K$="count":A=46:GOSUB INIT_CORE_SET_FUNCTION
- 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
+ REM K$="conj":A=47:GOSUB INIT_CORE_SET_FUNCTION
+ REM K$="seq":A=48:GOSUB INIT_CORE_SET_FUNCTION
+
+ K$="with-meta":A=49:GOSUB INIT_CORE_SET_FUNCTION
+ K$="meta":A=50:GOSUB INIT_CORE_SET_FUNCTION
+ K$="atom":A=51:GOSUB INIT_CORE_SET_FUNCTION
+ K$="atom?":A=52:GOSUB INIT_CORE_SET_FUNCTION
+ K$="deref":A=53:GOSUB INIT_CORE_SET_FUNCTION
+ K$="reset!":A=54:GOSUB INIT_CORE_SET_FUNCTION
- K$="eval":A=58:GOSUB INIT_CORE_SET_FUNCTION
+ K$="eval":A=55:GOSUB INIT_CORE_SET_FUNCTION
+ K$="read-file":A=56:GOSUB INIT_CORE_SET_FUNCTION
- K$="read-file":A=59:GOSUB INIT_CORE_SET_FUNCTION
+ REM these are in DO_TCO_FUNCTION
+ K$="apply":A=61:GOSUB INIT_CORE_SET_FUNCTION
+ K$="map":A=62:GOSUB INIT_CORE_SET_FUNCTION
+ K$="swap!":A=63:GOSUB INIT_CORE_SET_FUNCTION
RETURN
#!/bin/bash
-(echo "(list $(for a in "${@}"; do echo -n "\"${a}\""; done))") > $(dirname $0)/.args.mal
-exec cbmbasic $(dirname $0)/${STEP:-stepA_mal}.bas "${@}"
+cd $(dirname $0)
+(echo "(list $(for a in "${@}"; do echo -n "\"${a}\""; done))") > .args.mal
+exec cbmbasic ${STEP:-stepA_mal}.bas "${@}"
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
X=X+1:X%(X)=R: REM push eval'd list
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_IF:
GOSUB EVAL_GET_A1: REM set A1
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_IF:
GOSUB EVAL_GET_A1: REM set A1
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="(load-file (first -*ARGS*-))"
GOSUB RE
IF ER<>-2 THEN GOSUB PRINT_ERROR
- END
+ GOTO QUIT
REPL_LOOP:
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_QUOTE:
R=Z%(A,1)+1:GOSUB DEREF_R
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="(load-file (first -*ARGS*-))"
GOSUB RE
IF ER<>-2 THEN GOSUB PRINT_ERROR
- END
+ GOTO QUIT
REPL_LOOP:
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
IF (Z%(B,0)AND31)<>11 THEN GOTO MACROEXPAND_DONE
REM apply
- F=B:AR=Z%(A,1):GOSUB APPLY
+ X=X+1:X%(X)=5: REM push APPLY return label/address
+ F=B:AR=Z%(A,1):GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_MACROEXPAND:
+
A=R
AY=X%(X)
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_QUOTE:
R=Z%(A,1)+1:GOSUB DEREF_R
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="(load-file (first -*ARGS*-))"
GOSUB RE
IF ER<>-2 THEN GOSUB PRINT_ERROR
- END
+ GOTO QUIT
REPL_LOOP:
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
IF (Z%(B,0)AND31)<>11 THEN GOTO MACROEXPAND_DONE
REM apply
- F=B:AR=Z%(A,1):GOSUB APPLY
+ X=X+1:X%(X)=5: REM push APPLY return label/address
+ F=B:AR=Z%(A,1):GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_MACROEXPAND:
+
A=R
AY=X%(X)
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_QUOTE:
R=Z%(A,1)+1:GOSUB DEREF_R
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="(load-file (first -*ARGS*-))"
GOSUB RE
IF ER<>-2 THEN GOSUB PRINT_ERROR
- END
+ GOTO QUIT
REPL_LOOP:
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
GOSUB READ_STR
RETURN
-REM PAIR_Q(B) -> R
-PAIR_Q:
- R=0
- IF (Z%(B,0)AND31)<>6 AND (Z%(B,0)AND31)<>7 THEN RETURN
- IF (Z%(B,1)=0) THEN RETURN
- R=1
- RETURN
-
REM QUASIQUOTE(A) -> R
QUASIQUOTE:
- B=A:GOSUB PAIR_Q
- IF R=1 THEN GOTO QQ_UNQUOTE
+ REM pair?
+ IF (Z%(A,0)AND31)<6 OR (Z%(A,0)AND31)>7 THEN GOTO QQ_QUOTE
+ IF (Z%(A,1)=0) THEN GOTO QQ_QUOTE
+ GOTO QQ_UNQUOTE
+
+ QQ_QUOTE:
REM ['quote, ast]
AS$="quote":T=5:GOSUB STRING
B2=R:B1=A:GOSUB LIST2
REM set A to ast[0] for last two cases
A=A+1:GOSUB DEREF_A
- B=A:GOSUB PAIR_Q
- IF R=0 THEN GOTO QQ_DEFAULT
+ REM pair?
+ IF (Z%(A,0)AND31)<6 OR (Z%(A,0)AND31)>7 THEN GOTO QQ_DEFAULT
+ IF (Z%(A,1)=0) THEN GOTO QQ_DEFAULT
+
B=A+1:GOSUB DEREF_B
IF (Z%(B,0)AND31)<>5 THEN GOTO QQ_DEFAULT
IF S$(Z%(B,1))<>"splice-unquote" THEN QQ_DEFAULT
IF (Z%(B,0)AND31)<>11 THEN GOTO MACROEXPAND_DONE
REM apply
- F=B:AR=Z%(A,1):GOSUB APPLY
+ X=X+1:X%(X)=5: REM push APPLY return label/address
+ F=B:AR=Z%(A,1):GOTO APPLY
+ REM APPLY return label/address popped by APPLY
+ APPLY_RETURN_MACROEXPAND:
+
A=R
AY=X%(X)
REM check if we are done evaluating the source sequence
IF Z%(A,1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+ REM if we are returning to DO, then skip last element
+ IF X%(X-6)=2 AND Z%(Z%(A,1),1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
+
REM if hashmap, skip eval of even entries (keys)
IF (X%(X-3)=8) AND ((X%(X-2) AND 1)=0) THEN GOTO EVAL_AST_DO_REF
GOTO EVAL_AST_DO_EVAL
REM pop EVAL AST return label/address
RN=X%(X):X=X-1
ON RN GOTO EVAL_AST_RETURN_1,EVAL_AST_RETURN_2,EVAL_AST_RETURN_3
- RETURN
REM EVAL(A, E)) -> R
EVAL:
REM push A and E on the stack
X=X+2:X%(X-1)=E:X%(X)=A
+ REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
+
EVAL_TCO_RECUR:
REM AZ=A:PR=1:GOSUB PR_STR
EVAL_DO:
A=Z%(A,1): REM rest
-
- REM TODO: TCO
+ X=X+1:X%(X)=A: REM push/save A
REM push EVAL_AST return label/address
X=X+1:X%(X)=2
GOTO EVAL_AST
+ REM return label/address already popped by EVAL_AST
EVAL_AST_RETURN_2:
- X=X+1:X%(X)=R: REM push eval'd list
- A=R:GOSUB LAST: REM return the last element
- AY=X%(X):X=X-1: REM pop eval'd list
- GOSUB RELEASE: REM release the eval'd list
- GOTO EVAL_RETURN
+ REM cleanup
+ AY=R: REM get eval'd list for release
+
+ A=X%(X):X=X-1: REM pop/restore original A for LAST
+ GOSUB LAST: REM get last element for return
+ A=R: REM new recur AST
+
+ REM cleanup
+ GOSUB RELEASE: REM release eval'd list
+ AY=A:GOSUB RELEASE: REM release LAST value (not sure why)
+
+ GOTO EVAL_TCO_RECUR: REM TCO loop
EVAL_QUOTE:
R=Z%(A,1)+1:GOSUB DEREF_R
ER=-1:ER$="apply of non-function":GOTO EVAL_RETURN
EVAL_DO_FUNCTION:
- GOSUB DO_FUNCTION
+ REM regular function
+ IF Z%(F,1)<60 THEN GOSUB DO_FUNCTION:GOTO DO_TCO_FUNCTION_RETURN_EVAL
+ REM for recur functions (apply, map, swap!), use GOTO
+ IF Z%(F,1)>60 THEN X=X+1:X%(X)=2:GOTO DO_TCO_FUNCTION
+ DO_TCO_FUNCTION_RETURN_EVAL:
REM pop and release f/args
AY=X%(X):X=X-1:GOSUB RELEASE
IF R2<>0 THEN AY=R2:GOSUB RELEASE
IF R1<>0 THEN AY=R1:GOSUB RELEASE
R$=RT$
- RETURN
+ GOTO REP_RETURN
REM MAIN program
MAIN:
A$="(load-file (first -*ARGS*-))"
GOSUB RE
IF ER<>-2 THEN GOSUB PRINT_ERROR
- END
+ GOTO QUIT
REPL:
REM print the REPL startup header
A$="user> ":GOSUB READLINE: REM call input parser
IF EOF=1 THEN GOTO QUIT
- A$=R$:GOSUB REP: REM call REP
+ A$=R$:GOTO REP: REM call REP
+ REP_RETURN:
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
PRINT R$
REM pending release stack
Y=-1:DIM Y%(Z4,1): REM stack of Z% indexes
- REM PRINT "Lisp data memory: "+STR$(T-FRE(0))
- REM PRINT "Interpreter working memory: "+STR$(FRE(0))
+ BT=TI
+
RETURN
REM EQUAL_Q(A, B) -> R
EQUAL_Q:
+ ED=0: REM recursion depth
+ R=-1: REM return value
+
+ EQUAL_Q_RECUR:
+
GOSUB DEREF_A
GOSUB DEREF_B
- R=0
+ REM push A and B
+ X=X+2:X%(X-1)=A:X%(X)=B
+ ED=ED+1
+
U1=Z%(A,0)AND31
U2=Z%(B,0)AND31
- 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
+ IF U1>5 AND U1<8 AND U2>5 AND U2<8 THEN GOTO EQUAL_Q_SEQ
+ IF U1=8 AND U2=8 THEN GOTO EQUAL_Q_HM
- IF Z%(A,1)=Z%(B,1) THEN R=1
- RETURN
+ IF U1<>U2 OR Z%(A,1)<>Z%(B,1) THEN R=0
+ GOTO EQUAL_Q_DONE
EQUAL_Q_SEQ:
- IF (Z%(A,1)=0) AND (Z%(B,1)=0) THEN R=1:RETURN
- IF (Z%(A,1)=0) OR (Z%(B,1)=0) THEN R=0:RETURN
+ IF (Z%(A,1)=0) AND (Z%(B,1)=0) THEN GOTO EQUAL_Q_DONE
+ IF (Z%(A,1)=0) OR (Z%(B,1)=0) THEN R=0:GOTO EQUAL_Q_DONE
- REM push A and B
- X=X+2:X%(X-1)=A:X%(X)=B
REM compare the elements
- A=Z%(A+1,1):B=Z%(B+1,1):GOSUB EQUAL_Q
- REM pop A and B
- A=X%(X-1):B=X%(X):X=X-2
- IF R=0 THEN RETURN
+ A=Z%(A+1,1):B=Z%(B+1,1)
+ GOTO EQUAL_Q_RECUR
+ EQUAL_Q_SEQ_CONTINUE:
REM next elements of the sequences
- A=Z%(A,1):B=Z%(B,1):GOTO EQUAL_Q_SEQ
+ A=X%(X-1):B=X%(X)
+ A=Z%(A,1):B=Z%(B,1)
+ X%(X-1)=A:X%(X)=B
+ GOTO EQUAL_Q_SEQ
+
EQUAL_Q_HM:
R=0
- RETURN
+ GOTO EQUAL_Q_DONE
+
+ EQUAL_Q_DONE:
+ X=X-2: REM pop current A and B
+ ED=ED-1
+ IF R>-1 AND ED>0 THEN GOTO EQUAL_Q_DONE: REM unwind
+ IF ED=0 AND R=-1 THEN R=1
+ IF ED=0 THEN RETURN
+ GOTO EQUAL_Q_SEQ_CONTINUE
REM string functions
IF S=0 THEN GOTO STRING_NOT_FOUND
REM search for matching string in S$
- FOR I=0 TO S-1
+ I=0
+ STRING_LOOP:
+ IF I>S-1 THEN GOTO STRING_NOT_FOUND
IF AS$=S$(I) THEN R=I:RETURN
- NEXT I
+ I=I+1
+ GOTO STRING_LOOP
STRING_NOT_FOUND:
S$(S)=AS$
MAL_FUNCTION:
T=10:L=A:M=P:N=E:GOSUB ALLOC
RETURN
-
-REM APPLY(F, AR) -> R
-REM restores E
-APPLY:
- REM if metadata, get the actual object
- IF (Z%(F,0)AND31)>=16 THEN F=Z%(F,1)
-
- IF (Z%(F,0)AND31)=9 THEN GOTO DO_APPLY_FUNCTION
- IF (Z%(F,0)AND31)=10 THEN GOTO DO_APPLY_MAL_FUNCTION
- IF (Z%(F,0)AND31)=11 THEN GOTO DO_APPLY_MAL_FUNCTION
-
- DO_APPLY_FUNCTION:
- GOSUB DO_FUNCTION
-
- RETURN
-
- DO_APPLY_MAL_FUNCTION:
- X=X+1:X%(X)=E: REM save the current environment
-
- REM create new environ using env and params stored in the
- REM function and bind the params to the apply arguments
- O=Z%(F+1,1):BI=Z%(F+1,0):EX=AR:GOSUB ENV_NEW_BINDS
-
- A=Z%(F,1):E=R:GOSUB EVAL
-
- AY=E:GOSUB RELEASE: REM release the new environment
-
- E=X%(X):X=X-1: REM pop/restore the saved environment
-
- RETURN
-
SZ : size argument to ALLOC
Reused/temporaries:
-
A0 : EVAL ast elements
A1 : EVAL ast elements
A2 : EVAL ast elements
A3 : EVAL ast elements
+
+ED : EQUAL_Q recursion depth counter
+RD : PR_OBJECT recursion depth
+SD : READ_STR sequence read recursion depth
+
CH$ : READ_TOKEN, SKIP_SPACES, SKIP_TO_EOL current character
I : STRING, REPLACE, SLICE, PR_MEMORY, PR_OBJECT
J : REPLACE
(def! eval-ast (fn* [ast env] (do
;;(do (prn "eval-ast" ast "/" (keys env)) )
(cond
- (symbol? ast) (or (get env (str ast))
- (throw (str ast " not found")))
+ (symbol? ast) (let* [res (get env (str ast))]
+ (if res res (throw (str ast " not found"))))
(list? ast) (map (fn* [exp] (EVAL exp env)) ast)