add simple pattern matcher contrib library
parent
035a64ad8b
commit
7a6ff3449a
|
@ -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"
|
||||
} ;
|
|
@ -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 ;
|
||||
|
||||
|
|
@ -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 } ;
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue