]> gitweb.factorcode.org Git - factor.git/commitdiff
Move match to basis since compiler.tree.debugger uses it, fix conflict
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Sat, 6 Sep 2008 00:48:44 +0000 (19:48 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Sat, 6 Sep 2008 00:48:44 +0000 (19:48 -0500)
18 files changed:
1  2 
basis/checksums/sha1/sha1.factor
basis/match/authors.txt
basis/match/match-docs.factor
basis/match/match-tests.factor
basis/match/match.factor
basis/match/summary.txt
basis/match/tags.txt
basis/tools/scaffold/scaffold.factor
core/sequences/sequences-docs.factor
core/sequences/sequences-tests.factor
core/sequences/sequences.factor
extra/match/authors.txt
extra/match/match-docs.factor
extra/match/match-tests.factor
extra/match/match.factor
extra/match/summary.txt
extra/match/tags.txt
extra/pack/pack.factor

index e75ebfb9e444d27508266ee3c371f0f0882121c9,ab813d529b227ab1453f0f19e72e1a05fe006d5c..0ddb429b285125367f2272d5affd22a572b1b49f
@@@ -1,9 -1,7 +1,9 @@@
 -USING: arrays combinators crypto.common kernel io
 -io.encodings.binary io.files io.streams.byte-array math.vectors
 -strings sequences namespaces math parser sequences vectors
 -io.binary hashtables symbols math.bitfields.lib checksums ;
 +! Copyright (C) 2006, 2008 Doug Coleman.
 +! See http://factorcode.org/license.txt for BSD license.
 +USING: arrays combinators kernel io io.encodings.binary io.files
 +io.streams.byte-array math.vectors strings sequences namespaces
 +math parser sequences assocs grouping vectors io.binary hashtables
 +symbols math.bitwise checksums checksums.common ;
  IN: checksums.sha1
  
  ! Implemented according to RFC 3174.
@@@ -47,9 -45,6 +47,9 @@@ SYMBOLS: h0 h1 h2 h3 h4 A B C D E w K 
          { 3 [ bitxor bitxor ] }
      } case ;
  
 +: nth-int-be ( string n -- int )
 +    4 * dup 4 + rot <slice> be> ; inline
 +
  : make-w ( str -- )
      #! compute w, steps a-b of RFC 3174, section 6.1
      16 [ nth-int-be w get push ] with each
@@@ -118,16 -113,8 +118,16 @@@ INSTANCE: sha1 checksu
  M: sha1 checksum-stream ( stream -- sha1 )
      drop [ initialize-sha1 stream>sha1 get-sha1 ] with-input-stream ;
  
 +: seq>2seq ( seq -- seq1 seq2 )
 +    #! { abcdefgh } -> { aceg } { bdfh }
 +    2 group flip dup empty? [ drop { } { } ] [ first2 ] if ;
 +
 +: 2seq>seq ( seq1 seq2 -- seq )
 +    #! { aceg } { bdfh } -> { abcdefgh }
 +    [ zip concat ] keep like ;
 +
  : sha1-interleave ( string -- seq )
-     [ zero? ] left-trim
+     [ zero? ] trim-left
      dup length odd? [ rest ] when
      seq>2seq [ sha1 checksum-bytes ] bi@
      2seq>seq ;
diff --combined basis/match/authors.txt
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..44b06f94bce2ac1f87c75319d38703e6ad205a53
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++Chris Double
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2e23721e93e60da5330e44ac97fbad65d00f573e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++! Copyright (C) 2006 Chris Double.
++! See http://factorcode.org/license.txt for BSD license.
++USING: help.markup help.syntax namespaces assocs sequences
++kernel combinators ;
++IN: match
++
++HELP: match 
++{ $values { "value1" object } { "value2" object } { "bindings" assoc }
++}
++{ $description "Pattern match value1 against value2. These values can be any Factor value, including sequences and tuples. The values can contain pattern variables, which are symbols that begin with '?'. The result is a hashtable of the bindings, mapping the pattern variables from one sequence to the equivalent value in the other sequence. The '_' symbol can be used to ignore the value at that point in the pattern for the match. " } 
++{ $examples 
++    { $unchecked-example "USE: match" "MATCH-VARS: ?a ?b ;\n{ ?a { 2 ?b } 5 } { 1 { 2 3 } _ } match ." "H{ { ?a 1 } { ?b 3 } }" }
++}
++{ $see-also match-cond POSTPONE: MATCH-VARS: replace-patterns match-replace } ;
++
++HELP: match-cond
++{ $values { "assoc" "a sequence of pairs" } }
++{ $description "Calls the second quotation in the first pair whose first sequence yields a successful " { $link match } " against the top of the stack. The second quotation, when called, has the hashtable returned from the " { $link match } " call bound as the top namespace so " { $link get } " can be used to retrieve the values. To have a fallthrough match clause use the '_' match variable." } 
++{ $examples 
++    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
++}
++{ $see-also match POSTPONE: MATCH-VARS: replace-patterns match-replace } ;
++
++
++HELP: MATCH-VARS:
++{ $syntax "MATCH-VARS: var ... ;" }
++{ $values { "var" "a match variable name beginning with '?'" } }
++{ $description "Creates a symbol that can be used in " { $link match } " and " { $link match-cond } " for binding values in the matched sequence. The symbol name is created as a word that is defined to get the value of the symbol out of the current namespace. This can be used in " { $link match-cond } " to retrive the values in the quotation body." }
++{ $examples 
++    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
++}
++{ $see-also match match-cond replace-patterns match-replace } ;
++
++HELP: replace-patterns
++{ $values { "object" object } { "result" object } }
++{ $description "Copy the object, replacing each occurrence of a pattern matching variable with the actual value of that variable." } 
++{ $see-also match-cond POSTPONE: MATCH-VARS: match-replace } ;
++
++HELP: match-replace
++{ $values { "object" object } { "pattern1" object } { "pattern2" object } { "result" object } }
++{ $description "Matches the " { $snippet "object" } " against " { $snippet "pattern1" } ". The pattern match variables in " { $snippet "pattern1" } " are assigned the values from the matching " { $snippet "object" } ". These are then replaced into the " { $snippet "pattern2" } " pattern match variables." } 
++{ $examples
++  { $example
++      "USING: match prettyprint ;"
++      "IN: scratchpad"
++      "MATCH-VARS: ?a ?b ;"
++      "{ 1 2 } { ?a ?b } { ?b ?a } match-replace ." 
++      "{ 2 1 }"
++  }
++}
++{ $see-also match-cond POSTPONE: MATCH-VARS: } ;
++
++ARTICLE: "match" "Pattern matching"
++"The " { $vocab-link "match" } " vocabulary implements ML-style pattern matching."
++$nl
++"Variables used for pattern matching must be explicitly defined first:"
++{ $subsection POSTPONE: MATCH-VARS: }
++"A basic pattern match:"
++{ $subsection match }
++"A conditional form analogous to " { $link cond } ":"
++{ $subsection match-cond }
++"Pattern replacement:"
++{ $subsection match-replace } ;
++
++ABOUT: "match"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..044b80fe9d06b736e1dccbb49eb10027f6ba9db8
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,87 @@@
++! Copyright (C) 2006 Chris Double.
++! See http://factorcode.org/license.txt for BSD license.
++USING: tools.test match namespaces arrays ;
++IN: match.tests
++
++MATCH-VARS: ?a ?b ;
++
++[ f ] [ { ?a ?a } { 1 2 } match ] unit-test
++
++[ H{ { ?a 1 } { ?b 2 } } ] [
++ { ?a ?b } { 1 2 } match
++] unit-test
++
++[ { 1 2 } ] [ 
++  { 1 2 } 
++  {
++    { { ?a ?b } [ ?a ?b 2array ] }
++  } match-cond
++] unit-test
++
++[ t ] [ 
++  { 1 2 } 
++  {
++    { { 1 2 } [ t ] }
++    { f [ f ] }
++  } match-cond
++] unit-test
++
++[ t ] [ 
++  { 1 3 } 
++  {
++    { { 1 2 } [ t ] }
++    { { 1 3 } [ t ] }
++  } match-cond
++] unit-test
++
++[ f ] [ 
++  { 1 5 } 
++  {
++    { { 1 2 } [ t ] }
++    { { 1 3 } [ t ] }
++    { _       [ f ] }
++  } match-cond
++] unit-test
++
++TUPLE: foo a b ;
++
++C: <foo> foo
++
++{ 1 2 } [
++  1 2 <foo> T{ foo f ?a ?b } match [
++    ?a ?b
++  ] bind
++] unit-test
++
++{ 1 2 } [
++  1 2 <foo> \ ?a \ ?b <foo> match [
++    ?a ?b
++  ] bind
++] unit-test
++
++{ H{ { ?a ?a } } } [ 
++  \ ?a \ ?a match 
++] unit-test
++
++[ "match" ] [ 
++  "abcd" {
++    { ?a [ "match" ] }
++  } match-cond
++] unit-test
++
++[
++  { 2 1 }
++] [
++  { "a" 1 2 "b" } { _ ?a ?b _ } { ?b ?a } match-replace
++] unit-test
++
++TUPLE: match-replace-test a b ;
++
++[
++    T{ match-replace-test f 2 1 }
++] [
++  T{ match-replace-test f 1 2 }
++  T{ match-replace-test f ?a ?b }
++  T{ match-replace-test f ?b ?a }
++  match-replace
++] unit-test
diff --combined basis/match/match.factor
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0ae285d20d47d469ffccfbda8e9bcbfa44ec5ab4
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,90 @@@
++! Copyright (C) 2006 Chris Double.
++! See http://factorcode.org/license.txt for BSD license.
++!
++! Based on pattern matching code from Paul Graham's book 'On Lisp'.
++USING: parser lexer kernel words namespaces sequences classes.tuple
++combinators macros assocs math effects ;
++IN: match
++
++SYMBOL: _
++
++: define-match-var ( name -- )
++    create-in
++    dup t "match-var" set-word-prop
++    dup [ get ] curry (( -- value )) define-declared ;
++
++: define-match-vars ( seq -- )
++    [ define-match-var ] each ;
++
++: MATCH-VARS: ! vars ...
++    ";" parse-tokens define-match-vars ; parsing
++
++: match-var? ( symbol -- bool )
++    dup word? [ "match-var" word-prop ] [ drop f ] if ;
++
++: set-match-var ( value var -- ? )
++    dup namespace key? [ get = ] [ set t ] if ;
++
++: (match) ( value1 value2 -- matched? )
++    {
++        { [ dup match-var? ] [ set-match-var ] }
++        { [ over match-var? ] [ swap set-match-var ] }
++        { [ 2dup = ] [ 2drop t ] }
++        { [ 2dup [ _ eq? ] either? ] [ 2drop t ] }
++        { [ 2dup [ sequence? ] both? ] [
++            2dup [ length ] bi@ =
++            [ [ (match) ] 2all? ] [ 2drop f ] if ] }
++        { [ 2dup [ tuple? ] both? ]
++          [ [ tuple>array ] bi@ [ (match) ] 2all? ] }
++        { [ t ] [ 2drop f ] }
++    } cond ;
++
++: match ( value1 value2 -- bindings )
++    [ (match) ] H{ } make-assoc swap [ drop f ] unless ;
++
++MACRO: match-cond ( assoc -- )
++    <reversed>
++    [ "Fall-through in match-cond" throw ]
++    [
++        first2
++        >r [ dupd match ] curry r>
++        [ bind ] curry rot
++        [ ?if ] 2curry append
++    ] reduce ;
++
++: replace-patterns ( object -- result )
++    {
++        { [ dup number? ] [ ] }
++        { [ dup match-var? ] [ get ] }
++        { [ dup sequence? ] [ [ replace-patterns ] map ] }
++        { [ dup tuple? ] [ tuple>array replace-patterns >tuple ] }
++        [ ]
++    } cond ;
++
++: match-replace ( object pattern1 pattern2 -- result )
++    -rot
++    match [ "Pattern does not match" throw ] unless*
++    [ replace-patterns ] bind ;
++
++: ?1-tail ( seq -- tail/f )
++    dup length zero? not [ rest ] [ drop f ] if ;
++
++: (match-first) ( seq pattern-seq -- bindings leftover/f )
++    2dup [ length ] bi@ < [ 2drop f f ]
++    [
++        2dup length head over match
++        [ nip swap ?1-tail ] [ >r rest r> (match-first) ] if*
++    ] if ;
++    
++: match-first ( seq pattern-seq -- bindings )
++    (match-first) drop ;
++
++: (match-all) ( seq pattern-seq -- )
++    tuck (match-first) swap 
++    [ 
++        , [ swap (match-all) ] [ drop ] if* 
++    ] [ 2drop ] if* ;
++
++: match-all ( seq pattern-seq -- bindings-seq )
++    [ (match-all) ] { } make ;
++    
diff --combined basis/match/summary.txt
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1666a2cbaac51c899430699399ee792202f0fd5d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++ML-style pattern matching
diff --combined basis/match/tags.txt
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f4274299b1c36db85f10b2e3f3e38f18fded1061
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++extensions
index 1312681f85535f6d95d82b412fdf18a919d32b9d,f12b8fda0e7e69dfdd0cebc281cea36452524030..74c92605aafdb23768ce6fb7e2f2a91078922224
@@@ -3,8 -3,8 +3,8 @@@
  USING: assocs io.files hashtables kernel namespaces sequences
  vocabs.loader io combinators io.encodings.utf8 calendar accessors
  math.parser io.streams.string ui.tools.operations quotations
 -strings arrays prettyprint words vocabs sorting sets cords
 -classes sequences.lib combinators.lib alien math ;
 +strings arrays prettyprint words vocabs sorting sets
- classes ;
++classes alien ;
  IN: tools.scaffold
  
  SYMBOL: developer-name
@@@ -95,6 -95,7 +95,7 @@@ ERROR: no-vocab vocab 
          { "obj3" object } { "obj4" object }
          { "quot" quotation } { "quot1" quotation }
          { "quot2" quotation } { "quot3" quotation }
+         { "quot'" quotation }
          { "string" string } { "string1" string }
          { "string2" string } { "string3" string }
          { "str" string }
          { "ch" "a character" }
          { "word" word }
          { "array" array }
+         { "duration" duration }
          { "path" "a pathname string" }
          { "vocab" "a vocabulary specifier" }
          { "vocab-root" "a vocabulary root string" }
+         { "c-ptr" c-ptr }
+         { "seq" sequence } { "seq1" sequence } { "seq2" sequence }
+         { "seq3" sequence } { "seq4" sequence }
+         { "seq1'" sequence } { "seq2'" sequence }
+         { "newseq" sequence } 
+         { "assoc" assoc } { "assoc1" assoc } { "assoc2" assoc }
+         { "assoc3" assoc } { "newassoc" assoc }
+         { "alist" "an array of key/value pairs" }
+         { "keys" sequence } { "values" sequence }
+         { "class" class }
      } at* ;
  
  : add-using ( object -- )
  
  : help-file-string ( str1 -- str2 )
      [
 -        [ "IN: " write print nl ]
 -        [ interesting-words. ]
 -        [ "ARTICLE: " write unparse dup write bl print ";" print nl ]
 -        [ "ABOUT: " write unparse print ] quad
 +        {
 +            [ "IN: " write print nl ]
 +            [ interesting-words. ]
 +            [ "ARTICLE: " write unparse dup write bl print ";" print nl ]
 +            [ "ABOUT: " write unparse print ]
 +        } cleave
      ] with-string-writer ;
  
  : write-using ( -- )
      "USING:" write
      using get keys
 -    { "help.markup" "help.syntax" } cord-append natural-sort 
 +    { "help.markup" "help.syntax" } append natural-sort 
      [ bl write ] each
      " ;" print ;
  
@@@ -227,3 -237,20 +239,20 @@@ PRIVATE
          [ drop scaffold-authors ]
          [ nip require ]
      } 2cleave ;
+ SYMBOL: examples-flag
+ : example ( -- )
+     {
+         "{ $example \"\" \"USING: prettyprint ;\""
+         "           \"\""
+         "           \"\""
+         "}"
+     } [ examples-flag get [ "    " write ] when print ] each ;
+ : examples ( n -- )
+     t \ examples-flag [
+         "{ $examples " print
+         [ example ] times
+         "}" print
+     ] with-variable ;
index baf68db112a63f6e7aa41a697584bed672cd668c,6c917f133b4234374d23fbbe2a06df29661d431a..4ada1ece9a514e535213b8808ba6e8c2dcced76c
@@@ -178,6 -178,16 +178,16 @@@ ARTICLE: "sequences-search" "Searching 
  { $subsection find-last }
  { $subsection find-last-from } ;
  
+ ARTICLE: "sequences-trimming" "Trimming sequences"
+ "Trimming words:"
+ { $subsection trim }
+ { $subsection trim-left }
+ { $subsection trim-right }
+ "Potentially more efficient trim:"
+ { $subsection trim-slice }
+ { $subsection trim-left-slice }
+ { $subsection trim-right-slice } ;
  ARTICLE: "sequences-destructive" "Destructive operations"
  "These words modify their input, instead of creating a new sequence."
  $nl
@@@ -245,6 -255,7 +255,7 @@@ $n
  { $subsection "sequences-sorting" }
  { $subsection "binary-search" }
  { $subsection "sets" }
+ { $subsection "sequences-trimming" }
  "For inner loops:"
  { $subsection "sequences-unsafe" } ;
  
@@@ -315,15 -326,6 +326,15 @@@ HELP: empty
  { $values { "seq" sequence } { "?" "a boolean" } }
  { $description "Tests if the sequence has zero length." } ;
  
 +HELP: if-empty
 +{ $values { "seq" sequence } { "quot1" quotation } { "quot2" quotation } }
 +{ $description "Makes an implicit check if the sequence is empty. An empty sequence is dropped and " { $snippet "quot1" } " is called. Otherwise, if the sequence has any elements, " { $snippet "quot2" } " is called on it." }
 +{ $example
 +    "USING: kernel prettyprint sequences sequences.lib ;"
 +    "{ 1 2 3 } [ \"empty sequence\" ] [ sum ] if-empty ."
 +    "6"
 +} ;
 +
  HELP: delete-all
  { $values { "seq" "a resizable sequence" } }
  { $description "Resizes the sequence to zero length, removing all elements. Not all sequences are resizable." }
@@@ -731,7 -733,7 +742,7 @@@ HELP: reverse-her
  
  HELP: padding
  { $values { "seq" sequence } { "n" "a non-negative integer" } { "elt" object } { "quot" "a quotation with stack effect " { $snippet "( seq1 seq2 -- newseq )" } } { "newseq" "a new sequence" } }
- { $description "Outputs a new string sequence of " { $snippet "elt" } " repeated, that when appended to " { $snippet "seq" } ", yields a sequence of length " { $snippet "n" } ". If the length of " { $snippet "seq" } " is greater than " { $snippet "n" } ", this word outputs an empty sequence." } ;
+ { $description "Outputs a new string sequence of " { $snippet "elt" } " repeated, that when appended to " { $snippet "seq" } ", yields a sequence of length " { $snippet "n" } ". If the length of " { $snippet "seq" } " is greater than " { $snippet "n" } ", this word outputs an empty sequence." } ;
  
  HELP: pad-left
  { $values { "seq" sequence } { "n" "a non-negative integer" } { "elt" object } { "padded" "a new sequence" } }
@@@ -1004,3 -1006,45 +1015,45 @@@ HELP: coun
      "50"
  } ;
  
+ HELP: pusher
+ { $values
+      { "quot" "a predicate quotation" }
+      { "quot" quotation } { "accum" vector } }
+ { $description "Creates a new vector to accumulate the values which return true for a predicate.  Returns a new quotation which accepts an object to be tested and stored in the accumulator if the test yields true. The accumulator is left on the stack for convenience." }
+ { $example "! Find all the even numbers:" "USING: prettyprint sequences math kernel ;"
+            "10 [ even? ] pusher [ each ] dip ."
+            "V{ 0 2 4 6 8 }"
+ }
+ { $notes "Used to implement the " { $link filter } " word." } ;
+ HELP: trim-left
+ { $values
+      { "seq" sequence } { "quot" quotation }
+      { "newseq" sequence } }
+ { $description "Removes elements starting from the left side of a sequence if they match a predicate. Once an element does not match, the test stops and the rest of the sequence is left on the stack as a new sequence." }
+ { $example "" "USING: prettyprint math sequences ;"
+            "{ 0 0 1 2 3 0 0 } [ zero? ] trim-left ."
+            "{ 1 2 3 0 0 }"
+ } ;
+ HELP: trim-right
+ { $values
+      { "seq" sequence } { "quot" quotation }
+      { "newseq" sequence } }
+ { $description "Removes elements starting from the right side of a sequence if they match a predicate. Once an element does not match, the test stops and the rest of the sequence is left on the stack as a new sequence." }
+ { $example "" "USING: prettyprint math sequences ;"
+            "{ 0 0 1 2 3 0 0 } [ zero? ] trim-right ."
+            "{ 0 0 1 2 3 }"
+ } ;
+ HELP: trim
+ { $values
+      { "seq" sequence } { "quot" quotation }
+      { "newseq" sequence } }
+ { $description "Removes elements starting from the left and right sides of a sequence if they match a predicate. Once an element does not match, the test stops and the rest of the sequence is left on the stack as a new sequence." }
+ { $example "" "USING: prettyprint math sequences ;"
+            "{ 0 0 1 2 3 0 0 } [ zero? ] trim ."
+            "{ 1 2 3 }"
+ } ;
+ { trim-left trim-right trim } related-words
index 8d7a0469a09f132db2de8cc24c139cf2705497a8,acfaa87e7d16a64b6e6c9f6d3d7dac81c30c7d1a..8018fe1cdc512bd4c924a26d33313ae5815e86ae
@@@ -3,9 -3,6 +3,9 @@@ sequences.private strings sbufs tools.t
  generic vocabs.loader ;
  IN: sequences.tests
  
 +[ "empty" ] [ { } [ "empty" ] [ "not empty" ] if-empty ] unit-test
 +[ { 1 } "not empty" ] [ { 1 } [ "empty" ] [ "not empty" ] if-empty ] unit-test
 +
  [ V{ 1 2 3 4 } ] [ 1 5 dup <slice> >vector ] unit-test
  [ 3 ] [ 1 4 dup <slice> length ] unit-test
  [ 2 ] [ 1 3 { 1 2 3 4 } <slice> length ] unit-test
@@@ -237,13 -234,13 +237,13 @@@ unit-tes
  
  [ -1./0. 0 delete-nth ] must-fail
  [ "" ] [ "" [ CHAR: \s = ] trim ] unit-test
- [ "" ] [ "" [ CHAR: \s = ] left-trim ] unit-test
- [ "" ] [ "" [ CHAR: \s = ] right-trim ] unit-test
- [ "" ] [ "  " [ CHAR: \s = ] left-trim ] unit-test
- [ "" ] [ "  " [ CHAR: \s = ] right-trim ] unit-test
+ [ "" ] [ "" [ CHAR: \s = ] trim-left ] unit-test
+ [ "" ] [ "" [ CHAR: \s = ] trim-right ] unit-test
+ [ "" ] [ "  " [ CHAR: \s = ] trim-left ] unit-test
+ [ "" ] [ "  " [ CHAR: \s = ] trim-right ] unit-test
  [ "asdf" ] [ " asdf " [ CHAR: \s = ] trim ] unit-test
- [ "asdf " ] [ " asdf " [ CHAR: \s = ] left-trim ] unit-test
- [ " asdf" ] [ " asdf " [ CHAR: \s = ] right-trim ] unit-test
+ [ "asdf " ] [ " asdf " [ CHAR: \s = ] trim-left ] unit-test
+ [ " asdf" ] [ " asdf " [ CHAR: \s = ] trim-right ] unit-test
  
  [ 328350 ] [ 100 [ sq ] sigma ] unit-test
  
@@@ -260,9 -257,3 +260,9 @@@ TUPLE: bogus-hashcode 
  M: bogus-hashcode hashcode* 2drop 0 >bignum ;
  
  [ 0 ] [ { T{ bogus-hashcode } } hashcode ] unit-test
 +
 +[ { 2 4 6 } { 1 3 5 7 } ] [ { 1 2 3 4 5 6 7 } [ even? ] partition ] unit-test
 +
 +[ { 1 3 7 } ] [ 2 { 1 3 5 7 } remove-nth ] unit-test
 +
 +[ { 1 3 "X" 5 7 } ] [ "X" 2 { 1 3 5 7 } insert-nth ] unit-test
index 2ce939d96f29e3a6eb6f74ea5afc68fc02465e86,5ab3e59284e3dbf45a4e3dabb60701546d66d43f..32671fc7f00a5991db9b778612a5c25be0136a83
@@@ -28,14 -28,6 +28,14 @@@ M: sequence lengthen 2dup length > [ se
  M: sequence shorten 2dup length < [ set-length ] [ 2drop ] if ;
  
  : empty? ( seq -- ? ) length zero? ; inline
 +
 +: if-empty ( seq quot1 quot2 -- )
 +    [ dup empty? ] [ [ drop ] prepose ] [ ] tri* if ; inline
 +
 +: when-empty ( seq quot1 -- ) [ ] if-empty ; inline
 +
 +: unless-empty ( seq quot1 -- ) [ ] swap if-empty ; inline
 +
  : delete-all ( seq -- ) 0 swap set-length ;
  
  : first ( seq -- first ) 0 swap nth ; inline
@@@ -426,15 -418,6 +426,15 @@@ PRIVATE
  : filter ( seq quot -- subseq )
      over >r pusher >r each r> r> like ; inline
  
 +: push-either ( elt quot accum1 accum2 -- )
 +    >r >r keep swap r> r> ? push ; inline
 +
 +: 2pusher ( quot -- quot accum1 accum2 )
 +    V{ } clone V{ } clone [ [ push-either ] 3curry ] 2keep ; inline
 +
 +: partition ( seq quot -- trueseq falseseq )
 +    over >r 2pusher >r >r each r> r> r> tuck [ like ] 2bi@ ; inline
 +
  : monotonic? ( seq quot -- ? )
      >r dup length 1- swap r> (monotonic) all? ; inline
  
@@@ -599,9 -582,6 +599,9 @@@ M: slice equal? over slice? [ sequence
      [ >r >r dup pick length + r> - over r> open-slice ] keep
      copy ;
  
 +: remove-nth ( n seq -- seq' )
 +    [ swap head-slice ] [ swap 1+ tail-slice ] 2bi append ;
 +
  : pop ( seq -- elt )
      [ length 1- ] [ [ nth ] [ shorten ] 2bi ] bi ;
  
  : cut-slice ( seq n -- before after )
      [ head-slice ] [ tail-slice ] 2bi ;
  
 +: insert-nth ( elt n seq -- seq' )
 +    swap cut-slice [ swap suffix ] dip append ;
 +
  : midpoint@ ( seq -- n ) length 2/ ; inline
  
  : halves ( seq -- first second )
@@@ -748,16 -725,25 +748,25 @@@ PRIVATE
      dup slice? [ { } like ] when 0 over length rot <slice> ;
      inline
  
- : left-trim ( seq quot -- newseq )
+ : trim-left-slice ( seq quot -- slice )
      over >r [ not ] compose find drop r> swap
-     [ tail ] [ dup length tail ] if* ; inline
+     [ tail-slice ] [ dup length tail-slice ] if* ; inline
+     
+ : trim-left ( seq quot -- newseq )
+     over [ trim-left-slice ] dip like ; inline
  
- : right-trim ( seq quot -- newseq )
+ : trim-right-slice ( seq quot -- slice )
      over >r [ not ] compose find-last drop r> swap
-     [ 1+ head ] [ 0 head ] if* ; inline
+     [ 1+ head-slice ] [ 0 head-slice ] if* ; inline
+ : trim-right ( seq quot -- newseq )
+     over [ trim-right-slice ] dip like ; inline
+ : trim-slice ( seq quot -- slice )
+     [ trim-left-slice ] [ trim-right-slice ] bi ;
  
  : trim ( seq quot -- newseq )
-     [ left-trim ] [ right-trim ] bi ; inline
+     over [ trim-slice ] dip like ; inline
  
  : sum ( seq -- n ) 0 [ + ] binary-reduce ;
  
diff --combined extra/match/authors.txt
index 44b06f94bce2ac1f87c75319d38703e6ad205a53,44b06f94bce2ac1f87c75319d38703e6ad205a53..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,1 -1,1 +1,0 @@@
--Chris Double
diff --combined extra/match/match-docs.factor
index 2e23721e93e60da5330e44ac97fbad65d00f573e,2e23721e93e60da5330e44ac97fbad65d00f573e..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,65 -1,65 +1,0 @@@
--! Copyright (C) 2006 Chris Double.
--! See http://factorcode.org/license.txt for BSD license.
--USING: help.markup help.syntax namespaces assocs sequences
--kernel combinators ;
--IN: match
--
--HELP: match 
--{ $values { "value1" object } { "value2" object } { "bindings" assoc }
--}
--{ $description "Pattern match value1 against value2. These values can be any Factor value, including sequences and tuples. The values can contain pattern variables, which are symbols that begin with '?'. The result is a hashtable of the bindings, mapping the pattern variables from one sequence to the equivalent value in the other sequence. The '_' symbol can be used to ignore the value at that point in the pattern for the match. " } 
--{ $examples 
--    { $unchecked-example "USE: match" "MATCH-VARS: ?a ?b ;\n{ ?a { 2 ?b } 5 } { 1 { 2 3 } _ } match ." "H{ { ?a 1 } { ?b 3 } }" }
--}
--{ $see-also match-cond POSTPONE: MATCH-VARS: replace-patterns match-replace } ;
--
--HELP: match-cond
--{ $values { "assoc" "a sequence of pairs" } }
--{ $description "Calls the second quotation in the first pair whose first sequence yields a successful " { $link match } " against the top of the stack. The second quotation, when called, has the hashtable returned from the " { $link match } " call bound as the top namespace so " { $link get } " can be used to retrieve the values. To have a fallthrough match clause use the '_' match variable." } 
--{ $examples 
--    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
--}
--{ $see-also match POSTPONE: MATCH-VARS: replace-patterns match-replace } ;
--
--
--HELP: MATCH-VARS:
--{ $syntax "MATCH-VARS: var ... ;" }
--{ $values { "var" "a match variable name beginning with '?'" } }
--{ $description "Creates a symbol that can be used in " { $link match } " and " { $link match-cond } " for binding values in the matched sequence. The symbol name is created as a word that is defined to get the value of the symbol out of the current namespace. This can be used in " { $link match-cond } " to retrive the values in the quotation body." }
--{ $examples 
--    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
--}
--{ $see-also match match-cond replace-patterns match-replace } ;
--
--HELP: replace-patterns
--{ $values { "object" object } { "result" object } }
--{ $description "Copy the object, replacing each occurrence of a pattern matching variable with the actual value of that variable." } 
--{ $see-also match-cond POSTPONE: MATCH-VARS: match-replace } ;
--
--HELP: match-replace
--{ $values { "object" object } { "pattern1" object } { "pattern2" object } { "result" object } }
--{ $description "Matches the " { $snippet "object" } " against " { $snippet "pattern1" } ". The pattern match variables in " { $snippet "pattern1" } " are assigned the values from the matching " { $snippet "object" } ". These are then replaced into the " { $snippet "pattern2" } " pattern match variables." } 
--{ $examples
--  { $example
--      "USING: match prettyprint ;"
--      "IN: scratchpad"
--      "MATCH-VARS: ?a ?b ;"
--      "{ 1 2 } { ?a ?b } { ?b ?a } match-replace ." 
--      "{ 2 1 }"
--  }
--}
--{ $see-also match-cond POSTPONE: MATCH-VARS: } ;
--
--ARTICLE: "match" "Pattern matching"
--"The " { $vocab-link "match" } " vocabulary implements ML-style pattern matching."
--$nl
--"Variables used for pattern matching must be explicitly defined first:"
--{ $subsection POSTPONE: MATCH-VARS: }
--"A basic pattern match:"
--{ $subsection match }
--"A conditional form analogous to " { $link cond } ":"
--{ $subsection match-cond }
--"Pattern replacement:"
--{ $subsection match-replace } ;
--
--ABOUT: "match"
diff --combined extra/match/match-tests.factor
index 044b80fe9d06b736e1dccbb49eb10027f6ba9db8,044b80fe9d06b736e1dccbb49eb10027f6ba9db8..0000000000000000000000000000000000000000
deleted file mode 100755,100755
+++ /dev/null
@@@ -1,87 -1,87 +1,0 @@@
--! Copyright (C) 2006 Chris Double.
--! See http://factorcode.org/license.txt for BSD license.
--USING: tools.test match namespaces arrays ;
--IN: match.tests
--
--MATCH-VARS: ?a ?b ;
--
--[ f ] [ { ?a ?a } { 1 2 } match ] unit-test
--
--[ H{ { ?a 1 } { ?b 2 } } ] [
-- { ?a ?b } { 1 2 } match
--] unit-test
--
--[ { 1 2 } ] [ 
--  { 1 2 } 
--  {
--    { { ?a ?b } [ ?a ?b 2array ] }
--  } match-cond
--] unit-test
--
--[ t ] [ 
--  { 1 2 } 
--  {
--    { { 1 2 } [ t ] }
--    { f [ f ] }
--  } match-cond
--] unit-test
--
--[ t ] [ 
--  { 1 3 } 
--  {
--    { { 1 2 } [ t ] }
--    { { 1 3 } [ t ] }
--  } match-cond
--] unit-test
--
--[ f ] [ 
--  { 1 5 } 
--  {
--    { { 1 2 } [ t ] }
--    { { 1 3 } [ t ] }
--    { _       [ f ] }
--  } match-cond
--] unit-test
--
--TUPLE: foo a b ;
--
--C: <foo> foo
--
--{ 1 2 } [
--  1 2 <foo> T{ foo f ?a ?b } match [
--    ?a ?b
--  ] bind
--] unit-test
--
--{ 1 2 } [
--  1 2 <foo> \ ?a \ ?b <foo> match [
--    ?a ?b
--  ] bind
--] unit-test
--
--{ H{ { ?a ?a } } } [ 
--  \ ?a \ ?a match 
--] unit-test
--
--[ "match" ] [ 
--  "abcd" {
--    { ?a [ "match" ] }
--  } match-cond
--] unit-test
--
--[
--  { 2 1 }
--] [
--  { "a" 1 2 "b" } { _ ?a ?b _ } { ?b ?a } match-replace
--] unit-test
--
--TUPLE: match-replace-test a b ;
--
--[
--    T{ match-replace-test f 2 1 }
--] [
--  T{ match-replace-test f 1 2 }
--  T{ match-replace-test f ?a ?b }
--  T{ match-replace-test f ?b ?a }
--  match-replace
--] unit-test
diff --combined extra/match/match.factor
index 0ae285d20d47d469ffccfbda8e9bcbfa44ec5ab4,0ae285d20d47d469ffccfbda8e9bcbfa44ec5ab4..0000000000000000000000000000000000000000
deleted file mode 100755,100755
+++ /dev/null
@@@ -1,90 -1,90 +1,0 @@@
--! Copyright (C) 2006 Chris Double.
--! See http://factorcode.org/license.txt for BSD license.
--!
--! Based on pattern matching code from Paul Graham's book 'On Lisp'.
--USING: parser lexer kernel words namespaces sequences classes.tuple
--combinators macros assocs math effects ;
--IN: match
--
--SYMBOL: _
--
--: define-match-var ( name -- )
--    create-in
--    dup t "match-var" set-word-prop
--    dup [ get ] curry (( -- value )) define-declared ;
--
--: define-match-vars ( seq -- )
--    [ define-match-var ] each ;
--
--: MATCH-VARS: ! vars ...
--    ";" parse-tokens define-match-vars ; parsing
--
--: match-var? ( symbol -- bool )
--    dup word? [ "match-var" word-prop ] [ drop f ] if ;
--
--: set-match-var ( value var -- ? )
--    dup namespace key? [ get = ] [ set t ] if ;
--
--: (match) ( value1 value2 -- matched? )
--    {
--        { [ dup match-var? ] [ set-match-var ] }
--        { [ over match-var? ] [ swap set-match-var ] }
--        { [ 2dup = ] [ 2drop t ] }
--        { [ 2dup [ _ eq? ] either? ] [ 2drop t ] }
--        { [ 2dup [ sequence? ] both? ] [
--            2dup [ length ] bi@ =
--            [ [ (match) ] 2all? ] [ 2drop f ] if ] }
--        { [ 2dup [ tuple? ] both? ]
--          [ [ tuple>array ] bi@ [ (match) ] 2all? ] }
--        { [ t ] [ 2drop f ] }
--    } cond ;
--
--: match ( value1 value2 -- bindings )
--    [ (match) ] H{ } make-assoc swap [ drop f ] unless ;
--
--MACRO: match-cond ( assoc -- )
--    <reversed>
--    [ "Fall-through in match-cond" throw ]
--    [
--        first2
--        >r [ dupd match ] curry r>
--        [ bind ] curry rot
--        [ ?if ] 2curry append
--    ] reduce ;
--
--: replace-patterns ( object -- result )
--    {
--        { [ dup number? ] [ ] }
--        { [ dup match-var? ] [ get ] }
--        { [ dup sequence? ] [ [ replace-patterns ] map ] }
--        { [ dup tuple? ] [ tuple>array replace-patterns >tuple ] }
--        [ ]
--    } cond ;
--
--: match-replace ( object pattern1 pattern2 -- result )
--    -rot
--    match [ "Pattern does not match" throw ] unless*
--    [ replace-patterns ] bind ;
--
--: ?1-tail ( seq -- tail/f )
--    dup length zero? not [ rest ] [ drop f ] if ;
--
--: (match-first) ( seq pattern-seq -- bindings leftover/f )
--    2dup [ length ] bi@ < [ 2drop f f ]
--    [
--        2dup length head over match
--        [ nip swap ?1-tail ] [ >r rest r> (match-first) ] if*
--    ] if ;
--    
--: match-first ( seq pattern-seq -- bindings )
--    (match-first) drop ;
--
--: (match-all) ( seq pattern-seq -- )
--    tuck (match-first) swap 
--    [ 
--        , [ swap (match-all) ] [ drop ] if* 
--    ] [ 2drop ] if* ;
--
--: match-all ( seq pattern-seq -- bindings-seq )
--    [ (match-all) ] { } make ;
--    
diff --combined extra/match/summary.txt
index 1666a2cbaac51c899430699399ee792202f0fd5d,1666a2cbaac51c899430699399ee792202f0fd5d..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,1 -1,1 +1,0 @@@
--ML-style pattern matching
diff --combined extra/match/tags.txt
index f4274299b1c36db85f10b2e3f3e38f18fded1061,f4274299b1c36db85f10b2e3f3e38f18fded1061..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,1 -1,1 +1,0 @@@
--extensions
diff --combined extra/pack/pack.factor
index adceab72f6692449112317d10a7addeb1c03492a,0bd4302fd708ad600d776a032411acf42e7fb574..b487b385b918ccde3c2c8bd9eac009e9176b6130
@@@ -1,7 -1,7 +1,7 @@@
  USING: alien alien.c-types arrays assocs byte-arrays io
  io.binary io.streams.string kernel math math.parser namespaces
  parser prettyprint quotations sequences strings vectors words
 -macros math.functions math.bitfields.lib ;
 +macros math.functions math.bitwise ;
  IN: pack
  
  SYMBOL: big-endian
@@@ -84,7 -84,7 +84,7 @@@ M: string b, ( n string -- ) heap-size 
      "\0" read-until [ drop f ] unless ;
  
  : read-c-string* ( n -- str/f )
-     read [ zero? ] right-trim dup empty? [ drop f ] when ;
+     read [ zero? ] trim-right dup empty? [ drop f ] when ;
  
  : (read-128-ber) ( n -- n )
      read1