diff --git a/core/alien/compiler/compiler.factor b/core/alien/compiler/compiler.factor index 54348e47f9..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 <alien> ] curry + alien-callback-xt [ word-xt drop <alien> ] curry recursive-state get infer-quot ; \ alien-callback [ @@ -398,7 +398,7 @@ TUPLE: callback-context ; callback-unwind %unwind ; : generate-callback ( node -- ) - dup alien-callback-xt dup rot [ + dup alien-callback-xt dup [ init-templates %save-word-xt %prologue-later @@ -407,7 +407,7 @@ TUPLE: callback-context ; dup wrap-callback-quot %alien-callback %callback-return ] with-stack-frame - ] generate-1 ; + ] with-generator ; M: alien-callback generate-node end-basic-block generate-callback iterate-next ; 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 ] [ \ <displaced-alien> "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/compiler/compiler.factor b/core/bootstrap/compiler/compiler.factor index ff9d5c5e1e..6d21504f8b 100755 --- a/core/bootstrap/compiler/compiler.factor +++ b/core/bootstrap/compiler/compiler.factor @@ -74,6 +74,12 @@ nl malloc free memcpy } compile -[ compiled-usages recompile ] recompile-hook set-global +: enable-compiler ( -- ) + [ compiled-usages recompile ] recompile-hook set-global ; + +: disable-compiler ( -- ) + [ [ f ] { } map>assoc modify-code-heap ] recompile-hook set-global ; + +enable-compiler " done" print flush 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/compiler.factor b/core/compiler/compiler.factor index 2674734483..f44e6c1387 100755 --- a/core/compiler/compiler.factor +++ b/core/compiler/compiler.factor @@ -30,7 +30,7 @@ IN: compiler : compile-succeeded ( word -- effect dependencies ) [ - dup word-dataflow >r swap dup r> optimize generate + [ word-dataflow optimize ] keep dup generate ] computing-dependencies ; : compile-failed ( word error -- ) 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/stack-trace.factor b/core/compiler/tests/stack-trace.factor index 71c95b1b61..137d86b489 100755 --- a/core/compiler/tests/stack-trace.factor +++ b/core/compiler/tests/stack-trace.factor @@ -1,7 +1,7 @@ IN: temporary USING: compiler tools.test namespaces sequences kernel.private kernel math continuations continuations.private -words splitting ; +words splitting sorting ; : symbolic-stack-trace ( -- newseq ) error-continuation get continuation-call callstack>array @@ -31,9 +31,9 @@ words splitting ; \ > stack-trace-contains? ] unit-test -: quux [ t [ "hi" throw ] when ] times ; +: quux { 1 2 3 } [ "hi" throw ] sort ; [ t ] [ [ 10 quux ] ignore-errors - \ (each-integer) stack-trace-contains? + \ sort stack-trace-contains? ] unit-test diff --git a/core/compiler/tests/templates-early.factor b/core/compiler/tests/templates-early.factor index e518d2de8a..13d834a489 100755 --- a/core/compiler/tests/templates-early.factor +++ b/core/compiler/tests/templates-early.factor @@ -44,7 +44,9 @@ words kernel math effects definitions compiler.units ; [ [ ] [ init-templates ] unit-test - [ ] [ init-generator ] unit-test + H{ } clone compiled set + + [ ] [ gensym gensym begin-compiling ] unit-test [ t ] [ [ end-basic-block ] { } make empty? ] 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/fixup/fixup.factor b/core/generator/fixup/fixup.factor index 17c0c64bf1..25e2f8222b 100755 --- a/core/generator/fixup/fixup.factor +++ b/core/generator/fixup/fixup.factor @@ -140,17 +140,19 @@ SYMBOL: literal-table V{ } clone relocation-table set V{ } clone label-table set ; -: generate-labels ( -- labels ) - label-table get [ +: resolve-labels ( labels -- labels' ) + [ first3 label-offset [ "Unresolved label" throw ] unless* 3array ] map concat ; -: fixup ( code -- relocation-table label-table code ) +: fixup ( code -- literals relocation labels code ) [ init-fixup dup stack-frame-size swap [ fixup* ] each drop + + literal-table get >array relocation-table get >array - generate-labels + label-table get resolve-labels ] { } make ; diff --git a/core/generator/generator-docs.factor b/core/generator/generator-docs.factor index 029749180e..4473df7277 100755 --- a/core/generator/generator-docs.factor +++ b/core/generator/generator-docs.factor @@ -22,34 +22,35 @@ HELP: compiled { $var-description "During compilation, holds a hashtable mapping words to 5-element arrays holding compiled code." } ; HELP: compiling-word -{ $var-description "The word currently being compiled, set by " { $link generate-1 } "." } ; +{ $var-description "The word currently being compiled, set by " { $link with-generator } "." } ; HELP: compiling-label -{ $var-description "The label currently being compiled, set by " { $link generate-1 } "." } ; +{ $var-description "The label currently being compiled, set by " { $link with-generator } "." } ; HELP: compiled-stack-traces? { $values { "?" "a boolean" } } { $description "Iftrue, compiled code blocks will retain what word they were compiled from. This information is used by " { $link :c } " to display call stack traces after an error is thrown from compiled code. This is on by default; the deployment tool switches it off to save some space in the deployed image." } ; HELP: literal-table -{ $var-description "Holds a vector of literal objects referenced from the currently compiling word. If " { $link compiled-stack-traces? } " is on, " { $link init-generator } " ensures that the first entry is the word being compiled." } ; +{ $var-description "Holds a vector of literal objects referenced from the currently compiling word. If " { $link compiled-stack-traces? } " is on, " { $link begin-compiling } " ensures that the first entry is the word being compiled." } ; -HELP: init-generator +HELP: begin-compiling +{ $values { "word" word } { "label" word } } { $description "Prepares to generate machine code for a word." } ; -HELP: generate-1 -{ $values { "word" word } { "label" word } { "node" "a dataflow node" } { "quot" "a quotation with stack effect " { $snippet "( node -- )" } } } +HELP: with-generator +{ $values { "node" "a dataflow node" } { "word" word } { "label" word } { "quot" "a quotation with stack effect " { $snippet "( node -- )" } } } { $description "Generates machine code for " { $snippet "label" } " by applying the quotation to the dataflow node." } ; HELP: generate-node { $values { "node" "a dataflow node" } { "next" "a dataflow node" } } { $contract "Generates machine code for a dataflow node, and outputs the next node to generate machine code for." } -{ $notes "This word can only be called from inside the quotation passed to " { $link generate-1 } "." } ; +{ $notes "This word can only be called from inside the quotation passed to " { $link with-generator } "." } ; HELP: generate-nodes { $values { "node" "a dataflow node" } } { $description "Recursively generate machine code for a dataflow graph." } -{ $notes "This word can only be called from inside the quotation passed to " { $link generate-1 } "." } ; +{ $notes "This word can only be called from inside the quotation passed to " { $link with-generator } "." } ; HELP: generate { $values { "word" word } { "label" word } { "node" "a dataflow node" } } diff --git a/core/generator/generator.factor b/core/generator/generator.factor index d8164fdce7..3514947e3d 100755 --- a/core/generator/generator.factor +++ b/core/generator/generator.factor @@ -11,12 +11,6 @@ IN: generator SYMBOL: compile-queue SYMBOL: compiled -: begin-compiling ( word -- ) - f swap compiled get set-at ; - -: finish-compiling ( word literals relocation labels code -- ) - 4array swap compiled get set-at ; - : queue-compile ( word -- ) { { [ dup compiled get key? ] [ drop ] } @@ -32,24 +26,31 @@ SYMBOL: compiling-word SYMBOL: compiling-label +SYMBOL: compiling-loops + ! Label of current word, after prologue, makes recursion faster SYMBOL: current-label-start : compiled-stack-traces? ( -- ? ) 36 getenv ; -: init-generator ( -- ) +: begin-compiling ( word label -- ) + H{ } clone compiling-loops set + compiling-label set + compiling-word set compiled-stack-traces? - compiling-word get f ? - 1vector literal-table set ; + compiling-word get f ? + 1vector literal-table set + f compiling-word get compiled get set-at ; -: generate-1 ( word label node quot -- ) - pick begin-compiling [ - roll compiling-word set - pick compiling-label set - init-generator - call - literal-table get >array - ] { } make fixup finish-compiling ; +: finish-compiling ( literals relocation labels code -- ) + 4array compiling-label get compiled get set-at ; + +: with-generator ( node word label quot -- ) + [ + >r begin-compiling r> + { } make fixup + finish-compiling + ] with-scope ; inline GENERIC: generate-node ( node -- next ) @@ -62,12 +63,12 @@ GENERIC: generate-node ( node -- next ) %prologue-later current-label-start define-label current-label-start resolve-label ; - -: generate ( word label node -- ) + +: generate ( node word label -- ) [ init-generate-nodes [ generate-nodes ] with-node-iterator - ] generate-1 ; + ] with-generator ; : word-dataflow ( word -- effect dataflow ) [ @@ -82,25 +83,6 @@ GENERIC: generate-node ( node -- next ) : if-intrinsics ( #call -- quot ) node-param "if-intrinsics" word-prop ; -DEFER: #terminal? - -PREDICATE: #merge #terminal-merge node-successor #terminal? ; - -PREDICATE: #values #terminal-values node-successor #terminal? ; - -PREDICATE: #call #terminal-call - dup node-successor #if? - over node-successor node-successor #terminal? and - swap if-intrinsics and ; - -UNION: #terminal - POSTPONE: f #return #terminal-values #terminal-merge ; - -: tail-call? ( -- ? ) - node-stack get [ - dup #terminal-call? swap node-successor #terminal? or - ] all? ; - ! node M: node generate-node drop iterate-next ; @@ -112,20 +94,34 @@ M: node generate-node drop iterate-next ; : generate-call ( label -- next ) dup maybe-compile end-basic-block - tail-call? [ - %jump f + dup compiling-loops get at [ + %jump-label f ] [ - 0 frame-required - %call - iterate-next - ] if ; + tail-call? [ + %jump f + ] [ + 0 frame-required + %call + iterate-next + ] if + ] ?if ; ! #label M: #label generate-node dup node-param generate-call >r - dup #label-word over node-param rot node-child generate + dup node-child over #label-word rot node-param generate r> ; +! #loop +: compiling-loop ( word -- ) + <label> dup resolve-label swap compiling-loops get set-at ; + +M: #loop generate-node + end-basic-block + dup node-param compiling-loop + node-child generate-nodes + iterate-next ; + ! #if : end-false-branch ( label -- ) tail-call? [ %return drop ] [ %jump-label ] if ; @@ -150,25 +146,18 @@ M: #if generate-node ! #dispatch : dispatch-branch ( node word -- label ) gensym [ - rot [ + [ copy-templates %save-dispatch-xt %prologue-later [ generate-nodes ] with-node-iterator - ] generate-1 + ] with-generator ] keep ; -: tail-dispatch? ( node -- ? ) - #! Is the dispatch a jump to a tail call to a word? - dup #call? swap node-successor #return? and ; - : dispatch-branches ( node -- ) node-children [ - dup tail-dispatch? [ - node-param - ] [ - compiling-word get dispatch-branch - ] if %dispatch-label + compiling-word get dispatch-branch + %dispatch-label ] each ; : generate-dispatch ( node -- ) @@ -182,10 +171,10 @@ M: #dispatch generate-node generate-dispatch iterate-next ] [ compiling-word get gensym [ - rot [ + [ init-generate-nodes generate-dispatch - ] generate-1 + ] with-generator ] keep generate-call ] if ; @@ -224,10 +213,11 @@ M: #dispatch generate-node : define-if-intrinsic ( word quot inputs -- ) 2array 1array define-if-intrinsics ; -: do-if-intrinsic ( #call pair -- next ) - <label> [ swap do-template ] keep - >r node-successor r> generate-if - node-successor ; +: do-if-intrinsic ( pair -- next ) + <label> [ + swap do-template + node> node-successor dup >node + ] keep generate-if ; : find-intrinsic ( #call -- pair/f ) intrinsics find-template ; @@ -249,7 +239,7 @@ M: #call generate-node ] [ node-param generate-call ] ?if - ] if* ; + ] ?if ; ! #call-label M: #call-label generate-node node-param generate-call ; @@ -274,4 +264,7 @@ M: #r> generate-node iterate-next ; ! #return -M: #return generate-node drop end-basic-block %return f ; +M: #return generate-node + end-basic-block + node-param compiling-loops get key? + [ %return ] unless f ; diff --git a/core/generator/registers/registers.factor b/core/generator/registers/registers.factor old mode 100644 new mode 100755 index 8dc9bd606f..307e3a99f1 --- a/core/generator/registers/registers.factor +++ b/core/generator/registers/registers.factor @@ -504,7 +504,7 @@ M: loc lazy-store : substitute-vregs ( values vregs -- ) [ vreg-substitution ] 2map [ substitute-vreg? ] assoc-subset >hashtable - [ swap substitute ] curry each-phantom ; + [ substitute-here ] curry each-phantom ; : set-operand ( value var -- ) >r dup constant? [ constant-value ] when r> set ; diff --git a/core/generic/math/math.factor b/core/generic/math/math.factor index 2cc28ac0d1..0b2b9fcca3 100755 --- a/core/generic/math/math.factor +++ b/core/generic/math/math.factor @@ -58,16 +58,15 @@ TUPLE: no-math-method left right generic ; 2drop object-method ] if ; -: math-vtable* ( picker max quot -- quot ) +: math-vtable ( picker quot -- quot ) [ - rot , \ tag , - [ >r [ bootstrap-type>class ] map r> map % ] { } make , + >r + , \ tag , + num-tags get [ bootstrap-type>class ] + r> compose map , \ dispatch , ] [ ] make ; inline -: math-vtable ( picker quot -- quot ) - num-tags get swap math-vtable* ; inline - TUPLE: math-combination ; M: math-combination make-default-method diff --git a/core/hashtables/hashtables.factor b/core/hashtables/hashtables.factor index b24928a71e..8c935db859 100755 --- a/core/hashtables/hashtables.factor +++ b/core/hashtables/hashtables.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2005, 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: arrays kernel kernel.private slots.private math assocs -math.private sequences sequences.private vectors -combinators ; +math.private sequences sequences.private vectors ; IN: hashtables <PRIVATE @@ -161,17 +160,10 @@ M: hashtable clone (clone) dup hash-array clone over set-hash-array ; M: hashtable equal? - { - { [ over hashtable? not ] [ 2drop f ] } - { [ 2dup [ assoc-size ] 2apply number= not ] [ 2drop f ] } - { [ t ] [ assoc= ] } - } cond ; - -M: hashtable hashcode* - [ - dup assoc-size 1 number= - [ assoc-hashcode ] [ nip assoc-size ] if - ] recursive-hashcode ; + over hashtable? [ + 2dup [ assoc-size ] 2apply number= + [ assoc= ] [ 2drop f ] if + ] [ 2drop f ] if ; ! Default method M: assoc new-assoc drop <hashtable> ; diff --git a/core/inference/dataflow/dataflow-docs.factor b/core/inference/dataflow/dataflow-docs.factor index 0f809fa2bd..66b3590253 100755 --- a/core/inference/dataflow/dataflow-docs.factor +++ b/core/inference/dataflow/dataflow-docs.factor @@ -1,4 +1,5 @@ -USING: inference.dataflow help.syntax help.markup ; +USING: help.syntax help.markup ; +IN: inference.dataflow HELP: #return { $values { "label" "a word or " { $link f } } { "node" "a new " { $link node } } } diff --git a/core/inference/dataflow/dataflow.factor b/core/inference/dataflow/dataflow.factor index 71cb0eef65..23b5343c9c 100755 --- a/core/inference/dataflow/dataflow.factor +++ b/core/inference/dataflow/dataflow.factor @@ -97,11 +97,13 @@ M: object flatten-curry , ; : node-child node-children first ; -TUPLE: #label word ; +TUPLE: #label word loop? ; : #label ( word label -- node ) \ #label param-node [ set-#label-word ] keep ; +PREDICATE: #label #loop #label-loop? ; + TUPLE: #entry ; : #entry ( -- node ) \ #entry all-out-node ; @@ -304,3 +306,19 @@ SYMBOL: node-stack node-children [ last-node ] map [ #terminate? not ] subset ; + +DEFER: #tail? + +PREDICATE: #merge #tail-merge node-successor #tail? ; + +PREDICATE: #values #tail-values node-successor #tail? ; + +UNION: #tail + POSTPONE: f #return #tail-values #tail-merge #terminate ; + +: tail-call? ( -- ? ) + #! We don't consider calls which do non-local exits to be + #! tail calls, because this gives better error traces. + node-stack get [ + node-successor dup #tail? swap #terminate? not and + ] all? ; diff --git a/core/inference/known-words/known-words.factor b/core/inference/known-words/known-words.factor index e6479d0c6a..9d0f959b68 100755 --- a/core/inference/known-words/known-words.factor +++ b/core/inference/known-words/known-words.factor @@ -345,7 +345,7 @@ M: object infer-call \ <word> { object object } { word } <effect> set-primitive-effect \ <word> make-flushable -\ word-xt { word } { integer } <effect> set-primitive-effect +\ word-xt { word } { integer integer } <effect> set-primitive-effect \ word-xt make-flushable \ getenv { fixnum } { object } <effect> set-primitive-effect diff --git a/core/inference/transforms/transforms.factor b/core/inference/transforms/transforms.factor index 7faeefc3d6..240f39218b 100755 --- a/core/inference/transforms/transforms.factor +++ b/core/inference/transforms/transforms.factor @@ -35,7 +35,7 @@ IN: inference.transforms dup peek swap 1 head* ] [ [ no-case ] swap - ] if hash-case>quot + ] if case>quot ] if ] 1 define-transform diff --git a/core/io/utf16/authors.txt b/core/io/encodings/binary/authors.txt similarity index 100% rename from core/io/utf16/authors.txt rename to core/io/encodings/binary/authors.txt diff --git a/core/io/encodings/binary/binary-docs.factor b/core/io/encodings/binary/binary-docs.factor new file mode 100644 index 0000000000..f8be5054df --- /dev/null +++ b/core/io/encodings/binary/binary-docs.factor @@ -0,0 +1,5 @@ +USING: help.syntax help.markup ; +IN: io.encodings.binary + +HELP: binary +{ $class-description "This is the encoding descriptor for binary I/O." } ; diff --git a/core/io/encodings/binary/binary.factor b/core/io/encodings/binary/binary.factor new file mode 100644 index 0000000000..b58f9836c0 --- /dev/null +++ b/core/io/encodings/binary/binary.factor @@ -0,0 +1,6 @@ +USING: kernel io.encodings ; + +TUPLE: binary ; + +M: binary init-decoding drop ; +M: binary init-encoding drop ; diff --git a/core/io/encodings/binary/summary.txt b/core/io/encodings/binary/summary.txt new file mode 100644 index 0000000000..a1eb4bc664 --- /dev/null +++ b/core/io/encodings/binary/summary.txt @@ -0,0 +1 @@ +Dummy encoding for binary I/O diff --git a/core/io/encodings/binary/tags.txt b/core/io/encodings/binary/tags.txt new file mode 100644 index 0000000000..8e27be7d61 --- /dev/null +++ b/core/io/encodings/binary/tags.txt @@ -0,0 +1 @@ +text diff --git a/core/io/encodings/encodings.factor b/core/io/encodings/encodings.factor index 767e9b266b..94a5bf8853 100755 --- a/core/io/encodings/encodings.factor +++ b/core/io/encodings/encodings.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2006, 2007 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: math kernel sequences sbufs vectors -namespaces unicode.syntax ; +USING: math kernel sequences sbufs vectors io.streams.lines io.streams.plain +namespaces unicode growable strings io classes io.streams.c +continuations ; IN: io.encodings TUPLE: encode-error ; @@ -18,11 +19,77 @@ SYMBOL: begin over push 0 begin ; : push-replacement ( buf -- buf ch state ) - UNICHAR: replacement-character decoded ; + CHAR: replacement-character decoded ; : finish-decoding ( buf ch state -- str ) begin eq? [ decode-error ] unless drop "" like ; -: decode ( seq quot -- str ) - >r [ length <sbuf> 0 begin ] keep r> each +: start-decoding ( seq length -- buf ch state seq ) + <sbuf> 0 begin roll ; + +GENERIC: decode-step ( buf byte ch state encoding -- buf ch state ) + +: decode ( seq quot -- string ) + >r dup length start-decoding r> + [ -rot ] swap compose each finish-decoding ; inline + +: space ( resizable -- room-left ) + dup underlying swap [ length ] 2apply - ; + +: full? ( resizable -- ? ) space zero? ; + +: end-read-loop ( buf ch state stream quot -- string/f ) + 2drop 2drop >string f like ; + +: decode-read-loop ( buf ch state stream encoding -- string/f ) + >r >r pick r> r> rot full? [ end-read-loop ] [ + over stream-read1 [ + -rot tuck >r >r >r -rot r> decode-step r> r> decode-read-loop + ] [ end-read-loop ] if* + ] if ; + +: decode-read ( length stream encoding -- string ) + >r swap start-decoding r> + decode-read-loop ; + +GENERIC: init-decoding ( stream encoding -- decoded-stream ) + +: <decoding> ( stream decoding-class -- decoded-stream ) + construct-empty init-decoding <line-reader> ; + +GENERIC: init-encoding ( stream encoding -- encoded-stream ) + +: <encoding> ( stream encoding-class -- encoded-stream ) + construct-empty init-encoding <plain-writer> ; + +GENERIC: encode-string ( string encoding -- byte-array ) +M: tuple-class encode-string construct-empty encode-string ; + +MIXIN: encoding-stream + +M: encoding-stream init-decoding ( stream encoding-stream -- encoding-stream ) + tuck set-delegate ; + +M: encoding-stream init-encoding ( stream encoding-stream -- encoding-stream ) + tuck set-delegate ; + +M: encoding-stream stream-read1 1 swap stream-read ; + +M: encoding-stream stream-read + [ delegate ] keep decode-read ; + +M: encoding-stream stream-read-partial stream-read ; + +M: encoding-stream stream-read-until + ! Copied from { c-reader stream-read-until }!!! + [ swap read-until-loop ] "" make + swap over empty? over not and [ 2drop f f ] when ; + +M: encoding-stream stream-write1 + >r 1string r> stream-write ; + +M: encoding-stream stream-write + [ encode-string ] keep delegate stream-write ; + +M: encoding-stream dispose delegate dispose ; diff --git a/core/io/utf8/authors.txt b/core/io/encodings/latin1/authors.txt similarity index 100% rename from core/io/utf8/authors.txt rename to core/io/encodings/latin1/authors.txt diff --git a/core/io/encodings/latin1/latin1-docs.factor b/core/io/encodings/latin1/latin1-docs.factor new file mode 100644 index 0000000000..5872b2bcfd --- /dev/null +++ b/core/io/encodings/latin1/latin1-docs.factor @@ -0,0 +1,5 @@ +USING: help.syntax help.markup ; +IN: io.encodings.latin1 + +HELP: latin1 +{ $class-description "This class is used for Latin 1 (ISO 8859-1) encoding and decoding" } ; diff --git a/core/io/encodings/latin1/latin1.factor b/core/io/encodings/latin1/latin1.factor new file mode 100755 index 0000000000..468324316d --- /dev/null +++ b/core/io/encodings/latin1/latin1.factor @@ -0,0 +1,19 @@ +USING: io io.encodings strings kernel ; +IN: io.encodings.latin1 + +TUPLE: latin1 stream ; + +M: latin1 init-decoding tuck set-latin1-stream ; +M: latin1 init-encoding drop ; + +M: latin1 stream-read1 + latin1-stream stream-read1 ; + +M: latin1 stream-read + latin1-stream stream-read >string ; + +M: latin1 stream-read-until + latin1-stream stream-read-until >string ; + +M: latin1 stream-readln + latin1-stream stream-readln >string ; diff --git a/core/io/encodings/latin1/summary.txt b/core/io/encodings/latin1/summary.txt new file mode 100644 index 0000000000..d40d628767 --- /dev/null +++ b/core/io/encodings/latin1/summary.txt @@ -0,0 +1 @@ +ISO 8859-1 encoding/decoding diff --git a/core/io/encodings/latin1/tags.txt b/core/io/encodings/latin1/tags.txt new file mode 100644 index 0000000000..8e27be7d61 --- /dev/null +++ b/core/io/encodings/latin1/tags.txt @@ -0,0 +1 @@ +text diff --git a/core/io/encodings/utf16/.utf16.factor.swo b/core/io/encodings/utf16/.utf16.factor.swo new file mode 100644 index 0000000000..01be8fdab2 Binary files /dev/null and b/core/io/encodings/utf16/.utf16.factor.swo differ diff --git a/core/io/encodings/utf16/authors.txt b/core/io/encodings/utf16/authors.txt new file mode 100644 index 0000000000..f990dd0ed2 --- /dev/null +++ b/core/io/encodings/utf16/authors.txt @@ -0,0 +1 @@ +Daniel Ehrenberg diff --git a/core/io/utf16/summary.txt b/core/io/encodings/utf16/summary.txt similarity index 100% rename from core/io/utf16/summary.txt rename to core/io/encodings/utf16/summary.txt diff --git a/core/io/encodings/utf16/tags.txt b/core/io/encodings/utf16/tags.txt new file mode 100644 index 0000000000..8e27be7d61 --- /dev/null +++ b/core/io/encodings/utf16/tags.txt @@ -0,0 +1 @@ +text diff --git a/core/io/utf16/utf16-docs.factor b/core/io/encodings/utf16/utf16-docs.factor similarity index 99% rename from core/io/utf16/utf16-docs.factor rename to core/io/encodings/utf16/utf16-docs.factor index 6d24f54694..c49c030ef3 100644 --- a/core/io/utf16/utf16-docs.factor +++ b/core/io/encodings/utf16/utf16-docs.factor @@ -1,5 +1,5 @@ USING: help.markup help.syntax io.encodings strings ; -IN: io.utf16 +IN: io.encodings.utf16 ARTICLE: "io.utf16" "Working with UTF16-encoded data" "The UTF16 encoding is a variable-width encoding. Unicode code points are encoded as 2 or 4 byte sequences." diff --git a/core/io/utf16/utf16-tests.factor b/core/io/encodings/utf16/utf16-tests.factor similarity index 50% rename from core/io/utf16/utf16-tests.factor rename to core/io/encodings/utf16/utf16-tests.factor index 9800a9827d..d1817db1e8 100755 --- a/core/io/utf16/utf16-tests.factor +++ b/core/io/encodings/utf16/utf16-tests.factor @@ -1,15 +1,15 @@ -USING: tools.test io.utf16 arrays unicode.syntax ; +USING: tools.test io.utf16 arrays unicode ; [ { CHAR: x } ] [ { 0 CHAR: x } decode-utf16be >array ] unit-test [ { HEX: 1D11E } ] [ { HEX: D8 HEX: 34 HEX: DD HEX: 1E } decode-utf16be >array ] unit-test -[ { UNICHAR: replacement-character } ] [ { BIN: 11011111 CHAR: q } decode-utf16be >array ] unit-test -[ { UNICHAR: replacement-character } ] [ { BIN: 11011011 CHAR: x BIN: 11011011 CHAR: x } decode-utf16be >array ] unit-test +[ { CHAR: replacement-character } ] [ { BIN: 11011111 CHAR: q } decode-utf16be >array ] unit-test +[ { CHAR: replacement-character } ] [ { BIN: 11011011 CHAR: x BIN: 11011011 CHAR: x } decode-utf16be >array ] unit-test [ B{ 0 120 216 52 221 30 } ] [ { CHAR: x HEX: 1d11e } encode-utf16be ] unit-test [ { CHAR: x } ] [ { CHAR: x 0 } decode-utf16le >array ] unit-test [ { 119070 } ] [ { HEX: 34 HEX: D8 HEX: 1E HEX: DD } decode-utf16le >array ] unit-test -[ { UNICHAR: replacement-character } ] [ { 0 BIN: 11011111 } decode-utf16le >array ] unit-test -[ { UNICHAR: replacement-character } ] [ { 0 BIN: 11011011 0 0 } decode-utf16le >array ] unit-test +[ { CHAR: replacement-character } ] [ { 0 BIN: 11011111 } decode-utf16le >array ] unit-test +[ { CHAR: replacement-character } ] [ { 0 BIN: 11011011 0 0 } decode-utf16le >array ] unit-test [ B{ 120 0 52 216 30 221 } ] [ { CHAR: x HEX: 1d11e } encode-utf16le ] unit-test diff --git a/core/io/utf16/utf16.factor b/core/io/encodings/utf16/utf16.factor similarity index 79% rename from core/io/utf16/utf16.factor rename to core/io/encodings/utf16/utf16.factor index 19ebc1d43a..84017324ee 100755 --- a/core/io/utf16/utf16.factor +++ b/core/io/encodings/utf16/utf16.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: math kernel sequences sbufs vectors namespaces io.binary io.encodings combinators splitting ; -IN: io.utf16 +IN: io.encodings.utf16 SYMBOL: double SYMBOL: quad1 @@ -30,7 +30,7 @@ SYMBOL: ignore >r 2 shift r> BIN: 11 bitand bitor quad3 ] [ 2drop do-ignore ] if ; -: (decode-utf16be) ( buf byte ch state -- buf ch state ) +: decode-utf16be-step ( buf byte ch state -- buf ch state ) { { begin [ drop begin-utf16be ] } { double [ end-multibyte ] } @@ -41,7 +41,7 @@ SYMBOL: ignore } case ; : decode-utf16be ( seq -- str ) - [ -rot (decode-utf16be) ] decode ; + [ decode-utf16be-step ] decode ; : handle-double ( buf byte ch -- buf ch state ) swap dup -3 shift BIN: 11011 = [ @@ -55,7 +55,7 @@ SYMBOL: ignore BIN: 11 bitand append-nums HEX: 10000 + decoded ] [ 2drop push-replacement ] if ; -: (decode-utf16le) ( buf byte ch state -- buf ch state ) +: decode-utf16le-step ( buf byte ch state -- buf ch state ) { { begin [ drop double ] } { double [ handle-double ] } @@ -65,7 +65,7 @@ SYMBOL: ignore } case ; : decode-utf16le ( seq -- str ) - [ -rot (decode-utf16le) ] decode ; + [ decode-utf16le-step ] decode ; : encode-first -10 shift @@ -104,13 +104,23 @@ SYMBOL: ignore : encode-utf16 ( str -- seq ) encode-utf16le bom-le swap append ; -: utf16le? ( seq1 -- seq2 ? ) bom-le ?head ; - -: utf16be? ( seq1 -- seq2 ? ) bom-be ?head ; - : decode-utf16 ( seq -- str ) { - { [ utf16le? ] [ decode-utf16le ] } - { [ utf16be? ] [ decode-utf16be ] } + { [ bom-le ?head ] [ decode-utf16le ] } + { [ bom-be ?head ] [ decode-utf16be ] } { [ t ] [ decode-error ] } } cond ; + +TUPLE: utf16le ; +: <utf16le> utf16le construct-delegate ; +INSTANCE: utf16le encoding-stream + +M: utf16le encode-string drop encode-utf16le ; +M: utf16le decode-step drop decode-utf16le-step ; + +TUPLE: utf16be ; +: <utf16be> utf16be construct-delegate ; +INSTANCE: utf16be encoding-stream + +M: utf16be encode-string drop encode-utf16be ; +M: utf16be decode-step drop decode-utf16be-step ; diff --git a/core/io/encodings/utf8/authors.txt b/core/io/encodings/utf8/authors.txt new file mode 100644 index 0000000000..f990dd0ed2 --- /dev/null +++ b/core/io/encodings/utf8/authors.txt @@ -0,0 +1 @@ +Daniel Ehrenberg diff --git a/core/io/utf8/summary.txt b/core/io/encodings/utf8/summary.txt similarity index 100% rename from core/io/utf8/summary.txt rename to core/io/encodings/utf8/summary.txt diff --git a/core/io/encodings/utf8/tags.txt b/core/io/encodings/utf8/tags.txt new file mode 100644 index 0000000000..8e27be7d61 --- /dev/null +++ b/core/io/encodings/utf8/tags.txt @@ -0,0 +1 @@ +text diff --git a/core/io/utf8/utf8-docs.factor b/core/io/encodings/utf8/utf8-docs.factor old mode 100644 new mode 100755 similarity index 86% rename from core/io/utf8/utf8-docs.factor rename to core/io/encodings/utf8/utf8-docs.factor index 28310b5d77..6e1923824f --- a/core/io/utf8/utf8-docs.factor +++ b/core/io/encodings/utf8/utf8-docs.factor @@ -1,12 +1,12 @@ USING: help.markup help.syntax io.encodings strings ; -IN: io.utf8 +IN: io.encodings.utf8 -ARTICLE: "io.utf8" "Working with UTF8-encoded data" +ARTICLE: "io.encodings.utf8" "Working with UTF8-encoded data" "The UTF8 encoding is a variable-width encoding. 7-bit ASCII characters are encoded as single bytes, and other Unicode code points are encoded as 2 to 4 byte sequences." { $subsection encode-utf8 } { $subsection decode-utf8 } ; -ABOUT: "io.utf8" +ABOUT: "io.encodings.utf8" HELP: decode-utf8 { $values { "seq" "a sequence of bytes" } { "str" string } } diff --git a/core/io/encodings/utf8/utf8-tests.factor b/core/io/encodings/utf8/utf8-tests.factor new file mode 100644 index 0000000000..ea7a238551 --- /dev/null +++ b/core/io/encodings/utf8/utf8-tests.factor @@ -0,0 +1,23 @@ +USING: io.encodings.utf8 tools.test sbufs kernel io +sequences strings arrays unicode ; + +: decode-utf8-w/stream ( array -- newarray ) + >sbuf dup reverse-here <utf8> contents >array ; + +: encode-utf8-w/stream ( array -- newarray ) + SBUF" " clone tuck <utf8> write >array ; + +[ { CHAR: replacement-character } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 11111111 } decode-utf8-w/stream >array ] unit-test + +[ { BIN: 101111111000000111111 } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } decode-utf8-w/stream >array ] unit-test + +[ "x" ] [ "x" decode-utf8-w/stream >string ] unit-test + +[ { BIN: 11111000000 } ] [ { BIN: 11011111 BIN: 10000000 } decode-utf8-w/stream >array ] unit-test + +[ { CHAR: replacement-character } ] [ { BIN: 10000000 } decode-utf8-w/stream >array ] unit-test + +[ { BIN: 1111000000111111 } ] [ { BIN: 11101111 BIN: 10000000 BIN: 10111111 } decode-utf8-w/stream >array ] unit-test + +[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ] +[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } encode-utf8 ] unit-test diff --git a/core/io/utf8/utf8.factor b/core/io/encodings/utf8/utf8.factor similarity index 77% rename from core/io/utf8/utf8.factor rename to core/io/encodings/utf8/utf8.factor index 213afb6eae..f681b18142 100644 --- a/core/io/utf8/utf8.factor +++ b/core/io/encodings/utf8/utf8.factor @@ -1,8 +1,10 @@ ! Copyright (C) 2006, 2007 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: math kernel sequences sbufs vectors -namespaces io.encodings combinators ; -IN: io.utf8 +USING: math kernel sequences sbufs vectors growable io continuations +namespaces io.encodings combinators strings io.streams.c ; +IN: io.encodings.utf8 + +! Decoding UTF-8 SYMBOL: double SYMBOL: triple @@ -31,7 +33,7 @@ SYMBOL: quad3 : end-multibyte ( buf byte ch -- buf ch state ) f append-nums [ decoded ] unless* ; -: (decode-utf8) ( buf byte ch state -- buf ch state ) +: decode-utf8-step ( buf byte ch state -- buf ch state ) { { begin [ drop begin-utf8 ] } { double [ end-multibyte ] } @@ -43,7 +45,9 @@ SYMBOL: quad3 } case ; : decode-utf8 ( seq -- str ) - [ -rot (decode-utf8) ] decode ; + [ decode-utf8-step ] decode ; + +! Encoding UTF-8 : encoded ( char -- ) BIN: 111111 bitand BIN: 10000000 bitor , ; @@ -70,3 +74,13 @@ SYMBOL: quad3 : encode-utf8 ( str -- seq ) [ [ char>utf8 ] each ] B{ } make ; + +! Interface for streams + +TUPLE: utf8 ; +: <utf8> utf8 construct-delegate ; +INSTANCE: utf8 encoding-stream + +M: utf8 encode-string drop encode-utf8 ; +M: utf8 decode-step drop decode-utf8-step ; +! In the future, this should detect and ignore a BOM at the beginning diff --git a/core/io/utf8/utf8-tests.factor b/core/io/utf8/utf8-tests.factor deleted file mode 100644 index 3576471586..0000000000 --- a/core/io/utf8/utf8-tests.factor +++ /dev/null @@ -1,16 +0,0 @@ -USING: io.utf8 tools.test strings arrays unicode.syntax ; - -[ { UNICHAR: replacement-character } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 11111111 } decode-utf8 >array ] unit-test - -[ { BIN: 101111111000000111111 } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } decode-utf8 >array ] unit-test - -[ "x" ] [ "x" decode-utf8 >string ] unit-test - -[ { BIN: 11111000000 } ] [ { BIN: 11011111 BIN: 10000000 } decode-utf8 >array ] unit-test - -[ { UNICHAR: replacement-character } ] [ { BIN: 10000000 } decode-utf8 >array ] unit-test - -[ { BIN: 1111000000111111 } ] [ { BIN: 11101111 BIN: 10000000 BIN: 10111111 } decode-utf8 >array ] unit-test - -[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ] -[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } encode-utf8 ] unit-test diff --git a/core/optimizer/backend/backend.factor b/core/optimizer/backend/backend.factor index c64d1fd010..1703bea5d4 100755 --- a/core/optimizer/backend/backend.factor +++ b/core/optimizer/backend/backend.factor @@ -3,8 +3,7 @@ USING: arrays generic assocs inference inference.class inference.dataflow inference.backend inference.state io kernel math namespaces sequences vectors words quotations hashtables -combinators classes generic.math continuations optimizer.def-use -optimizer.pattern-match generic.standard optimizer.specializers ; +combinators classes optimizer.def-use ; IN: optimizer.backend SYMBOL: class-substitutions @@ -38,10 +37,10 @@ GENERIC: optimize-node* ( node -- node/t changed? ) over assoc-empty? [ 2drop ] [ - 2dup node-in-d substitute - 2dup node-in-r substitute - 2dup node-out-d substitute - node-out-r substitute + 2dup node-in-d swap substitute-here + 2dup node-in-r swap substitute-here + 2dup node-out-d swap substitute-here + node-out-r swap substitute-here ] if ; : perform-substitutions ( node -- ) @@ -68,8 +67,6 @@ DEFER: optimize-nodes ] if ] when ; -M: f set-node-successor 2drop ; - : optimize-nodes ( node -- newnode ) [ class-substitutions [ clone ] change @@ -78,19 +75,9 @@ M: f set-node-successor 2drop ; optimizer-changed get ] with-scope optimizer-changed set ; -! Generic nodes M: node optimize-node* drop t f ; -: cleanup-inlining ( node -- newnode changed? ) - node-successor [ node-successor t ] [ t f ] if* ; - -! #return -M: #return optimize-node* cleanup-inlining ; - -! #values -M: #values optimize-node* cleanup-inlining ; - -! Some utilities for splicing in dataflow IR subtrees +! Post-inlining cleanup : follow ( key assoc -- value ) 2dup at* [ swap follow nip ] [ 2drop ] if ; @@ -103,277 +90,30 @@ M: #values optimize-node* cleanup-inlining ; #! Not very efficient. dupd union* update ; -: post-inline ( #call/#merge #return/#values -- assoc ) - >r node-out-d r> node-in-d 2array unify-lengths flip +: compute-value-substitutions ( #return/#values #call/#merge -- assoc ) + node-out-d swap node-in-d 2array unify-lengths flip [ = not ] assoc-subset >hashtable ; -: substitute-def-use ( node -- ) - #! As a first approximation, we take all the values used - #! by the set of new nodes, and push a 't' on their - #! def-use list here. We could perform a full graph - #! substitution, but we don't need to, because the next - #! optimizer iteration will do that. We just need a minimal - #! degree of accuracy; the new values should be marked as - #! having _some_ usage, so that flushing doesn't erronously - #! flush them away. - [ compute-def-use def-use get keys ] with-scope - def-use get [ [ t swap ?push ] change-at ] curry each ; +: cleanup-inlining ( #return/#values -- newnode changed? ) + dup node-successor dup [ + class-substitutions get pick node-classes update + literal-substitutions get pick node-literals update + tuck compute-value-substitutions value-substitutions get swap update* + node-successor t + ] [ + 2drop t f + ] if ; -: substitute-node ( old new -- ) - #! The last node of 'new' becomes 'old', then values are - #! substituted. A subsequent optimizer phase kills the - #! last node of 'new' and the first node of 'old'. - dup substitute-def-use - last-node - class-substitutions get over node-classes update - literal-substitutions get over node-literals update - 2dup post-inline value-substitutions get swap update* - set-node-successor ; +! #return +M: #return optimize-node* cleanup-inlining ; -GENERIC: remember-method* ( method-spec node -- ) +! #values +M: #values optimize-node* cleanup-inlining ; -M: #call remember-method* - [ node-history ?push ] keep set-node-history ; +M: f set-node-successor 2drop ; -M: node remember-method* - 2drop ; - -: remember-method ( method-spec node -- ) - swap dup second +inlined+ depends-on - [ swap remember-method* ] curry each-node ; - -: (splice-method) ( #call method-spec quot -- node ) - #! Must remember the method before splicing in, otherwise - #! the rest of the IR will also remember the method - pick node-in-d dataflow-with - [ remember-method ] keep - [ swap infer-classes/node ] 2keep - [ substitute-node ] keep ; - -: splice-quot ( #call quot -- node ) - over node-in-d dataflow-with - [ swap infer-classes/node ] 2keep - [ substitute-node ] keep ; +: splice-node ( old new -- ) + dup splice-def-use last-node set-node-successor ; : drop-inputs ( node -- #shuffle ) node-in-d clone \ #shuffle in-node ; - -! Constant branch folding -: fold-branch ( node branch# -- node ) - over node-children nth - swap node-successor over substitute-node ; - -! #if -: known-boolean-value? ( node value -- value ? ) - 2dup node-literal? [ - node-literal t - ] [ - node-class { - { [ dup null class< ] [ drop f f ] } - { [ dup general-t class< ] [ drop t t ] } - { [ dup \ f class< ] [ drop f t ] } - { [ t ] [ drop f f ] } - } cond - ] if ; - -M: #if optimize-node* - dup dup node-in-d first known-boolean-value? [ - over drop-inputs >r - 0 1 ? fold-branch - r> [ set-node-successor ] keep - t - ] [ 2drop t f ] if ; - -M: #dispatch optimize-node* - dup dup node-in-d first 2dup node-literal? [ - "Optimizing #dispatch" print - node-literal - over drop-inputs >r fold-branch r> [ set-node-successor ] keep t - ] [ - 3drop t f - ] if ; - -! #call -: splice-method ( #call method-spec/t quot/t -- node/t ) - #! t indicates failure - { - { [ dup t eq? ] [ 3drop t ] } - { [ 2over swap node-history member? ] [ 3drop t ] } - { [ t ] [ (splice-method) ] } - } cond ; - -! Single dispatch method inlining optimization -: already-inlined? ( node -- ? ) - #! Was this node inlined from definition of 'word'? - dup node-param swap node-history memq? ; - -: specific-method ( class word -- class ) order min-class ; - -: node-class# ( node n -- class ) - over node-in-d <reversed> ?nth node-class ; - -: dispatching-class ( node word -- class ) - [ dispatch# node-class# ] keep specific-method ; - -! A heuristic to avoid excessive inlining -DEFER: (flat-length) - -: word-flat-length ( word -- n ) - dup get over inline? not or - [ drop 1 ] [ dup dup set word-def (flat-length) ] if ; - -: (flat-length) ( seq -- n ) - [ - { - { [ dup quotation? ] [ (flat-length) 1+ ] } - { [ dup array? ] [ (flat-length) ] } - { [ dup word? ] [ word-flat-length ] } - { [ t ] [ drop 1 ] } - } cond - ] map sum ; - -: flat-length ( seq -- n ) - [ word-def (flat-length) ] with-scope ; - -: will-inline-method ( node word -- method-spec/t quot/t ) - #! t indicates failure - tuck dispatching-class dup [ - swap [ 2array ] 2keep - method method-word - dup flat-length 10 >= - [ 1quotation ] [ word-def ] if - ] [ - 2drop t t - ] if ; - -: inline-standard-method ( node word -- node ) - dupd will-inline-method splice-method ; - -! Partial dispatch of math-generic words -: math-both-known? ( word left right -- ? ) - math-class-max swap specific-method ; - -: will-inline-math-method ( word left right -- method-spec/t quot/t ) - #! t indicates failure - 3dup math-both-known? - [ [ 3array ] 3keep math-method ] [ 3drop t t ] if ; - -: inline-math-method ( #call word -- node ) - over node-input-classes first2 - will-inline-math-method splice-method ; - -: inline-method ( #call -- node ) - dup node-param { - { [ dup standard-generic? ] [ inline-standard-method ] } - { [ dup math-generic? ] [ inline-math-method ] } - { [ t ] [ 2drop t ] } - } cond ; - -! Resolve type checks at compile time where possible -: comparable? ( actual testing -- ? ) - #! If actual is a subset of testing or if the two classes - #! are disjoint, return t. - 2dup class< >r classes-intersect? not r> or ; - -: optimize-predicate? ( #call -- ? ) - dup node-param "predicating" word-prop dup [ - >r node-class-first r> comparable? - ] [ - 2drop f - ] if ; - -: literal-quot ( node literals -- quot ) - #! Outputs a quotation which drops the node's inputs, and - #! pushes some literals. - >r node-in-d length \ drop <repetition> - r> [ literalize ] map append >quotation ; - -: inline-literals ( node literals -- node ) - #! Make #shuffle -> #push -> #return -> successor - dupd literal-quot splice-quot ; - -: evaluate-predicate ( #call -- ? ) - dup node-param "predicating" word-prop >r - node-class-first r> class< ; - -: optimize-predicate ( #call -- node ) - dup evaluate-predicate swap - dup node-successor #if? [ - dup drop-inputs >r - node-successor swap 0 1 ? fold-branch - r> [ set-node-successor ] keep - ] [ - swap 1array inline-literals - ] if ; - -: optimizer-hooks ( node -- conditions ) - node-param "optimizer-hooks" word-prop ; - -: optimizer-hook ( node -- pair/f ) - dup optimizer-hooks [ first call ] find 2nip ; - -: optimize-hook ( node -- ) - dup optimizer-hook second call ; - -: define-optimizers ( word optimizers -- ) - "optimizer-hooks" set-word-prop ; - -: flush-eval? ( #call -- ? ) - dup node-param "flushable" word-prop [ - node-out-d [ unused? ] all? - ] [ - drop f - ] if ; - -: flush-eval ( #call -- node ) - dup node-param +inlined+ depends-on - dup node-out-d length f <repetition> inline-literals ; - -: partial-eval? ( #call -- ? ) - dup node-param "foldable" word-prop [ - dup node-in-d [ node-literal? ] with all? - ] [ - drop f - ] if ; - -: literal-in-d ( #call -- inputs ) - dup node-in-d [ node-literal ] with map ; - -: partial-eval ( #call -- node ) - dup node-param +inlined+ depends-on - dup literal-in-d over node-param 1quotation - [ with-datastack inline-literals ] [ 2drop 2drop t ] recover ; - -: define-identities ( words identities -- ) - [ "identities" set-word-prop ] curry each ; - -: find-identity ( node -- quot ) - [ node-param "identities" word-prop ] keep - [ swap first in-d-match? ] curry find - nip dup [ second ] when ; - -: apply-identities ( node -- node/f ) - dup find-identity dup [ splice-quot ] [ 2drop f ] if ; - -: optimistic-inline? ( #call -- ? ) - dup node-param "specializer" word-prop dup [ - >r node-input-classes r> specialized-length tail* - [ types length 1 = ] all? - ] [ - 2drop f - ] if ; - -: optimistic-inline ( #call -- node ) - dup node-param dup +inlined+ depends-on - word-def splice-quot ; - -M: #call optimize-node* - { - { [ dup flush-eval? ] [ flush-eval ] } - { [ dup partial-eval? ] [ partial-eval ] } - { [ dup find-identity ] [ apply-identities ] } - { [ dup optimizer-hook ] [ optimize-hook ] } - { [ dup optimize-predicate? ] [ optimize-predicate ] } - { [ dup optimistic-inline? ] [ optimistic-inline ] } - { [ t ] [ inline-method ] } - } cond dup not ; diff --git a/core/optimizer/control/control-tests.factor b/core/optimizer/control/control-tests.factor new file mode 100755 index 0000000000..b5b52e0e0e --- /dev/null +++ b/core/optimizer/control/control-tests.factor @@ -0,0 +1,181 @@ +IN: temporary +USING: tools.test optimizer.control combinators kernel +sequences inference.dataflow math inference classes strings +optimizer ; + +: label-is-loop? ( node word -- ? ) + [ + { + { [ over #label? not ] [ 2drop f ] } + { [ over #label-word over eq? not ] [ 2drop f ] } + { [ over #label-loop? not ] [ 2drop f ] } + { [ t ] [ 2drop t ] } + } cond + ] curry node-exists? ; + +: label-is-not-loop? ( node word -- ? ) + [ + { + { [ over #label? not ] [ 2drop f ] } + { [ over #label-word over eq? not ] [ 2drop f ] } + { [ over #label-loop? ] [ 2drop f ] } + { [ t ] [ 2drop t ] } + } cond + ] curry node-exists? ; + +: loop-test-1 ( a -- ) + dup [ 1+ loop-test-1 ] [ drop ] if ; inline + +[ t ] [ + [ loop-test-1 ] dataflow dup detect-loops + \ loop-test-1 label-is-loop? +] unit-test + +[ t ] [ + [ loop-test-1 1 2 3 ] dataflow dup detect-loops + \ loop-test-1 label-is-loop? +] unit-test + +[ t ] [ + [ [ loop-test-1 ] each ] dataflow dup detect-loops + \ loop-test-1 label-is-loop? +] unit-test + +[ t ] [ + [ [ loop-test-1 ] each ] dataflow dup detect-loops + \ (each-integer) label-is-loop? +] unit-test + +: loop-test-2 ( a -- ) + dup [ 1+ loop-test-2 1- ] [ drop ] if ; inline + +[ t ] [ + [ loop-test-2 ] dataflow dup detect-loops + \ loop-test-2 label-is-not-loop? +] unit-test + +: loop-test-3 ( a -- ) + dup [ [ loop-test-3 ] each ] [ drop ] if ; inline + +[ t ] [ + [ loop-test-3 ] dataflow dup detect-loops + \ loop-test-3 label-is-not-loop? +] unit-test + +: loop-test-4 ( a -- ) + dup [ + loop-test-4 + ] [ + drop + ] if ; inline + +: find-label ( node -- label ) + dup #label? [ node-successor find-label ] unless ; + +: test-loop-exits + dataflow dup detect-loops find-label + dup node-param swap + [ node-child find-tail find-loop-exits [ class ] map ] keep + #label-loop? ; + +[ { #values } t ] [ + [ loop-test-4 ] test-loop-exits +] unit-test + +: loop-test-5 ( a -- ) + dup [ + dup string? [ + loop-test-5 + ] [ + drop + ] if + ] [ + drop + ] if ; inline + +[ { #values #values } t ] [ + [ loop-test-5 ] test-loop-exits +] unit-test + +: loop-test-6 ( a -- ) + dup [ + dup string? [ + loop-test-6 + ] [ + 3 throw + ] if + ] [ + drop + ] if ; inline + +[ { #values } t ] [ + [ loop-test-6 ] test-loop-exits +] unit-test + +[ f ] [ + [ [ [ ] map ] map ] dataflow dup detect-loops + [ dup #label? swap #loop? not and ] node-exists? +] unit-test + +: blah f ; + +DEFER: a + +: b ( -- ) + blah [ b ] [ a ] if ; inline + +: a ( -- ) + blah [ b ] [ a ] if ; inline + +[ t ] [ + [ a ] dataflow dup detect-loops + \ a label-is-loop? +] unit-test + +[ t ] [ + [ a ] dataflow dup detect-loops + \ b label-is-loop? +] unit-test + +[ t ] [ + [ b ] dataflow dup detect-loops + \ a label-is-loop? +] unit-test + +[ t ] [ + [ a ] dataflow dup detect-loops + \ b label-is-loop? +] unit-test + +DEFER: a' + +: b' ( -- ) + blah [ b' b' ] [ a' ] if ; inline + +: a' ( -- ) + blah [ b' ] [ a' ] if ; inline + +[ f ] [ + [ a' ] dataflow dup detect-loops + \ a' label-is-loop? +] unit-test + +[ f ] [ + [ b' ] dataflow dup detect-loops + \ b' label-is-loop? +] unit-test + +! I used to think this should be f, but doing this on pen and +! paper almost convinced me that a loop conversion here is +! sound. The loop analysis algorithm looks pretty solid -- its +! a standard iterative dataflow problem after all -- so I'm +! tempted to believe the computer here +[ t ] [ + [ b' ] dataflow dup detect-loops + \ a' label-is-loop? +] unit-test + +[ f ] [ + [ a' ] dataflow dup detect-loops + \ b' label-is-loop? +] unit-test diff --git a/core/optimizer/control/control.factor b/core/optimizer/control/control.factor new file mode 100755 index 0000000000..b04d4677ce --- /dev/null +++ b/core/optimizer/control/control.factor @@ -0,0 +1,336 @@ +! Copyright (C) 2004, 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays generic assocs inference inference.class +inference.dataflow inference.backend inference.state io kernel +math namespaces sequences vectors words quotations hashtables +combinators classes generic.math continuations optimizer.def-use +optimizer.backend generic.standard ; +IN: optimizer.control + +! ! ! Rudimentary CFA + +! A LOOP +! +! #label A +! | +! #if ----> #merge ----> #return +! | +! ------------- +! | | +! #call-label A | +! | ... +! #values +! +! NOT A LOOP (call to A not in tail position): +! +! +! #label A +! | +! #if ----> ... ----> #merge ----> #return +! | +! ------------- +! | | +! #call-label A | +! | ... +! ... +! | +! #values +! +! NOT A LOOP (call to A nested inside another label which is +! not a loop): +! +! +! #label A +! | +! #if ----> #merge ----> ... ----> #return +! | +! ------------- +! | | +! ... #label B +! | +! #if -> ... +! | +! --------- +! | | +! #call-label A | +! | | +! #values | +! #call-label B +! | +! ... + +! Mapping word => { node { nesting tail? }+ height } +! We record all calls to a label, their control nesting and +! whether it is a tail call or not +SYMBOL: label-info + +GENERIC: collect-label-info* ( node -- ) + +M: #label collect-label-info* + [ V{ } clone node-stack get length 3array ] keep + node-param label-info get set-at ; + +USE: prettyprint + +M: #call-label collect-label-info* + node-param label-info get at + node-stack get over third tail + [ [ #label? ] subset [ node-param ] map ] keep + [ node-successor #tail? ] all? 2array + swap second push ; + +M: node collect-label-info* + drop ; + +: collect-label-info ( node -- ) + H{ } clone label-info set + [ collect-label-info* ] each-node ; + +! Mapping word => label +SYMBOL: potential-loops + +: remove-non-tail-calls ( -- ) + label-info get + [ nip second [ second ] all? ] assoc-subset + [ first ] assoc-map + potential-loops set ; + +: remove-non-loop-calls ( -- ) + ! Boolean is set to t if something changed. + ! We recurse until a fixed point is reached. + f label-info get [ + ! If label X is called from within a label Y that is + ! no longer a potential loop, then X is no longer a + ! potential loop either. + over potential-loops get key? [ + second [ first ] map concat + potential-loops get [ key? ] curry all? + [ drop ] [ potential-loops get delete-at t or ] if + ] [ 2drop ] if + ] assoc-each [ remove-non-loop-calls ] when ; + +: detect-loops ( nodes -- ) + [ + collect-label-info + remove-non-tail-calls + remove-non-loop-calls + potential-loops get [ + nip t swap set-#label-loop? + ] assoc-each + ] with-scope ; + +! ! ! Constant branch folding +! +! BEFORE +! +! #if ----> #merge ----> C +! | +! --------- +! | | +! A B +! | | +! #values | +! #values +! +! AFTER +! +! | +! A +! | +! #values +! | +! #merge +! | +! C + +: fold-branch ( node branch# -- node ) + over node-children nth + swap node-successor over splice-node ; + +! #if +: known-boolean-value? ( node value -- value ? ) + 2dup node-literal? [ + node-literal t + ] [ + node-class { + { [ dup null class< ] [ drop f f ] } + { [ dup general-t class< ] [ drop t t ] } + { [ dup \ f class< ] [ drop f t ] } + { [ t ] [ drop f f ] } + } cond + ] if ; + +: fold-if-branch? dup node-in-d first known-boolean-value? ; + +: fold-if-branch ( node value -- node' ) + over drop-inputs >r + 0 1 ? fold-branch + r> [ set-node-successor ] keep ; + +! ! ! Lifting code after a conditional if one branch throws + +! BEFORE +! +! #if ----> #merge ----> B ----> #return/#values +! | +! | +! --------- +! | | +! | A +! #terminate | +! #values +! +! AFTER +! +! #if ----> #merge (*) ----> #return/#values (**) +! | +! | +! --------- +! | | +! | A +! #terminate | +! #values +! | +! #merge (***) +! | +! B +! | +! #return/#values +! +! (*) has the same outputs as the inputs of (**), and it is not +! the same node as (***) +! +! Note: if (**) is #return is is sound to put #terminate there, +! but not if (**) is # + +: only-one ( seq -- elt/f ) + dup length 1 = [ first ] [ drop f ] if ; + +: lift-throw-tail? ( #if -- tail/? ) + dup node-successor #tail? + [ drop f ] [ active-children only-one ] if ; + +: clone-node ( node -- newnode ) + clone dup [ clone ] modify-values ; + +: lift-branch + over + last-node clone-node + dup node-in-d \ #merge out-node + [ set-node-successor ] keep -rot + >r dup node-successor r> splice-node + set-node-successor ; + +M: #if optimize-node* + dup fold-if-branch? [ fold-if-branch t ] [ + drop dup lift-throw-tail? dup [ + dupd lift-branch t + ] [ + 2drop t f + ] if + ] if ; + +! Loop tail hoising: code after a loop can sometimes go in the +! non-recursive branch of the loop + +! BEFORE: + +! #label -> C -> #return 1 +! | +! -> #if -> #merge (*) -> #return 2 +! | +! -------- +! | | +! A B +! | | +! #values | +! #call-label +! | +! | +! #values + +! AFTER: + +! #label -> #return 1 +! | +! -> #if -------> #merge (*) -> #return 2 +! | \-------------------/ +! ---------------- | +! | | | +! A B unreacachable code needed to +! | | preserve invariants +! #values | +! | #call-label +! #merge (*) | +! | | +! C #values +! | +! #return 1 + +: find-tail ( node -- tail ) + dup #terminate? [ + dup node-successor #tail? [ + node-successor find-tail + ] unless + ] unless ; + +: child-tails ( node -- seq ) + node-children [ find-tail ] map ; + +GENERIC: add-loop-exit* ( label node -- ) + +M: #branch add-loop-exit* + child-tails [ add-loop-exit* ] with each ; + +M: #call-label add-loop-exit* + tuck node-param eq? [ drop ] [ node-successor , ] if ; + +M: #terminate add-loop-exit* + 2drop ; + +M: node add-loop-exit* + nip node-successor dup #terminate? [ drop ] [ , ] if ; + +: find-loop-exits ( label node -- seq ) + [ add-loop-exit* ] { } make ; + +: find-final-if ( node -- #if/f ) + dup [ + dup #if? [ + dup node-successor #tail? [ + node-successor find-final-if + ] unless + ] [ + node-successor find-final-if + ] if + ] when ; + +: detach-node-successor ( node -- successor ) + dup node-successor #terminate rot set-node-successor ; + +: lift-loop-tail? ( #label -- tail/f ) + dup node-successor node-successor [ + dup node-param swap node-child find-final-if dup [ + find-loop-exits only-one + ] [ 2drop f ] if + ] [ drop f ] if ; + +M: #loop optimize-node* + dup lift-loop-tail? dup [ + last-node "values" set + + dup node-successor "tail" set + dup node-successor last-node "return" set + dup node-child find-final-if node-successor "merge" set + + ! #label -> #return + "return" get clone-node over set-node-successor + ! #merge -> C + "merge" get clone-node "tail" get over set-node-successor + ! #values -> #merge ->C + "values" get set-node-successor + + t + ] [ + 2drop t f + ] if ; diff --git a/core/optimizer/def-use/def-use.factor b/core/optimizer/def-use/def-use.factor index 9355b2bb70..df5c1e0aa4 100755 --- a/core/optimizer/def-use/def-use.factor +++ b/core/optimizer/def-use/def-use.factor @@ -70,20 +70,6 @@ M: #branch node-def-use #! #values node. dup branch-def-use (node-def-use) ; -! : dead-literals ( -- values ) -! def-use get [ >r value? r> empty? and ] assoc-subset ; -! -! : kill-node* ( node values -- ) -! [ swap remove-all ] curry modify-values ; -! -! : kill-node ( node values -- ) -! dup assoc-empty? -! [ 2drop ] [ [ kill-node* ] curry each-node ] if ; -! -! : kill-values ( node -- ) -! #! Remove literals which are not actually used anywhere. -! dead-literals kill-node ; - : compute-dead-literals ( -- values ) def-use get [ >r value? r> empty? and ] assoc-subset ; @@ -129,8 +115,18 @@ M: #r> kill-node* [ node-in-r empty? ] prune-if ; dead-literals [ kill-nodes ] with-variable ] if ; -! - : sole-consumer ( #call -- node/f ) node-out-d first used-by dup length 1 = [ first ] [ drop f ] if ; + +: splice-def-use ( node -- ) + #! As a first approximation, we take all the values used + #! by the set of new nodes, and push a 't' on their + #! def-use list here. We could perform a full graph + #! substitution, but we don't need to, because the next + #! optimizer iteration will do that. We just need a minimal + #! degree of accuracy; the new values should be marked as + #! having _some_ usage, so that flushing doesn't erronously + #! flush them away. + [ compute-def-use def-use get keys ] with-scope + def-use get [ [ t swap ?push ] change-at ] curry each ; diff --git a/core/optimizer/inlining/inlining.factor b/core/optimizer/inlining/inlining.factor new file mode 100755 index 0000000000..a272d05b5d --- /dev/null +++ b/core/optimizer/inlining/inlining.factor @@ -0,0 +1,227 @@ +! Copyright (C) 2004, 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays generic assocs inference inference.class +inference.dataflow inference.backend inference.state io kernel +math namespaces sequences vectors words quotations hashtables +combinators classes generic.math continuations optimizer.def-use +optimizer.backend generic.standard optimizer.specializers +optimizer.def-use optimizer.pattern-match generic.standard +optimizer.control ; +IN: optimizer.inlining + +GENERIC: remember-method* ( method-spec node -- ) + +M: #call remember-method* + [ node-history ?push ] keep set-node-history ; + +M: node remember-method* + 2drop ; + +: remember-method ( method-spec node -- ) + swap dup second +inlined+ depends-on + [ swap remember-method* ] curry each-node ; + +: (splice-method) ( #call method-spec quot -- node ) + #! Must remember the method before splicing in, otherwise + #! the rest of the IR will also remember the method + pick node-in-d dataflow-with + [ remember-method ] keep + [ swap infer-classes/node ] 2keep + [ splice-node ] keep ; + +: splice-quot ( #call quot -- node ) + over node-in-d dataflow-with + [ swap infer-classes/node ] 2keep + [ splice-node ] keep ; + +! #call +: splice-method ( #call method-spec/t quot/t -- node/t ) + #! t indicates failure + { + { [ dup t eq? ] [ 3drop t ] } + { [ 2over swap node-history member? ] [ 3drop t ] } + { [ t ] [ (splice-method) ] } + } cond ; + +! Single dispatch method inlining optimization +: already-inlined? ( node -- ? ) + #! Was this node inlined from definition of 'word'? + dup node-param swap node-history memq? ; + +: specific-method ( class word -- class ) order min-class ; + +: node-class# ( node n -- class ) + over node-in-d <reversed> ?nth node-class ; + +: dispatching-class ( node word -- class ) + [ dispatch# node-class# ] keep specific-method ; + +! A heuristic to avoid excessive inlining +DEFER: (flat-length) + +: word-flat-length ( word -- n ) + dup get over inline? not or + [ drop 1 ] [ dup dup set word-def (flat-length) ] if ; + +: (flat-length) ( seq -- n ) + [ + { + { [ dup quotation? ] [ (flat-length) 1+ ] } + { [ dup array? ] [ (flat-length) ] } + { [ dup word? ] [ word-flat-length ] } + { [ t ] [ drop 1 ] } + } cond + ] map sum ; + +: flat-length ( seq -- n ) + [ word-def (flat-length) ] with-scope ; + +: will-inline-method ( node word -- method-spec/t quot/t ) + #! t indicates failure + tuck dispatching-class dup [ + swap [ 2array ] 2keep + method method-word + dup flat-length 10 >= + [ 1quotation ] [ word-def ] if + ] [ + 2drop t t + ] if ; + +: inline-standard-method ( node word -- node ) + dupd will-inline-method splice-method ; + +! Partial dispatch of math-generic words +: math-both-known? ( word left right -- ? ) + math-class-max swap specific-method ; + +: will-inline-math-method ( word left right -- method-spec/t quot/t ) + #! t indicates failure + 3dup math-both-known? + [ [ 3array ] 3keep math-method ] [ 3drop t t ] if ; + +: inline-math-method ( #call word -- node ) + over node-input-classes first2 + will-inline-math-method splice-method ; + +: inline-method ( #call -- node ) + dup node-param { + { [ dup standard-generic? ] [ inline-standard-method ] } + { [ dup math-generic? ] [ inline-math-method ] } + { [ t ] [ 2drop t ] } + } cond ; + +! Resolve type checks at compile time where possible +: comparable? ( actual testing -- ? ) + #! If actual is a subset of testing or if the two classes + #! are disjoint, return t. + 2dup class< >r classes-intersect? not r> or ; + +: optimize-predicate? ( #call -- ? ) + dup node-param "predicating" word-prop dup [ + >r node-class-first r> comparable? + ] [ + 2drop f + ] if ; + +: literal-quot ( node literals -- quot ) + #! Outputs a quotation which drops the node's inputs, and + #! pushes some literals. + >r node-in-d length \ drop <repetition> + r> [ literalize ] map append >quotation ; + +: inline-literals ( node literals -- node ) + #! Make #shuffle -> #push -> #return -> successor + dupd literal-quot splice-quot ; + +: evaluate-predicate ( #call -- ? ) + dup node-param "predicating" word-prop >r + node-class-first r> class< ; + +: optimize-predicate ( #call -- node ) + #! If the predicate is followed by a branch we fold it + #! immediately + dup evaluate-predicate swap + dup node-successor #if? [ + dup drop-inputs >r + node-successor swap 0 1 ? fold-branch + r> [ set-node-successor ] keep + ] [ + swap 1array inline-literals + ] if ; + +: optimizer-hooks ( node -- conditions ) + node-param "optimizer-hooks" word-prop ; + +: optimizer-hook ( node -- pair/f ) + dup optimizer-hooks [ first call ] find 2nip ; + +: optimize-hook ( node -- ) + dup optimizer-hook second call ; + +: define-optimizers ( word optimizers -- ) + "optimizer-hooks" set-word-prop ; + +: flush-eval? ( #call -- ? ) + dup node-param "flushable" word-prop [ + node-out-d [ unused? ] all? + ] [ + drop f + ] if ; + +: flush-eval ( #call -- node ) + dup node-param +inlined+ depends-on + dup node-out-d length f <repetition> inline-literals ; + +: partial-eval? ( #call -- ? ) + dup node-param "foldable" word-prop [ + dup node-in-d [ node-literal? ] with all? + ] [ + drop f + ] if ; + +: literal-in-d ( #call -- inputs ) + dup node-in-d [ node-literal ] with map ; + +: partial-eval ( #call -- node ) + dup node-param +inlined+ depends-on + dup literal-in-d over node-param 1quotation + [ with-datastack inline-literals ] [ 2drop 2drop t ] recover ; + +: define-identities ( words identities -- ) + [ "identities" set-word-prop ] curry each ; + +: find-identity ( node -- quot ) + [ node-param "identities" word-prop ] keep + [ swap first in-d-match? ] curry find + nip dup [ second ] when ; + +: apply-identities ( node -- node/f ) + dup find-identity dup [ splice-quot ] [ 2drop f ] if ; + +: optimistic-inline? ( #call -- ? ) + dup node-param "specializer" word-prop dup [ + >r node-input-classes r> specialized-length tail* + [ types length 1 = ] all? + ] [ + 2drop f + ] if ; + +: optimistic-inline ( #call -- node ) + dup node-param dup +inlined+ depends-on + word-def splice-quot ; + +: method-body-inline? ( #call -- ? ) + node-param dup method-body? + [ flat-length 8 <= ] [ drop f ] if ; + +M: #call optimize-node* + { + { [ dup flush-eval? ] [ flush-eval ] } + { [ dup partial-eval? ] [ partial-eval ] } + { [ dup find-identity ] [ apply-identities ] } + { [ dup optimizer-hook ] [ optimize-hook ] } + { [ dup optimize-predicate? ] [ optimize-predicate ] } + { [ dup optimistic-inline? ] [ optimistic-inline ] } + { [ dup method-body-inline? ] [ optimistic-inline ] } + { [ t ] [ inline-method ] } + } cond dup not ; diff --git a/core/optimizer/known-words/known-words.factor b/core/optimizer/known-words/known-words.factor index 8534f1f090..d725396e77 100755 --- a/core/optimizer/known-words/known-words.factor +++ b/core/optimizer/known-words/known-words.factor @@ -8,7 +8,7 @@ assocs quotations sequences.private io.binary io.crc32 io.streams.string layouts splitting math.intervals math.floats.private tuples tuples.private classes optimizer.def-use optimizer.backend optimizer.pattern-match -float-arrays sequences.private combinators ; +optimizer.inlining float-arrays sequences.private combinators ; ! the output of <tuple> and <tuple-boa> has the class which is ! its second-to-last input diff --git a/core/optimizer/math/math.factor b/core/optimizer/math/math.factor index e048e29f48..9bd1fe3250 100755 --- a/core/optimizer/math/math.factor +++ b/core/optimizer/math/math.factor @@ -7,7 +7,7 @@ inference.class inference.dataflow vectors strings sbufs io namespaces assocs quotations math.intervals sequences.private combinators splitting layouts math.parser classes generic.math optimizer.pattern-match optimizer.backend optimizer.def-use -generic.standard system ; +optimizer.inlining generic.standard system ; { + bignum+ float+ fixnum+fast } { { { number 0 } [ drop ] } diff --git a/core/optimizer/optimizer-tests.factor b/core/optimizer/optimizer-tests.factor index 8f30abd09f..7092797acc 100755 --- a/core/optimizer/optimizer-tests.factor +++ b/core/optimizer/optimizer-tests.factor @@ -2,7 +2,7 @@ USING: arrays compiler generic hashtables inference kernel kernel.private math optimizer prettyprint sequences sbufs strings tools.test vectors words sequences.private quotations optimizer.backend classes inference.dataflow tuples.private -continuations growable ; +continuations growable optimizer.inlining namespaces ; IN: temporary [ H{ { 1 5 } { 3 4 } { 2 5 } } ] [ @@ -301,3 +301,53 @@ TUPLE: silly-tuple a b ; [ t ] [ \ array \ nth-unsafe should-inline? ] unit-test [ t ] [ \ growable \ nth-unsafe should-inline? ] unit-test [ t ] [ \ sbuf \ set-nth-unsafe should-inline? ] unit-test + +! Regression +: lift-throw-tail-regression + dup integer? [ "an integer" ] [ + dup string? [ "a string" ] [ + "error" throw + ] if + ] if ; + +[ t ] [ \ lift-throw-tail-regression compiled? ] unit-test +[ 3 "an integer" ] [ 3 lift-throw-tail-regression ] unit-test +[ "hi" "a string" ] [ "hi" lift-throw-tail-regression ] unit-test + +: lift-loop-tail-test-1 ( a quot -- ) + over even? [ + [ >r 3 - r> call ] keep lift-loop-tail-test-1 + ] [ + over 0 < [ + 2drop + ] [ + [ >r 2 - r> call ] keep lift-loop-tail-test-1 + ] if + ] if ; inline + +: lift-loop-tail-test-2 + 10 [ ] lift-loop-tail-test-1 1 2 3 ; + +[ 1 2 3 ] [ lift-loop-tail-test-2 ] unit-test + +! Make sure we don't lose +GENERIC: generic-inline-test ( x -- y ) +M: integer generic-inline-test ; + +: generic-inline-test-1 + 1 + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test + generic-inline-test ; + +[ { t f } ] [ + \ generic-inline-test-1 word-def dataflow + [ optimize-1 , optimize-1 , drop ] { } make +] unit-test diff --git a/core/optimizer/optimizer.factor b/core/optimizer/optimizer.factor index 1debf6c8cc..9e898450cc 100755 --- a/core/optimizer/optimizer.factor +++ b/core/optimizer/optimizer.factor @@ -1,7 +1,8 @@ -! Copyright (C) 2006, 2007 Slava Pestov. +! Copyright (C) 2006, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel namespaces optimizer.backend optimizer.def-use -optimizer.known-words optimizer.math inference.class ; +optimizer.known-words optimizer.math optimizer.control +optimizer.inlining inference.class ; IN: optimizer : optimize-1 ( node -- newnode ? ) @@ -11,6 +12,7 @@ IN: optimizer H{ } clone value-substitutions set dup compute-def-use kill-values + dup detect-loops dup infer-classes optimizer-changed off optimize-nodes diff --git a/core/optimizer/specializers/specializers.factor b/core/optimizer/specializers/specializers.factor index a4f5aaab95..10a9fda3ea 100755 --- a/core/optimizer/specializers/specializers.factor +++ b/core/optimizer/specializers/specializers.factor @@ -24,7 +24,7 @@ IN: optimizer.specializers \ dispatch , ] [ ] make ; -: specializer-methods ( word -- alist ) +: specializer-methods ( quot word -- default alist ) dup [ array? ] all? [ 1array ] unless [ [ make-specializer ] keep [ declare ] curry pick append diff --git a/core/parser/parser-docs.factor b/core/parser/parser-docs.factor index ae38925c68..ce6a119e32 100755 --- a/core/parser/parser-docs.factor +++ b/core/parser/parser-docs.factor @@ -266,19 +266,10 @@ HELP: escape { $description "Converts from a single-character escape code and the corresponding character." } { $examples { $example "CHAR: n escape CHAR: \\n = ." "t" } } ; -HELP: next-escape -{ $values { "m" "an index into " { $snippet "str" } } { "str" string } { "n" "an index into " { $snippet "str" } } { "ch" "a character" } } -{ $description "Helper word for " { $link parse-string } " which parses an escape sequence starting at the " { $snippet "m" } "th index of " { $snippet "str" } "." } -{ $errors "Throws a " { $link bad-escape } " if the string contains an invalid escape sequence." } ; - -HELP: next-char -{ $values { "m" "an index into " { $snippet "str" } } { "str" string } { "n" "an index into " { $snippet "str" } } { "ch" "a character" } } -{ $description "Helper word for " { $link parse-string } " which parses a character starting at the " { $snippet "m" } "th index of " { $snippet "str" } "." } ; - HELP: parse-string { $values { "str" "a new " { $link string } } } { $description "Parses the line until a quote (\"), interpreting escape codes along the way." } -{ $errors "Throws an " { $link bad-escape } " if the string contains an invalid escape sequence." } +{ $errors "Throws an error if the string contains an invalid escape sequence." } $parsing-note ; HELP: still-parsing? diff --git a/core/parser/parser.factor b/core/parser/parser.factor index 1bd7979a0c..c84c836390 100755 --- a/core/parser/parser.factor +++ b/core/parser/parser.factor @@ -119,22 +119,43 @@ M: bad-escape summary drop "Bad escape code" ; { CHAR: \" CHAR: \" } } at [ bad-escape ] unless* ; -: next-escape ( m str -- n ch ) - 2dup nth CHAR: u = - [ >r 1+ dup 6 + tuck r> subseq hex> ] - [ over 1+ -rot nth escape ] if ; +SYMBOL: name>char-hook -: next-char ( m str -- n ch ) - 2dup nth CHAR: \\ = - [ >r 1+ r> next-escape ] [ over 1+ -rot nth ] if ; +name>char-hook global [ + [ "Unicode support not available" throw ] or +] change-at -: (parse-string) ( m str -- n ) - 2dup nth CHAR: " = - [ drop 1+ ] [ [ next-char , ] keep (parse-string) ] if ; +: unicode-escape ( str -- ch str' ) + "{" ?head-slice [ + CHAR: } over index cut-slice + >r >string name>char-hook get call r> + 1 tail-slice + ] [ + 6 cut-slice >r hex> r> + ] if ; + +: next-escape ( str -- ch str' ) + "u" ?head-slice [ + unicode-escape + ] [ + unclip-slice escape swap + ] if ; + +: (parse-string) ( str -- m ) + dup [ "\"\\" member? ] find dup [ + >r cut-slice >r % r> 1 tail-slice r> + dup CHAR: " = [ + drop slice-from + ] [ + drop next-escape >r , r> (parse-string) + ] if + ] [ + "Unterminated string" throw + ] if ; : parse-string ( -- str ) lexer get [ - [ (parse-string) ] "" make swap + [ swap tail-slice (parse-string) ] "" make swap ] change-column ; TUPLE: parse-error file line col text ; diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index 967fcbbdc8..ee38d30750 100755 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -257,7 +257,7 @@ INSTANCE: repetition immutable-sequence : check-copy ( src n dst -- ) over 0 < [ bounds-error ] when - >r swap length + r> lengthen ; + >r swap length + r> lengthen ; inline PRIVATE> diff --git a/core/syntax/syntax-docs.factor b/core/syntax/syntax-docs.factor index 9ccfd2efcd..95a00f3801 100755 --- a/core/syntax/syntax-docs.factor +++ b/core/syntax/syntax-docs.factor @@ -100,13 +100,9 @@ ARTICLE: "escape" "Character escape codes" { { $snippet "\\0" } "a null byte (ASCII 0)" } { { $snippet "\\e" } "escape (ASCII 27)" } { { $snippet "\\\"" } { $snippet "\"" } } -} -"A Unicode character can be specified by its code number by writing " { $snippet "\\u" } " followed by a six-digit hexadecimal number. That is, the following two expressions are equivalent:" -{ $code - "CHAR: \\u000078" - "78" -} -"While not useful for single characters, this syntax is also permitted inside strings." ; + { { $snippet "\\u" { $emphasis "xxxxxx" } } { "The Unicode code point with hexadecimal number " { $snippet { $emphasis "xxxxxx" } } } } + { { $snippet "\\u{" { $emphasis "name" } "}" } { "The Unicode code point named " { $snippet { $emphasis "name" } } } } +} ; ARTICLE: "syntax-strings" "Character and string syntax" "Factor has no distinct character type, however Unicode character value integers can be read by specifying a literal character, or an escaped representation thereof." @@ -412,8 +408,17 @@ HELP: IN: HELP: CHAR: { $syntax "CHAR: token" } -{ $values { "token" "a literal character or escape code" } } -{ $description "Adds the Unicode code point of the character represented by the token to the parse tree." } ; +{ $values { "token" "a literal character, escape code, or Unicode character name" } } +{ $description "Adds a Unicode code point to the parse tree." } +{ $examples + { $code + "CHAR: x" + "CHAR: \\u000032" + "CHAR: \\u{exclamation-mark}" + "CHAR: exclamation-mark" + "CHAR: ugaritic-letter-samka" + } +} ; HELP: " { $syntax "\"string...\"" } diff --git a/core/syntax/syntax.factor b/core/syntax/syntax.factor index 67799b92ea..601c05d8d9 100755 --- a/core/syntax/syntax.factor +++ b/core/syntax/syntax.factor @@ -5,7 +5,8 @@ byte-vectors definitions generic hashtables kernel math namespaces parser sequences strings sbufs vectors words quotations io assocs splitting tuples generic.standard generic.math classes io.files vocabs float-arrays float-vectors -classes.union classes.mixin classes.predicate compiler.units ; +classes.union classes.mixin classes.predicate compiler.units +combinators ; IN: bootstrap.syntax ! These words are defined as a top-level form, instead of with @@ -56,7 +57,14 @@ IN: bootstrap.syntax "f" [ f parsed ] define-syntax "t" "syntax" lookup define-symbol - "CHAR:" [ 0 scan next-char nip parsed ] define-syntax + "CHAR:" [ + scan { + { [ dup length 1 = ] [ first ] } + { [ "\\" ?head ] [ next-escape drop ] } + { [ t ] [ name>char-hook get call ] } + } cond parsed + ] define-syntax + "\"" [ parse-string parsed ] define-syntax "SBUF\"" [ diff --git a/core/threads/threads-docs.factor b/core/threads/threads-docs.factor old mode 100644 new mode 100755 index 181979bfed..ece90d9a11 --- a/core/threads/threads-docs.factor +++ b/core/threads/threads-docs.factor @@ -9,6 +9,7 @@ $nl { $subsection in-thread } { $subsection yield } { $subsection sleep } +"Threads stop either when the quotation given to " { $link in-thread } " returns, or when the following word is called:" { $subsection stop } "Continuations can be added to the run queue directly:" { $subsection schedule-thread } @@ -21,7 +22,8 @@ ABOUT: "threads" HELP: run-queue { $values { "queue" dlist } } -{ $description "Outputs the runnable thread queue. By convention, continuations are queued with " { $link push-front } " and dequeued with " { $link pop-back } "." } ; +{ $description "Outputs the runnable thread queue. By convention, continuations are queued with " { $link push-front } +" and dequeued with " { $link pop-back } "." } ; HELP: schedule-thread { $values { "continuation" "a continuation reified by " { $link callcc0 } } } diff --git a/core/vocabs/loader/loader.factor b/core/vocabs/loader/loader.factor index 5e8a5630b2..a05cd2fa8c 100755 --- a/core/vocabs/loader/loader.factor +++ b/core/vocabs/loader/loader.factor @@ -1,10 +1,10 @@ ! Copyright (C) 2007, 2008 Eduardo Cavazos, Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: namespaces splitting sequences io.files kernel assocs -words vocabs definitions parser continuations inspector debugger -io io.styles io.streams.lines hashtables sorting prettyprint -source-files arrays combinators strings system math.parser -compiler.errors ; +USING: namespaces sequences io.files kernel assocs words vocabs +definitions parser continuations inspector debugger io io.styles +io.streams.lines hashtables sorting prettyprint source-files +arrays combinators strings system math.parser compiler.errors +splitting ; IN: vocabs.loader SYMBOL: vocab-roots @@ -16,7 +16,7 @@ V{ } clone vocab-roots set-global : vocab-dir ( vocab -- dir ) - vocab-name "." split "/" join ; + vocab-name { { CHAR: . CHAR: / } } substitute ; : vocab-dir+ ( vocab str/f -- path ) >r vocab-name "." split r> diff --git a/core/words/words-docs.factor b/core/words/words-docs.factor index 62848e46b2..91b5295427 100755 --- a/core/words/words-docs.factor +++ b/core/words/words-docs.factor @@ -245,8 +245,8 @@ HELP: remove-word-prop { $description "Removes a word property, so future lookups will output " { $link f } " until it is set again. Word property names are conventionally strings." } { $side-effects "word" } ; -HELP: word-xt -{ $values { "word" word } { "xt" "an execution token integer" } } +HELP: word-xt ( word -- start end ) +{ $values { "word" word } { "start" "the word's start address" } { "end" "the word's end address" } } { $description "Outputs the machine code address of the word's definition." } ; HELP: define-symbol diff --git a/extra/benchmark/benchmark.factor b/extra/benchmark/benchmark.factor old mode 100644 new mode 100755 index 46ff9a1ada..d453ee60ca --- a/extra/benchmark/benchmark.factor +++ b/extra/benchmark/benchmark.factor @@ -8,7 +8,7 @@ IN: benchmark : run-benchmark ( vocab -- result ) "=== Benchmark " write dup print flush dup require - [ [ run ] benchmark ] [ error. f f ] recover 2array + [ [ run ] benchmark ] [ error. drop f f ] recover 2array dup . ; : run-benchmarks ( -- assoc ) diff --git a/extra/benchmark/bootstrap2/bootstrap2.factor b/extra/benchmark/bootstrap2/bootstrap2.factor deleted file mode 100755 index f57e92e5e0..0000000000 --- a/extra/benchmark/bootstrap2/bootstrap2.factor +++ /dev/null @@ -1,14 +0,0 @@ -USING: io.files io.launcher system bootstrap.image -namespaces sequences kernel ; -IN: benchmark.bootstrap2 - -: bootstrap-benchmark - "." resource-path cd - [ - vm , - "-i=" my-boot-image-name append , - "-output-image=foo.image" , - "-no-user-init" , - ] { } make try-process ; - -MAIN: bootstrap-benchmark diff --git a/extra/benchmark/sockets/sockets.factor b/extra/benchmark/sockets/sockets.factor index e8efc11c32..f19a2127a5 100755 --- a/extra/benchmark/sockets/sockets.factor +++ b/extra/benchmark/sockets/sockets.factor @@ -22,7 +22,7 @@ IN: benchmark.sockets CHAR: x write1 ] with-stream ; -: socket-benchmark ( n -- ) +: clients ( n -- ) dup pprint " clients: " write [ [ simple-server ] in-thread @@ -33,11 +33,12 @@ IN: benchmark.sockets ] time ; : socket-benchmarks - 10 socket-benchmark - 20 socket-benchmark - 40 socket-benchmark - 80 socket-benchmark - 160 socket-benchmark - 320 socket-benchmark ; + 10 clients + 20 clients + 40 clients + 80 clients + 160 clients + 320 clients + 640 clients ; MAIN: socket-benchmarks diff --git a/extra/bootstrap/handbook/handbook.factor b/extra/bootstrap/handbook/handbook.factor new file mode 100755 index 0000000000..2ffb77de7a --- /dev/null +++ b/extra/bootstrap/handbook/handbook.factor @@ -0,0 +1,3 @@ +USING: vocabs.loader vocabs kernel ; + +"bootstrap.help" vocab [ "help.handbook" require ] when diff --git a/extra/bootstrap/help/help.factor b/extra/bootstrap/help/help.factor index ade60d4457..1680278fad 100755 --- a/extra/bootstrap/help/help.factor +++ b/extra/bootstrap/help/help.factor @@ -14,8 +14,6 @@ IN: bootstrap.help [ vocab-root ] subset [ vocab-source-loaded? ] subset [ dup vocab-docs-loaded? [ drop ] [ load-docs ] if ] each - ] with-variable - - "help.handbook" require ; + ] with-variable ; load-help diff --git a/extra/bootstrap/tools/tools.factor b/extra/bootstrap/tools/tools.factor index 7b909ea1f6..40d77e03be 100755 --- a/extra/bootstrap/tools/tools.factor +++ b/extra/bootstrap/tools/tools.factor @@ -4,10 +4,11 @@ USING: vocabs.loader sequences ; "bootstrap.image" "tools.annotations" "tools.crossref" - ! "tools.deploy" + "tools.deploy" "tools.memory" "tools.profiler" "tools.test" "tools.time" + "tools.disassembler" "editors" } [ require ] each diff --git a/extra/builder/builder.factor b/extra/builder/builder.factor index a5411e6129..cd17a32255 100644 --- a/extra/builder/builder.factor +++ b/extra/builder/builder.factor @@ -3,71 +3,43 @@ USING: kernel parser io io.files io.launcher io.sockets hashtables math threads arrays system continuations namespaces sequences splitting math.parser prettyprint tools.time calendar bake vars http.client combinators bootstrap.image bootstrap.image.download - combinators.cleave ; + combinators.cleave benchmark + classes strings quotations words parser-combinators new-slots accessors + assocs.lib smtp builder.util ; IN: builder ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: runtime ( quot -- time ) benchmark nip ; +SYMBOL: builds-dir + +: builds ( -- path ) + builds-dir get + home "/builds" append + or ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -SYMBOL: builder-recipients - -: host-name* ( -- name ) host-name "." split first ; - -: tag-subject ( str -- str ) `{ "builder@" ,[ host-name* ] ": " , } concat ; - -: email-string ( subject -- ) - `{ "mutt" "-s" ,[ tag-subject ] %[ builder-recipients get ] } - [ ] with-process-stream drop ; - -: email-file ( subject file -- ) - `{ - { +stdin+ , } - { +arguments+ - { "mutt" "-s" ,[ tag-subject ] %[ builder-recipients get ] } } - } - >hashtable run-process drop ; +: prepare-build-machine ( -- ) + builds make-directory + builds cd + { "git" "clone" "git://factorcode.org/git/factor.git" } run-process drop ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: target ( -- target ) `{ ,[ os ] %[ cpu "." split ] } "-" join ; +: builds-check ( -- ) builds exists? not [ prepare-build-machine ] when ; -: factor-binary ( -- name ) - os - { { "macosx" [ "./Factor.app/Contents/MacOS/factor" ] } - { "winnt" [ "./factor-nt.exe" ] } - [ drop "./factor" ] } - case ; - -: git-pull ( -- desc ) - { - "git" - "pull" - "--no-summary" - "git://factorcode.org/git/factor.git" - "master" - } ; +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : git-clone ( -- desc ) { "git" "clone" "../factor" } ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: datestamp ( -- string ) - now `{ ,[ dup timestamp-year ] - ,[ dup timestamp-month ] - ,[ dup timestamp-day ] - ,[ dup timestamp-hour ] - ,[ timestamp-minute ] } - [ pad-00 ] map "-" join ; - VAR: stamp : enter-build-dir ( -- ) datestamp >stamp - "/builds" cd + builds cd stamp> make-directory stamp> cd ; @@ -80,57 +52,59 @@ VAR: stamp : make-clean ( -- desc ) { "make" "clean" } ; -: make-vm ( -- ) - `{ - { +arguments+ { "make" ,[ target ] } } - { +stdout+ "../compile-log" } - { +stderr+ +stdout+ } - } - >hashtable ; +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: target ( -- target ) { os [ cpu "." split ] } to-strings "-" join ; + +: make-vm ( -- desc ) + <process*> + { "make" target } to-strings >>arguments + "../compile-log" >>stdout + +stdout+ >>stderr + >desc ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: factor-binary ( -- name ) + os + { { "macosx" [ "./Factor.app/Contents/MacOS/factor" ] } + { "winnt" [ "./factor-nt.exe" ] } + [ drop "./factor" ] } + case ; + +: bootstrap-cmd ( -- cmd ) + { factor-binary [ "-i=" my-boot-image-name append ] "-no-user-init" } + to-strings ; : bootstrap ( -- desc ) - `{ - { +arguments+ { - ,[ factor-binary ] - ,[ "-i=" my-boot-image-name append ] - "-no-user-init" - } } - { +stdout+ "../boot-log" } - { +stderr+ +stdout+ } - } - >hashtable ; + <process*> + bootstrap-cmd >>arguments + +closed+ >>stdin + "../boot-log" >>stdout + +stdout+ >>stderr + 20 minutes>ms >>timeout + >desc ; -: builder-test ( -- desc ) `{ ,[ factor-binary ] "-run=builder.test" } ; +: builder-test ( -- desc ) { factor-binary "-run=builder.test" } to-strings ; +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + SYMBOL: build-status -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -: milli-seconds>time ( n -- string ) - 1000 /i 60 /mod >r 60 /mod r> 3array [ pad-00 ] map ":" join ; - -: eval-file ( file -- obj ) <file-reader> contents eval ; - -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -: cat ( file -- ) <file-reader> contents print ; - -: run-or-bail ( desc quot -- ) - [ [ try-process ] curry ] - [ [ throw ] curry ] - bi* - recover ; - -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - : (build) ( -- ) + builds-check + + build-status off + enter-build-dir "report" [ "Build machine: " write host-name print - "Build directory: " write cwd print + "CPU: " write cpu print + "OS: " write os print + "Build directory: " write cwd print nl git-clone [ "git clone failed" print ] run-or-bail @@ -142,7 +116,7 @@ SYMBOL: build-status make-vm [ "vm compile error" print "../compile-log" cat ] run-or-bail - [ my-arch download-image ] [ "Image download error" print throw ] recover + [ retrieve-image ] [ "Image download error" print throw ] recover bootstrap [ "Bootstrap error" print "../boot-log" cat ] run-or-bail @@ -152,20 +126,50 @@ SYMBOL: build-status "Boot time: " write "../boot-time" eval-file milli-seconds>time print "Load time: " write "../load-time" eval-file milli-seconds>time print - "Test time: " write "../test-time" eval-file milli-seconds>time print + "Test time: " write "../test-time" eval-file milli-seconds>time print nl "Did not pass load-everything: " print "../load-everything-vocabs" cat "Did not pass test-all: " print "../test-all-vocabs" cat - ] with-file-out ; + "Benchmarks: " print + "../benchmarks" [ stdio get contents eval ] with-file-in benchmarks. -: build ( -- ) - [ (build) ] [ drop ] recover - "report" "../report" email-file ; + ] with-file-out + + build-status on ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: minutes>ms ( min -- ms ) 60 * 1000 * ; +SYMBOL: builder-from + +SYMBOL: builder-recipients + +: tag-subject ( str -- str ) { "builder@" host-name* ": " , } bake to-string ; + +: subject ( -- str ) build-status get [ "report" ] [ "error" ] if tag-subject ; + +: send-builder-email ( -- ) + <email> + builder-from get >>from + builder-recipients get >>to + subject >>subject + "../report" file>string >>body + send ; + +: build ( -- ) + [ (build) ] [ drop ] recover + [ send-builder-email ] [ drop "not sending mail" . ] recover ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: git-pull ( -- desc ) + { + "git" + "pull" + "--no-summary" + "git://factorcode.org/git/factor.git" + "master" + } ; : updates-available? ( -- ? ) git-id @@ -174,8 +178,9 @@ SYMBOL: build-status = not ; : build-loop ( -- ) + builds-check [ - "/builds/factor" cd + builds "/factor" append cd updates-available? [ build ] when diff --git a/extra/builder/server/server.factor b/extra/builder/server/server.factor index 672de1e47d..f3ec349557 100644 --- a/extra/builder/server/server.factor +++ b/extra/builder/server/server.factor @@ -41,28 +41,28 @@ IN: builder.server ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: build-server ( -- ) - receive - { - { - "start" - [ - build-status get "idle" = - build-status get f = - or - [ - [ [ build ] [ drop ] recover "idle" build-status set-global ] - in-thread - ] - when - ] - } +! : build-server ( -- ) +! receive +! { +! { +! "start" +! [ +! build-status get "idle" = +! build-status get f = +! or +! [ +! [ [ build ] [ drop ] recover "idle" build-status set-global ] +! in-thread +! ] +! when +! ] +! } - { - { ?from ?tag "status" } - [ `{ ?tag ,[ build-status get ] } ?from send ] - } - } - match-cond - build-server ; +! { +! { ?from ?tag "status" } +! [ `{ ?tag ,[ build-status get ] } ?from send ] +! } +! } +! match-cond +! build-server ; diff --git a/extra/builder/test/test.factor b/extra/builder/test/test.factor index f521af1b7c..7412dd9b36 100644 --- a/extra/builder/test/test.factor +++ b/extra/builder/test/test.factor @@ -6,7 +6,7 @@ USING: kernel namespaces sequences assocs builder continuations prettyprint tools.browser tools.test - bootstrap.stage2 ; + bootstrap.stage2 benchmark builder.util ; IN: builder.test @@ -16,9 +16,12 @@ IN: builder.test : do-tests ( -- ) run-all-tests keys "../test-all-vocabs" [ . ] with-file-out ; +: do-benchmarks ( -- ) run-benchmarks "../benchmarks" [ . ] with-file-out ; + : do-all ( -- ) bootstrap-time get "../boot-time" [ . ] with-file-out [ do-load ] runtime "../load-time" [ . ] with-file-out - [ do-tests ] runtime "../test-time" [ . ] with-file-out ; + [ do-tests ] runtime "../test-time" [ . ] with-file-out + do-benchmarks ; MAIN: do-all \ No newline at end of file diff --git a/extra/builder/util/util.factor b/extra/builder/util/util.factor new file mode 100644 index 0000000000..f9f432a8f6 --- /dev/null +++ b/extra/builder/util/util.factor @@ -0,0 +1,86 @@ + +USING: kernel words namespaces classes parser continuations + io io.files io.launcher io.sockets + math math.parser + combinators sequences splitting quotations arrays strings tools.time + parser-combinators accessors assocs.lib + combinators.cleave bake calendar new-slots ; + +IN: builder.util + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: runtime ( quot -- time ) benchmark nip ; + +: minutes>ms ( min -- ms ) 60 * 1000 * ; + +: file>string ( file -- string ) [ stdio get contents ] with-file-in ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +DEFER: to-strings + +: to-string ( obj -- str ) + dup class + { + { string [ ] } + { quotation [ call ] } + { word [ execute ] } + { fixnum [ number>string ] } + { array [ to-strings concat ] } + } + case ; + +: to-strings ( seq -- str ) + dup [ string? ] all? + [ ] + [ [ to-string ] map flatten ] + if ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +TUPLE: process* arguments stdin stdout stderr timeout ; + +: <process*> process* construct-empty ; + +: >desc ( process* -- desc ) + H{ } clone + over arguments>> [ +arguments+ swap put-at ] when* + over stdin>> [ +stdin+ swap put-at ] when* + over stdout>> [ +stdout+ swap put-at ] when* + over stderr>> [ +stderr+ swap put-at ] when* + over timeout>> [ +timeout+ swap put-at ] when* + nip ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: host-name* ( -- name ) host-name "." split first ; + +: datestamp ( -- string ) + now `{ ,[ dup timestamp-year ] + ,[ dup timestamp-month ] + ,[ dup timestamp-day ] + ,[ dup timestamp-hour ] + ,[ timestamp-minute ] } + [ pad-00 ] map "-" join ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +: milli-seconds>time ( n -- string ) + 1000 /i 60 /mod >r 60 /mod r> 3array [ pad-00 ] map ":" join ; + +: eval-file ( file -- obj ) file-contents eval ; + +: cat ( file -- ) file-contents print ; + +: run-or-bail ( desc quot -- ) + [ [ try-process ] curry ] + [ [ throw ] compose ] + bi* + recover ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +USING: bootstrap.image bootstrap.image.download io.streams.null ; + +: retrieve-image ( -- ) [ my-arch download-image ] with-null-stream ; \ No newline at end of file diff --git a/extra/const/const.factor b/extra/const/const.factor deleted file mode 100644 index 8efef7e372..0000000000 --- a/extra/const/const.factor +++ /dev/null @@ -1,24 +0,0 @@ -USING: kernel parser words sequences ; -IN: const - -: define-const ( word value -- ) - [ parsed ] curry dupd define - t "parsing" set-word-prop ; - -: CONST: - CREATE scan-word dup parsing? - [ execute dup pop ] when define-const ; parsing - -: define-enum ( words -- ) - dup length [ define-const ] 2each ; - -: ENUM: - ";" parse-tokens [ create-in ] map define-enum ; parsing - -: define-value ( word -- ) - { f } clone [ first ] curry define ; - -: VALUE: CREATE define-value ; parsing - -: set-value ( value word -- ) - word-def first set-first ; diff --git a/extra/db/db.factor b/extra/db/db.factor index 7bdb75af22..d88bbaee03 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -1,32 +1,29 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs classes continuations kernel math -namespaces sequences sequences.lib tuples words ; +namespaces sequences sequences.lib tuples words strings ; IN: db -TUPLE: db handle insert-statements update-statements delete-statements select-statements ; +TUPLE: db handle insert-statements update-statements delete-statements ; : <db> ( handle -- obj ) - H{ } clone - H{ } clone - H{ } clone - H{ } clone + H{ } clone H{ } clone H{ } clone db construct-boa ; GENERIC: db-open ( db -- ) HOOK: db-close db ( handle -- ) -: dispose-statements [ dispose drop ] assoc-each ; +: dispose-statements ( seq -- ) + [ dispose drop ] assoc-each ; : dispose-db ( db -- ) dup db [ dup db-insert-statements dispose-statements dup db-update-statements dispose-statements dup db-delete-statements dispose-statements - dup db-select-statements dispose-statements db-handle db-close ] with-variable ; -TUPLE: statement sql params handle bound? ; +TUPLE: statement sql params handle bound? slot-names ; TUPLE: simple-statement ; TUPLE: prepared-statement ; @@ -35,7 +32,17 @@ HOOK: <prepared-statement> db ( str -- statement ) GENERIC: prepare-statement ( statement -- ) GENERIC: bind-statement* ( obj statement -- ) GENERIC: reset-statement ( statement -- ) -GENERIC: execute-statement ( statement -- ) +GENERIC: insert-statement ( statement -- id ) + +TUPLE: result-set sql params handle n max ; +GENERIC: query-results ( query -- result-set ) +GENERIC: #rows ( result-set -- n ) +GENERIC: #columns ( result-set -- n ) +GENERIC# row-column 1 ( result-set n -- obj ) +GENERIC: advance-row ( result-set -- ) +GENERIC: more-rows? ( result-set -- ? ) + +: execute-statement ( statement -- ) query-results dispose ; : bind-statement ( obj statement -- ) dup statement-bound? [ dup reset-statement ] when @@ -43,19 +50,9 @@ GENERIC: execute-statement ( statement -- ) [ set-statement-params ] keep t swap set-statement-bound? ; -TUPLE: result-set sql params handle n max ; - -GENERIC: query-results ( query -- result-set ) -GENERIC: #rows ( result-set -- n ) -GENERIC: #columns ( result-set -- n ) -GENERIC# row-column 1 ( result-set n -- obj ) -GENERIC: advance-row ( result-set -- ? ) - -HOOK: last-id db ( -- id ) - : init-result-set ( result-set -- ) dup #rows over set-result-set-max - -1 swap set-result-set-n ; + 0 swap set-result-set-n ; : <result-set> ( query handle tuple -- result-set ) >r >r { statement-sql statement-params } get-slots r> @@ -69,10 +66,10 @@ HOOK: last-id db ( -- id ) dup #columns [ row-column ] with map ; : query-each ( statement quot -- ) - over advance-row [ - 2drop + over more-rows? [ + [ call ] 2keep over advance-row query-each ] [ - [ call ] 2keep query-each + 2drop ] if ; inline : query-map ( statement quot -- seq ) @@ -93,11 +90,6 @@ HOOK: last-id db ( -- id ) : do-bound-command ( obj query -- ) [ bind-statement ] keep execute-statement ; -: sql-query ( sql -- rows ) - <simple-statement> [ do-query ] with-disposal ; - -: sql-command ( sql -- ) - <simple-statement> [ execute-statement ] with-disposal ; SYMBOL: in-transaction HOOK: begin-transaction db ( -- ) @@ -111,3 +103,15 @@ HOOK: rollback-transaction db ( -- ) begin-transaction [ ] [ rollback-transaction ] cleanup commit-transaction ] with-variable ; + +: sql-query ( sql -- rows ) + <simple-statement> [ do-query ] with-disposal ; + +: sql-command ( sql -- ) + dup string? [ + <simple-statement> [ execute-statement ] with-disposal + ] [ + ! [ + [ sql-command ] each + ! ] with-transaction + ] if ; diff --git a/extra/db/postgresql/ffi/ffi.factor b/extra/db/postgresql/ffi/ffi.factor index 1ec6fc46f8..d14ec13ff8 100755 --- a/extra/db/postgresql/ffi/ffi.factor +++ b/extra/db/postgresql/ffi/ffi.factor @@ -50,6 +50,8 @@ IN: db.postgresql.ffi : PQERRORS_DEFAULT HEX: 1 ; inline : PQERRORS_VERBOSE HEX: 2 ; inline +: InvalidOid 0 ; inline + TYPEDEF: int size_t TYPEDEF: int ConnStatusType TYPEDEF: int ExecStatusType diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index a940a42ae4..c48eff964a 100644 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: arrays continuations db io kernel math namespaces -quotations sequences db.postgresql.ffi alien alien.c-types ; +quotations sequences db.postgresql.ffi alien alien.c-types +db.types ; IN: db.postgresql.lib : postgresql-result-error-message ( res -- str/f ) @@ -37,7 +38,8 @@ IN: db.postgresql.lib >r db get db-handle r> [ statement-sql ] keep [ statement-params length f ] keep - statement-params [ malloc-char-string ] map >c-void*-array + statement-params + [ first number>string* malloc-char-string ] map >c-void*-array f f 0 PQexecParams dup postgresql-result-ok? [ dup postgresql-result-error-message swap PQclear throw diff --git a/extra/db/postgresql/postgresql-tests.factor b/extra/db/postgresql/postgresql-tests.factor index 8c6791c767..36b6fc829b 100644 --- a/extra/db/postgresql/postgresql-tests.factor +++ b/extra/db/postgresql/postgresql-tests.factor @@ -2,7 +2,7 @@ ! Set username and password in the 'connect' word. USING: kernel db.postgresql alien continuations io prettyprint -sequences namespaces tools.test db ; +sequences namespaces tools.test db db.types ; IN: temporary IN: scratchpad @@ -40,13 +40,13 @@ IN: temporary test-db [ "select * from person where name = $1 and country = $2" <simple-statement> [ - { "Jane" "New Zealand" } + { { "Jane" TEXT } { "New Zealand" TEXT } } over do-bound-query { { "Jane" "New Zealand" } } = [ "test fails" throw ] unless - { "John" "America" } + { { "John" TEXT } { "America" TEXT } } swap do-bound-query ] with-disposal ] with-db diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 92e3fa5489..03746bcaa0 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -1,8 +1,10 @@ ! Copyright (C) 2007, 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs alien alien.syntax continuations io -kernel math namespaces prettyprint quotations -sequences debugger db db.postgresql.lib db.postgresql.ffi ; +kernel math math.parser namespaces prettyprint quotations +sequences debugger db db.postgresql.lib db.postgresql.ffi +db.tuples db.types tools.annotations math.ranges +combinators ; IN: db.postgresql TUPLE: postgresql-db host port pgopts pgtty db user pass ; @@ -51,11 +53,19 @@ M: postgresql-result-set #columns ( result-set -- n ) M: postgresql-result-set row-column ( result-set n -- obj ) >r dup result-set-handle swap result-set-n r> PQgetvalue ; -M: postgresql-statement execute-statement ( statement -- ) - query-results dispose ; +M: postgresql-result-set row-column-typed ( result-set n type -- obj ) + >r row-column r> sql-type>factor-type ; -: increment-n ( result-set -- n ) - dup result-set-n 1+ dup rot set-result-set-n ; +M: postgresql-result-set sql-type>factor-type ( obj type -- newobj ) + { + { INTEGER [ string>number ] } + { BIG_INTEGER [ string>number ] } + { DOUBLE [ string>number ] } + [ drop ] + } case ; + +M: postgresql-statement insert-statement ( statement -- id ) + query-results [ 0 row-column ] with-disposal string>number ; M: postgresql-statement query-results ( query -- result-set ) dup statement-params [ @@ -67,8 +77,11 @@ M: postgresql-statement query-results ( query -- result-set ) postgresql-result-set <result-set> dup init-result-set ; -M: postgresql-result-set advance-row ( result-set -- ? ) - dup increment-n swap result-set-max >= ; +M: postgresql-result-set advance-row ( result-set -- ) + dup result-set-n 1+ swap set-result-set-n ; + +M: postgresql-result-set more-rows? ( result-set -- ? ) + dup result-set-n swap result-set-max < ; M: postgresql-statement dispose ( query -- ) dup statement-handle PQclear @@ -103,3 +116,154 @@ M: postgresql-db commit-transaction ( -- ) M: postgresql-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; + +: postgresql-type-hash* ( -- assoc ) + H{ + { SERIAL "serial" } + } ; + +: postgresql-type-hash ( -- assoc ) + H{ + { INTEGER "integer" } + { SERIAL "integer" } + { TEXT "text" } + { VARCHAR "varchar" } + { DOUBLE "real" } + } ; + +: enquote ( str -- newstr ) "(" swap ")" 3append ; + +: postgresql-type ( str n/str -- newstr ) + " " swap number>string* enquote 3append ; + +: >sql-type* ( obj -- str ) + dup pair? [ + first2 >r >sql-type* r> postgresql-type + ] [ + dup postgresql-type-hash* at* [ + nip + ] [ + drop >sql-type + ] if + ] if ; + +M: postgresql-db >sql-type ( hash obj -- str ) + dup pair? [ + first2 >r >sql-type r> postgresql-type + ] [ + postgresql-type-hash at* [ + no-sql-type + ] unless + ] if ; + +: insert-function ( columns table -- sql ) + [ + >r remove-id r> + "create function add_" % dup % + "(" % + over [ "," % ] + [ third dup array? [ first ] when >sql-type % ] interleave + ")" % + " returns bigint as '" % + + 2dup "insert into " % + % + "(" % + dup [ ", " % ] [ second % ] interleave + ") " % + " values (" % + length [1,b] [ ", " % ] [ "$" % # ] interleave + "); " % + + "select currval(''" % % "_id_seq'');' language sql;" % + drop + ] "" make ; + +: drop-function ( columns table -- sql ) + [ + >r remove-id r> + "drop function add_" % % + "(" % + [ "," % ] [ third >sql-type % ] interleave + ")" % + ] "" make ; + +M: postgresql-db create-sql ( columns table -- seq ) + [ + [ + 2dup + "create table " % % + " (" % [ ", " % ] [ + dup second % " " % + dup third >sql-type* % " " % + sql-modifiers " " join % + ] interleave "); " % + ] "" make , + + over native-id? [ insert-function , ] [ 2drop ] if + ] { } make ; + +M: postgresql-db drop-sql ( columns table -- seq ) + [ + [ + dup "drop table " % % ";" % + ] "" make , + over native-id? [ drop-function , ] [ 2drop ] if + ] { } make ; + +M: postgresql-db insert-sql* ( columns table -- slot-names sql ) + [ + "select add_" % % + "(" % + length [1,b] [ ", " % ] [ "$" % # ] interleave + ")" % + ] "" make ; + +M: postgresql-db update-sql* ( columns table -- slot-names sql ) + [ + "update " % + % + " set " % + dup remove-id + dup length [1,b] swap 2array flip + [ ", " % ] [ first2 second % " = $" % # ] interleave + " where " % + [ primary-key? ] find nip second dup % " = $" % length 2 + # + ] "" make ; + +M: postgresql-db delete-sql* ( columns table -- slot-names sql ) + [ + "delete from " % + % + " where " % + first second % " = $1" % + ] "" make ; + +M: postgresql-db select-sql ( columns table -- slot-names sql ) + drop ; + +M: postgresql-db tuple>params ( columns tuple -- obj ) + [ >r dup third swap first r> get-slot-named swap ] + curry { } map>assoc ; + +: postgresql-db-modifiers ( -- hashtable ) + H{ + { +native-id+ "not null primary key" } + { +assigned-id+ "primary key" } + { +autoincrement+ "autoincrement" } + { +unique+ "unique" } + { +default+ "default" } + { +null+ "null" } + { +not-null+ "not null" } + } ; + +M: postgresql-db sql-modifiers* ( modifiers -- str ) + postgresql-db-modifiers swap [ + dup array? [ + first2 + >r swap at r> number>string* + " " swap 3append + ] [ + swap at + ] if + ] with map [ ] subset ; diff --git a/extra/db/sqlite/ffi/ffi.factor b/extra/db/sqlite/ffi/ffi.factor index 9ffe797248..8c957108e1 100755 --- a/extra/db/sqlite/ffi/ffi.factor +++ b/extra/db/sqlite/ffi/ffi.factor @@ -108,7 +108,7 @@ LIBRARY: sqlite FUNCTION: int sqlite3_open ( char* filename, void* ppDb ) ; FUNCTION: int sqlite3_close ( sqlite3* pDb ) ; FUNCTION: char* sqlite3_errmsg ( sqlite3* pDb ) ; -FUNCTION: int sqlite3_prepare_v2 ( sqlite3* pDb, char* zSql, int nBytes, void* ppStmt, void* pzTail ) ; +FUNCTION: int sqlite3_prepare ( sqlite3* pDb, char* zSql, int nBytes, void* ppStmt, void* pzTail ) ; FUNCTION: int sqlite3_finalize ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_reset ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_step ( sqlite3_stmt* pStmt ) ; @@ -125,6 +125,8 @@ FUNCTION: void* sqlite3_column_blob ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_bytes ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_decltype ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_int ( sqlite3_stmt* pStmt, int col ) ; +FUNCTION: sqlite3_int64 sqlite3_column_int64 ( sqlite3_stmt* pStmt, int col ) ; +FUNCTION: double sqlite3_column_double ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_name ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_text ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_type ( sqlite3_stmt* pStmt, int col ) ; diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor index 1780cc4a2d..85aa671d4d 100755 --- a/extra/db/sqlite/lib/lib.factor +++ b/extra/db/sqlite/lib/lib.factor @@ -30,7 +30,7 @@ IN: db.sqlite.lib : sqlite-prepare ( db sql -- handle ) dup length "void*" <c-object> "void*" <c-object> - [ sqlite3_prepare_v2 sqlite-check-result ] 2keep + [ sqlite3_prepare sqlite-check-result ] 2keep drop *void* ; : sqlite-bind-parameter-index ( handle name -- index ) @@ -74,10 +74,11 @@ IN: db.sqlite.lib dup array? [ first ] when { { INTEGER [ sqlite-bind-int-by-name ] } - { BIG_INTEGER [ sqlite-bind-int-by-name ] } + { BIG_INTEGER [ sqlite-bind-int64-by-name ] } { TEXT [ sqlite-bind-text-by-name ] } { VARCHAR [ sqlite-bind-text-by-name ] } { DOUBLE [ sqlite-bind-double-by-name ] } + { SERIAL [ sqlite-bind-int-by-name ] } ! { NULL [ sqlite-bind-null-by-name ] } [ no-sql-type ] } case ; @@ -95,17 +96,25 @@ IN: db.sqlite.lib : sqlite-column ( handle index -- string ) sqlite3_column_text ; +: sqlite-column-typed ( handle index type -- obj ) + { + { INTEGER [ sqlite3_column_int ] } + { BIG_INTEGER [ sqlite3_column_int64 ] } + { TEXT [ sqlite3_column_text ] } + { DOUBLE [ sqlite3_column_double ] } + } case ; + ! TODO : sqlite-row ( handle -- seq ) dup sqlite-#columns [ sqlite-column ] with map ; -: step-complete? ( step-result -- bool ) +: sqlite-step-has-more-rows? ( step-result -- bool ) dup SQLITE_ROW = [ - drop f + drop t ] [ dup SQLITE_DONE = - [ drop ] [ sqlite-check-result ] if t + [ drop ] [ sqlite-check-result ] if f ] if ; : sqlite-next ( prepared -- ? ) - sqlite3_step step-complete? ; + sqlite3_step sqlite-step-has-more-rows? ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index ad3a43bae3..4eabfc2ecd 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -25,9 +25,7 @@ M: sqlite-db dispose ( db -- ) dispose-db ; TUPLE: sqlite-statement ; C: <sqlite-statement> sqlite-statement -TUPLE: sqlite-result-set ; -: <sqlite-result-set> ( query -- sqlite-result-set ) - dup statement-handle sqlite-result-set <result-set> ; +TUPLE: sqlite-result-set has-more? ; M: sqlite-db <simple-statement> ( str -- obj ) <prepared-statement> ; @@ -52,8 +50,12 @@ M: sqlite-statement bind-statement* ( triples statement -- ) M: sqlite-statement reset-statement ( statement -- ) statement-handle sqlite-reset ; -M: sqlite-statement execute-statement ( statement -- ) - statement-handle sqlite-next drop ; +: last-insert-id ( -- id ) + db get db-handle sqlite3_last_insert_rowid + dup zero? [ "last-id failed" throw ] when ; + +M: sqlite-statement insert-statement ( statement -- id ) + execute-statement last-insert-id ; M: sqlite-result-set #columns ( result-set -- n ) result-set-handle sqlite-#columns ; @@ -61,11 +63,19 @@ M: sqlite-result-set #columns ( result-set -- n ) M: sqlite-result-set row-column ( result-set n -- obj ) >r result-set-handle r> sqlite-column ; -M: sqlite-result-set advance-row ( result-set -- handle ? ) - result-set-handle sqlite-next ; +M: sqlite-result-set row-column-typed ( result-set n type -- obj ) + >r result-set-handle r> sqlite-column-typed ; + +M: sqlite-result-set advance-row ( result-set -- ) + [ result-set-handle sqlite-next ] keep + set-sqlite-result-set-has-more? ; + +M: sqlite-result-set more-rows? ( result-set -- ? ) + sqlite-result-set-has-more? ; M: sqlite-statement query-results ( query -- result-set ) - dup statement-handle sqlite-result-set <result-set> ; + dup statement-handle sqlite-result-set <result-set> + dup advance-row ; M: sqlite-db begin-transaction ( -- ) "BEGIN" sql-command ; @@ -86,9 +96,10 @@ M: sqlite-db create-sql ( columns table -- sql ) ] interleave ")" % ] "" make ; -M: sqlite-db drop-sql ( table -- sql ) +M: sqlite-db drop-sql ( columns table -- sql ) [ "drop table " % % + drop ] "" make ; M: sqlite-db insert-sql* ( columns table -- sql ) @@ -103,6 +114,10 @@ M: sqlite-db insert-sql* ( columns table -- sql ) ")" % ] "" make ; +: where-primary-key% ( columns -- ) + " where " % + [ primary-key? ] find nip second dup % " = :" % % ; + M: sqlite-db update-sql* ( columns table -- sql ) [ "update " % @@ -110,8 +125,7 @@ M: sqlite-db update-sql* ( columns table -- sql ) " set " % dup remove-id [ ", " % ] [ second dup % " = :" % % ] interleave - " where " % - [ primary-key? ] find nip second dup % " = :" % % + where-primary-key% ] "" make ; M: sqlite-db delete-sql* ( columns table -- sql ) @@ -122,13 +136,18 @@ M: sqlite-db delete-sql* ( columns table -- sql ) first second dup % " = :" % % ] "" make ; -M: sqlite-db select-sql* ( columns table -- sql ) +: select-interval ( interval name -- ) + ; + +: select-sequence ( seq name -- ) + ; + +M: sqlite-db select-sql ( columns table -- sql ) [ "select ROWID, " % - swap [ ", " % ] [ second % ] interleave - " from " % - % - " where ROWID = :ID" % + over [ ", " % ] [ second % ] interleave + " from " % % + " where " % ] "" make ; M: sqlite-db tuple>params ( columns tuple -- obj ) @@ -137,10 +156,6 @@ M: sqlite-db tuple>params ( columns tuple -- obj ) dupd >r first r> get-slot-named swap third 3array ] curry map ; - -M: sqlite-db last-id ( -- id ) - db get db-handle sqlite3_last_insert_rowid ; - : sqlite-db-modifiers ( -- hashtable ) H{ @@ -167,6 +182,7 @@ M: sqlite-db sql-modifiers* ( modifiers -- str ) : sqlite-type-hash ( -- assoc ) H{ { INTEGER "integer" } + { SERIAL "integer" } { TEXT "text" } { VARCHAR "text" } { DOUBLE "real" } @@ -182,4 +198,3 @@ M: sqlite-db >sql-type ( obj -- str ) ! HOOK: get-column-value ( n result-set type -- ) ! M: sqlite get-column-value { { "TEXT" get-text-column } { ! "INTEGER" get-integer-column } ... } case ; - diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 474593ae3f..ea57193750 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -1,11 +1,12 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: io.files kernel tools.test db db.sqlite db.tuples -db.types continuations namespaces ; +db.types continuations namespaces db.postgresql math ; +! tools.time ; IN: temporary TUPLE: person the-id the-name the-number real ; -: <person> ( name age -- person ) +: <person> ( name age real -- person ) { set-person-the-name set-person-the-number @@ -29,21 +30,22 @@ SYMBOL: the-person [ ] [ the-person get update-tuple ] unit-test - [ ] [ the-person get delete-tuple ] unit-test ; + [ ] [ the-person get delete-tuple ] unit-test + ; ! 1 [ ] [ person drop-table ] unit-test ; : test-sqlite ( -- ) "tuples-test.db" resource-path <sqlite-db> [ test-tuples ] with-db ; -! : test-postgres ( -- ) - ! resource-path <postgresql-db> [ - ! test-tuples - ! ] with-db ; +: test-postgresql ( -- ) + "localhost" "postgres" "" "factor-test" <postgresql-db> [ + test-tuples + ] with-db ; person "PERSON" { - { "the-id" "ROWID" INTEGER +native-id+ } + { "the-id" "ID" SERIAL +native-id+ } { "the-name" "NAME" { VARCHAR 256 } +not-null+ } { "the-number" "AGE" INTEGER { +default+ 0 } } { "real" "REAL" DOUBLE { +default+ 0.3 } } @@ -51,18 +53,18 @@ person "PERSON" "billy" 10 3.14 <person> the-person set -test-sqlite -! test-postgres +! test-sqlite + test-postgresql -person "PERSON" -{ - { "the-id" "ROWID" INTEGER +assigned-id+ } - { "the-name" "NAME" { VARCHAR 256 } +not-null+ } - { "the-number" "AGE" INTEGER { +default+ 0 } } - { "real" "REAL" DOUBLE { +default+ 0.3 } } -} define-persistent +! person "PERSON" +! { + ! { "the-id" "ID" INTEGER +assigned-id+ } + ! { "the-name" "NAME" { VARCHAR 256 } +not-null+ } + ! { "the-number" "AGE" INTEGER { +default+ 0 } } + ! { "real" "REAL" DOUBLE { +default+ 0.3 } } +! } define-persistent -1 "billy" 20 6.28 <assigned-person> the-person set +! 1 "billy" 20 6.28 <assigned-person> the-person set -test-sqlite -! test-postgres +! test-sqlite +! test-postgresql diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index 099326e4c1..be18f71e1b 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -38,12 +38,28 @@ TUPLE: no-slot-named ; [ db-table dupd ] swap [ <prepared-statement> ] 3compose cache nip ; inline -HOOK: create-sql db ( columns table -- sql ) -HOOK: drop-sql db ( table -- sql ) -HOOK: insert-sql* db ( columns table -- sql ) -HOOK: update-sql* db ( columns table -- sql ) -HOOK: delete-sql* db ( columns table -- sql ) -HOOK: select-sql* db ( columns table -- sql ) +HOOK: create-sql db ( columns table -- seq ) +HOOK: drop-sql db ( columns table -- seq ) + +HOOK: insert-sql* db ( columns table -- slot-names sql ) +HOOK: update-sql* db ( columns table -- slot-names sql ) +HOOK: delete-sql* db ( columns table -- slot-names sql ) +HOOK: select-sql db ( tuple -- statement ) + +HOOK: row-column-typed db ( result-set n type -- sql ) +HOOK: sql-type>factor-type db ( obj type -- obj ) +HOOK: tuple>params db ( columns tuple -- obj ) + + +HOOK: make-slot-names* db ( quot -- seq ) +HOOK: column-slot-name% db ( spec -- ) +HOOK: column-bind-name% db ( spec -- ) + +: make-slots-names ( quot -- seq str ) + [ make-column-names ] "" make ; inline +: slot-name% ( seq -- ) first % ; +: column-name% ( seq -- ) second % ; +: column-type% ( seq -- ) third % ; : insert-sql ( columns class -- statement ) db get db-insert-statements [ insert-sql* ] cache-statement ; @@ -54,30 +70,29 @@ HOOK: select-sql* db ( columns table -- sql ) : delete-sql ( columns class -- statement ) db get db-delete-statements [ delete-sql* ] cache-statement ; -: select-sql ( columns class -- statement ) - db get db-select-statements [ select-sql* ] cache-statement ; - -HOOK: tuple>params db ( columns tuple -- obj ) : tuple-statement ( columns tuple quot -- statement ) >r [ tuple>params ] 2keep class r> call 2dup . . [ bind-statement ] keep ; -: do-tuple-statement ( tuple columns-quot statement-quot -- ) +: make-tuple-statement ( tuple columns-quot statement-quot -- statement ) >r [ class db-columns ] swap compose keep - r> tuple-statement execute-statement ; + r> tuple-statement ; + +: do-tuple-statement ( tuple columns-quot statement-quot -- ) + make-tuple-statement execute-statement ; : create-table ( class -- ) dup db-columns swap db-table create-sql sql-command ; : drop-table ( class -- ) - db-table drop-sql sql-command ; + dup db-columns swap db-table drop-sql sql-command ; : insert-tuple ( tuple -- ) [ - [ maybe-remove-id ] [ insert-sql ] do-tuple-statement - last-id + [ maybe-remove-id ] [ insert-sql ] + make-tuple-statement insert-statement ] keep set-primary-key ; : update-tuple ( tuple -- ) @@ -86,8 +101,8 @@ HOOK: tuple>params db ( columns tuple -- obj ) : delete-tuple ( tuple -- ) [ [ primary-key? ] subset ] [ delete-sql ] do-tuple-statement ; -! : select-tuple ( tuple -- ) - ! [ select-sql ] bind-tuple do-query ; +: select-tuple ( tuple -- ) + [ select-sql ] keep do-query ; : persist ( tuple -- ) dup primary-key [ update-tuple ] [ insert-tuple ] if ; diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index b8c82524a8..7cacbcf861 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -11,6 +11,12 @@ SYMBOL: +assigned-id+ : primary-key? ( spec -- ? ) [ { +native-id+ +assigned-id+ } member? ] contains? ; +: contains-id? ( columns id -- ? ) + swap [ member? ] with contains? ; + +: assigned-id? ( columns -- ? ) +assigned-id+ contains-id? ; +: native-id? ( columns -- ? ) +native-id+ contains-id? ; + ! Same concept, SQLite has autoincrement, PostgreSQL has serial SYMBOL: +autoincrement+ SYMBOL: +serial+ @@ -22,6 +28,7 @@ SYMBOL: +not-null+ SYMBOL: +has-many+ +SYMBOL: SERIAL SYMBOL: INTEGER SYMBOL: DOUBLE SYMBOL: BOOLEAN diff --git a/extra/delegate/protocols/protocols.factor b/extra/delegate/protocols/protocols.factor index 37f3812d2d..f9b4c8648d 100755 --- a/extra/delegate/protocols/protocols.factor +++ b/extra/delegate/protocols/protocols.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007 Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. USING: delegate sequences.private sequences assocs prettyprint.sections -io definitions kernel ; +io definitions kernel continuations ; IN: delegate.protocols PROTOCOL: sequence-protocol @@ -15,7 +15,7 @@ PROTOCOL: assoc-protocol ! everything should work, just slower (with >alist) PROTOCOL: stream-protocol - stream-read1 stream-read stream-read-until + stream-read1 stream-read stream-read-until dispose stream-flush stream-write1 stream-write stream-format stream-nl make-span-stream make-block-stream stream-readln make-cell-stream stream-write-table ; diff --git a/extra/help/handbook/handbook.factor b/extra/help/handbook/handbook.factor index 9472e1f519..90e780c1ad 100755 --- a/extra/help/handbook/handbook.factor +++ b/extra/help/handbook/handbook.factor @@ -1,8 +1,8 @@ -USING: help help.markup help.syntax help.topics -namespaces words sequences classes assocs vocabs kernel -arrays prettyprint.backend kernel.private io tools.browser -generic math tools.profiler system ui strings sbufs vectors -byte-arrays bit-arrays float-arrays quotations help.lint ; +USING: help help.markup help.syntax help.definitions help.topics +namespaces words sequences classes assocs vocabs kernel arrays +prettyprint.backend kernel.private io generic math system +strings sbufs vectors byte-arrays bit-arrays float-arrays +quotations ; IN: help.handbook ARTICLE: "conventions" "Conventions" @@ -161,15 +161,20 @@ ARTICLE: "io" "Input and output" { $subsection "io.timeouts" } ; ARTICLE: "tools" "Developer tools" -{ $subsection "tools.annotations" } -{ $subsection "tools.crossref" } +"Exploratory tools:" { $subsection "editor" } +{ $subsection "tools.crossref" } { $subsection "inspector" } +"Debugging tools:" +{ $subsection "tools.annotations" } +{ $subsection "tools.test" } { $subsection "meta-interpreter" } +"Performance tools:" { $subsection "tools.memory" } { $subsection "profiling" } -{ $subsection "tools.test" } { $subsection "timing" } +{ $subsection "tools.disassembler" } +"Deployment tools:" { $subsection "tools.deploy" } ; ARTICLE: "article-index" "Article index" @@ -201,7 +206,6 @@ ARTICLE: "handbook" "Factor documentation" { $subsection "cookbook" } { $subsection "first-program" } { $subsection "vocab-index" } -{ $subsection "changes" } { $heading "Language reference" } { $subsection "conventions" } { $subsection "syntax" } @@ -231,137 +235,6 @@ ARTICLE: "handbook" "Factor documentation" { $subsection "type-index" } { $subsection "class-index" } ; - -USING: io.files io.sockets float-arrays inference ; - -ARTICLE: "changes" "Changes in the latest release" -{ $heading "Factor 0.91" } -{ $subheading "Performance" } -{ $list - { "Continuations are now supported by the static stack effect system. This means that the " { $link infer } " word and the optimizing compiler now both support code which uses continuations." } - { "Many words which previously ran in the interpreter, such as error handling and I/O, are now compiled to optimized machine code." } - { "A non-optimizing, just-in-time compiler replaces the interpreter with no loss in functionality or introspective ability." } - { "The non-optimizing compiler compiles quotations the first time they are called, generating a series of stack pushes and subroutine calls. It offers a 33%-50% performance increase over the interpreter." } - { "The optimizing compiler now performs some more representation inference. Alien pointers are unboxed where possible. This improves performance of the " { $vocab-link "ogg.player" } " Ogg Theora video player." } - { "The queue of sleeping tasks is now a sorted priority queue. This reduces overhead for workloads involving large numbers of sleeping threads (Doug Coleman)" } - { "Improved hash code algorithm for sequences" } - { "New, efficient implementations of " { $link bit? } " and " { $link log2 } " runs in constant time for large bignums" } - { "New " { $link big-random } " word for generating large random numbers quickly" } - { "Improved profiler no longer has to be explicitly enabled and disabled with a full recompile; instead, the " { $link profile } " word can be used at any time, and it dynamically patches words to increment call counts. There is no overhead when the profiler is not in use." } - { "Calls to " { $link member? } " with a literal sequence are now open-coded. If there are four or fewer elements, a series of conditionals are generated; if there are more than four elements, there is a hash dispatch followed by conditionals in each branch." } -} -{ $subheading "IO" } -{ $list - { "More robust Windows CE native I/O" } - { "New " { $link os-envs } " word to get the current set of environment variables" } - { "Redesigned " { $vocab-link "io.launcher" } " supports passing environment variables to the child process" } - { { $link <process-stream> } " implemented on Windows (Doug Coleman)" } - { "Updated " { $vocab-link "io.mmap" } " for new module system, now supports Windows CE (Doug Coleman)" } - { { $vocab-link "io.sniffer" } " - packet sniffer library (Doug Coleman, Elie Chaftari)" } - { { $vocab-link "io.server" } " - improved logging support, logs to a file by default" } - { { $vocab-link "io.files" } " - several new file system manipulation words added" } - { { $vocab-link "tar" } " - tar file extraction in pure Factor (Doug Coleman)" } - { { $vocab-link "unix.linux" } ", " { $vocab-link "raptor" } " - ``Raptor Linux'', a set of alien bindings to low-level Linux features, such as network interface configuration, file system mounting/unmounting, etc, together with experimental boot scripts intended to entirely replace " { $snippet "/sbin/init" } ", " { $snippet "/etc/inittab" } " and " { $snippet "/etc/init.d/" } " (Eduardo Cavazos)." } -} -{ $subheading "Tools" } -{ $list - { "Graphical deploy tool added - see " { $link "ui.tools.deploy" } } - { "The deploy tool now supports Windows" } - { { $vocab-link "network-clipboard" } " - clipboard synchronization with a simple TCP/IP protocol" } -} -{ $subheading "UI" } -{ $list - { { $vocab-link "cairo" } " - updated for new module system, new features (Sampo Vuori)" } - { { $vocab-link "springies" } " - physics simulation UI demo (Eduardo Cavazos)" } - { { $vocab-link "ui.gadgets.buttons" } " - added check box and radio button gadgets" } - { "Double- and triple-click-drag now supported in the editor gadget to select words or lines at a time" } - { "Windows can be closed on request now using " { $link close-window } } - { "New icons (Elie Chaftari)" } -} -{ $subheading "Libraries" } -{ $list - { "The " { $snippet "queues" } " vocabulary has been removed because its functionality is a subset of " { $vocab-link "dlists" } } - { "The " { $vocab-link "webapps.cgi" } " vocabulary implements CGI support for the Factor HTTP server." } - { "The optimizing compiler no longer depends on the number tower and it is possible to bootstrap a minimal image by just passing " { $snippet "-include=compiler" } " to stage 2 bootstrap." } - { { $vocab-link "benchmark.knucleotide" } " - new benchmark (Eric Mertens)" } - { { $vocab-link "channels" } " - concurrent message passing over message channels" } - { { $vocab-link "destructors" } " - deterministic scope-based resource deallocation (Doug Coleman)" } - { { $vocab-link "dlists" } " - various updates (Doug Coleman)" } - { { $vocab-link "editors.emeditor" } " - EmEditor integration (Doug Coleman)" } - { { $vocab-link "editors.editplus" } " - EditPlus integration (Aaron Schaefer)" } - { { $vocab-link "editors.notepadpp" } " - Notepad++ integration (Doug Coleman)" } - { { $vocab-link "editors.ted-notepad" } " - TED Notepad integration (Doug Coleman)" } - { { $vocab-link "editors.ultraedit" } " - UltraEdit integration (Doug Coleman)" } - { { $vocab-link "globs" } " - simple Unix shell-style glob patterns" } - { { $vocab-link "heaps" } " - updated for new module system and cleaned up (Doug Coleman)" } - { { $vocab-link "peg" } " - Parser Expression Grammars, a new appoach to parser construction, similar to parser combinators (Chris Double)" } - { { $vocab-link "regexp" } " - revived from " { $snippet "unmaintained/" } " and completely redesigned (Doug Coleman)" } - { { $vocab-link "rss" } " - add Atom feed generation (Daniel Ehrenberg)" } - { { $vocab-link "tuples.lib" } " - some utility words for working with tuples (Doug Coleman)" } - { { $vocab-link "webapps.pastebin" } " - improved appearance, add Atom feed generation, add syntax highlighting using " { $vocab-link "xmode" } } - { { $vocab-link "webapps.planet" } " - add Atom feed generation" } -} -{ $heading "Factor 0.90" } -{ $subheading "Core" } -{ $list - { "New module system; see " { $link "vocabs.loader" } ". (Eduardo Cavazos)" } - { "Tuple constructors are defined differently now; see " { $link "tuple-constructors" } "." } - { "Mixin classes implemented; these are essentially extensible unions. See " { $link "mixins" } "." } - { "New " { $link float-array } " data type implements a space-efficient sequence of floats." } - { "Moved " { $link <file-appender> } ", " { $link delete-file } ", " { $link make-directory } ", " { $link delete-directory } " words from " { $snippet "libs/io" } " into the core, and fixed them to work on more platforms." } - { "New " { $link host-name } " word." } - { "The " { $link directory } " word now outputs an array of pairs, with the second element of each pair indicating if that entry is a subdirectory. This saves an unnecessary " { $link stat } " call when traversing directory hierarchies, which speeds things up." } - { "IPv6 is now supported, along with Unix domain sockets (the latter on Unix systems only). The stack effects of " { $link <client> } " and " { $link <server> } " have changed, since they now take generic address specifiers; see " { $link "network-streams" } "." } - { "The stage 2 bootstrap process is more flexible, and various subsystems such as help, tools and the UI can be omitted by supplying command line switches; see " { $link "bootstrap-cli-args" } "." } - { "The " { $snippet "-shell" } " command line switch has been replaced by a " { $snippet "-run" } " command line switch; see " { $link "standard-cli-args" } "." } - { "Variable usage inference has been removed; the " { $link infer } " word no longer reports this information." } - -} -{ $subheading "Tools" } -{ $list - { "Stand-alone image deployment; see " { $link "tools.deploy" } "." } - { "Stand-alone application bundle deployment on Mac OS X; see " { $vocab-link "tools.deploy.app" } "." } - { "New vocabulary browser tool in the UI." } - { "New profiler tool in the UI." } -} -{ $subheading "Extras" } -"Most existing libraries were improved when ported to the new module system; the most notable changes include:" -{ $list - { { $vocab-link "asn1" } ": ASN1 parser and writer. (Elie Chaftari)" } - { { $vocab-link "benchmark" } ": new set of benchmarks." } - { { $vocab-link "cfdg" } ": Context-free design grammar implementation; see " { $url "http://www.chriscoyne.com/cfdg/" } ". (Eduardo Cavazos)" } - { { $vocab-link "cryptlib" } ": Cryptlib library binding. (Elie Chaftari)" } - { { $vocab-link "cryptlib.streams" } ": Streams which perform SSL encryption and decryption. (Matthew Willis)" } - { { $vocab-link "hints" } ": Give type specialization hints to the compiler." } - { { $vocab-link "inverse" } ": Invertible computation and concatenative pattern matching. (Daniel Ehrenberg)" } - { { $vocab-link "ldap" } ": OpenLDAP library binding. (Elie Chaftari)" } - { { $vocab-link "locals" } ": Efficient lexically scoped locals, closures, and local words." } - { { $vocab-link "mortar" } ": Experimental message-passing object system. (Eduardo Cavazos)" } - { { $vocab-link "openssl" } ": OpenSSL library binding. (Elie Chaftari)" } - { { $vocab-link "pack" } ": Utility for reading and writing binary data. (Doug Coleman)" } - { { $vocab-link "pdf" } ": Haru PDF library binding. (Elie Chaftari)" } - { { $vocab-link "qualified" } ": Refer to words from another vocabulary without adding the entire vocabulary to the search path. (Daniel Ehrenberg)" } - { { $vocab-link "roman" } ": Reading and writing Roman numerals. (Doug Coleman)" } - { { $vocab-link "scite" } ": SciTE editor integration. (Clemens Hofreither)" } - { { $vocab-link "smtp" } ": SMTP client with support for CRAM-MD5 authentication. (Elie Chaftari, Dirk Vleugels)" } - { { $vocab-link "tuple-arrays" } ": Space-efficient packed tuple arrays. (Daniel Ehrenberg)" } - { { $vocab-link "unicode" } ": major new functionality added. (Daniel Ehrenberg)" } -} -{ $subheading "Performance" } -{ $list - { "The " { $link curry } " word now runs in constant time, and curried quotations can be called from compiled code; this allows for abstractions and idioms which were previously impractical due to performance issues. In particular, words such as " { $snippet "each-with" } " and " { $snippet "map-with" } " are gone; " { $snippet "each-with" } " can now be written as " { $snippet "with each" } ", and similarly for other " { $snippet "-with" } " combinators." } - "Improved generational promotion strategy in garbage collector reduces the amount of junk which makes its way into tenured space, which in turn reduces the frequency of full garbage collections." - "Faster generic word dispatch and union membership testing." - { "Alien memory accessors (" { $link "reading-writing-memory" } ") are compiled as intrinsics where possible, which improves performance in code which iteroperates with C libraries." } -} -{ $subheading "Platforms" } -{ $list - "Networking support added for Windows CE. (Doug Coleman)" - "UDP/IP networking support added for all Windows platforms. (Doug Coleman)" - "Solaris/x86 fixes. (Samuel Tardieu)" - "Linux/AMD64 port works again." -} ; - { <array> <string> <sbuf> <vector> <byte-array> <bit-array> <float-array> } related-words diff --git a/extra/http/http.factor b/extra/http/http.factor index 755f36a538..5c4dae94c7 100755 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2003, 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: hashtables io kernel math namespaces math.parser assocs -sequences strings splitting ascii io.utf8 assocs.lib +sequences strings splitting ascii io.encodings.utf8 assocs.lib namespaces unicode.case ; IN: http diff --git a/extra/icfp/2006/2006.factor b/extra/icfp/2006/2006.factor index 2a35ed08f8..ae0e058490 100755 --- a/extra/icfp/2006/2006.factor +++ b/extra/icfp/2006/2006.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2007 Gavin Harrison ! See http://factorcode.org/license.txt for BSD license. -USING: kernel math sequences kernel.private namespaces arrays io io.files - splitting io.binary math.functions vectors quotations sequences.private ; +USING: kernel math sequences kernel.private namespaces arrays io +io.files splitting io.binary math.functions vectors quotations +combinators ; IN: icfp.2006 SYMBOL: regs @@ -9,10 +10,6 @@ SYMBOL: arrays SYMBOL: finger SYMBOL: open-arrays -: call-nth ( n array -- ) - >r >fixnum r> 2dup nth quotation? - [ dispatch ] [ "Not a quotation" throw ] if ; inline - : reg-val ( m -- n ) regs get nth ; : set-reg ( val n -- ) regs get set-nth ; @@ -117,11 +114,21 @@ SYMBOL: open-arrays : run-op ( -- bool ) advance { - [ op0 ] [ op1 ] [ op2 ] [ op3 ] - [ op4 ] [ op5 ] [ op6 ] [ drop t ] - [ op8 ] [ op9 ] [ op10 ] [ op11 ] - [ op12 ] [ op13 ] - } call-nth ; + { 0 [ op0 ] } + { 1 [ op1 ] } + { 2 [ op2 ] } + { 3 [ op3 ] } + { 4 [ op4 ] } + { 5 [ op5 ] } + { 6 [ op6 ] } + { 7 [ drop t ] } + { 8 [ op8 ] } + { 9 [ op9 ] } + { 10 [ op10 ] } + { 11 [ op11 ] } + { 12 [ op12 ] } + { 13 [ op13 ] } + } case ; : exec-loop ( bool -- ) [ run-op exec-loop ] unless ; diff --git a/extra/io/launcher/launcher-docs.factor b/extra/io/launcher/launcher-docs.factor index 4f5a85244b..3a557e9fd5 100755 --- a/extra/io/launcher/launcher-docs.factor +++ b/extra/io/launcher/launcher-docs.factor @@ -90,6 +90,10 @@ HELP: get-environment { $values { "env" "an association" } } { $description "Combines the current environment with the value of " { $link +environment+ } " using " { $link +environment-mode+ } "." } ; +HELP: current-process-handle +{ $values { "handle" "a process handle" } } +{ $description "Returns the handle of the current process." } ; + HELP: run-process* { $values { "desc" "a launch descriptor" } { "handle" "a process handle" } } { $contract "Launches a process using the launch descriptor." } @@ -186,6 +190,8 @@ ARTICLE: "io.launcher" "Launching OS processes" { $subsection try-process } "Stopping processes:" { $subsection kill-process } +"Finding the current process handle:" +{ $subsection current-process-handle } "Redirecting standard input and output to a pipe:" { $subsection <process-stream> } { $subsection with-process-stream } diff --git a/extra/io/launcher/launcher.factor b/extra/io/launcher/launcher.factor index cbece818c9..dce893dcaf 100755 --- a/extra/io/launcher/launcher.factor +++ b/extra/io/launcher/launcher.factor @@ -76,6 +76,8 @@ SYMBOL: +append-environment+ { [ dup assoc? ] [ >hashtable ] } } cond ; +HOOK: current-process-handle io-backend ( -- handle ) + HOOK: run-process* io-backend ( desc -- handle ) : wait-for-process ( process -- status ) @@ -119,7 +121,9 @@ HOOK: process-stream* io-backend ( desc -- stream process ) TUPLE: process-stream process ; : <process-stream> ( desc -- stream ) - >descriptor process-stream* + >descriptor + [ process-stream* ] keep + +timeout+ swap at [ over set-timeout ] when* { set-delegate set-process-stream-process } process-stream construct ; diff --git a/extra/io/unix/launcher/launcher.factor b/extra/io/unix/launcher/launcher.factor index c0861788b6..5adf0d7453 100755 --- a/extra/io/unix/launcher/launcher.factor +++ b/extra/io/unix/launcher/launcher.factor @@ -4,7 +4,7 @@ USING: io io.backend io.launcher io.unix.backend io.unix.files io.nonblocking sequences kernel namespaces math system alien.c-types debugger continuations arrays assocs combinators unix.process parser-combinators memoize -promises strings threads ; +promises strings threads unix ; IN: io.unix.launcher ! Search unix first @@ -50,15 +50,16 @@ MEMO: 'arguments' ( -- parser ) : redirect ( obj mode fd -- ) { { [ pick not ] [ 2nip F_SETFL 0 fcntl io-error ] } - { [ pick +closed+ eq? ] [ close 2drop ] } { [ pick string? ] [ (redirect) ] } } cond ; +: ?closed dup +closed+ eq? [ drop "/dev/null" ] when ; + : setup-redirection ( -- ) - +stdin+ get read-flags 0 redirect - +stdout+ get write-flags 1 redirect + +stdin+ get ?closed read-flags 0 redirect + +stdout+ get ?closed write-flags 1 redirect +stderr+ get dup +stdout+ eq? - [ drop 1 2 dup2 io-error ] [ write-flags 2 redirect ] if ; + [ drop 1 2 dup2 io-error ] [ ?closed write-flags 2 redirect ] if ; : spawn-process ( -- ) [ @@ -70,6 +71,8 @@ MEMO: 'arguments' ( -- parser ) io-error ] [ error. :c flush ] recover 1 exit ; +M: unix-io current-process-handle ( -- handle ) getpid ; + M: unix-io run-process* ( desc -- pid ) [ [ spawn-process ] [ ] with-fork <process> diff --git a/extra/io/windows/launcher/launcher.factor b/extra/io/windows/launcher/launcher.factor index f3f78fbb88..cc3278dadc 100755 --- a/extra/io/windows/launcher/launcher.factor +++ b/extra/io/windows/launcher/launcher.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: alien alien.c-types arrays continuations destructors io -io.windows io.windows.pipes libc io.nonblocking +io.windows io.windows.nt.pipes libc io.nonblocking io.streams.duplex windows.types math windows.kernel32 windows namespaces io.launcher kernel sequences windows.errors assocs splitting system threads init strings combinators io.backend ; @@ -87,75 +87,29 @@ TUPLE: CreateProcess-args over set-CreateProcess-args-lpEnvironment ] when ; -: (redirect) ( path access-mode create-mode -- handle ) - >r >r - normalize-pathname - r> ! access-mode - share-mode - security-attributes-inherit - r> ! create-mode - FILE_ATTRIBUTE_NORMAL ! flags and attributes - f ! template file - CreateFile dup invalid-handle? dup close-later ; - -: redirect ( obj access-mode create-mode -- handle ) - { - { [ pick not ] [ 3drop f ] } - { [ pick +closed+ eq? ] [ 3drop t ] } - { [ pick string? ] [ (redirect) ] } - } cond ; - -: ?closed or dup t eq? [ drop f ] when ; - -: inherited-stdout ( args -- handle ) - CreateProcess-args-stdout-pipe - [ pipe-out ] [ STD_OUTPUT_HANDLE GetStdHandle ] if* ; - -: redirect-stdout ( args -- handle ) - +stdout+ get GENERIC_WRITE CREATE_ALWAYS redirect - swap inherited-stdout ?closed ; - -: inherited-stderr ( args -- handle ) - drop STD_ERROR_HANDLE GetStdHandle ; - -: redirect-stderr ( args -- handle ) - +stderr+ get - dup +stdout+ eq? [ - drop - CreateProcess-args-lpStartupInfo STARTUPINFO-hStdOutput - ] [ - GENERIC_WRITE CREATE_ALWAYS redirect - swap inherited-stderr ?closed - ] if ; - -: inherited-stdin ( args -- handle ) - CreateProcess-args-stdin-pipe - [ pipe-in ] [ STD_INPUT_HANDLE GetStdHandle ] if* ; - -: redirect-stdin ( args -- handle ) - +stdin+ get GENERIC_READ OPEN_EXISTING redirect - swap inherited-stdin ?closed ; - : fill-startup-info dup CreateProcess-args-lpStartupInfo - STARTF_USESTDHANDLES over set-STARTUPINFO-dwFlags + STARTF_USESTDHANDLES swap set-STARTUPINFO-dwFlags ; - over redirect-stdout over set-STARTUPINFO-hStdOutput - over redirect-stderr over set-STARTUPINFO-hStdError - over redirect-stdin over set-STARTUPINFO-hStdInput +HOOK: fill-redirection io-backend ( args -- args ) - drop ; +M: windows-ce-io fill-redirection ; : make-CreateProcess-args ( -- args ) default-CreateProcess-args wince? [ fill-lpApplicationName ] [ fill-lpCommandLine ] if fill-dwCreateFlags - fill-lpEnvironment ; + fill-lpEnvironment + fill-startup-info ; + +M: windows-io current-process-handle ( -- handle ) + GetCurrentProcessId ; M: windows-io run-process* ( desc -- handle ) [ [ - make-CreateProcess-args fill-startup-info + make-CreateProcess-args + fill-redirection dup call-CreateProcess CreateProcess-args-lpProcessInformation <process> ] with-descriptor diff --git a/extra/io/windows/nt/files/files.factor b/extra/io/windows/nt/files/files.factor index ecc989530e..f2be11855b 100755 --- a/extra/io/windows/nt/files/files.factor +++ b/extra/io/windows/nt/files/files.factor @@ -2,7 +2,7 @@ USING: continuations destructors io.buffers io.files io.backend io.timeouts io.nonblocking io.windows io.windows.nt.backend kernel libc math threads windows windows.kernel32 alien.c-types alien.arrays sequences combinators combinators.lib sequences.lib -ascii splitting alien strings ; +ascii splitting alien strings assocs ; IN: io.windows.nt.files M: windows-nt-io cwd @@ -60,7 +60,7 @@ M: windows-nt-io root-directory? ( path -- ? ) M: windows-nt-io normalize-pathname ( string -- string ) dup string? [ "pathname must be a string" throw ] unless - "/" split "\\" join + { { CHAR: / CHAR: \\ } } substitute cwd swap windows-path+ [ "/\\." member? ] right-trim dup peek CHAR: : = [ "\\" append ] when ; diff --git a/extra/io/windows/nt/launcher/launcher.factor b/extra/io/windows/nt/launcher/launcher.factor index c2f14c21bb..cd9bb9baef 100755 --- a/extra/io/windows/nt/launcher/launcher.factor +++ b/extra/io/windows/nt/launcher/launcher.factor @@ -3,13 +3,63 @@ USING: alien alien.c-types arrays continuations destructors io io.windows libc io.nonblocking io.streams.duplex windows.types math windows.kernel32 windows namespaces io.launcher kernel -sequences windows.errors assocs splitting system -io.windows.launcher io.windows.pipes ; +sequences windows.errors assocs splitting system strings +io.windows.launcher io.windows.nt.pipes io.backend +combinators ; IN: io.windows.nt.launcher ! The below code is based on the example given in ! http://msdn2.microsoft.com/en-us/library/ms682499.aspx +: (redirect) ( path access-mode create-mode -- handle ) + >r >r + normalize-pathname + r> ! access-mode + share-mode + security-attributes-inherit + r> ! create-mode + FILE_ATTRIBUTE_NORMAL ! flags and attributes + f ! template file + CreateFile dup invalid-handle? dup close-later ; + +: redirect ( obj access-mode create-mode -- handle ) + { + { [ pick not ] [ 3drop f ] } + { [ pick +closed+ eq? ] [ drop nip null-pipe ] } + { [ pick string? ] [ (redirect) ] } + } cond ; + +: ?closed or dup t eq? [ drop f ] when ; + +: inherited-stdout ( args -- handle ) + CreateProcess-args-stdout-pipe + [ pipe-out ] [ STD_OUTPUT_HANDLE GetStdHandle ] if* ; + +: redirect-stdout ( args -- handle ) + +stdout+ get GENERIC_WRITE CREATE_ALWAYS redirect + swap inherited-stdout ?closed ; + +: inherited-stderr ( args -- handle ) + drop STD_ERROR_HANDLE GetStdHandle ; + +: redirect-stderr ( args -- handle ) + +stderr+ get + dup +stdout+ eq? [ + drop + CreateProcess-args-lpStartupInfo STARTUPINFO-hStdOutput + ] [ + GENERIC_WRITE CREATE_ALWAYS redirect + swap inherited-stderr ?closed + ] if ; + +: inherited-stdin ( args -- handle ) + CreateProcess-args-stdin-pipe + [ pipe-in ] [ STD_INPUT_HANDLE GetStdHandle ] if* ; + +: redirect-stdin ( args -- handle ) + +stdin+ get GENERIC_READ OPEN_EXISTING redirect + swap inherited-stdin ?closed ; + : set-inherit ( handle ? -- ) >r HANDLE_FLAG_INHERIT r> >BOOLEAN SetHandleInformation win32-error=0/f ; @@ -30,14 +80,22 @@ IN: io.windows.nt.launcher dup pipe-out f set-inherit over set-CreateProcess-args-stdin-pipe ; -M: windows-io process-stream* +M: windows-nt-io fill-redirection + dup CreateProcess-args-lpStartupInfo + over redirect-stdout over set-STARTUPINFO-hStdOutput + over redirect-stderr over set-STARTUPINFO-hStdError + over redirect-stdin over set-STARTUPINFO-hStdInput + drop ; + +M: windows-nt-io process-stream* [ [ make-CreateProcess-args fill-stdout-pipe fill-stdin-pipe - fill-startup-info + + fill-redirection dup call-CreateProcess diff --git a/extra/benchmark/bootstrap2/authors.txt b/extra/io/windows/nt/pipes/authors.txt similarity index 100% rename from extra/benchmark/bootstrap2/authors.txt rename to extra/io/windows/nt/pipes/authors.txt diff --git a/extra/io/windows/pipes/pipes.factor b/extra/io/windows/nt/pipes/pipes.factor similarity index 74% rename from extra/io/windows/pipes/pipes.factor rename to extra/io/windows/nt/pipes/pipes.factor index 8c2acc4009..9591063609 100755 --- a/extra/io/windows/pipes/pipes.factor +++ b/extra/io/windows/nt/pipes/pipes.factor @@ -1,9 +1,10 @@ -! Copyright (C) 2007 Doug Coleman, Slava Pestov. +! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: alien alien.c-types arrays destructors io io.windows libc windows.types math windows.kernel32 windows namespaces kernel -sequences windows.errors assocs math.parser system random ; -IN: io.windows.pipes +sequences windows.errors assocs math.parser system random +combinators ; +IN: io.windows.nt.pipes ! This code is based on ! http://twistedmatrix.com/trac/browser/trunk/twisted/internet/iocpreactor/process.py @@ -65,3 +66,20 @@ TUPLE: pipe in out ; : <unique-outgoing-pipe> ( -- pipe ) unique-pipe-name <outgoing-pipe> ; + +! /dev/null simulation +: null-input ( -- pipe ) + <unique-outgoing-pipe> + dup pipe-out CloseHandle drop + pipe-in ; + +: null-output ( -- pipe ) + <unique-incoming-pipe> + dup pipe-in CloseHandle drop + pipe-out ; + +: null-pipe ( mode -- pipe ) + { + { [ dup GENERIC_READ = ] [ drop null-input ] } + { [ dup GENERIC_WRITE = ] [ drop null-output ] } + } cond ; diff --git a/extra/io/windows/pipes/authors.txt b/extra/io/windows/pipes/authors.txt deleted file mode 100755 index 1901f27a24..0000000000 --- a/extra/io/windows/pipes/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov diff --git a/extra/lazy-lists/lazy-lists.factor b/extra/lazy-lists/lazy-lists.factor index 1979819dd1..e3e7b14917 100644 --- a/extra/lazy-lists/lazy-lists.factor +++ b/extra/lazy-lists/lazy-lists.factor @@ -9,13 +9,10 @@ quotations promises combinators io ; IN: lazy-lists ! Lazy List Protocol +MIXIN: list GENERIC: car ( cons -- car ) GENERIC: cdr ( cons -- cdr ) GENERIC: nil? ( cons -- ? ) -GENERIC: list? ( object -- ? ) - -M: object list? ( object -- bool ) - drop f ; M: promise car ( promise -- car ) force car ; @@ -26,9 +23,6 @@ M: promise cdr ( promise -- cdr ) M: promise nil? ( cons -- bool ) force nil? ; -M: promise list? ( object -- bool ) - drop t ; - TUPLE: cons car cdr ; C: cons cons @@ -45,9 +39,6 @@ M: cons cdr ( cons -- cdr ) M: cons nil? ( cons -- bool ) nil eq? ; -M: cons list? ( object -- bool ) - drop t ; - : 1list ( obj -- cons ) nil cons ; @@ -74,9 +65,6 @@ M: lazy-cons cdr ( lazy-cons -- cdr ) M: lazy-cons nil? ( lazy-cons -- bool ) nil eq? ; -M: lazy-cons list? ( object -- bool ) - drop t ; - : 1lazy-list ( a -- lazy-cons ) [ nil ] lazy-cons ; @@ -138,9 +126,6 @@ M: memoized-cons nil? ( memoized-cons -- bool ) memoized-cons-nil? ] if ; -M: memoized-cons list? ( object -- bool ) - drop t ; - TUPLE: lazy-map cons quot ; C: <lazy-map> lazy-map @@ -159,9 +144,6 @@ M: lazy-map cdr ( lazy-map -- cdr ) M: lazy-map nil? ( lazy-map -- bool ) lazy-map-cons nil? ; -M: lazy-map list? ( object -- bool ) - drop t ; - TUPLE: lazy-map-with value cons quot ; C: <lazy-map-with> lazy-map-with @@ -182,9 +164,6 @@ M: lazy-map-with cdr ( lazy-map-with -- cdr ) M: lazy-map-with nil? ( lazy-map-with -- bool ) lazy-map-with-cons nil? ; -M: lazy-map-with list? ( object -- bool ) - drop t ; - TUPLE: lazy-take n cons ; C: <lazy-take> lazy-take @@ -206,9 +185,6 @@ M: lazy-take nil? ( lazy-take -- bool ) lazy-take-cons nil? ] if ; -M: lazy-take list? ( object -- bool ) - drop t ; - TUPLE: lazy-until cons quot ; C: <lazy-until> lazy-until @@ -226,9 +202,6 @@ M: lazy-until cdr ( lazy-until -- cdr ) M: lazy-until nil? ( lazy-until -- bool ) drop f ; -M: lazy-until list? ( lazy-until -- bool ) - drop t ; - TUPLE: lazy-while cons quot ; C: <lazy-while> lazy-while @@ -245,9 +218,6 @@ M: lazy-while cdr ( lazy-while -- cdr ) M: lazy-while nil? ( lazy-while -- bool ) [ car ] keep lazy-while-quot call not ; -M: lazy-while list? ( lazy-while -- bool ) - drop t ; - TUPLE: lazy-subset cons quot ; C: <lazy-subset> lazy-subset @@ -285,9 +255,6 @@ M: lazy-subset nil? ( lazy-subset -- bool ) ] if ] if ; -M: lazy-subset list? ( object -- bool ) - drop t ; - : list>vector ( list -- vector ) [ [ , ] leach ] V{ } make ; @@ -311,9 +278,6 @@ M: lazy-append cdr ( lazy-append -- cdr ) M: lazy-append nil? ( lazy-append -- bool ) drop f ; -M: lazy-append list? ( object -- bool ) - drop t ; - TUPLE: lazy-from-by n quot ; C: lfrom-by lazy-from-by ( n quot -- list ) @@ -331,9 +295,6 @@ M: lazy-from-by cdr ( lazy-from-by -- cdr ) M: lazy-from-by nil? ( lazy-from-by -- bool ) drop f ; -M: lazy-from-by list? ( object -- bool ) - drop t ; - TUPLE: lazy-zip list1 list2 ; C: <lazy-zip> lazy-zip @@ -351,9 +312,6 @@ M: lazy-zip cdr ( lazy-zip -- cdr ) M: lazy-zip nil? ( lazy-zip -- bool ) drop f ; -M: lazy-zip list? ( object -- bool ) - drop t ; - TUPLE: sequence-cons index seq ; C: <sequence-cons> sequence-cons @@ -376,9 +334,6 @@ M: sequence-cons cdr ( sequence-cons -- cdr ) M: sequence-cons nil? ( sequence-cons -- bool ) drop f ; -M: sequence-cons list? ( object -- bool ) - drop t ; - : >list ( object -- list ) { { [ dup sequence? ] [ 0 swap seq>list ] } @@ -419,9 +374,6 @@ M: lazy-concat nil? ( lazy-concat -- bool ) drop f ] if ; -M: lazy-concat list? ( object -- bool ) - drop t ; - : lcartesian-product ( list1 list2 -- result ) swap [ swap [ 2array ] lmap-with ] lmap-with lconcat ; @@ -492,3 +444,20 @@ M: lazy-io cdr ( lazy-io -- cdr ) M: lazy-io nil? ( lazy-io -- bool ) car not ; + +INSTANCE: cons list +INSTANCE: sequence-cons list +INSTANCE: memoized-cons list +INSTANCE: promise list +INSTANCE: lazy-io list +INSTANCE: lazy-concat list +INSTANCE: lazy-cons list +INSTANCE: lazy-map list +INSTANCE: lazy-map-with list +INSTANCE: lazy-take list +INSTANCE: lazy-append list +INSTANCE: lazy-from-by list +INSTANCE: lazy-zip list +INSTANCE: lazy-while list +INSTANCE: lazy-until list +INSTANCE: lazy-subset list diff --git a/extra/math/analysis/analysis.factor b/extra/math/analysis/analysis.factor old mode 100644 new mode 100755 index bde5cad7a0..0b4b14ce54 --- a/extra/math/analysis/analysis.factor +++ b/extra/math/analysis/analysis.factor @@ -1,5 +1,5 @@ USING: kernel math math.constants math.functions math.intervals -math.vectors namespaces sequences ; +math.vectors namespaces sequences combinators.cleave ; IN: math.analysis <PRIVATE @@ -108,3 +108,12 @@ PRIVATE> swap -1.0 * exp * ] if ; + +! James Stirling's approximation for N!: +! http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Numerical/Stirling/ + +: stirling-fact ( n -- fact ) + [ pi 2 * * sqrt ] + [ dup e / swap ^ ] + [ 12 * recip 1 + ] + tri * * ; diff --git a/extra/multiline/multiline.factor b/extra/multiline/multiline.factor index 4d777605cf..d32c11dd06 100755 --- a/extra/multiline/multiline.factor +++ b/extra/multiline/multiline.factor @@ -7,8 +7,11 @@ IN: multiline lexer get dup next-line lexer-line-text ; : (parse-here) ( -- ) - next-line-text dup ";" = - [ drop lexer get next-line ] [ % "\n" % (parse-here) ] if ; + next-line-text [ + dup ";" = + [ drop lexer get next-line ] + [ % "\n" % (parse-here) ] if + ] [ ";" unexpected-eof ] if* ; : parse-here ( -- str ) [ (parse-here) ] "" make 1 head* @@ -19,11 +22,13 @@ IN: multiline parse-here 1quotation define-inline ; parsing : (parse-multiline-string) ( start-index end-text -- end-index ) - lexer get lexer-line-text 2dup start - [ rot dupd >r >r swap subseq % r> r> length + ] [ - rot tail % "\n" % 0 - lexer get next-line swap (parse-multiline-string) - ] if* ; + lexer get lexer-line-text [ + 2dup start + [ rot dupd >r >r swap subseq % r> r> length + ] [ + rot tail % "\n" % 0 + lexer get next-line swap (parse-multiline-string) + ] if* + ] [ nip unexpected-eof ] if* ; : parse-multiline-string ( end-text -- str ) [ diff --git a/extra/optimizer/debugger/debugger.factor b/extra/optimizer/debugger/debugger.factor index 729281e81b..3cbddf8296 100755 --- a/extra/optimizer/debugger/debugger.factor +++ b/extra/optimizer/debugger/debugger.factor @@ -4,7 +4,7 @@ USING: classes inference inference.dataflow io kernel kernel.private math.parser namespaces optimizer prettyprint prettyprint.backend sequences words arrays match macros assocs sequences.private optimizer.specializers generic -combinators sorting math ; +combinators sorting math quotations ; IN: optimizer.debugger ! A simple tool for turning dataflow IR into quotations, for @@ -67,7 +67,7 @@ M: #shuffle node>quot [ , ] [ >r drop t r> ] if* dup effect-str "#shuffle: " swap append comment, ; -: pushed-literals node-out-d [ value-literal ] map ; +: pushed-literals node-out-d [ value-literal literalize ] map ; M: #push node>quot nip pushed-literals % ; @@ -82,7 +82,11 @@ M: #call node>quot #call>quot ; M: #call-label node>quot #call>quot ; M: #label node>quot - [ "#label: " over node-param word-name append comment, ] 2keep + [ + dup node-param literalize , + dup #label-loop? "#loop: " "#label: " ? + over node-param word-name append comment, + ] 2keep node-child swap dataflow>quot , \ call , ; M: #if node>quot @@ -95,14 +99,18 @@ M: #dispatch node>quot node-children swap [ dataflow>quot ] curry map , \ dispatch , ; -M: #return node>quot - dup node-param unparse "#return " swap append comment, ; - M: #>r node>quot nip node-in-d length \ >r <array> % ; M: #r> node>quot nip node-out-d length \ r> <array> % ; -M: object node>quot dup class word-name comment, ; +M: object node>quot + [ + dup class word-name % + " " % + dup node-param unparse % + " " % + dup effect-str % + ] "" make comment, ; : (dataflow>quot) ( ? node -- ) dup [ diff --git a/extra/optimizer/report/report.factor b/extra/optimizer/report/report.factor new file mode 100755 index 0000000000..6655d9dcf3 --- /dev/null +++ b/extra/optimizer/report/report.factor @@ -0,0 +1,28 @@ +IN: optimizer.report +USING: assocs words sequences arrays compiler tools.time +io.styles io prettyprint vocabs kernel sorting generator +optimizer ; + +: count-optimization-passes ( nodes n -- n ) + >r optimize-1 + [ r> 1+ count-optimization-passes ] [ drop r> ] if ; + +: word-table + [ [ second ] swap compose compare ] curry sort 20 tail* + print + standard-table-style + [ + [ [ [ pprint-cell ] each ] with-row ] each + ] tabular-output ; + +: optimizer-report + all-words [ compiled? ] subset + [ + dup [ + word-dataflow nip 1 count-optimization-passes + ] benchmark nip 2array + ] { } map>assoc + [ first ] "Worst number of optimizer passes:" results + [ second ] "Worst compile times:" results ; + +MAIN: optimizer-report diff --git a/extra/smtp/server/server.factor b/extra/smtp/server/server.factor index 275deee994..3ca1c72296 100755 --- a/extra/smtp/server/server.factor +++ b/extra/smtp/server/server.factor @@ -29,6 +29,7 @@ USING: combinators kernel prettyprint io io.timeouts io.server sequences namespaces io.sockets continuations ; +IN: smtp.server SYMBOL: data-mode @@ -55,7 +56,7 @@ SYMBOL: data-mode data-mode off "220 OK\r\n" write flush t ] } - { [ data-mode get ] [ t ] } + { [ data-mode get ] [ global [ print ] bind t ] } { [ t ] [ "500 ERROR\r\n" write flush t ] } @@ -68,5 +69,6 @@ SYMBOL: data-mode 60000 stdio get set-timeout "220 hello\r\n" write flush process + global [ flush ] bind ] with-stream ] with-disposal ; diff --git a/extra/smtp/smtp.factor b/extra/smtp/smtp.factor index 27aac1202e..47bc16e029 100755 --- a/extra/smtp/smtp.factor +++ b/extra/smtp/smtp.factor @@ -139,7 +139,7 @@ LOG: smtp-response DEBUG : prepare-message ( body headers -- body' ) [ prepare-headers - " " , + "" , dup string? [ string-lines ] when % ] { } make ; @@ -169,3 +169,15 @@ LOG: smtp-response DEBUG ! : cram-md5-auth ( key login -- ) ! "AUTH CRAM-MD5\r\n" get-ok ! (cram-md5-auth) "\r\n" append get-ok ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +USE: new-slots + +TUPLE: email from to subject body ; + +: <email> ( -- email ) email construct-empty ; + +: send ( email -- ) + { email-body email-subject email-to email-from } get-slots + send-simple-message ; \ No newline at end of file diff --git a/extra/tools/browser/browser.factor b/extra/tools/browser/browser.factor index b6c0ef3ecc..75ae377ea7 100755 --- a/extra/tools/browser/browser.factor +++ b/extra/tools/browser/browser.factor @@ -132,7 +132,7 @@ MEMO: all-vocabs-seq ( -- seq ) require-all ; : load-everything ( -- ) - try-everything drop ; + try-everything load-failures. ; : unrooted-child-vocabs ( prefix -- seq ) dup empty? [ CHAR: . add ] unless diff --git a/extra/tools/disassembler/authors.txt b/extra/tools/disassembler/authors.txt new file mode 100644 index 0000000000..ef44eb9634 --- /dev/null +++ b/extra/tools/disassembler/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Jorge Acereda Macia diff --git a/extra/tools/disassembler/disassembler-docs.factor b/extra/tools/disassembler/disassembler-docs.factor new file mode 100755 index 0000000000..f03861a8ed --- /dev/null +++ b/extra/tools/disassembler/disassembler-docs.factor @@ -0,0 +1,13 @@ +IN: tools.disassembler +USING: help.markup help.syntax sequences.private ; + +HELP: disassemble +{ $values { "obj" "a word or a pair of addresses" } } +{ $description "Disassembles either a compiled word definition or an arbitrary memory range (in the case " { $snippet "obj" } " is a pair of integers) by attaching " { $snippet "gdb" } " to the Factor VM and capturing the output." } +{ $notes "In some cases the Factor compiler emits data inline with code, which can confuse " { $snippet "gdb" } ". This occurs in words which call " { $link dispatch } ", where the jump table addresses are compiled inline. Also on the ARM architecture, various pointers are often compiled inline, and the preceeding instruction jumps over the inline pinter." } ; + +ARTICLE: "tools.disassembler" "Disassembling words" +"The " { $vocab-link "tools.disassembler" } " vocabulary integrates Factor with the GNU debugger (" { $snippet "gdb" } ") for viewing the assembly code generated by the compiler. It can be used on both Unix and Windows as long as a working copy of " { $snippet "gdb" } " is installed and available in the " { $snippet "PATH" } "." +{ $subsection disassemble } ; + +ABOUT: "tools.disassembler" diff --git a/extra/tools/disassembler/disassembler.factor b/extra/tools/disassembler/disassembler.factor new file mode 100755 index 0000000000..8fe3b9bdf0 --- /dev/null +++ b/extra/tools/disassembler/disassembler.factor @@ -0,0 +1,38 @@ +! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia. +! See http://factorcode.org/license.txt for BSD license. +USING: io.files io words alien kernel math.parser alien.syntax +io.launcher system assocs arrays sequences namespaces qualified +system math windows.kernel32 generator.fixup ; +IN: tools.disassembler + +: in-file "gdb-in.txt" resource-path ; + +: out-file "gdb-out.txt" resource-path ; + +GENERIC: make-disassemble-cmd ( obj -- ) + +M: word make-disassemble-cmd + word-xt code-format - 2array make-disassemble-cmd ; + +M: pair make-disassemble-cmd + in-file [ + "attach " write + current-process-handle number>string print + "disassemble " write + [ number>string write bl ] each + ] with-file-out ; + +: run-gdb ( -- lines ) + [ + +closed+ +stdin+ set + out-file +stdout+ set + [ "gdb" , "-x" , in-file , "-batch" , ] { } make +arguments+ set + ] { } make-assoc run-process drop + out-file file-lines ; + +: tabs>spaces ( str -- str' ) + { { CHAR: \t CHAR: \s } } substitute ; + +: disassemble ( word -- ) + make-disassemble-cmd run-gdb + [ tabs>spaces ] map [ print ] each ; diff --git a/extra/tools/disassembler/summary.txt b/extra/tools/disassembler/summary.txt new file mode 100644 index 0000000000..f1a689c877 --- /dev/null +++ b/extra/tools/disassembler/summary.txt @@ -0,0 +1 @@ +Disassemble words using gdb diff --git a/extra/tools/memory/memory-docs.factor b/extra/tools/memory/memory-docs.factor old mode 100644 new mode 100755 index 939dda0cfc..11bb8d859b --- a/extra/tools/memory/memory-docs.factor +++ b/extra/tools/memory/memory-docs.factor @@ -17,7 +17,7 @@ ARTICLE: "tools.memory" "Object memory tools" "The garbage collector can be invoked manually:" { $subsection data-gc } { $subsection code-gc } -{ $see-also "image" } ; +{ $see-also "images" } ; ABOUT: "tools.memory" diff --git a/extra/tools/test/test.factor b/extra/tools/test/test.factor index 62a4dab1eb..69093f18a6 100755 --- a/extra/tools/test/test.factor +++ b/extra/tools/test/test.factor @@ -53,12 +53,12 @@ SYMBOL: this-test : (run-test) ( vocab -- ) dup vocab-source-loaded? [ - [ "temporary" forget-vocab ] with-compilation-unit - vocab-tests dup [ run-file ] each + vocab-tests [ - dup [ forget-source ] each "temporary" forget-vocab + dup [ forget-source ] each ] with-compilation-unit + dup [ run-file ] each ] when drop ; : run-test ( vocab -- failures ) diff --git a/extra/ui/commands/commands.factor b/extra/ui/commands/commands.factor index 04f655853a..dbb838a5c5 100755 --- a/extra/ui/commands/commands.factor +++ b/extra/ui/commands/commands.factor @@ -51,7 +51,7 @@ GENERIC: command-word ( command -- word ) update-gestures ; : (command-name) ( string -- newstring ) - "-" split " " join >title ; + { { CHAR: - CHAR: \s } } substitute >title ; M: word command-name ( word -- str ) word-name diff --git a/extra/ui/x11/x11.factor b/extra/ui/x11/x11.factor index e4794452c7..082a27317a 100755 --- a/extra/ui/x11/x11.factor +++ b/extra/ui/x11/x11.factor @@ -1,11 +1,11 @@ ! Copyright (C) 2005, 2007 Eduardo Cavazos and Slava Pestov ! See http://factorcode.org/license.txt for BSD license. -USING: alien alien.c-types arrays ui ui.gadgets ui.gestures ui.backend -ui.clipboards ui.gadgets.worlds assocs kernel math namespaces -opengl sequences strings x11.xlib x11.events x11.xim x11.glx -x11.clipboard x11.constants x11.windows io.utf8 combinators -debugger system command-line ui.render math.vectors tuples -opengl.gl threads ; +USING: alien alien.c-types arrays ui ui.gadgets ui.gestures +ui.backend ui.clipboards ui.gadgets.worlds assocs kernel math +namespaces opengl sequences strings x11.xlib x11.events x11.xim +x11.glx x11.clipboard x11.constants x11.windows +io.encodings.utf8 combinators debugger system command-line +ui.render math.vectors tuples opengl.gl threads ; IN: ui.x11 TUPLE: x11-ui-backend ; diff --git a/extra/unicode/breaks/breaks.factor b/extra/unicode/breaks/breaks.factor index 70a9c781a2..1014d3ad7e 100644 --- a/extra/unicode/breaks/breaks.factor +++ b/extra/unicode/breaks/breaks.factor @@ -1,7 +1,7 @@ USING: unicode.categories kernel math combinators splitting sequences math.parser io.files io assocs arrays namespaces combinators.lib assocs.lib math.ranges unicode.normalize -unicode.syntax unicode.data compiler.units alien.syntax const ; +unicode.syntax unicode.data compiler.units alien.syntax ; IN: unicode.breaks C-ENUM: Any L V T Extend Control CR LF graphemes ; diff --git a/extra/unicode/data/data.factor b/extra/unicode/data/data.factor old mode 100644 new mode 100755 index c579d1fdfd..c3998a6132 --- a/extra/unicode/data/data.factor +++ b/extra/unicode/data/data.factor @@ -1,8 +1,16 @@ USING: assocs math kernel sequences io.files hashtables quotations splitting arrays math.parser combinators.lib hash2 -byte-arrays words namespaces words compiler.units const ; +byte-arrays words namespaces words compiler.units parser ; IN: unicode.data +<< +: VALUE: + CREATE dup reset-generic { f } clone [ first ] curry define ; parsing + +: set-value ( value word -- ) + word-def first set-first ; +>> + ! Convenience functions : 1+* ( n/f _ -- n+1 ) drop [ 1+ ] [ 0 ] if* ; @@ -59,7 +67,7 @@ IN: unicode.data : process-combining ( data -- hash ) 3 swap (process-data) [ string>number ] assoc-map - [ nip 0 = not ] assoc-subset + [ nip zero? not ] assoc-subset >hashtable ; : categories ( -- names ) @@ -85,13 +93,10 @@ IN: unicode.data : ascii-lower ( string -- lower ) [ dup CHAR: A CHAR: Z between? [ HEX: 20 + ] when ] map ; -: replace ( seq old new -- newseq ) - swap rot [ 2dup = [ drop over ] when ] map 2nip ; - : process-names ( data -- names-hash ) - 1 swap (process-data) - [ ascii-lower CHAR: \s CHAR: - replace swap ] assoc-map - >hashtable ; + 1 swap (process-data) [ + ascii-lower { { CHAR: \s CHAR: - } } substitute swap + ] assoc-map >hashtable ; : multihex ( hexstring -- string ) " " split [ hex> ] map [ ] subset ; diff --git a/extra/unicode/syntax/syntax-tests.factor b/extra/unicode/syntax/syntax-tests.factor deleted file mode 100644 index 1579e368c2..0000000000 --- a/extra/unicode/syntax/syntax-tests.factor +++ /dev/null @@ -1,4 +0,0 @@ -USING: unicode.syntax tools.test ; - -[ CHAR: ! ] [ UNICHAR: exclamation-mark ] unit-test -! Write a test for CATEGORY and CATEGORY-NOT diff --git a/extra/unicode/syntax/syntax.factor b/extra/unicode/syntax/syntax.factor old mode 100644 new mode 100755 index 6c75a77c76..bd3fd4ae2a --- a/extra/unicode/syntax/syntax.factor +++ b/extra/unicode/syntax/syntax.factor @@ -46,7 +46,3 @@ IN: unicode.syntax : CATEGORY-NOT: CREATE ";" parse-tokens categories swap seq-minus define-category ; parsing - -: UNICHAR: - ! This should be part of CHAR:. Also, name-map at ==> name>char - scan name>char [ parsed ] [ "Invalid character" throw ] if* ; parsing diff --git a/extra/unicode/unicode.factor b/extra/unicode/unicode.factor index 12673c3bde..0c22bfab8f 100755 --- a/extra/unicode/unicode.factor +++ b/extra/unicode/unicode.factor @@ -1,5 +1,9 @@ -USING: unicode.syntax unicode.data unicode.breaks unicode.normalize -unicode.case unicode.categories ; +USING: unicode.syntax unicode.data unicode.breaks +unicode.normalize unicode.case unicode.categories +parser kernel namespaces ; IN: unicode ! For now: convenience to load all Unicode vocabs + +[ name>char [ "Invalid character" throw ] unless* ] +name>char-hook set-global diff --git a/extra/unix/unix.factor b/extra/unix/unix.factor index 59141c1940..9d5a6122a2 100755 --- a/extra/unix/unix.factor +++ b/extra/unix/unix.factor @@ -125,6 +125,7 @@ FUNCTION: int futimes ( int id, timeval[2] times ) ; FUNCTION: char* gai_strerror ( int ecode ) ; FUNCTION: int getaddrinfo ( char* hostname, char* servname, addrinfo* hints, addrinfo** res ) ; FUNCTION: char* getcwd ( char* buf, size_t size ) ; +FUNCTION: pid_t getpid ; FUNCTION: int getdtablesize ; FUNCTION: gid_t getegid ; FUNCTION: uid_t geteuid ; diff --git a/extra/windows/kernel32/kernel32.factor b/extra/windows/kernel32/kernel32.factor index b8928c5820..3574df36db 100755 --- a/extra/windows/kernel32/kernel32.factor +++ b/extra/windows/kernel32/kernel32.factor @@ -895,7 +895,7 @@ FUNCTION: DWORD GetConsoleTitleW ( LPWSTR lpConsoleTitle, DWORD nSize ) ; FUNCTION: BOOL GetCurrentDirectoryW ( DWORD len, LPTSTR buf ) ; : GetCurrentDirectory GetCurrentDirectoryW ; inline FUNCTION: HANDLE GetCurrentProcess ( ) ; -! FUNCTION: GetCurrentProcessId +FUNCTION: DWORD GetCurrentProcessId ( ) ; FUNCTION: HANDLE GetCurrentThread ( ) ; ! FUNCTION: GetCurrentThreadId ! FUNCTION: GetDateFormatA diff --git a/extra/x11/clipboard/clipboard.factor b/extra/x11/clipboard/clipboard.factor old mode 100644 new mode 100755 index 5978ee6f7f..eb4191ebb1 --- a/extra/x11/clipboard/clipboard.factor +++ b/extra/x11/clipboard/clipboard.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2006, 2007 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: alien alien.c-types alien.syntax arrays kernel math -namespaces sequences io.utf8 x11.xlib x11.constants ; +namespaces sequences io.encodings.utf8 x11.xlib x11.constants ; IN: x11.clipboard ! This code was based on by McCLIM's Backends/CLX/port.lisp diff --git a/misc/factor.sh b/misc/factor.sh index 5d7e7d0b94..44feb329fb 100755 --- a/misc/factor.sh +++ b/misc/factor.sh @@ -14,16 +14,36 @@ NO_UI= GIT_PROTOCOL=${GIT_PROTOCOL:="git"} GIT_URL=${GIT_URL:=$GIT_PROTOCOL"://factorcode.org/git/factor.git"} +test_program_installed() { + if ! [[ -n `type -p $1` ]] ; then + return 0; + fi + return 1; +} ensure_program_installed() { - echo -n "Checking for $1..." - result=`type -p $1` - if ! [[ -n $result ]] ; then - echo "not found!" - echo "Install $1 and try again." - exit 1 - fi - echo "found!" + installed=0; + for i in $* ; + do + echo -n "Checking for $i..." + test_program_installed $i + if [[ $? -eq 0 ]]; then + echo -n "not " + else + installed=$(( $installed + 1 )) + fi + echo "found!" + done + if [[ $installed -eq 0 ]] ; then + echo -n "Install " + if [[ $# -eq 1 ]] ; then + echo -n $1 + else + echo -n "any of [ $* ]" + fi + echo " and try again." + exit 1 + fi } check_ret() { @@ -47,13 +67,33 @@ check_gcc_version() { echo "ok." } +set_downloader() { + test_program_installed wget + if [[ $? -ne 0 ]] ; then + DOWNLOAD=wget + else + DOWNLOAD="curl -O" + fi +} + +set_md5sum() { + test_program_installed md5sum + if [[ $? -ne 0 ]] ; then + MD5SUM=md5sum + else + MD5SUM="md5 -r" + fi +} + check_installed_programs() { ensure_program_installed chmod ensure_program_installed uname ensure_program_installed git - ensure_program_installed wget + ensure_program_installed wget curl ensure_program_installed gcc ensure_program_installed make + ensure_program_installed md5sum md5 + ensure_program_installed cut case $OS in netbsd) ensure_program_installed gmake;; esac @@ -234,36 +274,53 @@ make_factor() { invoke_make NO_UI=$NO_UI $MAKE_TARGET -j5 } -delete_boot_images() { +update_boot_images() { echo "Deleting old images..." - rm $BOOT_IMAGE > /dev/null 2>&1 + rm checksums.txt* > /dev/null 2>&1 rm $BOOT_IMAGE.* > /dev/null 2>&1 - rm staging.*.image > /dev/null 2>&1 + rm staging.*.image > /dev/null 2>&1 + if [[ -f $BOOT_IMAGE ]] ; then + get_url http://factorcode.org/images/latest/checksums.txt + factorcode_md5=`cat checksums.txt|grep $BOOT_IMAGE|cut -f2 -d' '`; + set_md5sum + disk_md5=`$MD5SUM $BOOT_IMAGE|cut -f1 -d' '`; + echo "Factorcode md5: $factorcode_md5"; + echo "Disk md5: $disk_md5"; + if [[ "$factorcode_md5" == "$disk_md5" ]] ; then + echo "Your disk boot image matches the one on factorcode.org." + else + rm $BOOT_IMAGE > /dev/null 2>&1 + get_boot_image; + fi + else + get_boot_image + fi } get_boot_image() { - wget http://factorcode.org/images/latest/$BOOT_IMAGE - check_ret wget + echo "Downloading boot image $BOOT_IMAGE." + get_url http://factorcode.org/images/latest/$BOOT_IMAGE +} + +get_url() { + if [[ $DOWNLOAD -eq "" ]] ; then + set_downloader; + fi + echo $DOWNLOAD $1 ; + $DOWNLOAD $1 + check_ret $DOWNLOAD } maybe_download_dlls() { if [[ $OS == winnt ]] ; then - wget http://factorcode.org/dlls/freetype6.dll - check_ret wget - wget http://factorcode.org/dlls/zlib1.dll - check_ret wget - wget http://factorcode.org/dlls/OpenAL32.dll - check_ret wget - wget http://factorcode.org/dlls/alut.dll - check_ret wget - wget http://factorcode.org/dlls/ogg.dll - check_ret wget - wget http://factorcode.org/dlls/theora.dll - check_ret wget - wget http://factorcode.org/dlls/vorbis.dll - check_ret wget - wget http://factorcode.org/dlls/sqlite3.dll - check_ret wget + get_url http://factorcode.org/dlls/freetype6.dll + get_url http://factorcode.org/dlls/zlib1.dll + get_url http://factorcode.org/dlls/OpenAL32.dll + get_url http://factorcode.org/dlls/alut.dll + get_url http://factorcode.org/dlls/ogg.dll + get_url http://factorcode.org/dlls/theora.dll + get_url http://factorcode.org/dlls/vorbis.dll + get_url http://factorcode.org/dlls/sqlite3.dll chmod 777 *.dll check_ret chmod fi @@ -299,8 +356,7 @@ update() { } update_bootstrap() { - delete_boot_images - get_boot_image + update_boot_images bootstrap } @@ -321,7 +377,7 @@ install_libraries() { } usage() { - echo "usage: $0 install|install-x11|self-update|quick-update|update|bootstrap|wget-bootstrap" + echo "usage: $0 install|install-x11|self-update|quick-update|update|bootstrap|net-bootstrap" echo "If you are behind a firewall, invoke as:" echo "env GIT_PROTOCOL=http $0 <command>" } @@ -333,6 +389,6 @@ case "$1" in quick-update) update; refresh_image ;; update) update; update_bootstrap ;; bootstrap) get_config_info; bootstrap ;; - wget-bootstrap) get_config_info; delete_boot_images; get_boot_image; bootstrap ;; + net-bootstrap) get_config_info; update_boot_images; bootstrap ;; *) usage ;; esac diff --git a/vm/types.c b/vm/types.c index 78e74535b8..fb61213385 100755 --- a/vm/types.c +++ b/vm/types.c @@ -70,11 +70,13 @@ DEFINE_PRIMITIVE(word) dpush(tag_object(allot_word(vocab,name))); } -/* word-xt ( word -- xt ) */ +/* word-xt ( word -- start end ) */ DEFINE_PRIMITIVE(word_xt) { - F_WORD *word = untag_word(dpeek()); - drepl(allot_cell((CELL)word->xt)); + F_WORD *word = untag_word(dpop()); + F_COMPILED *code = word->code; + dpush(allot_cell((CELL)code + sizeof(F_COMPILED))); + dpush(allot_cell((CELL)code + sizeof(F_COMPILED) + code->code_length)); } DEFINE_PRIMITIVE(wrapper)