diff --git a/basis/ascii/ascii-docs.factor b/basis/ascii/ascii-docs.factor index 6af697cf89..4c783e609c 100644 --- a/basis/ascii/ascii-docs.factor +++ b/basis/ascii/ascii-docs.factor @@ -37,6 +37,26 @@ HELP: quotable? { $values { "ch" "a character" } { "?" "a boolean" } } { $description "Tests for characters which may appear in a Factor string literal without escaping." } ; +HELP: ascii? +{ $values { "ch" "a character" } { "?" "a boolean" } } +{ $description "Tests for whether a number is an ASCII character." } ; + +HELP: ch>lower +{ $values { "ch" "a character" } { "lower" "a character" } } +{ $description "Converts an ASCII character to lower case." } ; + +HELP: ch>upper +{ $values { "ch" "a character" } { "upper" "a character" } } +{ $description "Converts an ASCII character to upper case." } ; + +HELP: >lower +{ $values { "str" "a string" } { "lower" "a string" } } +{ $description "Converts an ASCII string to lower case." } ; + +HELP: >upper +{ $values { "str" "a string" } { "upper" "a string" } } +{ $description "Converts an ASCII string to upper case." } ; + ARTICLE: "ascii" "ASCII character classes" "The " { $vocab-link "ascii" } " vocabulary implements traditional ASCII character classes:" { $subsection blank? } @@ -46,6 +66,12 @@ ARTICLE: "ascii" "ASCII character classes" { $subsection printable? } { $subsection control? } { $subsection quotable? } -"Modern applications should use Unicode 5.0 instead (" { $vocab-link "unicode.categories" } ")." ; +{ $subsection ascii? } +"ASCII case conversion is also implemented:" +{ $subsection ch>lower } +{ $subsection ch>upper } +{ $subsection >lower } +{ $subsection >upper } +"Modern applications should use Unicode 5.1 instead (" { $vocab-link "unicode.categories" } ")." ; ABOUT: "ascii" diff --git a/basis/ascii/ascii-tests.factor b/basis/ascii/ascii-tests.factor index 7dacce734b..6f39b32a01 100644 --- a/basis/ascii/ascii-tests.factor +++ b/basis/ascii/ascii-tests.factor @@ -12,3 +12,8 @@ IN: ascii.tests 0 "There are Four Upper Case characters" [ LETTER? [ 1+ ] when ] each ] unit-test + +[ t f ] [ CHAR: \s ascii? 400 ascii? ] unit-test + +[ "HELLO HOW ARE YOU?" ] [ "hellO hOw arE YOU?" >upper ] unit-test +[ "i'm good thx bai" ] [ "I'm Good THX bai" >lower ] unit-test diff --git a/basis/ascii/ascii.factor b/basis/ascii/ascii.factor index c009c66cde..a64a7b8eb5 100644 --- a/basis/ascii/ascii.factor +++ b/basis/ascii/ascii.factor @@ -4,6 +4,8 @@ USING: kernel math math.order sequences combinators.short-circuit ; IN: ascii +: ascii? ( ch -- ? ) 0 127 between? ; inline + : blank? ( ch -- ? ) " \t\n\r" member? ; inline : letter? ( ch -- ? ) CHAR: a CHAR: z between? ; inline @@ -25,3 +27,15 @@ IN: ascii : alpha? ( ch -- ? ) [ [ Letter? ] [ digit? ] ] 1|| ; + +: ch>lower ( ch -- lower ) + dup CHAR: A CHAR: Z between? [ HEX: 20 + ] when ; + +: >lower ( str -- lower ) + [ ch>lower ] map ; + +: ch>upper ( ch -- upper ) + dup CHAR: a CHAR: z between? [ HEX: 20 - ] when ; + +: >upper ( str -- upper ) + [ ch>upper ] map ; diff --git a/basis/bootstrap/help/help.factor b/basis/bootstrap/help/help.factor index 5b49ce2802..145738ff45 100644 --- a/basis/bootstrap/help/help.factor +++ b/basis/bootstrap/help/help.factor @@ -4,6 +4,7 @@ parser vocabs.loader vocabs.loader.private accessors assocs ; IN: bootstrap.help : load-help ( -- ) + "help.lint" require "alien.syntax" require "compiler" require diff --git a/basis/bootstrap/unicode/unicode.factor b/basis/bootstrap/unicode/unicode.factor index 1e9f8b8642..e69de29bb2 100644 --- a/basis/bootstrap/unicode/unicode.factor +++ b/basis/bootstrap/unicode/unicode.factor @@ -1,5 +0,0 @@ -USING: strings.parser kernel namespaces unicode unicode.data ; -IN: bootstrap.unicode - -[ name>char [ "Invalid character" throw ] unless* ] -name>char-hook set-global diff --git a/basis/combinators/smart/authors.txt b/basis/combinators/smart/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/combinators/smart/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/combinators/smart/smart-docs.factor b/basis/combinators/smart/smart-docs.factor new file mode 100644 index 0000000000..69ec3e7013 --- /dev/null +++ b/basis/combinators/smart/smart-docs.factor @@ -0,0 +1,91 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax kernel quotations math sequences +multiline ; +IN: combinators.smart + +HELP: inputarray +{ $values + { "quot" quotation } + { "newquot" quotation } +} +{ $description "Infers the number or outputs from the quotation and constructs an array from those outputs." } +{ $examples + { $example + <" USING: combinators combinators.smart math prettyprint ; +9 [ + { [ 1- ] [ 1+ ] [ sq ] } cleave +] output>array ."> + "{ 8 10 81 }" + } +} ; + +HELP: output>sequence +{ $values + { "quot" quotation } { "exemplar" "an exemplar" } + { "newquot" quotation } +} +{ $description "Infers the number of outputs from the quotation and constructs a new sequence from those objects of the same type as the exemplar." } +{ $examples + { $example + "USING: combinators.smart kernel math prettyprint ;" + "4 [ [ 1 + ] [ 2 + ] [ 3 + ] tri ] V{ } output>sequence ." + "V{ 5 6 7 }" + } +} ; + +HELP: reduce-output +{ $values + { "quot" quotation } { "operation" quotation } + { "newquot" quotation } +} +{ $description "Infers the number of outputs from " { $snippet "quot" } " and reduces them using " { $snippet "operation" } ". The identity for the " { $link reduce } " operation is the first output." } +{ $examples + { $example + "USING: combinators.smart kernel math prettyprint ;" + "3 [ [ 4 * ] [ 4 / ] [ 4 - ] tri ] [ * ] reduce-output ." + "-9" + } +} ; + +HELP: sum-outputs +{ $values + { "quot" quotation } + { "n" integer } +} +{ $description "Infers the number of outputs from " { $snippet "quot" } " and returns their sum." } +{ $examples + { $example + "USING: combinators.smart kernel math prettyprint ;" + "10 [ [ 1- ] [ 1+ ] bi ] sum-outputs ." + "20" + } +} ; + +ARTICLE: "combinators.smart" "Smart combinators" +"The " { $vocab-link "combinators.smart" } " vocabulary implements " { $emphasis "smart combinators" } ". A smart combinator is one whose behavior depends on the static stack effect of an input quotation." $nl +"Smart inputs from a sequence:" +{ $subsection inputsequence } +{ $subsection output>array } +"Reducing the output of a quotation:" +{ $subsection reduce-output } +"Summing the output of a quotation:" +{ $subsection sum-outputs } ; + +ABOUT: "combinators.smart" diff --git a/basis/combinators/smart/smart-tests.factor b/basis/combinators/smart/smart-tests.factor new file mode 100644 index 0000000000..4be445e465 --- /dev/null +++ b/basis/combinators/smart/smart-tests.factor @@ -0,0 +1,21 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: tools.test combinators.smart math kernel ; +IN: combinators.smart.tests + +: test-bi ( -- 9 11 ) + 10 [ 1- ] [ 1+ ] bi ; + +[ [ test-bi ] output>array ] must-infer +[ { 9 11 } ] [ [ test-bi ] output>array ] unit-test + +[ { 9 11 } [ + ] inputsequence ( quot exemplar -- newquot ) + [ dup infer out>> ] dip + '[ @ _ _ nsequence ] ; + +: output>array ( quot -- newquot ) + { } output>sequence ; inline + +MACRO: input> ] keep + '[ _ firstn @ ] ; + +MACRO: reduce-output ( quot operation -- newquot ) + [ dup infer out>> 1 [-] ] dip n*quot compose ; + +: sum-outputs ( quot -- n ) + [ + ] reduce-output ; inline diff --git a/basis/db/tester/authors.txt b/basis/db/tester/authors.txt new file mode 100644 index 0000000000..f372b574ae --- /dev/null +++ b/basis/db/tester/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Doug Coleman diff --git a/basis/db/tester/tester-tests.factor b/basis/db/tester/tester-tests.factor new file mode 100644 index 0000000000..6b39a7e218 --- /dev/null +++ b/basis/db/tester/tester-tests.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2008 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: tools.test db.tester ; +IN: db.tester.tests + +[ ] [ sqlite-test-db db-tester ] unit-test +[ ] [ sqlite-test-db db-tester2 ] unit-test diff --git a/basis/db/tester/tester.factor b/basis/db/tester/tester.factor new file mode 100644 index 0000000000..4e53ad3df7 --- /dev/null +++ b/basis/db/tester/tester.factor @@ -0,0 +1,57 @@ +! Copyright (C) 2008 Slava Pestov, Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: concurrency.combinators db.pools db.sqlite db.tuples +db.types kernel math random threads tools.test db sequences +io prettyprint ; +IN: db.tester + +TUPLE: test-1 id a b c ; + +test-1 "TEST1" { + { "id" "ID" INTEGER +db-assigned-id+ } + { "a" "A" { VARCHAR 256 } +not-null+ } + { "b" "B" { VARCHAR 256 } +not-null+ } + { "c" "C" { VARCHAR 256 } +not-null+ } +} define-persistent + +TUPLE: test-2 id x y z ; + +test-2 "TEST2" { + { "id" "ID" INTEGER +db-assigned-id+ } + { "x" "X" { VARCHAR 256 } +not-null+ } + { "y" "Y" { VARCHAR 256 } +not-null+ } + { "z" "Z" { VARCHAR 256 } +not-null+ } +} define-persistent + +: sqlite-test-db ( -- db ) "test.db" ; +: test-db ( -- db ) "test.db" ; + +: db-tester ( test-db -- ) + [ + [ + test-1 ensure-table + test-2 ensure-table + ] with-db + ] [ + 10 [ + drop + 10 [ + dup [ + f 100 random 100 random 100 random test-1 boa + insert-tuple yield + ] with-db + ] times + ] with parallel-each + ] bi ; + +: db-tester2 ( test-db -- ) + [ + [ test-1 recreate-table ] with-db + ] [ + [ + 2 [ + 10 random 100 random 100 random 100 random test-1 boa + insert-tuple yield + ] parallel-each + ] with-db + ] bi ; diff --git a/basis/grouping/grouping-docs.factor b/basis/grouping/grouping-docs.factor index 1eff4820dd..b9af98d1f8 100644 --- a/basis/grouping/grouping-docs.factor +++ b/basis/grouping/grouping-docs.factor @@ -49,7 +49,7 @@ HELP: } { $example "USING: kernel prettyprint sequences grouping ;" - "{ 1 2 3 4 5 6 } 3 0 swap nth ." + "{ 1 2 3 4 5 6 } 3 first ." "{ 1 2 3 }" } } ; @@ -66,7 +66,7 @@ HELP: } { $example "USING: kernel prettyprint sequences grouping ;" - "{ 1 2 3 4 5 6 } 3 1 swap nth ." + "{ 1 2 3 4 5 6 } 3 second ." "T{ slice { from 3 } { to 6 } { seq { 1 2 3 4 5 6 } } }" } } ; diff --git a/basis/io/files/info/unix/unix-docs.factor b/basis/io/files/info/unix/unix-docs.factor index 0dff2e4419..a6ee2b9597 100644 --- a/basis/io/files/info/unix/unix-docs.factor +++ b/basis/io/files/info/unix/unix-docs.factor @@ -22,11 +22,11 @@ HELP: file-permissions { "n" integer } } { $description "Returns the Unix file permissions for a given file." } ; -HELP: file-username +HELP: file-user-name { $values { "path" "a pathname string" } { "string" string } } -{ $description "Returns the username for a given file." } ; +{ $description "Returns the user-name for a given file." } ; HELP: file-user-id { $values @@ -110,7 +110,7 @@ HELP: set-file-times HELP: set-file-user { $values { "path" "a pathname string" } { "string/id" "a string or a user id" } } -{ $description "Sets a file's user id from the given user id or username." } ; +{ $description "Sets a file's user id from the given user id or user-name." } ; HELP: set-file-modified-time { $values @@ -258,7 +258,7 @@ ARTICLE: "unix-file-timestamps" "Unix file timestamps" ARTICLE: "unix-file-ids" "Unix file user and group ids" "Reading file user data:" { $subsection file-user-id } -{ $subsection file-username } +{ $subsection file-user-name } "Setting file user data:" { $subsection set-file-user } "Reading file group data:" diff --git a/basis/io/files/info/unix/unix.factor b/basis/io/files/info/unix/unix.factor index 66b95db144..9287e7f4ad 100644 --- a/basis/io/files/info/unix/unix.factor +++ b/basis/io/files/info/unix/unix.factor @@ -243,8 +243,8 @@ M: string set-file-group ( path string -- ) : file-user-id ( path -- uid ) normalize-path file-info uid>> ; -: file-username ( path -- string ) - file-user-id username ; +: file-user-name ( path -- string ) + file-user-id user-name ; : file-group-id ( path -- gid ) normalize-path file-info gid>> ; diff --git a/basis/math/bitwise/bitwise-tests.factor b/basis/math/bitwise/bitwise-tests.factor index 979c62dcfb..40eb20642c 100644 --- a/basis/math/bitwise/bitwise-tests.factor +++ b/basis/math/bitwise/bitwise-tests.factor @@ -32,3 +32,7 @@ IN: math.bitwise.tests [ 8 ] [ 0 3 toggle-bit ] unit-test [ 0 ] [ 8 3 toggle-bit ] unit-test + +[ 4 ] [ BIN: 1010101 bit-count ] unit-test +[ 0 ] [ BIN: 0 bit-count ] unit-test +[ 1 ] [ BIN: 1 bit-count ] unit-test diff --git a/basis/math/bitwise/bitwise.factor b/basis/math/bitwise/bitwise.factor index 2c03164ae7..e60815bf60 100755 --- a/basis/math/bitwise/bitwise.factor +++ b/basis/math/bitwise/bitwise.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays kernel math math.functions sequences sequences.private words namespaces macros hints -combinators fry io.binary ; +combinators fry io.binary combinators.smart ; IN: math.bitwise ! utilities @@ -76,12 +76,14 @@ DEFER: byte-bit-count GENERIC: (bit-count) ( x -- n ) M: fixnum (bit-count) - { - [ byte-bit-count ] - [ -8 shift byte-bit-count ] - [ -16 shift byte-bit-count ] - [ -24 shift byte-bit-count ] - } cleave + + + ; + [ + { + [ byte-bit-count ] + [ -8 shift byte-bit-count ] + [ -16 shift byte-bit-count ] + [ -24 shift byte-bit-count ] + } cleave + ] sum-outputs ; M: bignum (bit-count) dup 0 = [ drop 0 ] [ diff --git a/basis/regexp/nfa/nfa.factor b/basis/regexp/nfa/nfa.factor index 7620652948..dd116f3d7a 100644 --- a/basis/regexp/nfa/nfa.factor +++ b/basis/regexp/nfa/nfa.factor @@ -3,7 +3,10 @@ USING: accessors arrays assocs grouping kernel regexp.backend locals math namespaces regexp.parser sequences fry quotations math.order math.ranges vectors unicode.categories regexp.utils -regexp.transition-tables words sets regexp.classes unicode.case ; +regexp.transition-tables words sets regexp.classes unicode.case.private ; +! This uses unicode.case.private for ch>upper and ch>lower +! but case-insensitive matching should be done by case-folding everything +! before processing starts IN: regexp.nfa SYMBOL: negation-mode @@ -160,6 +163,8 @@ M: LETTER-class nfa-node ( node -- ) M: character-class-range nfa-node ( node -- ) case-insensitive option? [ + ! This should be implemented for Unicode by case-folding + ! the input and all strings in the regexp. dup [ from>> ] [ to>> ] bi 2dup [ Letter? ] bi@ and [ rot drop diff --git a/basis/regexp/parser/parser.factor b/basis/regexp/parser/parser.factor index 25509ec798..2f397538a0 100644 --- a/basis/regexp/parser/parser.factor +++ b/basis/regexp/parser/parser.factor @@ -3,8 +3,8 @@ USING: accessors arrays assocs combinators io io.streams.string kernel math math.parser namespaces sets quotations sequences splitting vectors math.order -unicode.categories strings regexp.backend regexp.utils -unicode.case words locals regexp.classes ; +strings regexp.backend regexp.utils +unicode.case unicode.categories words locals regexp.classes ; IN: regexp.parser FROM: math.ranges => [a,b] ; @@ -261,7 +261,7 @@ ERROR: bad-escaped-literals seq ; parse-til-E drop1 [ epsilon ] [ - [ quot call ] V{ } map-as + quot call [ ] V{ } map-as first|concatenation ] if-empty ; inline @@ -269,10 +269,10 @@ ERROR: bad-escaped-literals seq ; [ ] (parse-escaped-literals) ; : lower-case-literals ( -- obj ) - [ ch>lower ] (parse-escaped-literals) ; + [ >lower ] (parse-escaped-literals) ; : upper-case-literals ( -- obj ) - [ ch>upper ] (parse-escaped-literals) ; + [ >upper ] (parse-escaped-literals) ; : parse-escaped ( -- obj ) read1 diff --git a/basis/sorting/human/human-docs.factor b/basis/sorting/human/human-docs.factor new file mode 100644 index 0000000000..5342b28317 --- /dev/null +++ b/basis/sorting/human/human-docs.factor @@ -0,0 +1,71 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax kernel math.order quotations +sequences strings ; +IN: sorting.human + +HELP: find-numbers +{ $values + { "string" string } + { "seq" sequence } +} +{ $description "Splits a string on numbers and returns a sequence of sequences and integers." } ; + +HELP: human-<=> +{ $values + { "obj1" object } { "obj2" object } + { "<=>" "an ordering specifier" } +} +{ $description "Compares two objects after converting numbers in the string into integers." } ; + +HELP: human->=< +{ $values + { "obj1" object } { "obj2" object } + { ">=<" "an ordering specifier" } +} +{ $description "Compares two objects using the " { $link human-<=> } " word and inverts the result." } ; + +HELP: human-compare +{ $values + { "obj1" object } { "obj2" object } { "quot" quotation } + { "<=>" "an ordering specifier" } +} +{ $description "Compares the results of applying the quotation to both objects via <=>." } ; + +HELP: human-sort +{ $values + { "seq" sequence } + { "seq'" sequence } +} +{ $description "Sorts a sequence of objects by comparing the magnitude of any integers in the input string using the <=> word." } ; + +HELP: human-sort-keys +{ $values + { "seq" "an alist" } + { "sortedseq" "a new sorted sequence" } +} +{ $description "Sorts the elements comparing first elements of pairs using the " { $link human-<=> } " word." } ; + +HELP: human-sort-values +{ $values + { "seq" "an alist" } + { "sortedseq" "a new sorted sequence" } +} +{ $description "Sorts the elements comparing second elements of pairs using the " { $link human-<=> } " word." } ; + +{ <=> >=< human-compare human-sort human-sort-keys human-sort-values } related-words + +ARTICLE: "sorting.human" "sorting.human" +"The " { $vocab-link "sorting.human" } " vocabulary sorts by numbers as a human would -- by comparing their magnitudes -- rather than in a lexicographic way. For example, sorting a1, a10, a03, a2 with human sort returns a1, a2, a03, a10, while sorting with natural sort returns a03, a1, a10, a2." $nl +"Comparing two objects:" +{ $subsection human-<=> } +{ $subsection human->=< } +{ $subsection human-compare } +"Sort a sequence:" +{ $subsection human-sort } +{ $subsection human-sort-keys } +{ $subsection human-sort-values } +"Splitting a string into substrings and integers:" +{ $subsection find-numbers } ; + +ABOUT: "sorting.human" diff --git a/basis/sorting/human/human.factor b/basis/sorting/human/human.factor index 1c2ba419c7..2c4d391a60 100644 --- a/basis/sorting/human/human.factor +++ b/basis/sorting/human/human.factor @@ -1,10 +1,22 @@ ! Copyright (C) 2008 Doug Coleman, Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: peg.ebnf math.parser kernel assocs sorting ; +USING: peg.ebnf math.parser kernel assocs sorting fry +math.order sequences ascii splitting.monotonic ; IN: sorting.human : find-numbers ( string -- seq ) [EBNF Result = ([0-9]+ => [[ string>number ]] | (!([0-9]) .)+)* EBNF] ; -: human-sort ( seq -- seq' ) - [ dup find-numbers ] { } map>assoc sort-values keys ; +: human-<=> ( obj1 obj2 -- <=> ) [ find-numbers ] bi@ <=> ; + +: human->=< ( obj1 obj2 -- >=< ) human-<=> invert-comparison ; inline + +: human-compare ( obj1 obj2 quot -- <=> ) bi@ human-<=> ; + +: human-sort ( seq -- seq' ) [ human-<=> ] sort ; + +: human-sort-keys ( seq -- sortedseq ) + [ [ first ] human-compare ] sort ; + +: human-sort-values ( seq -- sortedseq ) + [ [ second ] human-compare ] sort ; diff --git a/basis/sorting/slots/authors.txt b/basis/sorting/slots/authors.txt new file mode 100644 index 0000000000..5674120196 --- /dev/null +++ b/basis/sorting/slots/authors.txt @@ -0,0 +1,2 @@ +Doug Coleman +Slava Pestov diff --git a/basis/sorting/slots/slots-docs.factor b/basis/sorting/slots/slots-docs.factor new file mode 100644 index 0000000000..64d0a1efdf --- /dev/null +++ b/basis/sorting/slots/slots-docs.factor @@ -0,0 +1,42 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax kernel quotations math.order +sequences ; +IN: sorting.slots + +HELP: compare-slots +{ $values + { "sort-specs" "a sequence of accessor/comparator pairs" } + { "<=>" { $link +lt+ } " " { $link +eq+ } " or " { $link +gt+ } } +} +{ $description "Compares two objects using a chain of intrinsic linear orders such that if two objects are " { $link +eq+ } ", then the next comparator is tried. The comparators are slot-name/comparator pairs." } ; + +HELP: sort-by-slots +{ $values + { "seq" sequence } { "sort-specs" "a sequence of accessor/comparator pairs" } + { "seq'" sequence } +} +{ $description "Sorts a sequence of tuples by the sort-specs in " { $snippet "sort-spec" } ". A sort-spec is a slot accessor and a comparator." } +{ $examples + "Sort by slot c, then b descending:" + { $example + "USING: accessors math.order prettyprint sorting.slots ;" + "IN: scratchpad" + "TUPLE: sort-me a b ;" + "{" + " T{ sort-me f 2 3 } T{ sort-me f 3 2 }" + " T{ sort-me f 4 3 } T{ sort-me f 2 1 }" + "}" + "{ { a>> <=> } { b>> >=< } } sort-by-slots ." + "{\n T{ sort-me { a 2 } { b 3 } }\n T{ sort-me { a 2 } { b 1 } }\n T{ sort-me { a 3 } { b 2 } }\n T{ sort-me { a 4 } { b 3 } }\n}" + } +} ; + +ARTICLE: "sorting.slots" "Sorting by slots" +"The " { $vocab-link "sorting.slots" } " vocabulary can sort tuples by slot in ascending or descending order, using subsequent slots as tie-breakers." $nl +"Comparing two objects by a sequence of slots:" +{ $subsection compare-slots } +"Sorting a sequence by a sequence of slots:" +{ $subsection sort-by-slots } ; + +ABOUT: "sorting.slots" diff --git a/basis/sorting/slots/slots-tests.factor b/basis/sorting/slots/slots-tests.factor new file mode 100644 index 0000000000..ab130d1eed --- /dev/null +++ b/basis/sorting/slots/slots-tests.factor @@ -0,0 +1,50 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors math.order sorting.slots tools.test +sorting.human ; +IN: sorting.literals.tests + +TUPLE: sort-test a b c ; + +[ + { + T{ sort-test { a 1 } { b 3 } { c 9 } } + T{ sort-test { a 1 } { b 1 } { c 10 } } + T{ sort-test { a 1 } { b 1 } { c 11 } } + T{ sort-test { a 2 } { b 5 } { c 2 } } + T{ sort-test { a 2 } { b 5 } { c 3 } } + } +] [ + { + T{ sort-test f 1 3 9 } + T{ sort-test f 1 1 10 } + T{ sort-test f 1 1 11 } + T{ sort-test f 2 5 3 } + T{ sort-test f 2 5 2 } + } { { a>> <=> } { b>> >=< } { c>> <=> } } sort-by-slots +] unit-test + +[ + { + T{ sort-test { a 1 } { b 3 } { c 9 } } + T{ sort-test { a 1 } { b 1 } { c 10 } } + T{ sort-test { a 1 } { b 1 } { c 11 } } + T{ sort-test { a 2 } { b 5 } { c 2 } } + T{ sort-test { a 2 } { b 5 } { c 3 } } + } +] [ + { + T{ sort-test f 1 3 9 } + T{ sort-test f 1 1 10 } + T{ sort-test f 1 1 11 } + T{ sort-test f 2 5 3 } + T{ sort-test f 2 5 2 } + } { { a>> human-<=> } { b>> human->=< } { c>> <=> } } sort-by-slots +] unit-test + +[ + { } +] [ + { } + { { a>> <=> } { b>> >=< } { c>> <=> } } sort-by-slots +] unit-test diff --git a/basis/sorting/slots/slots.factor b/basis/sorting/slots/slots.factor new file mode 100644 index 0000000000..02a11428f9 --- /dev/null +++ b/basis/sorting/slots/slots.factor @@ -0,0 +1,19 @@ +! Copyright (C) 2009 Slava Pestov, Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: combinators.short-circuit fry kernel macros math.order +sequences words sorting ; +IN: sorting.slots + + + +MACRO: compare-slots ( sort-specs -- <=> ) + #! sort-spec: { accessor comparator } + [ first2 slot-comparator ] map '[ _ 2|| +eq+ or ] ; + +: sort-by-slots ( seq sort-specs -- seq' ) + '[ _ compare-slots ] sort ; diff --git a/basis/soundex/soundex.factor b/basis/soundex/soundex.factor index 416ec4a6bc..164f634185 100644 --- a/basis/soundex/soundex.factor +++ b/basis/soundex/soundex.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: sequences grouping assocs kernel ascii unicode.case tr ; +USING: sequences grouping assocs kernel ascii ascii tr ; IN: soundex TR: soundex-tr diff --git a/basis/splitting/monotonic/monotonic-docs.factor b/basis/splitting/monotonic/monotonic-docs.factor new file mode 100644 index 0000000000..983c5b0dea --- /dev/null +++ b/basis/splitting/monotonic/monotonic-docs.factor @@ -0,0 +1,109 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax kernel quotations classes sequences +multiline ; +IN: splitting.monotonic + +HELP: monotonic-slice +{ $values + { "seq" sequence } { "quot" quotation } { "class" class } + { "slices" "a sequence of slices" } +} +{ $description "Monotonically splits a sequence into slices of the type " { $snippet "class" } "." } +{ $examples + { $example + "USING: splitting.monotonic math prettyprint ;" + "{ 1 2 3 2 3 4 } [ < ] upward-slice monotonic-slice ." + <" { + T{ upward-slice + { from 0 } + { to 3 } + { seq { 1 2 3 2 3 4 } } + } + T{ upward-slice + { from 3 } + { to 6 } + { seq { 1 2 3 2 3 4 } } + } +}"> + } +} ; + +HELP: monotonic-split +{ $values + { "seq" sequence } { "quot" quotation } + { "newseq" "a sequence of sequences" } +} +{ $description "Compares pairs of elements in a sequence and collects elements into sequences while they satisfy the predicate. Once the predicate fails, a new sequence is started, and all sequences are returned in a single sequence." } +{ $examples + { $example + "USING: splitting.monotonic math prettyprint ;" + "{ 1 2 3 2 3 4 } [ < ] monotonic-split ." + "{ V{ 1 2 3 } V{ 2 3 4 } }" + } +} ; + +HELP: downward-slices +{ $values + { "seq" sequence } + { "slices" "a sequence of downward-slices" } +} +{ $description "Returns an array of monotonically decreasing slices of type " { $link downward-slice } ". Slices of one element are discarded." } ; + +HELP: stable-slices +{ $values + { "seq" sequence } + { "slices" "a sequence of stable-slices" } +} +{ $description "Returns an array of monotonically decreasing slices of type " { $link downward-slice } ". Slices of one element are discarded." } ; + +HELP: upward-slices +{ $values + { "seq" sequence } + { "slices" "a sequence of upward-slices" } +} +{ $description "Returns an array of monotonically increasing slices of type " { $link downward-slice } ". Slices of one element are discarded." } ; + +HELP: trends +{ $values + { "seq" sequence } + { "slices" "a sequence of downward, stable, and upward slices" } +} +{ $description "Returns a sorted sequence of downward, stable, or upward slices. The endpoints of some slices may overlap with each other." } +{ $examples + { $example + "USING: splitting.monotonic math prettyprint ;" + "{ 1 2 3 3 2 1 } trends ." + <" { + T{ upward-slice + { from 0 } + { to 3 } + { seq { 1 2 3 3 2 1 } } + } + T{ stable-slice + { from 2 } + { to 4 } + { seq { 1 2 3 3 2 1 } } + } + T{ downward-slice + { from 3 } + { to 6 } + { seq { 1 2 3 3 2 1 } } + } +}"> + } +} ; + +ARTICLE: "splitting.monotonic" "Splitting trending sequences" +"The " { $vocab-link "splitting.monotonic" } " vocabulary splits sequences that are trending downwards, upwards, or stably." $nl +"Splitting into sequences:" +{ $subsection monotonic-split } +"Splitting into slices:" +{ $subsection monotonic-slice } +"Trending:" +{ $subsection downward-slices } +{ $subsection stable-slices } +{ $subsection upward-slices } +{ $subsection trends } ; + +ABOUT: "splitting.monotonic" diff --git a/basis/splitting/monotonic/monotonic-tests.factor b/basis/splitting/monotonic/monotonic-tests.factor index ab4c48b292..7bf9a38e8a 100644 --- a/basis/splitting/monotonic/monotonic-tests.factor +++ b/basis/splitting/monotonic/monotonic-tests.factor @@ -6,3 +6,48 @@ USING: tools.test math arrays kernel sequences ; [ { { 1 1 1 1 } { 2 2 } { 3 } { 4 } { 5 } { 6 6 6 } } ] [ { 1 1 1 1 2 2 3 4 5 6 6 6 } [ = ] monotonic-split [ >array ] map ] unit-test +[ { } ] +[ { } [ = ] slice monotonic-slice ] unit-test + +[ t ] +[ { 1 } [ = ] slice monotonic-slice [ slice? ] all? ] unit-test + +[ { { 1 } } ] +[ { 1 } [ = ] slice monotonic-slice [ >array ] map ] unit-test + +[ t ] +[ { 1 1 1 2 2 3 3 4 } [ = ] slice monotonic-slice [ slice? ] all? ] unit-test + +[ { { 1 1 1 } { 2 2 } { 3 3 } { 4 } } ] +[ { 1 1 1 2 2 3 3 4 } [ = ] slice monotonic-slice [ >array ] map ] unit-test + +[ { { 3 3 } } ] +[ { 3 3 } [ = ] slice monotonic-slice [ >array ] map ] unit-test + +[ + { + T{ upward-slice { from 0 } { to 3 } { seq { 1 2 3 2 1 } } } + T{ downward-slice { from 2 } { to 5 } { seq { 1 2 3 2 1 } } } + } +] +[ { 1 2 3 2 1 } trends ] unit-test + +[ + { + T{ upward-slice + { from 0 } + { to 3 } + { seq { 1 2 3 3 2 1 } } + } + T{ stable-slice + { from 2 } + { to 4 } + { seq { 1 2 3 3 2 1 } } + } + T{ downward-slice + { from 3 } + { to 6 } + { seq { 1 2 3 3 2 1 } } + } + } +] [ { 1 2 3 3 2 1 } trends ] unit-test diff --git a/basis/splitting/monotonic/monotonic.factor b/basis/splitting/monotonic/monotonic.factor index 5bc7a51522..e39bba25ab 100644 --- a/basis/splitting/monotonic/monotonic.factor +++ b/basis/splitting/monotonic/monotonic.factor @@ -1,8 +1,11 @@ -! Copyright (C) 2008 Doug Coleman. +! Copyright (C) 2008, 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: make namespaces sequences kernel fry ; +USING: make namespaces sequences kernel fry arrays compiler.utilities +math accessors circular grouping combinators sorting math.order ; IN: splitting.monotonic + + : monotonic-split ( seq quot -- newseq ) over empty? [ 2drop { } ] [ (monotonic-split) ] if ; inline + + 1 over change-circular-start ] tri + [ @ not [ , ] [ drop ] if ] 3each + ] { } make + dup empty? [ over length 1- prefix ] when -1 prefix 2 clump + [ first2 [ 1+ ] bi@ rot roll boa ] with with map ; inline + +PRIVATE> + +: monotonic-slice ( seq quot class -- slices ) + pick length { + { 0 [ 2drop ] } + { 1 [ nip [ 0 1 rot ] dip boa 1array ] } + [ drop (monotonic-slice) ] + } case ; + +TUPLE: downward-slice < slice ; +TUPLE: stable-slice < slice ; +TUPLE: upward-slice < slice ; + +: downward-slices ( seq -- slices ) + [ > ] downward-slice monotonic-slice [ length 1 > ] filter ; + +: stable-slices ( seq -- slices ) + [ = ] stable-slice monotonic-slice [ length 1 > ] filter ; + +: upward-slices ( seq -- slices ) + [ < ] upward-slice monotonic-slice [ length 1 > ] filter ; + +: trends ( seq -- slices ) + dup length { + { 0 [ ] } + { 1 [ [ 0 1 ] dip stable-slice boa ] } + [ + drop + [ downward-slices ] + [ stable-slices ] + [ upward-slices ] tri 3append [ [ from>> ] compare ] sort + ] + } case ; diff --git a/basis/tools/cocoa/cocoa.factor b/basis/tools/cocoa/cocoa.factor index a8cdf6f41c..9dd1895a68 100644 --- a/basis/tools/cocoa/cocoa.factor +++ b/basis/tools/cocoa/cocoa.factor @@ -1,16 +1,18 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: arrays cocoa.messages cocoa.runtime combinators -prettyprint ; +prettyprint combinators.smart ; IN: tools.cocoa : method. ( method -- ) - { - [ method_getName sel_getName ] - [ method-return-type ] - [ method-arg-types ] - [ method_getImplementation ] - } cleave 4array . ; + [ + { + [ method_getName sel_getName ] + [ method-return-type ] + [ method-arg-types ] + [ method_getImplementation ] + } cleave + ] output>array . ; : methods. ( class -- ) [ method. ] each-method-in-class ; diff --git a/basis/tools/files/files.factor b/basis/tools/files/files.factor index 3670891e41..e6ca02d5f9 100755 --- a/basis/tools/files/files.factor +++ b/basis/tools/files/files.factor @@ -5,6 +5,8 @@ io.directories kernel math.parser sequences system vocabs.loader calendar math fry prettyprint ; IN: tools.files +SYMBOLS: permissions file-name nlinks file-size date ; + > file-type>ch 1string ] - [ user-read? read>string ] - [ user-write? write>string ] - [ [ uid? ] [ user-execute? ] bi 2array "s" unix-execute>string ] - [ group-read? read>string ] - [ group-write? write>string ] - [ [ gid? ] [ group-execute? ] bi 2array "s" unix-execute>string ] - [ other-read? read>string ] - [ other-write? write>string ] - [ [ sticky? ] [ other-execute? ] bi 2array "t" unix-execute>string ] - } cleave 10 narray concat ; + [ + { + [ type>> file-type>ch 1string ] + [ user-read? read>string ] + [ user-write? write>string ] + [ [ uid? ] [ user-execute? ] bi 2array "s" unix-execute>string ] + [ group-read? read>string ] + [ group-write? write>string ] + [ [ gid? ] [ group-execute? ] bi 2array "s" unix-execute>string ] + [ other-read? read>string ] + [ other-write? write>string ] + [ [ sticky? ] [ other-execute? ] bi 2array "t" unix-execute>string ] + } cleave + ] output>array concat ; : mode>symbol ( mode -- ch ) S_IFMT bitand @@ -45,15 +47,16 @@ IN: tools.files.unix M: unix (directory.) ( path -- lines ) [ [ [ - dup file-info - { - [ permissions-string ] - [ nlink>> number>string 3 CHAR: \s pad-left ] - ! [ uid>> ] - ! [ gid>> ] - [ size>> number>string 15 CHAR: \s pad-left ] - [ modified>> ls-timestamp ] - } cleave 4 narray swap suffix " " join + dup file-info [ + { + [ permissions-string ] + [ nlink>> number>string 3 CHAR: \s pad-left ] + [ uid>> user-name ] + [ gid>> group-name ] + [ size>> number>string 15 CHAR: \s pad-left ] + [ modified>> ls-timestamp ] + } cleave + ] output>array swap suffix " " join ] map ] with-group-cache ] with-user-cache ; diff --git a/basis/tr/tr-tests.factor b/basis/tr/tr-tests.factor index c168f5384d..3434c28216 100644 --- a/basis/tr/tr-tests.factor +++ b/basis/tr/tr-tests.factor @@ -1,5 +1,5 @@ IN: tr.tests -USING: tr tools.test unicode.case ; +USING: tr tools.test ascii ; TR: tr-test ch>upper "ABC" "XYZ" ; diff --git a/basis/tr/tr.factor b/basis/tr/tr.factor index 66d8df7d44..ce535f335a 100644 --- a/basis/tr/tr.factor +++ b/basis/tr/tr.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: byte-arrays strings sequences sequences.private +USING: byte-arrays strings sequences sequences.private ascii fry kernel words parser lexer assocs math math.order summary ; IN: tr @@ -11,8 +11,6 @@ M: bad-tr summary array ; : checkmark-vertices ( dim -- vertices ) checkmark-points concat >float-array ; diff --git a/basis/unicode/breaks/breaks.factor b/basis/unicode/breaks/breaks.factor index 1d2f821750..df3b2f03e8 100644 --- a/basis/unicode/breaks/breaks.factor +++ b/basis/unicode/breaks/breaks.factor @@ -192,22 +192,22 @@ to: word-table : word-table-nth ( class1 class2 -- ? ) word-table nth nth ; -: property-not= ( i str property -- ? ) - pick [ - [ ?nth ] dip swap - [ word-break-prop = not ] [ drop f ] if* - ] [ 3drop t ] if ; +:: property-not= ( i str property -- ? ) + i [ + i str ?nth [ word-break-prop property = not ] + [ f ] if* + ] [ t ] if ; : format/extended? ( ch -- ? ) word-break-prop { 4 5 } member? ; :: walk-up ( str i -- j ) i 1 + str [ format/extended? not ] find-from drop - 1+ str [ format/extended? not ] find-from drop ; ! possible bounds error? + [ 1+ str [ format/extended? not ] find-from drop ] [ f ] if* ; :: walk-down ( str i -- j ) i str [ format/extended? not ] find-last-from drop - 1- str [ format/extended? not ] find-last-from drop ; ! possible bounds error? + [ 1- str [ format/extended? not ] find-last-from drop ] [ f ] if* ; :: word-break? ( table-entry i str -- ? ) table-entry { @@ -224,9 +224,11 @@ to: word-table } case ; :: word-break-next ( old-class new-char i str -- next-class ? ) - new-char word-break-prop dup { 4 5 } member? - [ drop old-class dup { 1 2 3 } member? ] - [ old-class over word-table-nth i str word-break? ] if ; + new-char dup format/extended? + [ drop old-class dup { 1 2 3 } member? ] [ + word-break-prop old-class over word-table-nth + i str word-break? + ] if ; PRIVATE> diff --git a/basis/unicode/case/case-docs.factor b/basis/unicode/case/case-docs.factor index da582c659a..02da8e7635 100644 --- a/basis/unicode/case/case-docs.factor +++ b/basis/unicode/case/case-docs.factor @@ -9,10 +9,6 @@ ARTICLE: "unicode.case" "Case mapping" { $subsection >lower } { $subsection >title } { $subsection >case-fold } -"There are analogous routines which operate on individual code points, but these should " { $emphasis "not be used" } " in general as they have slightly different behavior. In some cases, for example, they do not perform the case operation, as a single code point must expand to more than one." -{ $subsection ch>upper } -{ $subsection ch>lower } -{ $subsection ch>title } "To test if a string is in a given case:" { $subsection upper? } { $subsection lower? } @@ -53,18 +49,3 @@ HELP: title? HELP: case-fold? { $values { "string" string } { "?" "a boolean" } } { $description "Tests if a string is in case-folded form." } ; - -HELP: ch>lower -{ $values { "ch" "a code point" } { "lower" "a code point" } } -{ $description "Converts a code point to lower case." } -{ $warning "Don't use this unless you know what you're doing! " { $code ">lower" } " is not the same as " { $code "[ ch>lower ] map" } "." } ; - -HELP: ch>upper -{ $values { "ch" "a code point" } { "upper" "a code point" } } -{ $description "Converts a code point to upper case." } -{ $warning "Don't use this unless you know what you're doing! " { $code ">upper" } " is not the same as " { $code "[ ch>upper ] map" } "." } ; - -HELP: ch>title -{ $values { "ch" "a code point" } { "title" "a code point" } } -{ $description "Converts a code point to title case." } -{ $warning "Don't use this unless you know what you're doing! " { $code ">title" } " is not the same as " { $code "[ ch>title ] map" } "." } ; diff --git a/basis/unicode/case/case.factor b/basis/unicode/case/case.factor index b0472cd9cb..773bbeed5f 100644 --- a/basis/unicode/case/case.factor +++ b/basis/unicode/case/case.factor @@ -1,24 +1,24 @@ ! Copyright (C) 2008 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: unicode.data sequences sequences.next namespaces make +USING: unicode.data sequences sequences.next namespaces make unicode.syntax unicode.normalize math unicode.categories combinators unicode.syntax assocs strings splitting kernel accessors unicode.breaks fry ; IN: unicode.case : ch>lower ( ch -- lower ) simple-lower at-default ; : ch>upper ( ch -- upper ) simple-upper at-default ; : ch>title ( ch -- title ) simple-title at-default ; +PRIVATE> SYMBOL: locale ! Just casing locale, or overall? char ( name -- char ) name-map at ; : char>name ( char -- name ) name-map value-at ; : property? ( char property -- ? ) properties at interval-key? ; @@ -128,12 +129,9 @@ VALUE: properties cat categories index char table ?set-nth ] assoc-each table fill-ranges ] ; -: ascii-lower ( string -- lower ) - [ dup CHAR: A CHAR: Z between? [ HEX: 20 + ] when ] map ; - : process-names ( data -- names-hash ) 1 swap (process-data) [ - ascii-lower { { CHAR: \s CHAR: - } } substitute swap + >lower { { CHAR: \s CHAR: - } } substitute swap ] H{ } assoc-map-as ; : multihex ( hexstring -- string ) @@ -183,6 +181,13 @@ load-data { [ process-category to: category-map ] } cleave +: postprocess-class ( -- ) + combine-map [ [ second ] map ] map concat + [ combining-class not ] filter + [ 0 swap class-map set-at ] each ; + +postprocess-class + load-special-casing to: special-casing load-properties to: properties @@ -214,3 +219,6 @@ SYMBOL: interned : load-script ( filename -- table ) ascii parse-script process-script ; + +[ name>char [ "Invalid character" throw ] unless* ] +name>char-hook set-global diff --git a/basis/unicode/normalize/normalize.factor b/basis/unicode/normalize/normalize.factor index 58ce412a2e..7a41a768cd 100644 --- a/basis/unicode/normalize/normalize.factor +++ b/basis/unicode/normalize/normalize.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2008 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: sequences namespaces make unicode.data kernel math arrays -locals sorting.insertion accessors assocs math.order ; +locals sorting.insertion accessors assocs math.order combinators +unicode.syntax strings sbufs ; IN: unicode.normalize jamo % ] - [ dup quot call [ % ] [ , ] ?if ] if - ] each - ] "" make - dup reorder - ] if ; inline + [let | out [ string length ] | + string [ + dup hangul? [ hangul>jamo out push-all ] + [ dup quot call [ out push-all ] [ out push ] ?if ] if + ] each out >string + ] dup reorder ; + +: with-string ( str quot -- str ) + over aux>> [ call ] [ drop ] if ; inline + +: (nfd) ( string -- nfd ) + [ canonical-entry ] decompose ; + +: (nfkd) ( string -- nfkd ) + [ compatibility-entry ] decompose ; PRIVATE> : nfd ( string -- nfd ) - [ canonical-entry ] decompose ; + [ (nfd) ] with-string ; : nfkd ( string -- nfkd ) - [ compatibility-entry ] decompose ; + [ (nfkd) ] with-string ; : string-append ( s1 s2 -- string ) [ append ] keep @@ -138,20 +142,26 @@ DEFER: compose-iter : compose-iter ( last-class -- ) current [ - dup combining-class - [ try-compose to compose-iter ] - [ swap [ drop ] [ try-noncombining ] if ] if* + dup combining-class { + { f [ 2drop ] } + { 0 [ swap [ drop ] [ try-noncombining ] if ] } + [ try-compose to compose-iter ] + } case ] [ drop ] if* ; : ?new-after ( -- ) after [ dup empty? [ drop SBUF" " clone ] unless ] change ; +: compose-combining ( ch -- ) + char set to ?new-after + f compose-iter + char get , after get % ; + : (compose) ( -- ) current [ dup jamo? [ drop compose-jamo ] [ - char set to ?new-after - f compose-iter - char get , after get % + 1 get-str combining-class + [ compose-combining ] [ , to ] if ] if (compose) ] when* ; @@ -166,7 +176,7 @@ DEFER: compose-iter PRIVATE> : nfc ( string -- nfc ) - nfd combine ; + [ (nfd) combine ] with-string ; : nfkc ( string -- nfkc ) - nfkd combine ; + [ (nfkd) combine ] with-string ; diff --git a/basis/unix/groups/groups-tests.factor b/basis/unix/groups/groups-tests.factor index 7e7ebd902a..75f5d64b5f 100644 --- a/basis/unix/groups/groups-tests.factor +++ b/basis/unix/groups/groups-tests.factor @@ -3,7 +3,6 @@ USING: tools.test unix.groups kernel strings math ; IN: unix.groups.tests - [ ] [ all-groups drop ] unit-test \ all-groups must-infer @@ -24,3 +23,7 @@ IN: unix.groups.tests [ ] [ effective-group-id [ ] with-effective-group ] unit-test [ ] [ [ ] with-group-cache ] unit-test + +[ ] [ real-group-id group-name drop ] unit-test + +[ "888888888888888" ] [ 888888888888888 group-name ] unit-test diff --git a/basis/unix/groups/groups.factor b/basis/unix/groups/groups.factor index 60785a5b17..164afa46fb 100644 --- a/basis/unix/groups/groups.factor +++ b/basis/unix/groups/groups.factor @@ -43,7 +43,7 @@ PRIVATE> : group-name ( id -- string ) dup group-cache get [ - at + dupd at* [ name>> nip ] [ drop number>string ] if ] [ group-struct group-gr_name ] if* @@ -71,7 +71,7 @@ M: string user-groups ( string -- seq ) (user-groups) ; M: integer user-groups ( id -- seq ) - username (user-groups) ; + user-name (user-groups) ; : all-groups ( -- seq ) [ getgrent dup ] [ group-struct>group ] [ drop ] produce ; diff --git a/basis/unix/users/users-docs.factor b/basis/unix/users/users-docs.factor index 0740561cc1..2d46ab2d81 100644 --- a/basis/unix/users/users-docs.factor +++ b/basis/unix/users/users-docs.factor @@ -7,13 +7,13 @@ HELP: all-users { $values { "seq" sequence } } { $description "Returns a sequence of high-level " { $link passwd } " tuples that are platform-dependent and field for field complete with the Unix " { $link passwd } " structure." } ; -HELP: effective-username +HELP: effective-user-name { $values { "string" string } } -{ $description "Returns the effective username for the current user." } ; +{ $description "Returns the effective user-name for the current user." } ; HELP: effective-user-id { $values { "id" integer } } -{ $description "Returns the effective username id for the current user." } ; +{ $description "Returns the effective user-name id for the current user." } ; HELP: new-passwd { $values { "passwd" passwd } } @@ -31,9 +31,9 @@ HELP: passwd>new-passwd { "new-passwd" "a passwd tuple" } } { $description "A platform-specific conversion routine from a passwd structure to a passwd tuple." } ; -HELP: real-username +HELP: real-user-name { $values { "string" string } } -{ $description "The real username of the current user." } ; +{ $description "The real user-name of the current user." } ; HELP: real-user-id { $values { "id" integer } } @@ -41,34 +41,34 @@ HELP: real-user-id HELP: set-effective-user { $values { "string/id" "a string or a user id" } } -{ $description "Sets the current effective user given a username or a user id." } ; +{ $description "Sets the current effective user given a user-name or a user id." } ; HELP: set-real-user { $values { "string/id" "a string or a user id" } } -{ $description "Sets the current real user given a username or a user id." } ; +{ $description "Sets the current real user given a user-name or a user id." } ; HELP: user-passwd { $values { "obj" object } { "passwd/f" "passwd or f" } } -{ $description "Returns the passwd tuple given a username string or user id." } ; +{ $description "Returns the passwd tuple given a user-name string or user id." } ; -HELP: username +HELP: user-name { $values { "id" integer } { "string" string } } -{ $description "Returns the username associated with the user id." } ; +{ $description "Returns the user-name associated with the user id." } ; HELP: user-id { $values { "string" string } { "id" integer } } -{ $description "Returns the user id associated with the username." } ; +{ $description "Returns the user id associated with the user-name." } ; HELP: with-effective-user { $values { "string/id" "a string or a uid" } { "quot" quotation } } -{ $description "Sets the effective username and calls the quotation. Restores the current username on success or on error after the call." } ; +{ $description "Sets the effective user-name and calls the quotation. Restores the current user-name on success or on error after the call." } ; HELP: with-user-cache { $values @@ -78,11 +78,11 @@ HELP: with-user-cache HELP: with-real-user { $values { "string/id" "a string or a uid" } { "quot" quotation } } -{ $description "Sets the real username and calls the quotation. Restores the current username on success or on error after the call." } ; +{ $description "Sets the real user-name and calls the quotation. Restores the current user-name on success or on error after the call." } ; { - real-username real-user-id set-real-user - effective-username effective-user-id + real-user-name real-user-id set-real-user + effective-user-name effective-user-id set-effective-user } related-words @@ -93,11 +93,11 @@ $nl { $subsection all-users } "Returning a passwd tuple:" "Real user:" -{ $subsection real-username } +{ $subsection real-user-name } { $subsection real-user-id } { $subsection set-real-user } "Effective user:" -{ $subsection effective-username } +{ $subsection effective-user-name } { $subsection effective-user-id } { $subsection set-effective-user } "Combinators to change users:" diff --git a/basis/unix/users/users-tests.factor b/basis/unix/users/users-tests.factor index 5a4639c856..f2a4b7bc27 100644 --- a/basis/unix/users/users-tests.factor +++ b/basis/unix/users/users-tests.factor @@ -8,8 +8,8 @@ IN: unix.users.tests \ all-users must-infer -[ t ] [ real-username string? ] unit-test -[ t ] [ effective-username string? ] unit-test +[ t ] [ real-user-name string? ] unit-test +[ t ] [ effective-user-name string? ] unit-test [ t ] [ real-user-id integer? ] unit-test [ t ] [ effective-user-id integer? ] unit-test @@ -17,14 +17,14 @@ IN: unix.users.tests [ ] [ real-user-id set-real-user ] unit-test [ ] [ effective-user-id set-effective-user ] unit-test -[ ] [ real-username [ ] with-real-user ] unit-test +[ ] [ real-user-name [ ] with-real-user ] unit-test [ ] [ real-user-id [ ] with-real-user ] unit-test -[ ] [ effective-username [ ] with-effective-user ] unit-test +[ ] [ effective-user-name [ ] with-effective-user ] unit-test [ ] [ effective-user-id [ ] with-effective-user ] unit-test [ ] [ [ ] with-user-cache ] unit-test -[ "9999999999999999999" ] [ 9999999999999999999 username ] unit-test +[ "9999999999999999999" ] [ 9999999999999999999 user-name ] unit-test [ f ] [ 89898989898989898989898989898 user-passwd ] unit-test diff --git a/basis/unix/users/users.factor b/basis/unix/users/users.factor index 21538080c9..da38972955 100644 --- a/basis/unix/users/users.factor +++ b/basis/unix/users/users.factor @@ -7,7 +7,7 @@ accessors math.parser fry assocs namespaces continuations vocabs.loader system ; IN: unix.users -TUPLE: passwd username password uid gid gecos dir shell ; +TUPLE: passwd user-name password uid gid gecos dir shell ; HOOK: new-passwd os ( -- passwd ) HOOK: passwd>new-passwd os ( passwd -- new-passwd ) @@ -20,7 +20,7 @@ M: unix new-passwd ( -- passwd ) M: unix passwd>new-passwd ( passwd -- seq ) [ new-passwd ] dip { - [ passwd-pw_name >>username ] + [ passwd-pw_name >>user-name ] [ passwd-pw_passwd >>password ] [ passwd-pw_uid >>uid ] [ passwd-pw_gid >>gid ] @@ -56,9 +56,9 @@ M: integer user-passwd ( id -- passwd/f ) M: string user-passwd ( string -- passwd/f ) getpwnam dup [ passwd>new-passwd ] when ; -: username ( id -- string ) +: user-name ( id -- string ) dup user-passwd - [ nip username>> ] [ number>string ] if* ; + [ nip user-name>> ] [ number>string ] if* ; : user-id ( string -- id ) user-passwd uid>> ; @@ -66,14 +66,14 @@ M: string user-passwd ( string -- passwd/f ) : real-user-id ( -- id ) getuid ; inline -: real-username ( -- string ) - real-user-id username ; inline +: real-user-name ( -- string ) + real-user-id user-name ; inline : effective-user-id ( -- id ) geteuid ; inline -: effective-username ( -- string ) - effective-user-id username ; inline +: effective-user-name ( -- string ) + effective-user-id user-name ; inline GENERIC: set-real-user ( string/id -- ) diff --git a/basis/values/values-docs.factor b/basis/values/values-docs.factor index 866af469e9..59bf77da3a 100644 --- a/basis/values/values-docs.factor +++ b/basis/values/values-docs.factor @@ -15,7 +15,16 @@ ABOUT: "values" HELP: VALUE: { $syntax "VALUE: word" } { $values { "word" "a word to be created" } } -{ $description "Creates a value on the given word, initializing it to hold " { $code f } ". To get the value, just run the word. To set it, use " { $link set-value } "." } ; +{ $description "Creates a value on the given word, initializing it to hold " { $snippet "f" } ". To get the value, just run the word. To set it, use " { $link POSTPONE: to: } "." } +{ $examples + { $example + "USING: values math prettyprint ;" + "VALUE: x" + "2 2 + to: x" + "x ." + "4" + } +} ; HELP: get-value { $values { "word" "a value word" } { "value" "the contents" } } diff --git a/basis/xmode/marker/marker.factor b/basis/xmode/marker/marker.factor index c37d60df14..3e632cc5af 100644 --- a/basis/xmode/marker/marker.factor +++ b/basis/xmode/marker/marker.factor @@ -5,7 +5,7 @@ USING: kernel namespaces make xmode.rules xmode.tokens xmode.marker.state xmode.marker.context xmode.utilities xmode.catalog sequences math assocs combinators strings parser-combinators.regexp splitting parser-combinators ascii -unicode.case combinators.short-circuit accessors ; +ascii combinators.short-circuit accessors ; ! Based on org.gjt.sp.jedit.syntax.TokenMarker diff --git a/core/math/order/order-docs.factor b/core/math/order/order-docs.factor index ef006bbc21..1bdd1009e9 100644 --- a/core/math/order/order-docs.factor +++ b/core/math/order/order-docs.factor @@ -15,6 +15,12 @@ HELP: <=> } } ; +HELP: >=< +{ $values { "obj1" object } { "obj2" object } { ">=<" "an ordering specifier" } } +{ $description "Compares two objects using the " { $link <=> } " comparator and inverts the output." } ; + +{ <=> >=< } related-words + HELP: +lt+ { $description "Output by " { $link <=> } " when the first object is strictly less than the second object." } ; @@ -85,6 +91,7 @@ ARTICLE: "order-specifiers" "Ordering specifiers" ARTICLE: "math.order" "Linear order protocol" "Some classes have an intrinsic order amongst instances:" { $subsection <=> } +{ $subsection >=< } { $subsection compare } { $subsection invert-comparison } "The above words output order specifiers." diff --git a/core/math/order/order.factor b/core/math/order/order.factor index aae5841185..a06209bf63 100644 --- a/core/math/order/order.factor +++ b/core/math/order/order.factor @@ -13,6 +13,8 @@ SYMBOL: +gt+ GENERIC: <=> ( obj1 obj2 -- <=> ) +: >=< ( obj1 obj2 -- >=< ) <=> invert-comparison ; inline + M: real <=> 2dup < [ 2drop +lt+ ] [ number= +eq+ +gt+ ? ] if ; GENERIC: before? ( obj1 obj2 -- ? ) diff --git a/extra/benchmark/reverse-complement/reverse-complement.factor b/extra/benchmark/reverse-complement/reverse-complement.factor index 3298706da3..4147ffabdf 100755 --- a/extra/benchmark/reverse-complement/reverse-complement.factor +++ b/extra/benchmark/reverse-complement/reverse-complement.factor @@ -3,7 +3,7 @@ USING: io io.files io.files.temp io.streams.duplex kernel sequences sequences.private strings vectors words memoize splitting grouping hints tr continuations io.encodings.ascii -unicode.case ; +ascii ; IN: benchmark.reverse-complement TR: trans-map ch>upper "ACGTUMRYKVHDB" "TGCAAKYRMBDHV" ; diff --git a/extra/geo-ip/geo-ip.factor b/extra/geo-ip/geo-ip.factor index c878306d7d..ad6302ca55 100644 --- a/extra/geo-ip/geo-ip.factor +++ b/extra/geo-ip/geo-ip.factor @@ -4,7 +4,7 @@ USING: kernel sequences io.files io.files.temp io.launcher io.pathnames io.encodings.ascii io.streams.string http.client generalizations combinators math.parser math.vectors math.intervals interval-maps memoize csv accessors assocs -strings math splitting grouping arrays ; +strings math splitting grouping arrays combinators.smart ; IN: geo-ip : db-path ( -- path ) "IpToCountry.csv" temp-file ; @@ -20,15 +20,17 @@ IN: geo-ip TUPLE: ip-entry from to registry assigned city cntry country ; : parse-ip-entry ( row -- ip-entry ) - 7 firstn { - [ string>number ] - [ string>number ] - [ ] - [ ] - [ ] - [ ] - [ ] - } spread ip-entry boa ; + [ + { + [ string>number ] + [ string>number ] + [ ] + [ ] + [ ] + [ ] + [ ] + } spread + ] input> "Minneapolis" = ] unit-test diff --git a/extra/usa-cities/usa-cities.factor b/extra/usa-cities/usa-cities.factor index deb3e15845..25ec30ac78 100644 --- a/extra/usa-cities/usa-cities.factor +++ b/extra/usa-cities/usa-cities.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: io.files io.encodings.ascii sequences generalizations math.parser combinators kernel memoize csv summary -words accessors math.order binary-search ; +words accessors math.order binary-search combinators.smart ; IN: usa-cities SINGLETONS: AK AL AR AS AZ CA CO CT DC DE FL GA HI IA ID IL IN @@ -30,15 +30,17 @@ first-zip name state latitude longitude gmt-offset dst-offset ; MEMO: cities ( -- seq ) "resource:extra/usa-cities/zipcode.csv" ascii csv rest-slice [ - 7 firstn { - [ string>number ] - [ ] - [ string>state ] - [ string>number ] - [ string>number ] - [ string>number ] - [ string>number ] - } spread city boa + [ + { + [ string>number ] + [ ] + [ string>state ] + [ string>number ] + [ string>number ] + [ string>number ] + [ string>number ] + } spread + ] input @@ -28,6 +28,14 @@ :group 'fuel :group 'languages) +(defcustom factor-mode-cycle-always-ask-p t + "Whether to always ask for file creation when cycling to a +source/docs/tests file. + +When set to false, you'll be asked only once." + :type 'boolean + :group 'factor-mode) + (defcustom factor-mode-use-fuel t "Whether to use the full FUEL facilities in factor mode. @@ -174,33 +182,58 @@ code in the buffer." (defconst factor-mode--cycle-endings '(".factor" "-tests.factor" "-docs.factor")) -(defconst factor-mode--regex-cycle-endings - (format "\\(.*?\\)\\(%s\\)$" - (regexp-opt factor-mode--cycle-endings))) +(make-local-variable + (defvar factor-mode--cycling-no-ask nil)) -(defconst factor-mode--cycle-endings-ring +(defvar factor-mode--cycle-ring (let ((ring (make-ring (length factor-mode--cycle-endings)))) (dolist (e factor-mode--cycle-endings ring) - (ring-insert ring e)))) + (ring-insert ring e)) + ring)) + +(defconst factor-mode--cycle-basename-regex + (format "\\(.+?\\)\\(%s\\)$" (regexp-opt factor-mode--cycle-endings))) + +(defun factor-mode--cycle-split (basename) + (when (string-match factor-mode--cycle-basename-regex basename) + (cons (match-string 1 basename) (match-string 2 basename)))) (defun factor-mode--cycle-next (file) - (let* ((match (string-match factor-mode--regex-cycle-endings file)) - (base (and match (match-string-no-properties 1 file))) - (ending (and match (match-string-no-properties 2 file))) - (idx (and ending (ring-member factor-mode--cycle-endings-ring ending))) - (gfl (lambda (i) (concat base (ring-ref factor-mode--cycle-endings-ring i))))) - (if (not idx) file - (let ((l (length factor-mode--cycle-endings)) (i 1) next) - (while (and (not next) (< i l)) - (when (file-exists-p (funcall gfl (+ idx i))) - (setq next (+ idx i))) - (setq i (1+ i))) - (funcall gfl (or next idx)))))) + (let* ((dir (file-name-directory file)) + (basename (file-name-nondirectory file)) + (p/s (factor-mode--cycle-split basename)) + (prefix (car p/s)) + (ring factor-mode--cycle-ring) + (idx (or (ring-member ring (cdr p/s)) 0)) + (len (ring-size ring)) + (i 1) + (result nil)) + (while (and (< i len) (not result)) + (let* ((suffix (ring-ref ring (+ i idx))) + (path (expand-file-name (concat prefix suffix) dir))) + (when (or (file-exists-p path) + (and (not (member suffix factor-mode--cycling-no-ask)) + (y-or-n-p (format "Create %s? " path)))) + (setq result path)) + (when (and (not factor-mode-cycle-always-ask-p) + (not (member suffix factor-mode--cycling-no-ask))) + (setq factor-mode--cycling-no-ask + (cons name factor-mode--cycling-no-ask)))) + (setq i (1+ i))) + result)) + +(defsubst factor-mode--cycling-setup () + (setq factor-mode--cycling-no-ask nil)) (defun factor-mode-visit-other-file (&optional file) "Cycle between code, tests and docs factor files." (interactive) - (find-file (factor-mode--cycle-next (or file (buffer-file-name))))) + (let ((file (factor-mode--cycle-next (or file (buffer-file-name))))) + (unless file (error "No other file found")) + (find-file file) + (unless (file-exists-p file) + (set-buffer-modified-p t) + (save-buffer)))) ;;; Keymap: @@ -237,6 +270,7 @@ code in the buffer." (factor-mode--keymap-setup) (factor-mode--indentation-setup) (factor-mode--syntax-setup) + (factor-mode--cycling-setup) (when factor-mode-use-fuel (require 'fuel-mode) (fuel-mode)) (run-hooks 'factor-mode-hook))