1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-21 10:37:58 +03:00
mal/basic/step4_if_fn_do.in.bas

372 lines
8.7 KiB
QBasic
Raw Normal View History

2016-09-12 05:36:15 +03:00
GOTO MAIN
REM $INCLUDE: 'mem.in.bas'
2016-09-12 05:36:15 +03:00
REM $INCLUDE: 'types.in.bas'
REM $INCLUDE: 'readline.in.bas'
2016-09-12 05:36:15 +03:00
REM $INCLUDE: 'reader.in.bas'
REM $INCLUDE: 'printer.in.bas'
REM $INCLUDE: 'env.in.bas'
REM $INCLUDE: 'core.in.bas'
REM $INCLUDE: 'debug.in.bas'
REM READ(A$) -> R
2016-09-12 05:36:15 +03:00
MAL_READ:
GOSUB READ_STR
RETURN
REM EVAL_AST(A, E) -> R
SUB EVAL_AST
REM push A and E on the stack
Q=E:GOSUB PUSH_Q
GOSUB PUSH_A
2016-09-12 05:36:15 +03:00
IF ER<>-2 THEN GOTO EVAL_AST_RETURN
2016-09-12 05:36:15 +03:00
GOSUB TYPE_A
IF T=5 THEN GOTO EVAL_AST_SYMBOL
IF T>=6 AND T<=8 THEN GOTO EVAL_AST_SEQ
REM scalar: deref to actual value and inc ref cnt
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
R=A
GOSUB INC_REF_R
2016-09-12 05:36:15 +03:00
GOTO EVAL_AST_RETURN
EVAL_AST_SYMBOL:
K=A:GOTO ENV_GET
ENV_GET_RETURN:
2016-09-12 05:36:15 +03:00
GOTO EVAL_AST_RETURN
2016-09-12 05:36:15 +03:00
EVAL_AST_SEQ:
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM setup the stack for the loop
GOSUB MAP_LOOP_START
2016-09-12 05:36:15 +03:00
EVAL_AST_SEQ_LOOP:
REM check if we are done evaluating the source sequence
IF Z%(A+1)=0 THEN GOTO EVAL_AST_SEQ_LOOP_DONE
2016-09-12 05:36:15 +03:00
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM call EVAL for each entry
GOSUB PUSH_A
IF T<>8 THEN A=Z%(A+2)
IF T=8 THEN A=Z%(A+3)
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
Q=T:GOSUB PUSH_Q: REM push/save type
CALL EVAL
GOSUB POP_Q:T=Q: REM pop/restore type
GOSUB POP_A
M=R
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM if error, release the unattached element
REM TODO: is R=0 correct?
IF ER<>-2 THEN AY=R:GOSUB RELEASE:R=0:GOTO EVAL_AST_SEQ_LOOP_DONE
2016-09-12 05:36:15 +03:00
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM for hash-maps, copy the key (inc ref since we are going to
REM release it below)
IF T=8 THEN N=M:M=Z%(A+2):Z%(M)=Z%(M)+32
2016-09-12 05:36:15 +03:00
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM update the return sequence structure
REM release N (and M if T=8) since seq takes full ownership
C=1:GOSUB MAP_LOOP_UPDATE
2016-09-12 05:36:15 +03:00
REM process the next sequence entry from source list
A=Z%(A+1)
2016-09-12 05:36:15 +03:00
GOTO EVAL_AST_SEQ_LOOP
EVAL_AST_SEQ_LOOP_DONE:
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM cleanup stack and get return value
GOSUB MAP_LOOP_DONE
2016-09-12 05:36:15 +03:00
GOTO EVAL_AST_RETURN
EVAL_AST_RETURN:
REM pop A and E off the stack
GOSUB POP_A
GOSUB POP_Q:E=Q
END SUB
2016-09-12 05:36:15 +03:00
REM EVAL(A, E) -> R
SUB EVAL
LV=LV+1: REM track basic return stack level
2016-09-12 05:36:15 +03:00
REM push A and E on the stack
Q=E:GOSUB PUSH_Q
GOSUB PUSH_A
2016-09-12 05:36:15 +03:00
REM PRINT "EVAL A:"+STR$(A)+",X:"+STR$(X)+",LV:"+STR$(LV)+",FRE:"+STR$(FRE(0))
2016-09-12 05:36:15 +03:00
EVAL_TCO_RECUR:
IF ER<>-2 THEN GOTO EVAL_RETURN
REM AZ=A:B=1:GOSUB PR_STR
REM PRINT "EVAL: "+R$+" [A:"+STR$(A)+", LV:"+STR$(LV)+"]"
2016-09-12 05:36:15 +03:00
GOSUB LIST_Q
IF R THEN GOTO APPLY_LIST
2016-09-12 05:36:15 +03:00
REM ELSE
CALL EVAL_AST
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
APPLY_LIST:
GOSUB EMPTY_Q
IF R THEN R=A:GOSUB INC_REF_R:GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
A0=Z%(A+2)
2016-09-12 05:36:15 +03:00
REM get symbol in A$
IF (Z%(A0)AND 31)<>5 THEN A$=""
IF (Z%(A0)AND 31)=5 THEN A$=S$(Z%(A0+1))
2016-09-12 05:36:15 +03:00
IF A$="def!" THEN GOTO EVAL_DEF
IF A$="let*" THEN GOTO EVAL_LET
IF A$="do" THEN GOTO EVAL_DO
IF A$="if" THEN GOTO EVAL_IF
IF A$="fn*" THEN GOTO EVAL_FN
GOTO EVAL_INVOKE
EVAL_GET_A3:
A3=Z%(Z%(Z%(Z%(A+1)+1)+1)+2)
2016-09-12 05:36:15 +03:00
EVAL_GET_A2:
A2=Z%(Z%(Z%(A+1)+1)+2)
2016-09-12 05:36:15 +03:00
EVAL_GET_A1:
A1=Z%(Z%(A+1)+2)
2016-09-12 05:36:15 +03:00
RETURN
EVAL_DEF:
REM PRINT "def!"
GOSUB EVAL_GET_A2: REM set A1 and A2
Q=A1:GOSUB PUSH_Q
A=A2:CALL EVAL: REM eval a2
GOSUB POP_Q:A1=Q
IF ER<>-2 THEN GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
REM set a1 in env to a2
K=A1:C=R:GOSUB ENV_SET
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
EVAL_LET:
REM PRINT "let*"
GOSUB EVAL_GET_A2: REM set A1 and A2
Q=A2:GOSUB PUSH_Q: REM push/save A2
2016-09-12 05:36:15 +03:00
REM create new environment with outer as current environment
C=E:GOSUB ENV_NEW
E=R
2016-09-12 05:36:15 +03:00
EVAL_LET_LOOP:
IF Z%(A1+1)=0 THEN GOTO EVAL_LET_LOOP_DONE
Q=A1:GOSUB PUSH_Q: REM push A1
2016-09-12 05:36:15 +03:00
REM eval current A1 odd element
A=Z%(Z%(A1+1)+2):CALL EVAL
GOSUB POP_Q:A1=Q: REM pop A1
IF ER<>-2 THEN GOTO EVAL_LET_LOOP_DONE
REM set key/value in the environment
K=Z%(A1+2):C=R:GOSUB ENV_SET
AY=R:GOSUB RELEASE: REM release our use, ENV_SET took ownership
REM skip to the next pair of A1 elements
A1=Z%(Z%(A1+1)+1)
2016-09-12 05:36:15 +03:00
GOTO EVAL_LET_LOOP
2016-09-12 05:36:15 +03:00
EVAL_LET_LOOP_DONE:
GOSUB POP_Q:A2=Q: REM pop A2
A=A2:CALL EVAL: REM eval A2 using let_env
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
EVAL_DO:
A=Z%(A+1): REM rest
2016-09-12 05:36:15 +03:00
CALL EVAL_AST
2016-09-12 05:36:15 +03:00
GOSUB PUSH_R: REM push eval'd list
A=R:GOSUB LAST: REM return the last element
GOSUB POP_Q:AY=Q: REM pop eval'd list
GOSUB RELEASE: REM release the eval'd list
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
EVAL_IF:
GOSUB EVAL_GET_A1: REM set A1
GOSUB PUSH_A: REM push/save A
A=A1:CALL EVAL
GOSUB POP_A: REM pop/restore A
IF (R=0) OR (R=2) THEN GOTO EVAL_IF_FALSE
2016-09-12 05:36:15 +03:00
EVAL_IF_TRUE:
AY=R:GOSUB RELEASE
GOSUB EVAL_GET_A2: REM set A1 and A2 after EVAL
A=A2:GOTO EVAL_TCO_RECUR: REM TCO loop
2016-09-12 05:36:15 +03:00
EVAL_IF_FALSE:
AY=R:GOSUB RELEASE
REM if no false case (A3), return nil
GOSUB COUNT
IF R<4 THEN R=0:GOSUB INC_REF_R:GOTO EVAL_RETURN
GOSUB EVAL_GET_A3: REM set A1 - A3 after EVAL
A=A3:GOTO EVAL_TCO_RECUR: REM TCO loop
2016-09-12 05:36:15 +03:00
EVAL_FN:
GOSUB EVAL_GET_A2: REM set A1 and A2
T=10:L=A2:M=A1:N=E:GOSUB ALLOC: REM mal function
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
EVAL_INVOKE:
CALL EVAL_AST
2016-09-12 05:36:15 +03:00
REM if error, return f/args for release by caller
IF ER<>-2 THEN GOTO EVAL_RETURN
REM push f/args for release after call
GOSUB PUSH_R
AR=Z%(R+1): REM rest
F=Z%(R+2)
2016-09-12 05:36:15 +03:00
REM if metadata, get the actual object
GOSUB TYPE_F
IF T=14 THEN F=Z%(F+1):GOSUB TYPE_F
ON T-8 GOTO EVAL_DO_FUNCTION,EVAL_DO_MAL_FUNCTION,EVAL_DO_MAL_FUNCTION
REM if error, pop and return f/args for release by caller
GOSUB POP_R
ER=-1:E$="apply of non-function":GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
EVAL_DO_FUNCTION:
REM regular function
IF Z%(F+1)<60 THEN GOSUB DO_FUNCTION:GOTO EVAL_DO_FUNCTION_SKIP
REM for recur functions (apply, map, swap!), use GOTO
IF Z%(F+1)>60 THEN CALL DO_TCO_FUNCTION
EVAL_DO_FUNCTION_SKIP:
REM pop and release f/args
GOSUB POP_Q:AY=Q
GOSUB RELEASE
2016-09-12 05:36:15 +03:00
GOTO EVAL_RETURN
2016-09-12 05:36:15 +03:00
EVAL_DO_MAL_FUNCTION:
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
Q=E:GOSUB PUSH_Q: REM save the current environment for release
REM create new environ using env and params stored in function
C=Z%(F+3):A=Z%(F+2):B=AR:GOSUB ENV_NEW_BINDS
REM release previous env if it is not the top one on the
REM stack (X%(X-2)) because our new env refers to it and
REM we no longer need to track it (since we are TCO recurring)
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
GOSUB POP_Q:AY=Q
GOSUB PEEK_Q_2
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
IF AY<>Q THEN GOSUB RELEASE
REM claim the AST before releasing the list containing it
A=Z%(F+1):Z%(A)=Z%(A)+32
REM add AST to pending release queue to free as soon as EVAL
REM actually returns (LV+1)
LV=LV+1:GOSUB PEND_A_LV:LV=LV-1
REM pop and release f/args
GOSUB POP_Q:AY=Q
GOSUB RELEASE
REM A set above
E=R:GOTO EVAL_TCO_RECUR: REM TCO loop
2016-09-12 05:36:15 +03:00
EVAL_RETURN:
REM AZ=R: B=1: GOSUB PR_STR
REM PRINT "EVAL_RETURN R: ["+R$+"] ("+STR$(R)+"), LV:"+STR$(LV)+",ER:"+STR$(ER)
REM release environment if not the top one on the stack
GOSUB PEEK_Q_1
IF E<>Q THEN AY=E:GOSUB RELEASE
LV=LV-1: REM track basic return stack level
REM release everything we couldn't release earlier
GOSUB RELEASE_PEND
2016-09-12 05:36:15 +03:00
REM trigger GC
#cbm T=FRE(0)
#qbasic T=0
REM pop A and E off the stack
GOSUB POP_A
GOSUB POP_Q:E=Q
2016-09-12 05:36:15 +03:00
END SUB
2016-09-12 05:36:15 +03:00
REM PRINT(A) -> R$
2016-09-12 05:36:15 +03:00
MAL_PRINT:
AZ=A:B=1:GOSUB PR_STR
2016-09-12 05:36:15 +03:00
RETURN
REM RE(A$) -> R
REM Assume D has repl_env
REM caller must release result
RE:
R1=-1
GOSUB MAL_READ
R1=R
IF ER<>-2 THEN GOTO RE_DONE
A=R:E=D:CALL EVAL
RE_DONE:
REM Release memory from MAL_READ
AY=R1:GOSUB RELEASE
RETURN: REM caller must release result of EVAL
2016-09-12 05:36:15 +03:00
REM REP(A$) -> R$
REM Assume D has repl_env
SUB REP
R2=-1
GOSUB RE
R2=R
IF ER<>-2 THEN GOTO REP_DONE
A=R:GOSUB MAL_PRINT
REP_DONE:
REM Release memory from MAL_READ and EVAL
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
AY=R2:GOSUB RELEASE
END SUB
2016-09-12 05:36:15 +03:00
REM MAIN program
MAIN:
GOSUB INIT_MEMORY
LV=0
2016-09-12 05:36:15 +03:00
REM create repl_env
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
C=0:GOSUB ENV_NEW:D=R
2016-09-12 05:36:15 +03:00
REM core.EXT: defined in Basic
E=D:GOSUB INIT_CORE_NS: REM set core functions in repl_env
ZT=ZI: REM top of memory after base repl_env
REM core.mal: defined using the language itself
A$="(def! not (fn* (a) (if a false true)))"
GOSUB RE:AY=R:GOSUB RELEASE
2016-09-12 05:36:15 +03:00
REPL_LOOP:
A$="user> ":GOSUB READLINE: REM call input parser
IF EZ=1 THEN GOTO QUIT
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
IF R$="" THEN GOTO REPL_LOOP
A$=R$:CALL REP: REM call REP
IF ER<>-2 THEN GOSUB PRINT_ERROR:GOTO REPL_LOOP
2016-09-12 05:36:15 +03:00
PRINT R$
GOTO REPL_LOOP
2016-09-12 05:36:15 +03:00
QUIT:
Basic: refactor of hashmaps, map loops, remove derefs. - Alternate memory layout of hash-maps: Instead of hash-maps being an alternating sequence of keys and values, combine the key/values into a single entry. In other words, switch from this: 8 -> next Z% index (0 for last) 14 key/value (alternating) To this: 8 -> next Z% index (0 for last) key value This requires refactoring of the sequence reader, EVAL_AST and especially DO_HASHMAP and DO_KEY_VALS. So that leads to the next big refactoring: - Change mapping/lapping constructs to share code: Several pieces of mapping/looping code have a common structure, so this moves that common structure to types.in.bas: MAP_LOOP_START, MAP_LOOP_UPDATE, MAP_LOOP_DONE. Then use this code in: - EVAL_AST - READ_SEQ_* - DO_MAP - DO_HASH_MAP - DO_KEYS_VALS This also fixes the issue that several of these looping constructs were creating new empty sequence entries instead of using the common ones at the beginning of memory. - Remove the use of DEREF_*. This isn't actually needed because we no longer create structure that refer to multiple levels of type 14 references. Replace DEREF_* with VAL_* which gets the value of a particular sequence element i.e. Z%(A+1,1). All together, the above changes save over 300 bytes. Also: - Fix empty nil/false/true entries so they are treated the same as other types of data with regards to reference counting and ALLOC/RELEASE. - Add a new memory summary function in debug.in.bas that just prints out free, value count, and references for the early scalar and empty list elements. Comment out the larger one. This saves about 90 bytes.
2016-11-16 07:38:09 +03:00
REM GOSUB PR_MEMORY_SUMMARY_SMALL
#cbm END
#qbasic SYSTEM
2016-09-12 05:36:15 +03:00
PRINT_ERROR:
PRINT "Error: "+E$
ER=-2:E$=""
RETURN