]> gitweb.factorcode.org Git - factor.git/blob - basis/match/match.factor
factor: trim using lists
[factor.git] / basis / match / match.factor
1 ! Copyright (C) 2006 Chris Double.
2 ! See http://factorcode.org/license.txt for BSD license.
3 !
4 ! Based on pattern matching code from Paul Graham's book 'On Lisp'.
5 USING: assocs classes classes.tuple combinators kernel lexer
6 make namespaces parser quotations sequences summary words ;
7 IN: match
8
9 SYMBOL: _
10
11 : define-match-var ( name -- )
12     create-word-in
13     dup t "match-var" set-word-prop
14     dup [ get ] curry ( -- value ) define-declared ;
15
16 : define-match-vars ( seq -- )
17     [ define-match-var ] each ;
18
19 SYNTAX: MATCH-VARS: ! vars ...
20     ";" [ define-match-var ] each-token ;
21
22 PREDICATE: match-var < word "match-var" word-prop ;
23
24 : set-match-var ( value var -- ? )
25     building get ?at [ = ] [ ,, t ] if ;
26
27 : (match) ( value1 value2 -- matched? )
28     {
29         { [ dup match-var? ] [ set-match-var ] }
30         { [ over match-var? ] [ swap set-match-var ] }
31         { [ 2dup = ] [ 2drop t ] }
32         { [ 2dup [ _ eq? ] either? ] [ 2drop t ] }
33         { [ 2dup [ sequence? ] both? ] [
34             2dup [ length ] same? [
35                 [ (match) ] 2all?
36             ] [ 2drop f ] if ] }
37         { [ 2dup [ tuple? ] both? ] [
38             2dup [ class-of ] same? [
39                 [ tuple-slots ] bi@ [ (match) ] 2all?
40             ] [ 2drop f ] if ] }
41         [ 2drop f ]
42     } cond ;
43
44 : match ( value1 value2 -- bindings )
45     [ (match) ] H{ } make swap [ drop f ] unless ;
46
47 ERROR: no-match-cond ;
48
49 M: no-match-cond summary drop "Fall-through in match-cond" ;
50
51 MACRO: match-cond ( assoc -- quot )
52     <reversed>
53     dup ?first callable? [ unclip ] [ [ no-match-cond ] ] if
54     [
55         first2
56         [ [ dupd match ] curry ] dip
57         [ with-variables ] curry rot
58         [ ?if ] 2curry append
59     ] reduce ;
60
61 GENERIC: replace-patterns ( object -- result )
62 M: object replace-patterns ;
63 M: match-var replace-patterns get ;
64 M: sequence replace-patterns [ replace-patterns ] map ;
65 M: tuple replace-patterns tuple>array replace-patterns >tuple ;
66
67 : match-replace ( object pattern1 pattern2 -- result )
68     [ match [ "Pattern does not match" throw ] unless* ] dip swap
69     [ replace-patterns ] with-variables ;
70
71 : ?rest ( seq -- tailseq/f )
72     [ f ] [ rest ] if-empty ;
73
74 : (match-first) ( seq pattern-seq -- bindings leftover/f )
75     2dup shorter? [
76         2drop f f
77     ] [
78         2dup length head over match
79         [ swap ?rest ] [ [ rest ] dip (match-first) ] ?if
80     ] if ;
81
82 : match-first ( seq pattern-seq -- bindings )
83     (match-first) drop ;
84
85 : (match-all) ( seq pattern-seq -- )
86     [ (match-first) ] keep
87     [ , [ swap (match-all) ] [ drop ] if* ] [ 2drop ] if* ;
88
89 : match-all ( seq pattern-seq -- bindings-seq )
90     [ (match-all) ] { } make ;