3 REM boolean 1 -> 0: false, 1: true
4 REM integer 2 -> int value
6 REM string/kw 4 -> ZS$ index
7 REM symbol 5 -> ZS$ index
8 REM list next/val 6 -> next Z% index (0 for last)
9 REM followed by value (unless empty)
10 REM vector next/val 7 -> next Z% index (0 for last)
11 REM followed by value (unless empty)
12 REM hashmap next/val 8 -> next Z% index (0 for last)
13 REM followed by key or value (alternating)
14 REM function 9 -> function index
15 REM mal function 10 -> body AST Z% index
16 REM followed by param and env Z% index
17 REM atom 11 -> Z% index
18 REM environment 13 -> data/hashmap Z% index
19 REM followed by 13 and outer Z% index (-1 for none)
20 REM reference/ptr 14 -> Z% index / or 0
21 REM next free ptr 15 -> Z% index / or 0
26 S1
%=3072: REM Z% (boxed memory) size (X2)
27 REM S1%=4096: REM Z% (boxed memory) size (X2)
28 S2
%=256: REM ZS% (string memory) size
29 S3
%=256: REM ZZ% (call stack) size
30 S4
%=128: REM ZR% (release stack) size
32 REM global error state
36 REM boxed element memory
37 DIM Z
%(S1
%,1): REM TYPE ARRAY
39 REM Predefine nil, false, true
47 REM start of unused memory
50 REM start of free list
53 REM string memory storage
59 DIM ZZ
%(S3
%): REM stack of Z% indexes
61 REM pending release stack
63 DIM ZR
%(S4
%): REM stack of Z% indexes
65 REM PRINT "Lisp data memory: " + STR$(T%-FRE(0))
66 REM PRINT "Interpreter working memory: " + STR$(FRE(0))
73 REM PRINT "ALLOC SZ%: "+STR$(SZ%)+", ZK%: "+STR$(ZK%)
77 IF U4
%=ZI
% THEN GOTO ALLOC_UNUSED
78 REM TODO sanity check that type is 15
79 IF ((Z
%(U4
%,0)AND-16)/16)=SZ
% THEN GOTO ALLOC_MIDDLE
80 REM PRINT "ALLOC search: U3%: "+STR$(U3%)+", U4%: "+STR$(U4%)
81 U3
%=U4
%: REM previous set to current
82 U4
%=Z
%(U4
%,1): REM current set to next
85 REM PRINT "ALLOC_MIDDLE: U3%: "+STR$(U3%)+", U4%: "+STR$(U4%)
87 REM set free pointer (ZK%) to next free
88 IF U4
%=ZK
% THEN ZK
%=Z
%(U4
%,1)
89 REM set previous free to next free
90 IF U4
%<>ZK
% THEN Z
%(U3
%,1)=Z
%(U4
%,1)
93 REM PRINT "ALLOC_UNUSED ZI%: "+STR$(ZI%)+", U3%: "+STR$(U3%)+", U4%: "+STR$(U4%)
96 IF U3
%=U4
% THEN ZK
%=ZI
%
97 REM set previous free to new memory top
98 IF U3
%<>U4
% THEN Z
%(U3
%,1)=ZI
%
101 REM FREE(AY%, SZ%) -> nil
103 REM assumes reference count cleanup already (see RELEASE)
104 Z
%(AY
%,0) = (SZ
%*16)+15: REM set type(15) and size
106 IF SZ
%>=2 THEN Z
%(AY
%+1,0)=0
107 IF SZ
%>=2 THEN Z
%(AY
%+1,1)=0
108 IF SZ
%>=3 THEN Z
%(AY
%+2,0)=0
109 IF SZ
%>=3 THEN Z
%(AY
%+2,1)=0
114 REM RELEASE(AY%) -> nil
115 REM R% should not be affected by this call
125 REM pop next object to release, decrease remaining count
126 AY
%=ZZ
%(ZL
%): ZL
%=ZL
%-1
132 IF AY
%<3 THEN GOTO RELEASE_TOP
134 U6
%=Z
%(AY
%,0)AND15
: REM type
136 REM AZ%=AY%: PR%=1: GOSUB PR_STR
137 REM PRINT "RELEASE AY%:"+STR$(AY%)+"["+R$+"] (byte0:"+STR$(Z%(AY%,0))+")"
139 REM sanity check not already freed
140 IF (U6
%)=15 THEN ER
%=1: ER
$="Free of free memory
: " + STR$(AY%): RETURN
141 IF Z%(AY%,0)<15 THEN ER%=1: ER$="Free of freed object: " + STR
$(AY%): RETURN
143 REM decrease reference count by one
144 Z
%(AY
%,0)=Z
%(AY
%,0)-16
146 REM our reference count is not 0, so don't release
147 IF Z
%(AY
%,0)>=16 GOTO RELEASE_TOP
150 IF (U6
%<=5) OR (U6
%=9) THEN GOTO RELEASE_SIMPLE
151 IF (U6
%>=6) AND (U6
%<=8) THEN GOTO RELEASE_SEQ
152 IF U6
%=10 THEN GOTO RELEASE_MAL_FUNCTION
153 IF U6
%=13 THEN GOTO RELEASE_ENV
154 IF U6
%=14 THEN GOTO RELEASE_REFERENCE
155 IF U6
%=15 THEN ER
%=1: ER
$="RELEASE of already freed
: "+STR$(AY%): RETURN
156 ER%=1: ER$="RELEASE not defined for type " + STR
$(U6%): RETURN
159 REM simple type (no recursing), just call FREE on it
163 REM free the current element and continue
167 IF Z
%(AY
%,1)=0 THEN GOTO RELEASE_SIMPLE_2
168 IF Z
%(AY
%+1,0)<>14 THEN ER
%=1: ER
$="invalid list value
"+STR$(AY%+1): RETURN
169 REM add value and next element to stack
170 RC%=RC%+2: ZL%=ZL%+2: ZZ%(ZL%-1)=Z%(AY%+1,1): ZZ%(ZL%)=Z%(AY%,1)
171 GOTO RELEASE_SIMPLE_2
172 RELEASE_MAL_FUNCTION:
173 REM add ast, params and environment to stack
175 ZZ%(ZL%-2)=Z%(AY%,1): ZZ%(ZL%-1)=Z%(AY%+1,0): ZZ%(ZL%)=Z%(AY%+1,1)
176 REM free the current 2 element mal_function and continue
180 REM add the hashmap data to the stack
181 RC%=RC%+1: ZL%=ZL%+1: ZZ%(ZL%)=Z%(AY%,1)
183 IF Z%(AY%+1,1)=-1 THEN GOTO RELEASE_ENV_FREE
184 REM add outer environment to the stack
185 RC%=RC%+1: ZL%=ZL%+1: ZZ%(ZL%)=Z%(AY%+1,1)
187 REM free the current 2 element environment and continue
191 IF Z%(AY%,1)=0 THEN GOTO RELEASE_SIMPLE
192 REM add the referred element to the stack
193 RC%=RC%+1: ZL%=ZL%+1: ZZ%(ZL%)=Z%(AY%,1)
194 REM free the current element and continue
198 REM RELEASE_PEND() -> nil
200 REM REM IF ER%<>0 THEN RETURN
202 REM PRINT "here2 RELEASE_PEND releasing
:"+STR$(ZR%(ZM%))
203 AY%=ZR%(ZM%): GOSUB RELEASE
207 REM DEREF_R(R%) -> R%
209 IF (Z%(R%,0)AND15)=14 THEN R%=Z%(R%,1): GOTO DEREF_R
212 REM DEREF_A(A%) -> A%
214 IF (Z%(A%,0)AND15)=14 THEN A%=Z%(A%,1): GOTO DEREF_A
217 REM DEREF_B(B%) -> B%
219 IF (Z%(B%,0)AND15)=14 THEN B%=Z%(B%,1): GOTO DEREF_B
223 P1%=ZK%: P2%=0: REM start and accumulator
224 CHECK_FREE_LIST_LOOP:
225 IF P1%>=ZI% THEN GOTO CHECK_FREE_LIST_DONE
226 IF (Z%(P1%,0)AND15)<>15 THEN P2%=-1: GOTO CHECK_FREE_LIST_DONE
227 P2%=P2%+(Z%(P1%,0)AND-16)/16
229 GOTO CHECK_FREE_LIST_LOOP
230 CHECK_FREE_LIST_DONE:
231 IF P2%=-1 THEN PRINT "corrupt free list at
"+STR$(P1%)
235 GOSUB CHECK_FREE_LIST: REM get count in P2%
237 PRINT "Free
memory (FRE
) : " + STR$(FRE(0))
238 PRINT "Value
memory (Z
%) : " + STR$(ZI%-1) + " /" + STR$(S1%)
240 PRINT " used
:"+STR$(ZI%-1-P2%)+", freed:"+STR
$(P2%);
241 PRINT
", post repl_env:"+STR
$(ZT%)
242 PRINT
"String values (ZS$) : " + STR
$(ZJ%) + " /" + STR
$(S2%)
243 PRINT
"Call stack size (ZZ%) : " + STR
$(ZL%+1) + " /" + STR
$(S3%)
246 REM PR_MEMORY(P1%, P2%) -> nil
248 IF P2
%<P1
% THEN P2
%=ZI
%-1
250 PRINT
"Z% Value Memory"+STR
$(P1%)+"->"+STR$(P2%);
251 PRINT
" (ZI%: "+STR
$(ZI%)+", ZK
%: "+STR$(ZK%)+"):"
252 IF P2%<P1% THEN PRINT " ---": GOTO PR_MEMORY_AFTER_VALUES
254 PR_MEMORY_VALUE_LOOP:
255 IF I>P2% THEN GOTO PR_MEMORY_AFTER_VALUES
257 IF (Z%(I,0)AND15)=15 THEN GOTO PR_MEMORY_FREE
258 PRINT ": ref cnt
: " + STR$((Z%(I,0)AND-16)/16);
259 PRINT ", type: " + STR$(Z%(I,0)AND15) + ", value
: " + STR$(Z%(I,1))
261 IF (Z%(I-1,0)AND15)<>10 THEN GOTO PR_MEMORY_VALUE_LOOP
262 PRINT " "+STR$(I)+": ";
263 PRINT
"params: "+STR
$(Z%(I+1,0))+", env
:"+STR$(Z%(I+1,1))
265 GOTO PR_MEMORY_VALUE_LOOP
267 PRINT ": FREE size
: "+STR$((Z%(I,0)AND-16)/16)+", next: "+STR
$(Z%(I,1));
268 IF I
=ZK
% THEN PRINT
" (free list start)";
270 IF (Z
%(I
,0)AND-16)=32 THEN I
=I
+1: PRINT
" "+STR
$(I)+": ---"
272 GOTO PR_MEMORY_VALUE_LOOP
273 PR_MEMORY_AFTER_VALUES:
274 PRINT "ZS
% String Memory (ZJ
%: " + STR$(ZJ%) + "):"
275 IF ZJ%<=0 THEN PRINT " ---": GOTO PR_MEMORY_SKIP_STRINGS
277 PRINT " " + STR$(I) + ": '" + ZS$(I) + "'"
279 PR_MEMORY_SKIP_STRINGS:
280 PRINT
"ZZ% Stack Memory (ZL%: " + STR
$(ZL%) + "):"
281 IF ZL
%<0 THEN PRINT
" ---": GOTO PR_MEMORY_SKIP_STACK
283 PRINT
" "+STR
$(I)+": "+STR$(ZZ%(I))
285 PR_MEMORY_SKIP_STACK:
290 REM general functions
292 REM EQUAL_Q(A%, B%) -> R%
294 GOSUB DEREF_A: GOSUB DEREF_B
297 U1%=(Z%(A%,0)AND15): U2%=(Z%(B%,0)AND15)
298 IF NOT ((U1%=U2%) OR ((U1%=6 OR U1%=7) AND (U2%=6 OR U2%=7))) THEN RETURN
299 IF U1%=6 THEN GOTO EQUAL_Q_SEQ
300 IF U1%=7 THEN GOTO EQUAL_Q_SEQ
301 IF U1%=8 THEN GOTO EQUAL_Q_HM
303 IF Z%(A%,1)=Z%(B%,1) THEN R%=1
307 IF (Z%(A%,1)=0) AND (Z%(B%,1)=0) THEN R%=1: RETURN
308 IF (Z%(A%,1)=0) OR (Z%(B%,1)=0) THEN R%=0: RETURN
311 ZL%=ZL%+2: ZZ%(ZL%-1)=A%: ZZ%(ZL%)=B%
312 A%=Z%(A%+1,1): B%=Z%(B%+1,1): GOSUB EQUAL_Q
314 A%=ZZ%(ZL%-1): B%=ZZ%(ZL%): ZL%=ZL%-2
317 REM next elements of the sequences
318 A%=Z%(A%,1): B%=Z%(B%,1): GOTO EQUAL_Q_SEQ
325 REM STRING_(AS$) -> R%
326 REM intern string (returns string index, not Z% index)
328 IF ZJ%=0 THEN GOTO STRING_NOT_FOUND
330 REM search for matching string in ZS$
332 IF AS$=ZS$(I) THEN R%=I: RETURN
349 IF (Z%(A%,0)AND15)=6 THEN R%=1
352 REM EMPTY_Q(A%) -> R%
355 IF Z%(A%,1)=0 THEN R%=1
363 IF Z%(A%,1)<>0 THEN A%=Z%(A%,1): GOTO DO_COUNT_LOOP
368 REM TODO check that actually a list/vector
369 IF Z%(A%,1)=0 THEN R%=0: RETURN: REM empty seq, return nil
372 IF Z%(A%,1)=0 THEN GOTO LAST_DONE: REM end, return previous value
373 T6%=A%: REM current becomes previous entry
374 A%=Z%(A%,1): REM next entry
377 R%=T6%+1: GOSUB DEREF_R
381 REM hashmap functions
392 REM ASSOC1(HM%, K%, V%) -> R%
394 REM deref to actual key and value
395 R%=K%: GOSUB DEREF_R: K%=R%
396 R%=V%: GOSUB DEREF_R: V%=R%
398 REM inc ref count of key and value
404 Z%(R%,1) = R%+2: REM point to next element (value)
409 Z%(R%+2,1) = HM%: REM hashmap to assoc onto
414 REM ASSOC1(HM%, K$, V%) -> R%
416 REM add the key string, then call ASSOC1
420 Z%(R%,0) = 4: REM key ref cnt will be inc'd by ASSOC1
426 REM HASHMAP_GET(HM%, K%) -> R%
429 T1$=ZS$(Z%(K%,1)): REM search key string
430 T3%=0: REM whether found or not (for HASHMAP_CONTAINS)
433 REM no matching key found
434 IF Z%(H2%,1)=0 THEN R%=0: RETURN
435 REM follow value ptrs
438 IF Z%(T2%,0)=14 THEN T2%=Z%(T2%,1): GOTO HASHMAP_GET_DEREF
441 REM if they are equal, we found it
442 IF T1$=T2$ THEN T3%=1: R%=Z%(H2%,1)+1: RETURN
445 GOTO HASHMAP_GET_LOOP
447 REM HASHMAP_CONTAINS(HM%, K%) -> R%
453 REM NATIVE_FUNCTION(A%) -> R%
460 REM NATIVE_FUNCTION(A%, P%, E%) -> R%