2015-02-18 02:47:23 +03:00
|
|
|
require str.fs
|
|
|
|
|
2015-02-05 04:05:03 +03:00
|
|
|
\ === sorted-array === /
|
|
|
|
\ Here are a few utility functions useful for creating and maintaining
|
|
|
|
\ the deftype* method tables. The keys array is kept in sorted order,
|
|
|
|
\ and the methods array is maintained in parallel so that an index into
|
|
|
|
\ one corresponds to an index in the other.
|
|
|
|
|
|
|
|
\ Search a sorted array for key, returning the index of where it was
|
|
|
|
\ found. If key is not in the array, return the index where it would
|
|
|
|
\ be if added.
|
|
|
|
: array-find { a-length a-addr key -- index found? }
|
|
|
|
0 a-length ( start end )
|
|
|
|
begin
|
|
|
|
\ cr 2dup . .
|
|
|
|
2dup + 2 / dup ( start end middle middle )
|
|
|
|
cells a-addr + @ ( start end middle mid-val )
|
|
|
|
dup key < if
|
|
|
|
drop rot ( end middle start )
|
|
|
|
2dup = if
|
|
|
|
2drop dup ( end end )
|
|
|
|
else
|
|
|
|
drop swap ( middle end )
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
key > if ( start end middle )
|
2015-02-06 10:38:58 +03:00
|
|
|
nip ( start middle )
|
2015-02-05 04:05:03 +03:00
|
|
|
else
|
|
|
|
-rot 2drop dup ( middle middle )
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
2dup = until
|
|
|
|
cells a-addr + @ key =
|
|
|
|
;
|
|
|
|
|
|
|
|
\ Create a new array, one cell in length, initialized the provided value
|
|
|
|
: new-array { value -- array }
|
|
|
|
cell allocate throw value over ! ;
|
|
|
|
|
|
|
|
\ Resize a heap-allocated array to be one cell longer, inserting value
|
|
|
|
\ at idx, and shifting the tail of the array as necessary. Returns the
|
|
|
|
\ (possibly new) array address
|
|
|
|
: array-insert { old-array-length old-array idx value -- array }
|
|
|
|
old-array old-array-length 1+ cells resize throw
|
|
|
|
{ a }
|
|
|
|
a idx cells + dup cell+ old-array-length idx - cells cmove>
|
|
|
|
value a idx cells + !
|
|
|
|
a
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2015-02-06 08:38:34 +03:00
|
|
|
\ === deftype* -- protocol-enabled structs === /
|
|
|
|
\ Each type has MalTypeType% struct allocated on the stack, with
|
|
|
|
\ mutable fields pointing to all class-shared resources, specifically
|
|
|
|
\ the data needed to allocate new instances, and the table of protocol
|
|
|
|
\ methods that have been extended to the type.
|
|
|
|
\ Use 'deftype*' to define a new type, and 'new' to create new
|
|
|
|
\ instances of that type.
|
|
|
|
|
|
|
|
struct
|
|
|
|
cell% field mal-type
|
2015-02-19 03:57:39 +03:00
|
|
|
cell% field mal-meta
|
2015-02-06 08:38:34 +03:00
|
|
|
\ cell% field ref-count \ Ha, right.
|
|
|
|
end-struct MalType%
|
|
|
|
|
|
|
|
struct
|
|
|
|
cell% 2 * field MalTypeType-struct
|
|
|
|
cell% field MalTypeType-methods
|
|
|
|
cell% field MalTypeType-method-keys
|
|
|
|
cell% field MalTypeType-method-vals
|
2015-02-13 03:27:00 +03:00
|
|
|
cell% field MalTypeType-name-addr
|
|
|
|
cell% field MalTypeType-name-len
|
2015-02-06 08:38:34 +03:00
|
|
|
end-struct MalTypeType%
|
|
|
|
|
|
|
|
: new ( MalTypeType -- obj )
|
|
|
|
dup MalTypeType-struct 2@ %allocate throw ( MalTypeType obj ) \ create struct
|
|
|
|
dup -rot mal-type ! ( obj ) \ set struct's type pointer to this type
|
2015-02-19 03:57:39 +03:00
|
|
|
nil over mal-meta !
|
2015-02-06 08:38:34 +03:00
|
|
|
;
|
|
|
|
|
|
|
|
: deftype* ( struct-align struct-len -- MalTypeType )
|
|
|
|
MalTypeType% %allot ( s-a s-l MalTypeType )
|
|
|
|
dup 2swap rot ( MalTypeType s-a s-l MalTypeType )
|
|
|
|
MalTypeType-struct 2! ( MalTypeType ) \ store struct info
|
|
|
|
dup MalTypeType-methods 0 swap ! ( MalTypeType )
|
|
|
|
dup MalTypeType-method-keys nil swap ! ( MalTypeType )
|
|
|
|
dup MalTypeType-method-vals nil swap ! ( MalTypeType )
|
2015-02-13 03:27:00 +03:00
|
|
|
dup MalTypeType-name-len 0 swap ! ( MalTypeType )
|
2015-02-06 08:38:34 +03:00
|
|
|
;
|
|
|
|
|
2015-02-15 00:08:17 +03:00
|
|
|
\ parse-name uses temporary space, so copy into dictionary stack:
|
|
|
|
: parse-allot-name { -- new-str-addr str-len }
|
|
|
|
parse-name { str-addr str-len }
|
|
|
|
here { new-str-addr } str-len allot
|
|
|
|
str-addr new-str-addr str-len cmove
|
|
|
|
new-str-addr str-len ;
|
|
|
|
|
2015-02-13 03:27:00 +03:00
|
|
|
: deftype ( struct-align struct-len R:type-name -- )
|
2015-02-15 00:08:17 +03:00
|
|
|
parse-allot-name { name-addr name-len }
|
2015-02-13 03:27:00 +03:00
|
|
|
|
|
|
|
\ allot and initialize type structure
|
|
|
|
deftype* { mt }
|
|
|
|
name-addr mt MalTypeType-name-addr !
|
|
|
|
name-len mt MalTypeType-name-len !
|
|
|
|
\ ." Defining " mt MalTypeType-name-addr @ mt MalTypeType-name-len @ type cr
|
|
|
|
mt name-addr name-len nextname 1 0 const-does> ;
|
|
|
|
|
|
|
|
: type-name ( mal-type )
|
|
|
|
dup MalTypeType-name-addr @ ( mal-type name-addr )
|
|
|
|
swap MalTypeType-name-len @ ( name-addr name-len )
|
|
|
|
;
|
|
|
|
|
|
|
|
MalType% deftype MalDefault
|
2015-02-06 08:38:34 +03:00
|
|
|
|
|
|
|
\ nil type and instance to support extending protocols to it
|
2015-02-15 21:33:44 +03:00
|
|
|
MalType% deftype MalNil MalNil new constant mal-nil
|
|
|
|
MalType% deftype MalTrue MalTrue new constant mal-true
|
|
|
|
MalType% deftype MalFalse MalFalse new constant mal-false
|
|
|
|
|
|
|
|
: mal-bool
|
|
|
|
0= if mal-false else mal-true endif ;
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
: not-object? ( obj -- bool )
|
|
|
|
dup 7 and 0 <> if
|
2015-02-16 01:44:52 +03:00
|
|
|
drop true
|
2015-02-14 23:18:18 +03:00
|
|
|
else
|
|
|
|
1000000 <
|
|
|
|
endif ;
|
|
|
|
|
2015-02-05 04:05:03 +03:00
|
|
|
\ === protocol methods === /
|
|
|
|
|
2015-02-16 00:46:34 +03:00
|
|
|
0 constant trace
|
|
|
|
|
2015-02-05 04:05:03 +03:00
|
|
|
\ Used by protocol methods to find the appropriate implementation of
|
|
|
|
\ themselves for the given object, and then execute that implementation.
|
|
|
|
: execute-method { obj pxt -- }
|
2015-02-14 23:18:18 +03:00
|
|
|
obj not-object? if
|
2015-02-18 02:47:23 +03:00
|
|
|
0 0 obj int>str s" ' on non-object: " pxt >name name>string
|
|
|
|
s" Refusing to invoke protocol fn '" ...throw-str
|
2015-02-14 23:18:18 +03:00
|
|
|
endif
|
2015-02-05 04:05:03 +03:00
|
|
|
obj mal-type @ dup MalTypeType-methods 2@ swap ( type methods method-keys )
|
|
|
|
dup 0= if \ No protocols extended to this type; check for a default
|
|
|
|
2drop drop MalDefault MalTypeType-methods 2@ swap
|
|
|
|
endif
|
|
|
|
|
|
|
|
pxt array-find ( type idx found? )
|
|
|
|
dup 0= if \ No implementation found for this method; check for a default
|
2015-02-05 05:44:37 +03:00
|
|
|
2drop drop MalDefault dup MalTypeType-methods 2@ swap
|
2015-02-05 04:05:03 +03:00
|
|
|
pxt array-find ( type idx found? )
|
|
|
|
endif
|
2015-02-13 03:27:00 +03:00
|
|
|
0= if ( type idx )
|
|
|
|
2drop
|
2015-02-18 02:47:23 +03:00
|
|
|
0 0 s" '" obj mal-type @ type-name s" ' extended to type '"
|
|
|
|
pxt >name name>string s" No protocol fn '" ...throw-str
|
2015-02-13 03:27:00 +03:00
|
|
|
endif
|
2015-02-16 00:46:34 +03:00
|
|
|
trace if ." Calling '" pxt >name name>string type ." ' on " obj mal-type @ type-name type cr endif
|
2015-02-05 04:05:03 +03:00
|
|
|
|
|
|
|
cells swap MalTypeType-method-vals @ + @ ( xt )
|
2015-02-16 00:46:34 +03:00
|
|
|
obj swap execute ;
|
2015-02-05 04:05:03 +03:00
|
|
|
|
|
|
|
\ Extend a type with a protocol method. This mutates the MalTypeType
|
|
|
|
\ object that represents the MalType being extended.
|
|
|
|
: extend-method* { type pxt ixt -- type }
|
|
|
|
type MalTypeType-methods 2@ swap ( methods method-keys )
|
|
|
|
dup 0= if \ no protocols extended to this type
|
|
|
|
2drop
|
|
|
|
1 type MalTypeType-methods !
|
|
|
|
pxt new-array type MalTypeType-method-keys !
|
|
|
|
ixt new-array type MalTypeType-method-vals !
|
|
|
|
else
|
|
|
|
pxt array-find { idx found? }
|
|
|
|
found? if \ overwrite
|
|
|
|
." Warning: overwriting protocol method implementation"
|
|
|
|
type MalTypeType-method-vals @ idx cells + ixt !
|
|
|
|
else \ resize
|
|
|
|
type MalTypeType-methods dup @ 1+ dup rot ! ( new-count )
|
|
|
|
1- dup type MalTypeType-method-keys @ idx pxt array-insert ( old-count new-array )
|
|
|
|
type MalTypeType-method-keys ! ( old-count )
|
|
|
|
type MalTypeType-method-vals @ idx ixt array-insert ( new-array )
|
|
|
|
type MalTypeType-method-vals !
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
type
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2015-02-05 05:44:37 +03:00
|
|
|
\ def-protocol-method pr-str ...can be written:
|
|
|
|
\ : pr-str ( obj -- str ) [ latestxt ] literal execute-method ;
|
|
|
|
: def-protocol-method ( "name" -- )
|
|
|
|
create latestxt ,
|
|
|
|
does> ( ??? obj xt-ref -- ??? )
|
|
|
|
@ execute-method ;
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-15 00:08:17 +03:00
|
|
|
: extend ( type -- type pxt install-xt <noname...>)
|
2015-02-05 05:44:37 +03:00
|
|
|
parse-name find-name name>int ( type pxt )
|
2015-02-15 00:08:17 +03:00
|
|
|
['] extend-method*
|
2015-02-05 05:44:37 +03:00
|
|
|
:noname
|
|
|
|
;
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-05 05:44:37 +03:00
|
|
|
: ;; ( type pxt <noname...> -- type )
|
2015-02-15 00:08:17 +03:00
|
|
|
[compile] ; ( type pxt install-xt ixt )
|
|
|
|
swap execute
|
2015-02-05 05:44:37 +03:00
|
|
|
; immediate
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-05 05:44:37 +03:00
|
|
|
(
|
|
|
|
\ These whole-protocol names are only needed for 'satisfies?':
|
2015-02-05 04:05:03 +03:00
|
|
|
protocol IPrintable
|
2015-02-05 05:44:37 +03:00
|
|
|
def-protocol-method pr-str
|
2015-02-05 04:05:03 +03:00
|
|
|
end-protocol
|
|
|
|
|
2015-02-05 05:44:37 +03:00
|
|
|
MalList IPrintable extend
|
2015-02-05 04:05:03 +03:00
|
|
|
' pr-str :noname drop s" <unprintable>" ; extend-method*
|
|
|
|
|
|
|
|
extend-method pr-str
|
2015-02-05 05:44:37 +03:00
|
|
|
drop s" <unprintable>" ;;
|
2015-02-05 04:05:03 +03:00
|
|
|
end-extend
|
|
|
|
)
|
|
|
|
|
2015-02-06 08:38:34 +03:00
|
|
|
\ === Mal types and protocols === /
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-14 21:40:07 +03:00
|
|
|
def-protocol-method conj ( obj this -- this )
|
|
|
|
def-protocol-method assoc ( k v this -- this )
|
2015-02-19 03:57:39 +03:00
|
|
|
def-protocol-method dissoc ( k this -- this )
|
2015-02-14 21:40:07 +03:00
|
|
|
def-protocol-method get ( not-found k this -- value )
|
|
|
|
def-protocol-method mal= ( a b -- bool )
|
|
|
|
def-protocol-method as-native ( obj -- )
|
2015-02-15 21:33:44 +03:00
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
def-protocol-method to-list ( obj -- mal-list )
|
2015-02-15 21:33:44 +03:00
|
|
|
def-protocol-method empty? ( obj -- mal-bool )
|
|
|
|
def-protocol-method mal-count ( obj -- mal-int )
|
2015-02-19 03:57:39 +03:00
|
|
|
def-protocol-method sequential? ( obj -- mal-bool )
|
|
|
|
|
|
|
|
|
|
|
|
\ Fully evalutate any Mal object:
|
|
|
|
def-protocol-method mal-eval ( env ast -- val )
|
|
|
|
|
|
|
|
\ Invoke an object, given whole env and unevaluated argument forms:
|
|
|
|
def-protocol-method eval-invoke ( env list obj -- ... )
|
|
|
|
|
|
|
|
\ Invoke a function, given parameter values
|
|
|
|
def-protocol-method invoke ( argv argc mal-fn -- ... )
|
|
|
|
|
|
|
|
|
2015-02-14 21:40:07 +03:00
|
|
|
: m= ( a b -- bool )
|
|
|
|
2dup = if
|
2015-02-16 01:44:52 +03:00
|
|
|
2drop true
|
2015-02-14 21:40:07 +03:00
|
|
|
else
|
|
|
|
mal=
|
|
|
|
endif ;
|
|
|
|
|
2015-02-15 21:33:44 +03:00
|
|
|
|
|
|
|
MalType%
|
|
|
|
cell% field MalInt/int
|
|
|
|
deftype MalInt
|
|
|
|
|
|
|
|
: MalInt. { int -- mal-int }
|
|
|
|
MalInt new dup MalInt/int int swap ! ;
|
|
|
|
|
|
|
|
MalInt
|
|
|
|
extend mal= ( other this -- bool )
|
|
|
|
over mal-type @ MalInt = if
|
|
|
|
MalInt/int @ swap MalInt/int @ =
|
|
|
|
else
|
|
|
|
2drop 0
|
|
|
|
endif ;;
|
|
|
|
|
|
|
|
extend as-native ( mal-int -- int )
|
|
|
|
MalInt/int @ ;;
|
|
|
|
drop
|
|
|
|
|
|
|
|
|
2015-02-06 08:38:34 +03:00
|
|
|
MalType%
|
2015-02-14 23:18:18 +03:00
|
|
|
cell% field MalList/count
|
|
|
|
cell% field MalList/start
|
2015-02-13 03:27:00 +03:00
|
|
|
deftype MalList
|
2015-02-06 08:38:34 +03:00
|
|
|
|
2015-02-19 03:57:39 +03:00
|
|
|
: MalList. ( start count -- mal-list )
|
|
|
|
MalList new
|
|
|
|
swap over MalList/count ! ( start list )
|
|
|
|
swap over MalList/start ! ( list ) ;
|
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
: here>MalList ( old-here -- mal-list )
|
2015-02-13 03:27:00 +03:00
|
|
|
here over - { bytes } ( old-here )
|
2015-02-14 23:18:18 +03:00
|
|
|
MalList new bytes ( old-here mal-list bytes )
|
|
|
|
allocate throw dup { target } over MalList/start ! ( old-here mal-list )
|
|
|
|
bytes cell / over MalList/count ! ( old-here mal-list )
|
|
|
|
swap target bytes cmove ( mal-list )
|
|
|
|
0 bytes - allot \ pop list contents from dictionary stack
|
2015-02-13 03:27:00 +03:00
|
|
|
;
|
|
|
|
|
2015-02-19 03:57:39 +03:00
|
|
|
: MalList/concat ( list-of-lists )
|
|
|
|
dup MalList/start @ swap MalList/count @ { lists argc }
|
|
|
|
0 lists argc cells + lists +do ( count )
|
|
|
|
i @ to-list MalList/count @ +
|
|
|
|
cell +loop { count }
|
|
|
|
count cells allocate throw { start }
|
|
|
|
start lists argc cells + lists +do ( target )
|
|
|
|
i @ to-list MalList/count @ cells 2dup i @ to-list MalList/start @ -rot ( target bytes src target bytes )
|
|
|
|
cmove ( target bytes )
|
|
|
|
+ ( new-target )
|
|
|
|
cell +loop
|
|
|
|
drop start count MalList. ;
|
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
MalList
|
|
|
|
extend to-list ;;
|
2015-02-19 03:57:39 +03:00
|
|
|
extend sequential? drop mal-true ;;
|
2015-02-14 23:18:18 +03:00
|
|
|
extend conj { elem old-list -- list }
|
|
|
|
old-list MalList/count @ 1+ { new-count }
|
2015-02-14 21:40:07 +03:00
|
|
|
new-count cells allocate throw { new-start }
|
|
|
|
elem new-start !
|
|
|
|
new-count 1 > if
|
2015-02-14 23:18:18 +03:00
|
|
|
old-list MalList/start @ new-start cell+ new-count 1- cells cmove
|
2015-02-14 21:40:07 +03:00
|
|
|
endif
|
2015-02-19 03:57:39 +03:00
|
|
|
new-start new-count MalList. ;;
|
2015-02-15 21:33:44 +03:00
|
|
|
extend empty? MalList/count @ 0= mal-bool ;;
|
|
|
|
extend mal-count MalList/count @ MalInt. ;;
|
|
|
|
extend mal=
|
2015-02-20 02:34:59 +03:00
|
|
|
over mal-nil = if
|
|
|
|
2drop false
|
2015-02-15 21:33:44 +03:00
|
|
|
else
|
2015-02-20 02:34:59 +03:00
|
|
|
swap to-list dup 0= if
|
|
|
|
nip
|
2015-02-15 21:33:44 +03:00
|
|
|
else
|
2015-02-20 02:34:59 +03:00
|
|
|
2dup MalList/count @ swap MalList/count @ over = if ( list-a list-b count )
|
|
|
|
-rot MalList/start @ swap MalList/start @ { start-b start-a }
|
|
|
|
true swap ( return-val count )
|
|
|
|
0 ?do
|
|
|
|
start-a i cells + @
|
|
|
|
start-b i cells + @
|
|
|
|
m= if else
|
|
|
|
drop false leave
|
|
|
|
endif
|
|
|
|
loop
|
|
|
|
else
|
|
|
|
drop 2drop false
|
|
|
|
endif
|
2015-02-15 21:33:44 +03:00
|
|
|
endif
|
|
|
|
endif ;;
|
2015-02-14 21:40:07 +03:00
|
|
|
drop
|
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
MalList new 0 over MalList/count ! constant MalList/Empty
|
2015-02-05 04:05:03 +03:00
|
|
|
|
2015-02-17 04:12:44 +03:00
|
|
|
: MalList/rest { list -- list }
|
2015-02-19 03:57:39 +03:00
|
|
|
list MalList/start @ cell+
|
|
|
|
list MalList/count @ 1-
|
|
|
|
MalList. ;
|
2015-02-17 04:12:44 +03:00
|
|
|
|
|
|
|
|
2015-02-07 07:58:41 +03:00
|
|
|
MalType%
|
|
|
|
cell% field MalVector/list
|
2015-02-13 03:27:00 +03:00
|
|
|
deftype MalVector
|
2015-02-07 07:58:41 +03:00
|
|
|
|
2015-02-14 21:40:07 +03:00
|
|
|
MalVector
|
2015-02-19 03:57:39 +03:00
|
|
|
extend sequential? drop mal-true ;;
|
2015-02-14 23:18:18 +03:00
|
|
|
extend to-list
|
2015-02-16 00:46:34 +03:00
|
|
|
MalVector/list @ ;;
|
2015-02-15 21:33:44 +03:00
|
|
|
extend empty?
|
|
|
|
MalVector/list @
|
|
|
|
MalList/count @ 0= mal-bool ;;
|
|
|
|
extend mal-count
|
|
|
|
MalVector/list @
|
|
|
|
MalList/count @ MalInt. ;;
|
2015-02-16 00:46:34 +03:00
|
|
|
extend mal=
|
|
|
|
MalVector/list @ swap m= ;;
|
2015-02-19 03:57:39 +03:00
|
|
|
extend conj
|
|
|
|
MalVector/list @ { elem old-list }
|
|
|
|
old-list MalList/count @ { old-count }
|
|
|
|
old-count 1+ cells allocate throw { new-start }
|
|
|
|
elem new-start old-count cells + !
|
|
|
|
old-list MalList/start @ new-start old-count cells cmove
|
|
|
|
new-start old-count 1+ MalList.
|
|
|
|
MalVector new swap
|
|
|
|
over MalVector/list ! ;;
|
2015-02-14 21:40:07 +03:00
|
|
|
drop
|
|
|
|
|
2015-02-07 18:01:31 +03:00
|
|
|
MalType%
|
|
|
|
cell% field MalMap/list
|
2015-02-13 03:27:00 +03:00
|
|
|
deftype MalMap
|
|
|
|
|
2015-02-14 23:18:18 +03:00
|
|
|
MalMap new MalList/Empty over MalMap/list ! constant MalMap/Empty
|
2015-02-13 03:27:00 +03:00
|
|
|
|
|
|
|
MalMap
|
|
|
|
extend conj ( kv map -- map )
|
|
|
|
MalMap/list @ \ get list
|
2015-02-14 23:18:18 +03:00
|
|
|
over MalList/start @ cell+ @ swap conj \ add value
|
|
|
|
swap MalList/start @ @ swap conj \ add key
|
2015-02-14 21:40:07 +03:00
|
|
|
MalMap new dup -rot MalMap/list ! \ put back in map
|
2015-02-13 03:27:00 +03:00
|
|
|
;;
|
|
|
|
extend assoc ( k v map -- map )
|
|
|
|
MalMap/list @ \ get list
|
2015-02-14 23:18:18 +03:00
|
|
|
conj conj
|
2015-02-13 03:27:00 +03:00
|
|
|
MalMap new dup -rot MalMap/list ! \ put back in map
|
|
|
|
;;
|
2015-02-19 03:57:39 +03:00
|
|
|
extend dissoc { k map -- map }
|
|
|
|
map MalMap/list @
|
|
|
|
dup MalList/start @ swap MalList/count @ { start count }
|
|
|
|
map \ return original if key not found
|
|
|
|
count 0 +do
|
|
|
|
start i cells + @ k mal= if
|
|
|
|
drop here
|
|
|
|
start i MalList. ,
|
|
|
|
start i 2 + cells + count i - 2 - MalList. ,
|
|
|
|
here>MalList MalList/concat
|
|
|
|
MalMap new dup -rot MalMap/list ! \ put back in map
|
|
|
|
endif
|
|
|
|
2 +loop ;;
|
2015-02-14 21:40:07 +03:00
|
|
|
extend get { not-found k map -- value }
|
|
|
|
map MalMap/list @
|
2015-02-14 23:18:18 +03:00
|
|
|
dup MalList/start @ { start }
|
|
|
|
MalList/count @ { count }
|
2015-02-14 21:40:07 +03:00
|
|
|
0
|
2015-02-13 03:27:00 +03:00
|
|
|
begin
|
2015-02-14 21:40:07 +03:00
|
|
|
dup count >= if
|
2015-02-16 01:44:52 +03:00
|
|
|
drop not-found true
|
2015-02-13 03:27:00 +03:00
|
|
|
else
|
2015-02-14 21:40:07 +03:00
|
|
|
start over cells + @ k m= if
|
2015-02-16 01:44:52 +03:00
|
|
|
start swap cells + cell+ @ true \ found it ( value true )
|
2015-02-13 03:27:00 +03:00
|
|
|
else
|
2015-02-16 01:44:52 +03:00
|
|
|
2 + false
|
2015-02-13 03:27:00 +03:00
|
|
|
endif
|
|
|
|
endif
|
|
|
|
until ;;
|
2015-02-15 21:33:44 +03:00
|
|
|
extend empty?
|
|
|
|
MalMap/list @
|
|
|
|
MalList/count @ 0= mal-bool ;;
|
|
|
|
extend mal-count
|
|
|
|
MalMap/list @
|
|
|
|
MalList/count @ 2 / MalInt. ;;
|
2015-02-13 03:27:00 +03:00
|
|
|
drop
|
2015-02-07 18:01:31 +03:00
|
|
|
|
2015-02-05 05:44:37 +03:00
|
|
|
\ Examples of extending existing protocol methods to existing type
|
|
|
|
MalDefault
|
|
|
|
extend conj ( obj this -- this )
|
2015-02-06 10:38:58 +03:00
|
|
|
nip ;;
|
2015-02-13 03:27:00 +03:00
|
|
|
extend as-native ;; ( obj -- obj )
|
2015-02-15 21:33:44 +03:00
|
|
|
extend to-list drop 0 ;;
|
2015-02-17 05:28:05 +03:00
|
|
|
extend empty? drop mal-true ;;
|
2015-02-19 03:57:39 +03:00
|
|
|
extend sequential? drop mal-false ;;
|
2015-02-20 02:34:59 +03:00
|
|
|
extend mal= = ;;
|
2015-02-05 05:44:37 +03:00
|
|
|
drop
|
|
|
|
|
|
|
|
MalNil
|
2015-02-14 23:18:18 +03:00
|
|
|
extend conj ( item nil -- mal-list )
|
|
|
|
drop MalList/Empty conj ;;
|
2015-02-13 03:27:00 +03:00
|
|
|
extend as-native drop 0 ;;
|
2015-02-19 03:57:39 +03:00
|
|
|
extend get drop 2drop mal-nil ;;
|
|
|
|
extend to-list drop MalList/Empty ;;
|
2015-02-15 21:33:44 +03:00
|
|
|
extend empty? drop mal-true ;;
|
|
|
|
extend mal-count drop 0 MalInt. ;;
|
|
|
|
extend mal= drop mal-nil = ;;
|
2015-02-13 03:27:00 +03:00
|
|
|
drop
|
|
|
|
|
2015-02-06 08:38:34 +03:00
|
|
|
MalType%
|
|
|
|
cell% field MalSymbol/sym-addr
|
|
|
|
cell% field MalSymbol/sym-len
|
|
|
|
cell% field MalSymbol/meta
|
2015-02-13 03:27:00 +03:00
|
|
|
deftype MalSymbol
|
2015-02-06 08:38:34 +03:00
|
|
|
|
|
|
|
: MalSymbol. { str-addr str-len -- mal-sym }
|
|
|
|
MalSymbol new { sym }
|
|
|
|
str-addr sym MalSymbol/sym-addr !
|
|
|
|
str-len sym MalSymbol/sym-len !
|
2015-02-13 03:27:00 +03:00
|
|
|
MalMap/Empty sym MalSymbol/meta !
|
2015-02-06 08:38:34 +03:00
|
|
|
sym ;
|
2015-02-06 10:38:58 +03:00
|
|
|
|
2015-02-13 03:27:00 +03:00
|
|
|
: unpack-sym ( mal-string -- addr len )
|
|
|
|
dup MalSymbol/sym-addr @
|
|
|
|
swap MalSymbol/sym-len @ ;
|
|
|
|
|
|
|
|
MalSymbol
|
|
|
|
extend mal= ( other this -- bool )
|
|
|
|
over mal-type @ MalSymbol = if
|
|
|
|
unpack-sym rot unpack-sym str=
|
|
|
|
else
|
|
|
|
2drop 0
|
|
|
|
endif ;;
|
|
|
|
' as-native ' unpack-sym extend-method*
|
|
|
|
drop
|
|
|
|
|
|
|
|
MalType%
|
|
|
|
cell% field MalKeyword/str-addr
|
|
|
|
cell% field MalKeyword/str-len
|
|
|
|
deftype MalKeyword
|
|
|
|
|
|
|
|
: unpack-keyword ( mal-keyword -- addr len )
|
|
|
|
dup MalKeyword/str-addr @
|
|
|
|
swap MalKeyword/str-len @ ;
|
|
|
|
|
|
|
|
MalKeyword
|
|
|
|
extend mal= ( other this -- bool )
|
|
|
|
over mal-type @ MalKeyword = if
|
|
|
|
unpack-keyword rot unpack-keyword str=
|
|
|
|
else
|
|
|
|
2drop 0
|
|
|
|
endif ;;
|
|
|
|
' as-native ' unpack-keyword extend-method*
|
|
|
|
drop
|
|
|
|
|
|
|
|
: MalKeyword. { str-addr str-len -- mal-keyword }
|
|
|
|
MalKeyword new { kw }
|
|
|
|
str-addr kw MalKeyword/str-addr !
|
|
|
|
str-len kw MalKeyword/str-len !
|
|
|
|
kw ;
|
|
|
|
|
2015-02-06 10:38:58 +03:00
|
|
|
MalType%
|
|
|
|
cell% field MalString/str-addr
|
|
|
|
cell% field MalString/str-len
|
2015-02-13 03:27:00 +03:00
|
|
|
deftype MalString
|
2015-02-06 10:38:58 +03:00
|
|
|
|
2015-02-18 02:47:23 +03:00
|
|
|
: MalString.0 { str-addr str-len -- mal-str }
|
2015-02-06 10:38:58 +03:00
|
|
|
MalString new { str }
|
|
|
|
str-addr str MalString/str-addr !
|
|
|
|
str-len str MalString/str-len !
|
|
|
|
str ;
|
2015-02-18 02:47:23 +03:00
|
|
|
' MalString.0 is MalString.
|
2015-02-13 03:27:00 +03:00
|
|
|
|
|
|
|
: unpack-str ( mal-string -- addr len )
|
|
|
|
dup MalString/str-addr @
|
|
|
|
swap MalString/str-len @ ;
|
|
|
|
|
|
|
|
MalString
|
|
|
|
extend mal= ( other this -- bool )
|
|
|
|
over mal-type @ MalString = if
|
|
|
|
unpack-str rot unpack-str str=
|
|
|
|
else
|
|
|
|
2drop 0
|
|
|
|
endif ;;
|
|
|
|
' as-native ' unpack-str extend-method*
|
|
|
|
drop
|
|
|
|
|
|
|
|
|
|
|
|
MalType%
|
2015-02-15 22:10:47 +03:00
|
|
|
cell% field MalNativeFn/xt
|
|
|
|
cell% field MalNativeFn/meta
|
|
|
|
deftype MalNativeFn
|
|
|
|
|
|
|
|
: MalNativeFn. { xt -- mal-fn }
|
|
|
|
MalNativeFn new { mal-fn }
|
|
|
|
xt mal-fn MalNativeFn/xt !
|
|
|
|
MalMap/Empty mal-fn MalNativeFn/meta !
|
2015-02-13 03:27:00 +03:00
|
|
|
mal-fn ;
|
|
|
|
|
2015-02-15 22:10:47 +03:00
|
|
|
MalNativeFn
|
2015-02-13 03:27:00 +03:00
|
|
|
extend as-native
|
2015-02-15 22:10:47 +03:00
|
|
|
MalNativeFn/xt @ ;;
|
2015-02-13 03:27:00 +03:00
|
|
|
drop
|
2015-02-14 21:40:07 +03:00
|
|
|
|
|
|
|
|
2015-02-15 22:10:47 +03:00
|
|
|
MalType%
|
2015-02-17 17:40:03 +03:00
|
|
|
cell% field MalUserFn/is-macro?
|
2015-02-15 22:10:47 +03:00
|
|
|
cell% field MalUserFn/env
|
|
|
|
cell% field MalUserFn/formal-args
|
|
|
|
cell% field MalUserFn/var-arg
|
|
|
|
cell% field MalUserFn/body
|
|
|
|
deftype MalUserFn
|
|
|
|
|
|
|
|
|
2015-02-14 21:40:07 +03:00
|
|
|
MalType%
|
|
|
|
cell% field SpecialOp/xt
|
|
|
|
deftype SpecialOp
|
|
|
|
|
|
|
|
: SpecialOp.
|
|
|
|
SpecialOp new swap over SpecialOp/xt ! ;
|
2015-02-19 03:57:39 +03:00
|
|
|
|
|
|
|
MalType%
|
|
|
|
cell% field Atom/val
|
|
|
|
deftype Atom
|
|
|
|
|
|
|
|
: Atom. Atom new swap over Atom/val ! ;
|