def null func =null { | pop "`null` must not be assigned a value!" panic } def program-name def print'pre-std &print =print'pre-std func print { | _str !!- print'pre-std inline-callable } func println { | _str !!- "\n" concat print } construct error { kind message object trace mr-trace } construct FrameInfo { file function } construct _str_ext { ; new { any | :mkinstance:construct } mkinstance { any | with this ; null clone this settype } to-bytes { [int] | str-to-bytes } split { str | with splitter this ; splitter:to-bytes this:to-bytes:split:map<{ | bytes-to-str }> } replace { str | with replacee replacement this ; replacee:to-bytes replacement:to-bytes this:to-bytes:replace:to-str } find { idx | with search this ; search _barray this _barray :find } contains { bool | with search this ; search this:find null eq not } starts-with { bool | with beginning this ; beginning:to-bytes this:to-bytes:starts-with } ends-with { bool | with ending this ; ending:to-bytes this:to-bytes:ends-with } escape { formatted | with this ; "\"" this:replace<"\\" "\\\\">:replace<"\"" "\\\"">:replace<"\n" "\\n">:replace<"\r" "\\r"> concat "\"" concat } _char { int | with this ; 0 (this _array):get } readf { [str] | with pat this ; !!- pat this str-readf } readf1 { str | with pat this ; !!- pat this:readf dup null eq not if { :0 } } uppercase { str | with this ; this _array :cmap<{ | with chr ; chr chr "a" :_char lt not chr "z" :_char gt not and if { pop (chr "a" :_char -) "A" :_char + } }> _str } lowercase { str | with this ; this _array :cmap<{ | with chr ; chr chr "A" :_char lt not chr "Z" :_char gt not and if { pop (chr "A" :_char -) "a" :_char + } }> _str } _mega_radix { mega | with radix this ; this radix str-to-mega-radix } } include _str_ext in str construct _mega-ext { ; swap { .. | with this ; this mswap this -- mswap } mswap { .. | mswap } foreach { | with callable this ; def i 0 =i while { !!- i this lt } { !!- i callable call i 1 + =i } } fforeach { | with callable this ; 0 while { !!- dup2 this lt } { !!- callable callp 1 + } } _str_radix { str | with radix this ; this radix mega-to-str-radix } iter { MegaIter | with this ; this MegaIter:new } } include _mega-ext in mega construct _array-ext { ; another { array | with this ; this gettype =this this "array" eq if { anew } this "bytearray" eq if { banew } } get { any | array-get } sget { any|null | with idx this ; idx this:len lt idx -1 gt and dup if { pop idx this:get 2 stop } not if { null } } len { mega | array-len } set { any | array-set } to-stack { .. | with this ; def len this:len =len def i 0 =i while { i len lt } { i this:get i ++ =i } } foreach { | with callable this ; def i 0 =i while { i this:len lt } { i this:get callable call i ++ =i } } map { | with callable this ; def i 0 =i while { i this:len lt } { i this:get callable call i this:set; i ++ =i } this } cmap { | with callable this ; this clone =this def i 0 =i while { i this:len lt } { i this:get callable call i this:set; i ++ =i } this } to-str { str | bytes-to-str } sub { [any] | with begin end this ; this (end begin - this:another) begin 0 (end begin -) acopy } split { arr | with splitter this ; def i 0 =i [ [ while { i this:len lt } { def match 0 =match while { match i + this:len lt match splitter:len lt and } { i match + this:get (match splitter:get) eq dup if { match ++ =match } not if { 0 =match 3 stop } } i this:get match splitter:len eq if { pop ] [ i match + 1 - =i } i ++ =i } ] ] } replace { arr | with replacee replacement this ; def i 0 =i [ while { i this:len lt } { def match 0 =match while { match i + this:len lt match replacee:len lt and } { i match + this:get (match replacee:get) eq dup if { match ++ =match } not if { 0 =match 3 stop } } i this:get match replacee:len eq if { pop replacement:to-stack i match + 1 - =i } i ++ =i } ] } find { idx | with search this ; def i 0 =i while { i this:len lt } { def match 0 =match while { match i + this:len lt match search:len lt and } { i match + this:get (match search:get) eq dup if { match ++ =match } not if { 0 =match 3 stop } } match search:len eq if { i 4 stop } i ++ =i } null } contains { bool | with search this ; search awrap this:find null eq not } starts-with { bool | with beginning this ; this:len beginning:len lt if { 0 2 stop } 0 beginning:len this:sub beginning eq } ends-with { bool | with ending this ; this:len ending:len lt if { 0 2 stop } this:len ending:len - this:len this:sub ending eq } last { | with this ; this:len -- this:get } =last { | with this ; this:len -- this:set; } 0 { any | with this ; 0 this:get } 1 { any | with this ; 1 this:get } 2 { any | with this ; 2 this:get } 3 { any | with this ; 3 this:get } 4 { any | with this ; 4 this:get } =0 { | with this ; 0 this:set; } =1 { | with this ; 1 this:set; } =2 { | with this ; 2 this:set; } =3 { | with this ; 3 this:set; } =4 { | with this ; 4 this:set; } } include _array-ext in array include _array-ext in bytearray construct _func-ext { args ; call { | with this ; this:args null eq if { 0 anew this:=args } this:args:to-stack this call } add-args { this | with args this ; this:args null eq if { 0 anew this:=args } [ this:args:to-stack args:to-stack ] this:=args this } add-arg { this | with arg this ; this:args null eq if { 0 anew this:=args } [ this:args:to-stack arg ] this:=args this } } include _func-ext in func "#iter.spl" import construct List { array ; construct { this | with this ; 0 anew this:=array this } from { this | with array this ; array this:=array this } foreach { | :array:foreach } get { any | :array:get } sget { any|null | :array:sget } len { mega | :array:len } set { any | :array:set } to-stack { .. | :array:to-stack } to-str { str | :array:to-str } sub { [any] | :array:sub } clear { | :=array<0 anew> } } construct _GrowingArray { ; push-front { | with item this ; [ item this:array:to-stack ] this:=array } push { | with item this ; [ this:array:to-stack item ] this:=array } insert { | with item index this ; this:array:len index - =index [ this:array:to-stack index:mswap item (index ++):mswap ] this:=array } } construct _ShrinkingArray { ; pop-front { any | with this ; 0 this:remove } pop { any | with this ; this:array:len not if { null 2 stop } def item [ this:array:to-stack =item ] this:=array item } remove { any | with index this ; this:array:len not if { null 2 stop } def item this:array:len index - =index [ this:array:to-stack index:mswap =item (index --):mswap ] this:=array item } } include _GrowingArray in List include _ShrinkingArray in List construct ArrayIter { array idx ; construct { this | with array this ; array this:=array 0 this:=idx this } next { any | with this ; this:idx dup ++ this:=idx this:array:sget } } construct _IterableArray { ; iter { ArrayIter | with this ; this gettype:ends-with<"array"> dup if { pop this ArrayIter:new 2 stop } not if { this:array ArrayIter:new } } } include _Iter in ArrayIter include _IterableArray in List include _IterableArray in array include _IterableArray in bytearray construct MicroMap { pairs ; construct { this | with this ; List:new this:=pairs this } from { this | with pairs this ; pairs this:=pairs this } get-entry { [any,any]|null | with key this ; this:pairs:iter { mega | 0 swap:get key eq } swap:filter :next } get-or-create-entry { [any,any] | with key this ; { [any,any] | [ key null ] dup this:pairs:push } key this:get-entry:unwrap-or } get { any | with key this ; this:pairs:iter { mega | 0 swap:get key eq } swap:filter { any | 1 swap:get } swap:map :next } set { any | with key val this ; val 1 (key this:get-or-create-entry):set } remove { any | with key this ; this:pairs:iter { mega | 0 swap:get key eq not } swap:filter :collect List:new:from =pairs } iter { ArrayIter | with this ; this:pairs:iter } foreach { | with callable this ; callable this:pairs:foreach } clear { | with this ; this:pairs:clear; } to-str { str | with this ; "{ " { | with item ; "'" concat 0 item:get dup null eq if { "key is null" panic } _str concat "': '" concat 1 item:get dup null eq if { "value is null" panic } _str concat "', " concat } this:foreach "}" concat } } construct Range { lower upper step ; construct { this | with lower upper this ; lower _mega this:=lower upper _mega this:=upper 1 this:=step this } set-step { this | with step this ; step this:=step this } iter { RangeIter | with this ; this RangeIter:new } item { mega|null | with index this ; def itm index this:step * this:lower + =itm (itm this:upper lt) (itm this:lower lt not) and dup if { pop itm 2 stop } not if { null 2 stop } } } construct RangeIter { upper step idx ; construct { this | with range this ; range:lower this:=idx range:upper this:=upper range:step this:=step this } next { mega | with this ; !!- this:idx dup this:step + this:=idx dup this:upper lt not if { pop null } } } include _Iter in RangeIter construct MegaIter { i d ; construct { this | with d this ; d this:=d 0 this:=i this } next { i | with this ; this:i dup ++ this:=i dup this:d lt not if { pop null } } } include _Iter in MegaIter construct shadow { } func aadd { array | with arr1 arr2 ; def newarr arr1:len arr2:len + arr1:another =newarr arr1 newarr 0 0 arr1:len acopy; arr2 newarr 0 arr1:len arr2:len acopy; newarr } func concat { str | with a b ; a _array b _array aadd _str } func nconcat { str | with amt ; _array (amt 1 -):foreach<{ | pop swap _array swap aadd }> _str } def cached-results MicroMap:new =cached-results func cache { ... | with arg-amt id body ; def args arg-amt anew =args def i arg-amt -- =i while { i 0 lt not } { "from stack"; i args:set; i -- =i } def result [ args id ] cached-results:get =result result null eq if { args:to-stack body call dup =result [ args id ] swap cached-results:set; } result } func panic-handler { | "to be overridden"; } def do-not-dump 0 =do-not-dump func handle-panic { | with msg trace ; program-name dup if { program-name print " panicked at:" println } not if { "Program panicked at:" println } &println trace:foreach "\nPanic message:" println " " print msg println panic-handler def map env =map "SPL_PANIC_DUMP" env:get dup if { "Dumping because SPL_PANIC_DUMP is set." println null =map dyn-__dump } not if { do-not-dump if { "Not dumping." println 2 stop } "SPL_PLAIN_PANIC" map:get dup if { "Not dumping because SPL_PLAIN_PANIC is set." println } not if { "Type 'Yes^M' to dump. You can set SPL_PANIC_DUMP to always dump " "on panic, or SPL_PLAIN_PANIC to never dump." concat println readln "Yes" eq if { null =map dyn-__dump } } } "Exiting." println 1 exit } func panic { | trace handle-panic } { | with msg this ; this not if { "Assertion failed!" panic } } "assert" "int" dyn-def-method { | with msg this ; this if { "Assertion failed!" panic } } "nassert" "int" dyn-def-method func assert-eq { any any | with a b ; a b eq not if { "Equality assertion failed!" panic } a b } func awrap { array | with item ; item 1 anew =item 0 item:set; item } func [ { shadow | "array" "shadow" settype } func ] { array | [ alit-end } func env { MicroMap | get-env List:new:from MicroMap:new:from } func ++ { mega | 1 + } func -- { mega | 1 - } func times { | with amount callable ; def i 0 =i while { i amount lt } { i callable call i ++ =i } } func check-match { bool | with input output ; input null eq if { 0 2 stop } output gettype "func" eq if { 1 2 stop } input output eq if { 1 2 stop } output gettype "array" eq if { def i, n 0 =i output:len =n input:len n eq not if { 0 3 stop } 1 while { i n lt } { input:get output:get check-match and i ++ =i } 2 stop } 0 } func match-unchecked { | with input output ; output gettype "func" eq if { input output call 2 stop } output gettype "array" eq if { def i, n 0 =i output:len =n input:len n eq not if { 3 stop } while { i n lt } { input:get output:get match-unchecked i ++ =i } } } func match { bool | with input output ; input null eq if { 0 2 stop } output gettype "func" eq if { input output call 1 2 stop } input output eq if { 1 2 stop } output gettype "array" eq if { def i, n 0 =i output:len =n input:len n eq not if { 0 3 stop } 1 while { i n lt } { input:get output:get check-match and i ++ =i } dup if { 0 =i while { i n lt } { input:get output:get match-unchecked i ++ =i } } 2 stop } 0 } func _'match-else-error { | not if { "match unsuccessful" throw } } func _'match-else-push { | dup if { swap pop } } def _'has-been-called 0 =_'has-been-called func _ { | _'has-been-called not if { "WARN: The _ function is deprecated!" println 1 =_'has-been-called } } func call-main-on-file { | with file ; catch { "@" (0 (file _array):get 0 ("#" _array):get eq) if { pop "" } file concat import update-types argv main exit } { with err ; err:message dup null eq if { pop "Uncaught error." } err:trace handle-panic } } func update-types { | { | with type ; { self | } "unwrap" type dyn-def-method { self | swap pop } "unwrap-or" type dyn-def-method } dyn-all-types:foreach { | with this ; "null cannot be unwrapped." panic } "unwrap" "null" dyn-def-method { any | with fb this ; fb call } "unwrap-or" "null" dyn-def-method } update-types "Adds a field to a namespace and initially sets it to the field's name."; func register-field { | with field-name namespace-name ; def namespace-path def iter namespace-name:split<":"> =namespace-path; namespace-path:iter =iter field-name namespace-name dyn-def-field; "adds the desired field to the namespace construct"; ( iter:next dyn-call iter:foreach<&dyn-objcall> ) namespace-name settype "updates and gets the namespace object"; ("=" namespace-path:last concat) namespace-path:=last; namespace-path:iter =iter iter:next dyn-call iter:foreach<&dyn-objcall> }