Commit | Line | Data |
---|---|---|
b7b1787f JM |
1 | REM Z 0 -> 1 |
2 | REM nil 0 -> (unused) | |
3 | REM boolean 1 -> 0: false, 1: true | |
4 | REM integer 2 -> int value | |
5 | REM float 3 -> ??? | |
cc9dbd92 JM |
6 | REM string/kw 4 -> S$ index |
7 | REM symbol 5 -> S$ index | |
60270667 | 8 | REM list next/val 6 -> next Z% index (0 for last) |
b7b1787f | 9 | REM followed by value (unless empty) |
60270667 | 10 | REM vector next/val 7 -> next Z% index (0 for last) |
b7b1787f | 11 | REM followed by value (unless empty) |
60270667 | 12 | REM hashmap next/val 8 -> next Z% index (0 for last) |
b7b1787f | 13 | REM followed by key or value (alternating) |
60270667 | 14 | REM function 9 -> function index |
4b84a23b JM |
15 | REM mal function 10 -> body AST Z% index |
16 | REM followed by param and env Z% index | |
70f29a2b JM |
17 | REM macro (same as 10) 11 -> body AST Z% index |
18 | REM followed by param and env Z% index | |
bf8d1f7d | 19 | REM atom 12 -> Z% index |
4b84a23b JM |
20 | REM environment 13 -> data/hashmap Z% index |
21 | REM followed by 13 and outer Z% index (-1 for none) | |
22 | REM reference/ptr 14 -> Z% index / or 0 | |
23 | REM next free ptr 15 -> Z% index / or 0 | |
11f94d2e JM |
24 | |
25 | INIT_MEMORY: | |
cc9dbd92 | 26 | T=FRE(0) |
4b84a23b | 27 | |
cc9dbd92 JM |
28 | Z1=2048+512: REM Z% (boxed memory) size (4 bytes each) |
29 | Z2=256: REM S$ (string memory) size (3 bytes each) | |
30 | Z3=256: REM S% (call stack) size (2 bytes each) | |
31 | Z4=64: REM ZR% (release stack) size (4 bytes each) | |
b7b1787f | 32 | |
11f94d2e | 33 | REM global error state |
5e5ca0d4 JM |
34 | REM -2 : no error |
35 | REM -1 : string error in ER$ | |
36 | REM >=0 : pointer to error object | |
cc9dbd92 | 37 | ER=-2 |
5e5ca0d4 | 38 | ER$="" |
11f94d2e | 39 | |
b7b1787f | 40 | REM boxed element memory |
cc9dbd92 | 41 | DIM Z%(Z1,1): REM TYPE ARRAY |
11f94d2e | 42 | |
9e8f5211 | 43 | REM Predefine nil, false, true, and an empty list |
60ef223c JM |
44 | Z%(0,0)=0:Z%(0,1)=0 |
45 | Z%(1,0)=1:Z%(1,1)=0 | |
46 | Z%(2,0)=1:Z%(2,1)=1 | |
47 | Z%(3,0)=6+16:Z%(3,1)=0 | |
48 | Z%(4,0)=0:Z%(4,1)=0 | |
4b84a23b JM |
49 | |
50 | REM start of unused memory | |
cc9dbd92 | 51 | ZI=5 |
11f94d2e | 52 | |
4b84a23b | 53 | REM start of free list |
cc9dbd92 | 54 | ZK=5 |
4b84a23b | 55 | |
b7b1787f | 56 | REM string memory storage |
cc9dbd92 | 57 | ZJ=0:DIM S$(Z2) |
b7b1787f | 58 | |
60270667 | 59 | REM call/logic stack |
cc9dbd92 | 60 | X=-1:DIM S%(Z3): REM stack of Z% indexes |
b7b1787f | 61 | |
4b84a23b | 62 | REM pending release stack |
cc9dbd92 | 63 | ZM%=-1:DIM ZR%(Z4,1): REM stack of Z% indexes |
4b84a23b | 64 | |
cc9dbd92 | 65 | REM PRINT "Lisp data memory: "+STR$(T-FRE(0)) |
bf8d1f7d | 66 | REM PRINT "Interpreter working memory: "+STR$(FRE(0)) |
b7b1787f JM |
67 | RETURN |
68 | ||
4b84a23b JM |
69 | REM memory functions |
70 | ||
cc9dbd92 | 71 | REM ALLOC(SZ) -> R |
4b84a23b | 72 | ALLOC: |
cc9dbd92 JM |
73 | REM PRINT "ALLOC SZ: "+STR$(SZ)+", ZK: "+STR$(ZK) |
74 | U3=ZK | |
75 | U4=ZK | |
4b84a23b | 76 | ALLOC_LOOP: |
cc9dbd92 | 77 | IF U4=ZI THEN GOTO ALLOC_UNUSED |
4b84a23b | 78 | REM TODO sanity check that type is 15 |
cc9dbd92 JM |
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 | |
4b84a23b JM |
83 | GOTO ALLOC_LOOP |
84 | ALLOC_MIDDLE: | |
cc9dbd92 JM |
85 | REM PRINT "ALLOC_MIDDLE: U3: "+STR$(U3)+", U4: "+STR$(U4) |
86 | R=U4 | |
87 | REM set free pointer (ZK) to next free | |
88 | IF U4=ZK THEN ZK=Z%(U4,1) | |
4b84a23b | 89 | REM set previous free to next free |
cc9dbd92 | 90 | IF U4<>ZK THEN Z%(U3,1)=Z%(U4,1) |
4b84a23b JM |
91 | RETURN |
92 | ALLOC_UNUSED: | |
cc9dbd92 JM |
93 | REM PRINT "ALLOC_UNUSED ZI: "+STR$(ZI)+", U3: "+STR$(U3)+", U4: "+STR$(U4) |
94 | R=U4 | |
95 | ZI=ZI+SZ | |
96 | IF U3=U4 THEN ZK=ZI | |
4b84a23b | 97 | REM set previous free to new memory top |
cc9dbd92 | 98 | IF U3<>U4 THEN Z%(U3,1)=ZI |
4b84a23b JM |
99 | RETURN |
100 | ||
cc9dbd92 | 101 | REM FREE(AY, SZ) -> nil |
4b84a23b JM |
102 | FREE: |
103 | REM assumes reference count cleanup already (see RELEASE) | |
cc9dbd92 JM |
104 | Z%(AY,0)=(SZ*16)+15: REM set type(15) and size |
105 | Z%(AY,1)=ZK | |
106 | ZK=AY | |
107 | IF SZ>=2 THEN Z%(AY+1,0)=0:Z%(AY+1,1)=0 | |
108 | IF SZ>=3 THEN Z%(AY+2,0)=0:Z%(AY+2,1)=0 | |
4b84a23b JM |
109 | RETURN |
110 | ||
111 | ||
cc9dbd92 JM |
112 | REM RELEASE(AY) -> nil |
113 | REM R should not be affected by this call | |
4b84a23b | 114 | RELEASE: |
cc9dbd92 | 115 | RC=0 |
4b84a23b JM |
116 | |
117 | GOTO RELEASE_ONE | |
118 | ||
119 | RELEASE_TOP: | |
120 | ||
cc9dbd92 | 121 | IF RC=0 THEN RETURN |
4b84a23b JM |
122 | |
123 | REM pop next object to release, decrease remaining count | |
cc9dbd92 JM |
124 | AY=S%(X):X=X-1 |
125 | RC=RC-1 | |
4b84a23b JM |
126 | |
127 | RELEASE_ONE: | |
128 | ||
129 | REM nil, false, true | |
cc9dbd92 | 130 | IF AY<3 THEN GOTO RELEASE_TOP |
4b84a23b | 131 | |
cc9dbd92 | 132 | U6=Z%(AY,0)AND15: REM type |
412e7348 | 133 | |
cc9dbd92 JM |
134 | REM AZ=AY: PR=1: GOSUB PR_STR |
135 | REM PRINT "RELEASE AY:"+STR$(AY)+"["+R$+"] (byte0:"+STR$(Z%(AY,0))+")" | |
412e7348 | 136 | |
4b84a23b | 137 | REM sanity check not already freed |
cc9dbd92 JM |
138 | IF (U6)=15 THEN ER=-1:ER$="Free of free memory: "+STR$(AY):RETURN |
139 | IF U6=14 THEN GOTO RELEASE_REFERENCE | |
140 | IF Z%(AY,0)<15 THEN ER=-1:ER$="Free of freed object: "+STR$(AY):RETURN | |
4b84a23b JM |
141 | |
142 | REM decrease reference count by one | |
cc9dbd92 | 143 | Z%(AY,0)=Z%(AY,0)-16 |
4b84a23b JM |
144 | |
145 | REM our reference count is not 0, so don't release | |
cc9dbd92 | 146 | IF Z%(AY,0)>=16 GOTO RELEASE_TOP |
4b84a23b JM |
147 | |
148 | REM switch on type | |
cc9dbd92 JM |
149 | IF (U6<=5) OR (U6=9) THEN GOTO RELEASE_SIMPLE |
150 | IF (U6>=6) AND (U6<=8) THEN GOTO RELEASE_SEQ | |
151 | IF U6=10 THEN GOTO RELEASE_MAL_FUNCTION | |
152 | IF U6=11 THEN GOTO RELEASE_MAL_FUNCTION | |
153 | IF U6=12 THEN GOTO RELEASE_ATOM | |
154 | IF U6=13 THEN GOTO RELEASE_ENV | |
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 | |
4b84a23b JM |
157 | |
158 | RELEASE_SIMPLE: | |
159 | REM simple type (no recursing), just call FREE on it | |
cc9dbd92 | 160 | SZ=1:GOSUB FREE |
4b84a23b JM |
161 | GOTO RELEASE_TOP |
162 | RELEASE_SIMPLE_2: | |
163 | REM free the current element and continue | |
cc9dbd92 | 164 | SZ=2:GOSUB FREE |
4b84a23b JM |
165 | GOTO RELEASE_TOP |
166 | RELEASE_SEQ: | |
cc9dbd92 JM |
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 | |
4b84a23b | 169 | REM add value and next element to stack |
cc9dbd92 | 170 | RC=RC+2:X=X+2:S%(X-1)=Z%(AY+1,1):S%(X)=Z%(AY,1) |
4b84a23b | 171 | GOTO RELEASE_SIMPLE_2 |
85d70fb7 JM |
172 | RELEASE_ATOM: |
173 | REM add contained/referred value | |
cc9dbd92 | 174 | RC=RC+1:X=X+1:S%(X)=Z%(AY,1) |
85d70fb7 JM |
175 | REM free the atom itself |
176 | GOTO RELEASE_SIMPLE | |
4b84a23b JM |
177 | RELEASE_MAL_FUNCTION: |
178 | REM add ast, params and environment to stack | |
cc9dbd92 JM |
179 | RC=RC+3:X=X+3 |
180 | S%(X-2)=Z%(AY,1):S%(X-1)=Z%(AY+1,0):S%(X)=Z%(AY+1,1) | |
4b84a23b | 181 | REM free the current 2 element mal_function and continue |
cc9dbd92 | 182 | SZ=2:GOSUB FREE |
4b84a23b JM |
183 | GOTO RELEASE_TOP |
184 | RELEASE_ENV: | |
185 | REM add the hashmap data to the stack | |
cc9dbd92 | 186 | RC=RC+1:X=X+1:S%(X)=Z%(AY,1) |
4b84a23b | 187 | REM if no outer set |
cc9dbd92 | 188 | IF Z%(AY+1,1)=-1 THEN GOTO RELEASE_ENV_FREE |
4b84a23b | 189 | REM add outer environment to the stack |
cc9dbd92 | 190 | RC=RC+1:X=X+1:S%(X)=Z%(AY+1,1) |
4b84a23b JM |
191 | RELEASE_ENV_FREE: |
192 | REM free the current 2 element environment and continue | |
cc9dbd92 | 193 | SZ=2:GOSUB FREE |
4b84a23b JM |
194 | GOTO RELEASE_TOP |
195 | RELEASE_REFERENCE: | |
cc9dbd92 | 196 | IF Z%(AY,1)=0 THEN GOTO RELEASE_SIMPLE |
4b84a23b | 197 | REM add the referred element to the stack |
cc9dbd92 | 198 | RC=RC+1:X=X+1:S%(X)=Z%(AY,1) |
4b84a23b | 199 | REM free the current element and continue |
cc9dbd92 | 200 | SZ=1:GOSUB FREE |
4b84a23b JM |
201 | GOTO RELEASE_TOP |
202 | ||
cc9dbd92 | 203 | REM RELEASE_PEND(LV) -> nil |
4b84a23b JM |
204 | RELEASE_PEND: |
205 | IF ZM%<0 THEN RETURN | |
cc9dbd92 | 206 | IF ZR%(ZM%,1)<=LV THEN RETURN |
9e8f5211 | 207 | REM PRINT "RELEASE_PEND releasing:"+STR$(ZR%(ZM%,0)) |
cc9dbd92 | 208 | AY=ZR%(ZM%,0):GOSUB RELEASE |
4b84a23b JM |
209 | ZM%=ZM%-1 |
210 | GOTO RELEASE_PEND | |
211 | ||
cc9dbd92 | 212 | REM DEREF_R(R) -> R |
4b84a23b | 213 | DEREF_R: |
cc9dbd92 | 214 | IF (Z%(R,0)AND15)=14 THEN R=Z%(R,1):GOTO DEREF_R |
4b84a23b JM |
215 | RETURN |
216 | ||
cc9dbd92 | 217 | REM DEREF_A(A) -> A |
4b84a23b | 218 | DEREF_A: |
cc9dbd92 | 219 | IF (Z%(A,0)AND15)=14 THEN A=Z%(A,1):GOTO DEREF_A |
4b84a23b JM |
220 | RETURN |
221 | ||
cc9dbd92 | 222 | REM DEREF_B(B) -> B |
4b84a23b | 223 | DEREF_B: |
cc9dbd92 | 224 | IF (Z%(B,0)AND15)=14 THEN B=Z%(B,1):GOTO DEREF_B |
4b84a23b JM |
225 | RETURN |
226 | ||
227 | CHECK_FREE_LIST: | |
60ef223c | 228 | REM start and accumulator |
cc9dbd92 | 229 | P1%=ZK |
60ef223c | 230 | P2%=0 |
4b84a23b | 231 | CHECK_FREE_LIST_LOOP: |
cc9dbd92 | 232 | IF P1%>=ZI THEN GOTO CHECK_FREE_LIST_DONE |
60ef223c | 233 | IF (Z%(P1%,0)AND15)<>15 THEN P2%=-1:GOTO CHECK_FREE_LIST_DONE |
4b84a23b JM |
234 | P2%=P2%+(Z%(P1%,0)AND-16)/16 |
235 | P1%=Z%(P1%,1) | |
236 | GOTO CHECK_FREE_LIST_LOOP | |
237 | CHECK_FREE_LIST_DONE: | |
238 | IF P2%=-1 THEN PRINT "corrupt free list at "+STR$(P1%) | |
239 | RETURN | |
241d5d57 | 240 | |
4b84a23b JM |
241 | |
242 | REM general functions | |
b7b1787f | 243 | |
cc9dbd92 | 244 | REM EQUAL_Q(A, B) -> R |
241d5d57 | 245 | EQUAL_Q: |
60ef223c JM |
246 | GOSUB DEREF_A |
247 | GOSUB DEREF_B | |
4b84a23b | 248 | |
cc9dbd92 JM |
249 | R=0 |
250 | U1=(Z%(A,0)AND15) | |
251 | U2=(Z%(B,0)AND15) | |
252 | IF NOT ((U1=U2) OR ((U1=6 OR U1=7) AND (U2=6 OR U2=7))) THEN RETURN | |
253 | IF U1=6 THEN GOTO EQUAL_Q_SEQ | |
254 | IF U1=7 THEN GOTO EQUAL_Q_SEQ | |
255 | IF U1=8 THEN GOTO EQUAL_Q_HM | |
241d5d57 | 256 | |
cc9dbd92 | 257 | IF Z%(A,1)=Z%(B,1) THEN R=1 |
241d5d57 JM |
258 | RETURN |
259 | ||
260 | EQUAL_Q_SEQ: | |
cc9dbd92 JM |
261 | IF (Z%(A,1)=0) AND (Z%(B,1)=0) THEN R=1:RETURN |
262 | IF (Z%(A,1)=0) OR (Z%(B,1)=0) THEN R=0:RETURN | |
4b84a23b | 263 | |
cc9dbd92 JM |
264 | REM push A and B |
265 | X=X+2:S%(X-1)=A:S%(X)=B | |
60ef223c | 266 | REM compare the elements |
cc9dbd92 JM |
267 | A=Z%(A+1,1):B=Z%(B+1,1):GOSUB EQUAL_Q |
268 | REM pop A and B | |
269 | A=S%(X-1):B=S%(X):X=X-2 | |
270 | IF R=0 THEN RETURN | |
4b84a23b JM |
271 | |
272 | REM next elements of the sequences | |
cc9dbd92 | 273 | A=Z%(A,1):B=Z%(B,1):GOTO EQUAL_Q_SEQ |
241d5d57 | 274 | EQUAL_Q_HM: |
cc9dbd92 | 275 | R=0 |
241d5d57 JM |
276 | RETURN |
277 | ||
278 | REM string functions | |
b7b1787f | 279 | |
cc9dbd92 | 280 | REM STRING_(AS$) -> R |
241d5d57 | 281 | REM intern string (returns string index, not Z% index) |
bf8d1f7d | 282 | STRING_: |
cc9dbd92 | 283 | IF ZJ=0 THEN GOTO STRING_NOT_FOUND |
b7b1787f | 284 | |
cc9dbd92 JM |
285 | REM search for matching string in S$ |
286 | FOR I=0 TO ZJ-1 | |
287 | IF AS$=S$(I) THEN R=I:RETURN | |
241d5d57 JM |
288 | NEXT I |
289 | ||
290 | STRING_NOT_FOUND: | |
cc9dbd92 JM |
291 | S$(ZJ)=AS$ |
292 | R=ZJ | |
293 | ZJ=ZJ+1 | |
241d5d57 JM |
294 | RETURN |
295 | ||
cc9dbd92 | 296 | REM STRING(AS$, T) -> R |
bf8d1f7d JM |
297 | REM intern string and allocate reference (return Z% index) |
298 | STRING: | |
299 | GOSUB STRING_ | |
cc9dbd92 JM |
300 | TS%=R |
301 | SZ=1:GOSUB ALLOC | |
302 | Z%(R,0)=T | |
303 | Z%(R,1)=TS% | |
bf8d1f7d JM |
304 | RETURN |
305 | ||
85d70fb7 JM |
306 | REM REPLACE(R$, S1$, S2$) -> R$ |
307 | REPLACE: | |
308 | T3$=R$ | |
309 | R$="" | |
60ef223c JM |
310 | I=1 |
311 | J=LEN(T3$) | |
85d70fb7 JM |
312 | REPLACE_LOOP: |
313 | IF I>J THEN RETURN | |
314 | CH$=MID$(T3$,I,LEN(S1$)) | |
60ef223c JM |
315 | IF CH$=S1$ THEN R$=R$+S2$:I=I+LEN(S1$) |
316 | IF CH$<>S1$ THEN R$=R$+MID$(T3$,I,1):I=I+1 | |
85d70fb7 | 317 | GOTO REPLACE_LOOP |
241d5d57 JM |
318 | |
319 | ||
320 | REM list functions | |
321 | ||
cc9dbd92 | 322 | REM LIST_Q(A) -> R |
b7b1787f | 323 | LIST_Q: |
cc9dbd92 JM |
324 | R=0 |
325 | IF (Z%(A,0)AND15)=6 THEN R=1 | |
b7b1787f JM |
326 | RETURN |
327 | ||
cc9dbd92 | 328 | REM EMPTY_Q(A) -> R |
b7b1787f | 329 | EMPTY_Q: |
cc9dbd92 JM |
330 | R=0 |
331 | IF Z%(A,1)=0 THEN R=1 | |
b7b1787f JM |
332 | RETURN |
333 | ||
cc9dbd92 | 334 | REM COUNT(A) -> R |
4b84a23b | 335 | COUNT: |
cc9dbd92 | 336 | R=-1 |
4b84a23b | 337 | DO_COUNT_LOOP: |
cc9dbd92 JM |
338 | R=R+1 |
339 | IF Z%(A,1)<>0 THEN A=Z%(A,1):GOTO DO_COUNT_LOOP | |
4b84a23b JM |
340 | RETURN |
341 | ||
cc9dbd92 | 342 | REM LAST(A) -> R |
241d5d57 JM |
343 | LAST: |
344 | REM TODO check that actually a list/vector | |
cc9dbd92 JM |
345 | IF Z%(A,1)=0 THEN R=0:RETURN: REM empty seq, return nil |
346 | T6=0 | |
241d5d57 | 347 | LAST_LOOP: |
cc9dbd92 JM |
348 | IF Z%(A,1)=0 THEN GOTO LAST_DONE: REM end, return previous value |
349 | T6=A: REM current becomes previous entry | |
350 | A=Z%(A,1): REM next entry | |
241d5d57 | 351 | GOTO LAST_LOOP |
4b84a23b | 352 | LAST_DONE: |
cc9dbd92 JM |
353 | R=T6+1:GOSUB DEREF_R |
354 | Z%(R,0)=Z%(R,0)+16 | |
4b84a23b | 355 | RETURN |
241d5d57 | 356 | |
cc9dbd92 | 357 | REM CONS(A,B) -> R |
85d70fb7 | 358 | CONS: |
cc9dbd92 JM |
359 | SZ=2:GOSUB ALLOC |
360 | Z%(R,0)=6+16 | |
361 | Z%(R,1)=B | |
362 | Z%(R+1,0)=14 | |
363 | Z%(R+1,1)=A | |
85d70fb7 | 364 | REM inc ref cnt of item we are including |
cc9dbd92 | 365 | Z%(A,0)=Z%(A,0)+16 |
85d70fb7 | 366 | REM inc ref cnt of list we are prepending |
cc9dbd92 | 367 | Z%(B,0)=Z%(B,0)+16 |
85d70fb7 JM |
368 | RETURN |
369 | ||
cc9dbd92 JM |
370 | REM SLICE(A,B,C) -> R |
371 | REM make copy of sequence A from index B to C | |
372 | REM returns R6 as reference to last element of slice | |
373 | REM returns A as next element following slice (of original) | |
9e8f5211 JM |
374 | SLICE: |
375 | I=0 | |
cc9dbd92 JM |
376 | R5=-1: REM temporary for return as R |
377 | R6=0: REM previous list element | |
9e8f5211 | 378 | SLICE_LOOP: |
5e5ca0d4 | 379 | REM always allocate at least one list element |
cc9dbd92 JM |
380 | SZ=2:GOSUB ALLOC |
381 | Z%(R,0)=6+16:Z%(R,1)=0:Z%(R+1,0)=14:Z%(R+1,1)=0 | |
382 | IF R5=-1 THEN R5=R | |
383 | IF R5<>-1 THEN Z%(R6,1)=R | |
384 | REM advance A to position B | |
9e8f5211 | 385 | SLICE_FIND_B: |
cc9dbd92 JM |
386 | IF I<B AND Z%(A,1)<>0 THEN A=Z%(A,1):I=I+1:GOTO SLICE_FIND_B |
387 | REM if current position is C, then return | |
388 | IF C<>-1 AND I>=C THEN R=R5:RETURN | |
389 | REM if we reached end of A, then return | |
390 | IF Z%(A,1)=0 THEN R=R5:RETURN | |
391 | R6=R: REM save previous list element | |
9e8f5211 | 392 | REM copy value and inc ref cnt |
cc9dbd92 JM |
393 | Z%(R6+1,1)=Z%(A+1,1) |
394 | R=A+1:GOSUB DEREF_R:Z%(R,0)=Z%(R,0)+16 | |
395 | REM advance to next element of A | |
396 | A=Z%(A,1) | |
9e8f5211 JM |
397 | I=I+1 |
398 | GOTO SLICE_LOOP | |
399 | ||
cc9dbd92 | 400 | REM LIST2(B2%,B1%) -> R |
bf8d1f7d JM |
401 | LIST2: |
402 | REM terminator | |
cc9dbd92 JM |
403 | SZ=2:GOSUB ALLOC:TB%=R |
404 | Z%(R,0)=6+16:Z%(R,1)=0:Z%(R+1,0)=0:Z%(R+1,1)=0 | |
bf8d1f7d JM |
405 | |
406 | REM second element is B1% | |
cc9dbd92 JM |
407 | SZ=2:GOSUB ALLOC:TC%=R |
408 | Z%(R,0)=6+16:Z%(R,1)=TB%:Z%(R+1,0)=14:Z%(R+1,1)=B1% | |
bf8d1f7d JM |
409 | Z%(B1%,0)=Z%(B1%,0)+16 |
410 | ||
411 | REM first element is B2% | |
cc9dbd92 JM |
412 | SZ=2:GOSUB ALLOC |
413 | Z%(R,0)=6+16:Z%(R,1)=TC%:Z%(R+1,0)=14:Z%(R+1,1)=B2% | |
bf8d1f7d JM |
414 | Z%(B2%,0)=Z%(B2%,0)+16 |
415 | ||
416 | RETURN | |
417 | ||
cc9dbd92 | 418 | REM LIST3(B3%,B2%,B1%) -> R |
bf8d1f7d | 419 | LIST3: |
cc9dbd92 | 420 | GOSUB LIST2:TC%=R |
bf8d1f7d JM |
421 | |
422 | REM first element is B3% | |
cc9dbd92 JM |
423 | SZ=2:GOSUB ALLOC |
424 | Z%(R,0)=6+16:Z%(R,1)=TC%:Z%(R+1,0)=14:Z%(R+1,1)=B3% | |
bf8d1f7d JM |
425 | Z%(B3%,0)=Z%(B3%,0)+16 |
426 | ||
427 | RETURN | |
428 | ||
241d5d57 | 429 | REM hashmap functions |
b7b1787f | 430 | |
cc9dbd92 | 431 | REM HASHMAP() -> R |
b7b1787f | 432 | HASHMAP: |
cc9dbd92 JM |
433 | SZ=2:GOSUB ALLOC |
434 | Z%(R,0)=8+16 | |
435 | Z%(R,1)=0 | |
436 | Z%(R+1,0)=14 | |
437 | Z%(R+1,1)=0 | |
b7b1787f JM |
438 | RETURN |
439 | ||
cc9dbd92 | 440 | REM ASSOC1(H, K, V) -> R |
b7b1787f | 441 | ASSOC1: |
4b84a23b | 442 | REM deref to actual key and value |
cc9dbd92 JM |
443 | R=K:GOSUB DEREF_R:K=R |
444 | R=V:GOSUB DEREF_R:V=R | |
4b84a23b JM |
445 | |
446 | REM inc ref count of key and value | |
cc9dbd92 JM |
447 | Z%(K,0)=Z%(K,0)+16 |
448 | Z%(V,0)=Z%(V,0)+16 | |
449 | SZ=4:GOSUB ALLOC | |
b7b1787f | 450 | REM key ptr |
cc9dbd92 JM |
451 | Z%(R,0)=8+16 |
452 | Z%(R,1)=R+2: REM point to next element (value) | |
453 | Z%(R+1,0)=14 | |
454 | Z%(R+1,1)=K | |
b7b1787f | 455 | REM value ptr |
cc9dbd92 JM |
456 | Z%(R+2,0)=8+16 |
457 | Z%(R+2,1)=H: REM hashmap to assoc onto | |
458 | Z%(R+3,0)=14 | |
459 | Z%(R+3,1)=V | |
b7b1787f JM |
460 | RETURN |
461 | ||
cc9dbd92 | 462 | REM ASSOC1(H, K$, V) -> R |
b7b1787f JM |
463 | ASSOC1_S: |
464 | REM add the key string, then call ASSOC1 | |
cc9dbd92 JM |
465 | SZ=1:GOSUB ALLOC |
466 | K=R | |
467 | S$(ZJ)=K$ | |
468 | Z%(R,0)=4: REM key ref cnt will be inc'd by ASSOC1 | |
469 | Z%(R,1)=ZJ | |
470 | ZJ=ZJ+1 | |
b7b1787f JM |
471 | GOSUB ASSOC1 |
472 | RETURN | |
473 | ||
cc9dbd92 | 474 | REM HASHMAP_GET(H, K) -> R |
b7b1787f | 475 | HASHMAP_GET: |
cc9dbd92 JM |
476 | H2%=H |
477 | T1$=S$(Z%(K,1)): REM search key string | |
478 | T3=0: REM whether found or not (for HASHMAP_CONTAINS) | |
479 | R=0 | |
b7b1787f JM |
480 | HASHMAP_GET_LOOP: |
481 | REM no matching key found | |
cc9dbd92 | 482 | IF Z%(H2%,1)=0 THEN R=0:RETURN |
b7b1787f | 483 | REM follow value ptrs |
cc9dbd92 | 484 | T2=H2%+1 |
b7b1787f | 485 | HASHMAP_GET_DEREF: |
cc9dbd92 | 486 | IF Z%(T2,0)=14 THEN T2=Z%(T2,1):GOTO HASHMAP_GET_DEREF |
b7b1787f | 487 | REM get key string |
cc9dbd92 | 488 | T2$=S$(Z%(T2,1)) |
b7b1787f | 489 | REM if they are equal, we found it |
cc9dbd92 | 490 | IF T1$=T2$ THEN T3=1:R=Z%(H2%,1)+1:RETURN |
b7b1787f JM |
491 | REM skip to next key |
492 | H2%=Z%(Z%(H2%,1),1) | |
493 | GOTO HASHMAP_GET_LOOP | |
494 | ||
cc9dbd92 | 495 | REM HASHMAP_CONTAINS(H, K) -> R |
b7b1787f JM |
496 | HASHMAP_CONTAINS: |
497 | GOSUB HASHMAP_GET | |
cc9dbd92 | 498 | R=T3 |
b7b1787f JM |
499 | RETURN |
500 | ||
cc9dbd92 | 501 | REM NATIVE_FUNCTION(A) -> R |
b7b1787f | 502 | NATIVE_FUNCTION: |
cc9dbd92 JM |
503 | SZ=1:GOSUB ALLOC |
504 | Z%(R,0)=9+16 | |
505 | Z%(R,1)=A | |
b7b1787f | 506 | RETURN |
11f94d2e | 507 | |
cc9dbd92 | 508 | REM MAL_FUNCTION(A, P, E) -> R |
b7b1787f | 509 | MAL_FUNCTION: |
cc9dbd92 JM |
510 | SZ=2:GOSUB ALLOC |
511 | Z%(A,0)=Z%(A,0)+16 | |
512 | Z%(P,0)=Z%(P,0)+16 | |
513 | Z%(E,0)=Z%(E,0)+16 | |
514 | ||
515 | Z%(R,0)=10+16 | |
516 | Z%(R,1)=A | |
517 | Z%(R+1,0)=P | |
518 | Z%(R+1,1)=E | |
11f94d2e | 519 | RETURN |
70f29a2b | 520 | |
cc9dbd92 JM |
521 | REM APPLY(F, AR) -> R |
522 | REM restores E | |
70f29a2b | 523 | APPLY: |
cc9dbd92 JM |
524 | IF (Z%(F,0)AND15)=9 THEN GOTO DO_APPLY_FUNCTION |
525 | IF (Z%(F,0)AND15)=10 THEN GOTO DO_APPLY_MAL_FUNCTION | |
526 | IF (Z%(F,0)AND15)=11 THEN GOTO DO_APPLY_MAL_FUNCTION | |
70f29a2b JM |
527 | |
528 | DO_APPLY_FUNCTION: | |
529 | GOSUB DO_FUNCTION | |
530 | ||
531 | RETURN | |
532 | ||
533 | DO_APPLY_MAL_FUNCTION: | |
cc9dbd92 | 534 | X=X+1:S%(X)=E: REM save the current environment |
70f29a2b JM |
535 | |
536 | REM create new environ using env and params stored in the | |
537 | REM function and bind the params to the apply arguments | |
cc9dbd92 | 538 | O=Z%(F+1,1):BI%=Z%(F+1,0):EX%=AR:GOSUB ENV_NEW_BINDS |
70f29a2b | 539 | |
cc9dbd92 | 540 | A=Z%(F,1):E=R:GOSUB EVAL |
70f29a2b | 541 | |
cc9dbd92 | 542 | AY=E:GOSUB RELEASE: REM release the new environment |
70f29a2b | 543 | |
cc9dbd92 | 544 | E=S%(X):X=X-1: REM pop/restore the saved environment |
70f29a2b JM |
545 | |
546 | RETURN | |
547 |