Basic: variable renaming. Save 2 kbytes.
[jackhill/mal.git] / basic / types.in.bas
CommitLineData
b7b1787f
JM
1REM Z 0 -> 1
2REM nil 0 -> (unused)
3REM boolean 1 -> 0: false, 1: true
4REM integer 2 -> int value
5REM float 3 -> ???
cc9dbd92
JM
6REM string/kw 4 -> S$ index
7REM symbol 5 -> S$ index
60270667 8REM list next/val 6 -> next Z% index (0 for last)
b7b1787f 9REM followed by value (unless empty)
60270667 10REM vector next/val 7 -> next Z% index (0 for last)
b7b1787f 11REM followed by value (unless empty)
60270667 12REM hashmap next/val 8 -> next Z% index (0 for last)
b7b1787f 13REM followed by key or value (alternating)
60270667 14REM function 9 -> function index
4b84a23b
JM
15REM mal function 10 -> body AST Z% index
16REM followed by param and env Z% index
70f29a2b
JM
17REM macro (same as 10) 11 -> body AST Z% index
18REM followed by param and env Z% index
bf8d1f7d 19REM atom 12 -> Z% index
4b84a23b
JM
20REM environment 13 -> data/hashmap Z% index
21REM followed by 13 and outer Z% index (-1 for none)
22REM reference/ptr 14 -> Z% index / or 0
23REM next free ptr 15 -> Z% index / or 0
11f94d2e
JM
24
25INIT_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
69REM memory functions
70
cc9dbd92 71REM ALLOC(SZ) -> R
4b84a23b 72ALLOC:
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 101REM FREE(AY, SZ) -> nil
4b84a23b
JM
102FREE:
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
112REM RELEASE(AY) -> nil
113REM R should not be affected by this call
4b84a23b 114RELEASE:
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 203REM RELEASE_PEND(LV) -> nil
4b84a23b
JM
204RELEASE_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 212REM DEREF_R(R) -> R
4b84a23b 213DEREF_R:
cc9dbd92 214 IF (Z%(R,0)AND15)=14 THEN R=Z%(R,1):GOTO DEREF_R
4b84a23b
JM
215 RETURN
216
cc9dbd92 217REM DEREF_A(A) -> A
4b84a23b 218DEREF_A:
cc9dbd92 219 IF (Z%(A,0)AND15)=14 THEN A=Z%(A,1):GOTO DEREF_A
4b84a23b
JM
220 RETURN
221
cc9dbd92 222REM DEREF_B(B) -> B
4b84a23b 223DEREF_B:
cc9dbd92 224 IF (Z%(B,0)AND15)=14 THEN B=Z%(B,1):GOTO DEREF_B
4b84a23b
JM
225 RETURN
226
227CHECK_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
242REM general functions
b7b1787f 243
cc9dbd92 244REM EQUAL_Q(A, B) -> R
241d5d57 245EQUAL_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
278REM string functions
b7b1787f 279
cc9dbd92 280REM STRING_(AS$) -> R
241d5d57 281REM intern string (returns string index, not Z% index)
bf8d1f7d 282STRING_:
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 296REM STRING(AS$, T) -> R
bf8d1f7d
JM
297REM intern string and allocate reference (return Z% index)
298STRING:
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
306REM REPLACE(R$, S1$, S2$) -> R$
307REPLACE:
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
320REM list functions
321
cc9dbd92 322REM LIST_Q(A) -> R
b7b1787f 323LIST_Q:
cc9dbd92
JM
324 R=0
325 IF (Z%(A,0)AND15)=6 THEN R=1
b7b1787f
JM
326 RETURN
327
cc9dbd92 328REM EMPTY_Q(A) -> R
b7b1787f 329EMPTY_Q:
cc9dbd92
JM
330 R=0
331 IF Z%(A,1)=0 THEN R=1
b7b1787f
JM
332 RETURN
333
cc9dbd92 334REM COUNT(A) -> R
4b84a23b 335COUNT:
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 342REM LAST(A) -> R
241d5d57
JM
343LAST:
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 357REM CONS(A,B) -> R
85d70fb7 358CONS:
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
370REM SLICE(A,B,C) -> R
371REM make copy of sequence A from index B to C
372REM returns R6 as reference to last element of slice
373REM returns A as next element following slice (of original)
9e8f5211
JM
374SLICE:
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 400REM LIST2(B2%,B1%) -> R
bf8d1f7d
JM
401LIST2:
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 418REM LIST3(B3%,B2%,B1%) -> R
bf8d1f7d 419LIST3:
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 429REM hashmap functions
b7b1787f 430
cc9dbd92 431REM HASHMAP() -> R
b7b1787f 432HASHMAP:
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 440REM ASSOC1(H, K, V) -> R
b7b1787f 441ASSOC1:
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 462REM ASSOC1(H, K$, V) -> R
b7b1787f
JM
463ASSOC1_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 474REM HASHMAP_GET(H, K) -> R
b7b1787f 475HASHMAP_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 495REM HASHMAP_CONTAINS(H, K) -> R
b7b1787f
JM
496HASHMAP_CONTAINS:
497 GOSUB HASHMAP_GET
cc9dbd92 498 R=T3
b7b1787f
JM
499 RETURN
500
cc9dbd92 501REM NATIVE_FUNCTION(A) -> R
b7b1787f 502NATIVE_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 508REM MAL_FUNCTION(A, P, E) -> R
b7b1787f 509MAL_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
521REM APPLY(F, AR) -> R
522REM restores E
70f29a2b 523APPLY:
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