add simple pattern matcher contrib library

chris.double 2006-09-05 03:04:27 +00:00
parent 035a64ad8b
commit 7a6ff3449a
4 changed files with 111 additions and 0 deletions

View File

@ -0,0 +1,8 @@
! Copyright (C) 2006 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
PROVIDE: match {
"match.factor"
"match.facts"
} {
"tests.factor"
} ;

View File

@ -0,0 +1,38 @@
! 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'.
IN: match
USING: kernel words sequences namespaces hashtables ;
SYMBOL: _
: match-var? ( symbol -- bool )
dup word? [
word-name first CHAR: ? =
] [
drop f
] if ;
: (match) ( seq1 seq2 -- matched? )
{
{ [ 2dup = ] [ 2drop t ] }
{ [ over _ = ] [ 2drop t ] }
{ [ dup _ = ] [ 2drop t ] }
{ [ dup match-var? ] [ set t ] }
{ [ over match-var? ] [ swap set t ] }
{ [ over sequence? over sequence? and [ over first over first (match) ] [ f ] if ] [ >r 1 tail r> 1 tail (match) ] }
{ [ t ] [ 2drop f ] }
} cond ;
: match ( seq1 seq2 -- bindings )
[ (match) ] make-hash swap [ drop f ] unless ;
SYMBOL: result
: match-cond ( seq assoc -- )
[
[ first over match dup result set ] find 2nip dup [ result get [ second call ] bind ] [ no-cond ] if
] with-scope ;

22
contrib/match/match.facts Normal file
View File

@ -0,0 +1,22 @@
! Copyright (C) 2006 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
USING: help match namespaces ;
HELP: match
{ $values { "seq1" "A sequence" } { "seq2" "A sequence" } { "bindings" "A hashtable" }
}
{ $description "Pattern match seq1 against seq2. The sequences 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
{ $example "SYMBOL: ?a\nSYMBOL: ?b\n{ ?a { 2 ?b } 5 } { 1 { 2 3 } _ } match\n => H{ { ?a 1 } { ?b 3 } }" }
}
{ $see-also match-cond } ;
HELP: match-cond
{ $values { "seq" "A sequence" } { "assoc" "A sequence of quotation pairs" }
}
{ $description "Calls the second quotation in the first pair whose first sequence yields a successful " { $link match } " against seq. 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
{ $example "SYMBOL: ?value\n{ increment ?value } {\n { { increment ?value } [ ?value get do-something ] }\n { { decrement ?value } [ ?value get do-something-else ] }\n { _ [ no-match-found ] }\n} match-cond" }
}
{ $see-also match } ;

View File

@ -0,0 +1,43 @@
! Copyright (C) 2006 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
USING: test match namespaces arrays ;
IN: temporary
SYMBOL: ?a
SYMBOL: ?b
[ H{ { ?a 1 } { ?b 2 } } ] [
{ ?a ?b } { 1 2 } match
] unit-test
[ { 1 2 } ] [
{ 1 2 }
{
{ { ?a ?b } [ ?a get ?b get 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