diff --git a/core/alien/compiler/compiler.factor b/core/alien/compiler/compiler.factor index 282a849c34..f68bdcf0a2 100755 --- a/core/alien/compiler/compiler.factor +++ b/core/alien/compiler/compiler.factor @@ -326,7 +326,7 @@ M: alien-callback-error summary drop "Words calling ``alien-callback'' must be compiled with the optimizing compiler." ; : callback-bottom ( node -- ) - alien-callback-xt [ word-xt ] curry + alien-callback-xt [ word-xt drop ] curry recursive-state get infer-quot ; \ alien-callback [ diff --git a/core/alien/structs/structs-tests.factor b/core/alien/structs/structs-tests.factor index b2da0e8392..b934cd56a3 100644 --- a/core/alien/structs/structs-tests.factor +++ b/core/alien/structs/structs-tests.factor @@ -9,18 +9,20 @@ C-STRUCT: bar [ 36 ] [ "bar" heap-size ] unit-test [ t ] [ \ "bar" c-type c-type-getter memq? ] unit-test -C-STRUCT: align-test - { "int" "x" } - { "double" "y" } ; +! This was actually only correct on Windows/x86: -[ 16 ] [ "align-test" heap-size ] unit-test - -cell 4 = [ - C-STRUCT: one - { "long" "a" } { "double" "b" } { "int" "c" } ; - - [ 24 ] [ "one" heap-size ] unit-test -] when +! C-STRUCT: align-test +! { "int" "x" } +! { "double" "y" } ; +! +! [ 16 ] [ "align-test" heap-size ] unit-test +! +! cell 4 = [ +! C-STRUCT: one +! { "long" "a" } { "double" "b" } { "int" "c" } ; +! +! [ 24 ] [ "one" heap-size ] unit-test +! ] when : MAX_FOOS 30 ; diff --git a/core/assocs/assocs-docs.factor b/core/assocs/assocs-docs.factor index 2eabe9b0bc..716ac64c9b 100755 --- a/core/assocs/assocs-docs.factor +++ b/core/assocs/assocs-docs.factor @@ -59,6 +59,7 @@ ARTICLE: "assocs-sets" "Set-theoretic operations on assocs" { $subsection diff } { $subsection remove-all } { $subsection substitute } +{ $subsection substitute-here } { $see-also key? } ; ARTICLE: "assocs-mutation" "Storing keys and values in assocs" @@ -266,12 +267,16 @@ HELP: remove-all { $notes "The values of the keys in the assoc are disregarded, so this word is usually used for set-theoretic calculations where the assoc in question either has dummy sentinels as values, or the values equal the keys." } { $side-effects "assoc" } ; -HELP: substitute -{ $values { "assoc" assoc } { "seq" "a mutable sequence" } } -{ $description "Replaces elements of " { $snippet "seq" } " which appear in as keys in " { $snippet "assoc" } " with the corresponding values, acting as the identity on all other elements." } +HELP: substitute-here +{ $values { "seq" "a mutable sequence" } { "assoc" assoc } } +{ $description "Replaces elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " with the corresponding values, acting as the identity on all other elements." } { $errors "Throws an error if " { $snippet "assoc" } " contains values whose types are not permissible in " { $snippet "seq" } "." } { $side-effects "seq" } ; +HELP: substitute +{ $values { "seq" sequence } { "assoc" assoc } { "newseq" sequence } } +{ $description "Creates a new sequence where elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " are replaced by the corresponding values, and all other elements are unchanged." } ; + HELP: cache { $values { "key" "a key" } { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key -- value )" } } { "value" "a previously-retained or freshly-computed value" } } { $description "If the key is present in the assoc, outputs the associated value, otherwise calls the quotation to produce a value and stores the key/value pair into the assoc." } diff --git a/core/assocs/assocs.factor b/core/assocs/assocs.factor index d8cf01e1bd..ff0938e001 100755 --- a/core/assocs/assocs.factor +++ b/core/assocs/assocs.factor @@ -124,8 +124,14 @@ M: assoc assoc-clone-like ( assoc exemplar -- newassoc ) : remove-all ( assoc seq -- subseq ) swap [ key? not ] curry subset ; -: substitute ( assoc seq -- ) - swap [ dupd at* [ nip ] [ drop ] if ] curry change-each ; +: (substitute) + [ dupd at* [ nip ] [ drop ] if ] curry ; inline + +: substitute-here ( seq assoc -- ) + (substitute) change-each ; + +: substitute ( seq assoc -- newseq ) + (substitute) map ; : cache ( key assoc quot -- value ) 2over at [ diff --git a/core/bootstrap/stage2.factor b/core/bootstrap/stage2.factor index cd99796e7e..3bc82bbe6a 100755 --- a/core/bootstrap/stage2.factor +++ b/core/bootstrap/stage2.factor @@ -59,7 +59,7 @@ SYMBOL: bootstrap-time default-image-name "output-image" set-global - "math help compiler tools ui ui.tools io" "include" set-global + "math help handbook compiler tools ui ui.tools io" "include" set-global "" "exclude" set-global parse-command-line diff --git a/core/combinators/combinators-docs.factor b/core/combinators/combinators-docs.factor index d91c920def..5b87297b0c 100755 --- a/core/combinators/combinators-docs.factor +++ b/core/combinators/combinators-docs.factor @@ -7,11 +7,7 @@ ARTICLE: "combinators-quot" "Quotation construction utilities" "Some words for creating quotations which can be useful for implementing method combinations and compiler transforms:" { $subsection cond>quot } { $subsection case>quot } -{ $subsection alist>quot } -"A powerful tool used to optimize code in several places is open-coded hashtable dispatch:" -{ $subsection hash-case>quot } -{ $subsection distribute-buckets } -{ $subsection hash-dispatch-quot } ; +{ $subsection alist>quot } ; ARTICLE: "combinators" "Additional combinators" "The " { $vocab-link "combinators" } " vocabulary is usually used because it provides two combinators which abstract out nested chains of " { $link if } ":" @@ -104,19 +100,17 @@ HELP: case>quot { $values { "assoc" "a sequence of pairs of quotations" } { "default" quotation } { "quot" quotation } } { $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "." $nl -"The quotation actually tests each possible case in order;" { $link hash-case>quot } " produces more efficient code." } ; +"This word uses three strategies:" +{ $list + "If the assoc only has a few keys, a linear search is generated." + { "If the assoc has a large number of keys which form a contiguous range of integers, a direct dispatch is generated using the " { $link dispatch } " word together with a bounds check." } + "Otherwise, an open-coded hashtable dispatch is generated." +} } ; HELP: distribute-buckets { $values { "assoc" "an alist" } { "initial" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- assoc )" } } { "buckets" "a new array" } } { $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." } -{ $notes "This word is used in the implemention of " { $link hash-case>quot } " and " { $link standard-combination } "." } ; - -HELP: hash-case>quot -{ $values { "default" quotation } { "assoc" "an association list mapping quotations to quotations" } { "quot" quotation } } -{ $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "." -$nl -"The quotation uses an efficient hash-based search to avoid testing the object against all possible keys." } -{ $notes "This word is used behind the scenes to compile " { $link case } " forms efficiently; it can also be called directly, which is useful for meta-programming." } ; +{ $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ; HELP: dispatch ( n array -- ) { $values { "n" "a fixnum" } { "array" "an array of quotations" } } diff --git a/core/combinators/combinators-tests.factor b/core/combinators/combinators-tests.factor old mode 100644 new mode 100755 index 3cefda7f71..ce8e180867 --- a/core/combinators/combinators-tests.factor +++ b/core/combinators/combinators-tests.factor @@ -69,3 +69,10 @@ namespaces combinators words ; ! Interpreted [ "a hashtable" ] [ H{ } \ case-test-3 word-def call ] unit-test + +[ 1 3 t ] [ { 1 3 2 } contiguous-range? ] unit-test +[ f ] [ { 1 2 2 4 } contiguous-range? 2nip ] unit-test +[ f ] [ { + 3 2 } contiguous-range? 2nip ] unit-test +[ f ] [ { 1 0 7 } contiguous-range? 2nip ] unit-test +[ f ] [ { 1 1 3 7 } contiguous-range? 2nip ] unit-test +[ 4 8 t ] [ { 7 6 4 8 5 } contiguous-range? ] unit-test diff --git a/core/combinators/combinators.factor b/core/combinators/combinators.factor index 0ba8b583be..ffd1576e6e 100755 --- a/core/combinators/combinators.factor +++ b/core/combinators/combinators.factor @@ -1,8 +1,9 @@ -! Copyright (C) 2006, 2007 Slava Pestov. +! Copyright (C) 2006, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. IN: combinators USING: arrays sequences sequences.private math.private -kernel kernel.private math assocs quotations vectors ; +kernel kernel.private math assocs quotations vectors +hashtables sorting ; TUPLE: no-cond ; @@ -31,16 +32,24 @@ TUPLE: no-case ; : recursive-hashcode ( n obj quot -- code ) pick 0 <= [ 3drop 0 ] [ rot 1- -rot call ] if ; inline +! These go here, not in sequences and hashtables, since those +! two depend on combinators M: sequence hashcode* [ sequence-hashcode ] recursive-hashcode ; +M: hashtable hashcode* + [ + dup assoc-size 1 number= + [ assoc-hashcode ] [ nip assoc-size ] if + ] recursive-hashcode ; + : alist>quot ( default assoc -- quot ) [ rot \ if 3array append [ ] like ] assoc-each ; : cond>quot ( assoc -- quot ) reverse [ no-cond ] swap alist>quot ; -: case>quot ( default assoc -- quot ) +: linear-case-quot ( default assoc -- quot ) [ >r [ dupd = ] curry r> \ drop add* ] assoc-map alist>quot ; @@ -63,20 +72,50 @@ M: sequence hashcode* : hash-case-table ( default assoc -- array ) V{ } [ 1array ] distribute-buckets - [ case>quot ] with map ; + [ linear-case-quot ] with map ; : hash-dispatch-quot ( table -- quot ) [ length 1- [ fixnum-bitand ] curry ] keep [ dispatch ] curry append ; -: hash-case>quot ( default assoc -- quot ) +: hash-case-quot ( default assoc -- quot ) + hash-case-table hash-dispatch-quot + [ dup hashcode >fixnum ] swap append ; + +: contiguous-range? ( keys -- from to ? ) + dup [ fixnum? ] all? [ + dup all-unique? [ + dup infimum over supremum + [ - swap prune length + 1 = ] 2keep rot + ] [ + drop f f f + ] if + ] [ + drop f f f + ] if ; + +: dispatch-case ( value from to default array -- ) + >r >r 3dup between? [ + drop - >fixnum r> drop r> dispatch + ] [ + 2drop r> call r> drop + ] if ; inline + +: dispatch-case-quot ( default assoc from to -- quot ) + -roll -roll sort-keys values [ >quotation ] map + [ dispatch-case ] 2curry 2curry ; + +: case>quot ( default assoc -- quot ) dup empty? [ drop ] [ dup length 4 <= [ - case>quot + linear-case-quot ] [ - hash-case-table hash-dispatch-quot - [ dup hashcode >fixnum ] swap append + dup keys contiguous-range? [ + dispatch-case-quot + ] [ + 2drop hash-case-quot + ] if ] if ] if ; diff --git a/core/compiler/tests/simple.factor b/core/compiler/tests/simple.factor index 1ed43120d3..6deed6c756 100755 --- a/core/compiler/tests/simple.factor +++ b/core/compiler/tests/simple.factor @@ -227,3 +227,6 @@ M: f single-combination-test-2 single-combination-test-4 ; [ 3 ] [ t single-combination-test-2 ] unit-test [ 3 ] [ 3 single-combination-test-2 ] unit-test [ f ] [ f single-combination-test-2 ] unit-test + +! Regression +[ 100 ] [ [ 100 [ [ ] times ] keep ] compile-call ] unit-test diff --git a/core/compiler/tests/templates.factor b/core/compiler/tests/templates.factor index 74e5ab80a4..4be700f221 100755 --- a/core/compiler/tests/templates.factor +++ b/core/compiler/tests/templates.factor @@ -3,7 +3,7 @@ USING: arrays compiler kernel kernel.private math hashtables.private math.private namespaces sequences sequences.private tools.test namespaces.private slots.private sequences.private byte-arrays alien alien.accessors layouts -words definitions compiler.units ; +words definitions compiler.units io combinators ; IN: temporary ! Oops! @@ -191,3 +191,18 @@ TUPLE: my-tuple ; 2 1 [ 2dup fixnum< [ >r die r> ] when ] compile-call ] unit-test + +! Regression +: a-dummy drop "hi" print ; + +[ ] [ + 1 [ + dup 0 2 3dup pick >= [ >= ] [ 2drop f ] if [ + drop - >fixnum { + [ a-dummy ] + [ a-dummy ] + [ a-dummy ] + } dispatch + ] [ 2drop no-case ] if + ] compile-call +] unit-test diff --git a/core/debugger/debugger-tests.factor b/core/debugger/debugger-tests.factor new file mode 100755 index 0000000000..31c3e8a762 --- /dev/null +++ b/core/debugger/debugger-tests.factor @@ -0,0 +1,4 @@ +IN: temporary +USING: debugger kernel continuations tools.test ; + +[ ] [ [ drop ] [ error. ] recover ] unit-test diff --git a/core/generator/generator.factor b/core/generator/generator.factor index 8b6742e700..3514947e3d 100755 --- a/core/generator/generator.factor +++ b/core/generator/generator.factor @@ -26,7 +26,7 @@ SYMBOL: compiling-word SYMBOL: compiling-label -SYMBOL: compiling-loop? +SYMBOL: compiling-loops ! Label of current word, after prologue, makes recursion faster SYMBOL: current-label-start @@ -34,7 +34,7 @@ SYMBOL: current-label-start : compiled-stack-traces? ( -- ? ) 36 getenv ; : begin-compiling ( word label -- ) - compiling-loop? off + H{ } clone compiling-loops set compiling-label set compiling-word set compiled-stack-traces? @@ -94,8 +94,8 @@ M: node generate-node drop iterate-next ; : generate-call ( label -- next ) dup maybe-compile end-basic-block - dup compiling-label get eq? compiling-loop? get and [ - drop current-label-start get %jump-label f + dup compiling-loops get at [ + %jump-label f ] [ tail-call? [ %jump f @@ -104,7 +104,7 @@ M: node generate-node drop iterate-next ; %call iterate-next ] if - ] if ; + ] ?if ; ! #label M: #label generate-node @@ -113,17 +113,13 @@ M: #label generate-node r> ; ! #loop +: compiling-loop ( word -- ) +