344 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Factor
		
	
	
| ! Copyright (C) 2008, 2009 Doug Coleman, Daniel Ehrenberg.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: accessors kernel math math.order words combinators
 | |
| combinators.smart combinators.short-circuit locals
 | |
| unicode.categories sequences fry macros arrays assocs sets
 | |
| classes unicode.script unicode.data ;
 | |
| FROM: ascii => ascii? ;
 | |
| IN: regexp.classes
 | |
| 
 | |
| SINGLETONS: dot letter-class LETTER-class Letter-class digit-class
 | |
| alpha-class non-newline-blank-class
 | |
| ascii-class punctuation-class java-printable-class blank-class
 | |
| control-character-class hex-digit-class java-blank-class c-identifier-class
 | |
| unmatchable-class terminator-class word-boundary-class ;
 | |
| 
 | |
| SINGLETONS: beginning-of-input ^ end-of-input $ end-of-file
 | |
| ^unix $unix word-break ;
 | |
| 
 | |
| TUPLE: range-class { from read-only } { to read-only } ;
 | |
| C: <range-class> range-class
 | |
| 
 | |
| TUPLE: primitive-class { class read-only } ;
 | |
| C: <primitive-class> primitive-class
 | |
| 
 | |
| TUPLE: category-class { category read-only } ;
 | |
| C: <category-class> category-class
 | |
| 
 | |
| TUPLE: category-range-class { category read-only } ;
 | |
| C: <category-range-class> category-range-class
 | |
| 
 | |
| TUPLE: script-class { script read-only } ;
 | |
| C: <script-class> script-class
 | |
| 
 | |
| GENERIC: class-member? ( obj class -- ? )
 | |
| 
 | |
| M: t class-member? ( obj class -- ? ) 2drop t ; inline
 | |
| 
 | |
| M: integer class-member? ( obj class -- ? ) = ; inline
 | |
| 
 | |
| M: range-class class-member? ( obj class -- ? )
 | |
|     [ from>> ] [ to>> ] bi between? ; inline
 | |
| 
 | |
| M: letter-class class-member? ( obj class -- ? )
 | |
|     drop letter? ; inline
 | |
| 
 | |
| M: LETTER-class class-member? ( obj class -- ? )
 | |
|     drop LETTER? ; inline
 | |
| 
 | |
| M: Letter-class class-member? ( obj class -- ? )
 | |
|     drop Letter? ; inline
 | |
| 
 | |
| M: ascii-class class-member? ( obj class -- ? )
 | |
|     drop ascii? ; inline
 | |
| 
 | |
| M: digit-class class-member? ( obj class -- ? )
 | |
|     drop digit? ; inline
 | |
| 
 | |
| : c-identifier-char? ( ch -- ? )
 | |
|     { [ alpha? ] [ CHAR: _ = ] } 1|| ;
 | |
| 
 | |
| M: c-identifier-class class-member? ( obj class -- ? )
 | |
|     drop c-identifier-char? ; inline
 | |
| 
 | |
| M: alpha-class class-member? ( obj class -- ? )
 | |
|     drop alpha? ; inline
 | |
| 
 | |
| : punct? ( ch -- ? )
 | |
|     "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" member? ;
 | |
| 
 | |
| M: punctuation-class class-member? ( obj class -- ? )
 | |
|     drop punct? ; inline
 | |
| 
 | |
| : java-printable? ( ch -- ? )
 | |
|     { [ alpha? ] [ punct? ] } 1|| ;
 | |
| 
 | |
| M: java-printable-class class-member? ( obj class -- ? )
 | |
|     drop java-printable? ; inline
 | |
| 
 | |
| M: non-newline-blank-class class-member? ( obj class -- ? )
 | |
|     drop { [ blank? ] [ CHAR: \n = not ] } 1&& ; inline
 | |
| 
 | |
| M: control-character-class class-member? ( obj class -- ? )
 | |
|     drop control? ; inline
 | |
| 
 | |
| : hex-digit? ( ch -- ? )
 | |
|     {
 | |
|         [ CHAR: A CHAR: F between? ]
 | |
|         [ CHAR: a CHAR: f between? ]
 | |
|         [ CHAR: 0 CHAR: 9 between? ]
 | |
|     } 1|| ;
 | |
| 
 | |
| M: hex-digit-class class-member? ( obj class -- ? )
 | |
|     drop hex-digit? ; inline
 | |
| 
 | |
| : java-blank? ( ch -- ? )
 | |
|     {
 | |
|         CHAR: \s CHAR: \t CHAR: \n
 | |
|         0xb 0x7 CHAR: \r
 | |
|     } member? ;
 | |
| 
 | |
| M: java-blank-class class-member? ( obj class -- ? )
 | |
|     drop java-blank? ; inline
 | |
| 
 | |
| M: unmatchable-class class-member? ( obj class -- ? )
 | |
|     2drop f ; inline
 | |
| 
 | |
| M: terminator-class class-member? ( obj class -- ? )
 | |
|     drop "\r\n\u000085\u002029\u002028" member? ; inline
 | |
| 
 | |
| M: f class-member? 2drop f ; inline
 | |
| 
 | |
| : same? ( obj1 obj2 quot1: ( obj1 -- val1 ) quot2: ( obj2 -- val2 ) -- ? )
 | |
|     bi* = ; inline
 | |
| 
 | |
| M: script-class class-member?
 | |
|     [ script-of ] [ script>> ] same? ; inline
 | |
| 
 | |
| M: category-class class-member?
 | |
|     [ category ] [ category>> ] same? ; inline
 | |
| 
 | |
| M: category-range-class class-member? inline
 | |
|     [ category first ] [ category>> ] same? ; inline
 | |
| 
 | |
| TUPLE: not-class { class read-only } ;
 | |
| 
 | |
| PREDICATE: not-integer < not-class class>> integer? ;
 | |
| 
 | |
| UNION: simple-class
 | |
|     primitive-class range-class dot ;
 | |
| PREDICATE: not-simple < not-class class>> simple-class? ;
 | |
| 
 | |
| M: not-class class-member?
 | |
|     class>> class-member? not ; inline
 | |
| 
 | |
| TUPLE: or-class { seq read-only } ;
 | |
| 
 | |
| M: or-class class-member?
 | |
|     seq>> [ class-member? ] with any? ; inline
 | |
| 
 | |
| TUPLE: and-class { seq read-only } ;
 | |
| 
 | |
| M: and-class class-member?
 | |
|     seq>> [ class-member? ] with all? ; inline
 | |
| 
 | |
| DEFER: substitute
 | |
| 
 | |
| : flatten ( seq class -- newseq )
 | |
|     '[ dup _ instance? [ seq>> ] [ 1array ] if ] map concat ; inline
 | |
| 
 | |
| :: sequence>instance ( seq empty class -- instance )
 | |
|     seq length {
 | |
|         { 0 [ empty ] }
 | |
|         { 1 [ seq first ] }
 | |
|         [ drop seq { } like class boa ]
 | |
|     } case ; inline
 | |
| 
 | |
| TUPLE: class-partition integers not-integers simples not-simples and or other ;
 | |
| 
 | |
| : partition-classes ( seq -- class-partition )
 | |
|     members
 | |
|     [ integer? ] partition
 | |
|     [ not-integer? ] partition
 | |
|     [ simple-class? ] partition
 | |
|     [ not-simple? ] partition
 | |
|     [ and-class? ] partition
 | |
|     [ or-class? ] partition
 | |
|     class-partition boa ;
 | |
| 
 | |
| : class-partition>sequence ( class-partition -- seq )
 | |
|     {
 | |
|         [ integers>> ]
 | |
|         [ not-integers>> ]
 | |
|         [ simples>> ]
 | |
|         [ not-simples>> ]
 | |
|         [ and>> ]
 | |
|         [ or>> ]
 | |
|         [ other>> ]
 | |
|     } cleave>array concat ;
 | |
| 
 | |
| : repartition ( partition -- partition' )
 | |
|     ! This could be made more efficient; only and and or are effected
 | |
|     class-partition>sequence partition-classes ;
 | |
| 
 | |
| : filter-not-integers ( partition -- partition' )
 | |
|     dup
 | |
|     [ simples>> ] [ not-simples>> ] [ or>> ] tri
 | |
|     3append and-class boa
 | |
|     '[ [ class>> _ class-member? ] filter ] change-not-integers ;
 | |
| 
 | |
| : answer-ors ( partition -- partition' )
 | |
|     dup [ not-integers>> ] [ not-simples>> ] [ simples>> ] tri 3append
 | |
|     '[ [ _ [ t substitute ] each ] map ] change-or ;
 | |
| 
 | |
| : contradiction? ( partition -- ? )
 | |
|     {
 | |
|         [ [ simples>> ] [ not-simples>> ] bi intersects? ]
 | |
|         [ other>> f swap member? ]
 | |
|     } 1|| ;
 | |
| 
 | |
| : make-and-class ( partition -- and-class )
 | |
|     answer-ors repartition
 | |
|     [ t swap remove ] change-other
 | |
|     dup contradiction?
 | |
|     [ drop f ]
 | |
|     [ filter-not-integers class-partition>sequence members t and-class sequence>instance ] if ;
 | |
| 
 | |
| : <and-class> ( seq -- class )
 | |
|     dup and-class flatten partition-classes
 | |
|     dup integers>> length {
 | |
|         { 0 [ nip make-and-class ] }
 | |
|         { 1 [ integers>> first [ '[ _ swap class-member? ] all? ] keep and ] }
 | |
|         [ 3drop f ]
 | |
|     } case ;
 | |
| 
 | |
| : filter-integers ( partition -- partition' )
 | |
|     dup
 | |
|     [ simples>> ] [ not-simples>> ] [ and>> ] tri
 | |
|     3append or-class boa
 | |
|     '[ [ _ class-member? ] reject ] change-integers ;
 | |
| 
 | |
| : answer-ands ( partition -- partition' )
 | |
|     dup [ integers>> ] [ not-simples>> ] [ simples>> ] tri 3append
 | |
|     '[ [ _ [ f substitute ] each ] map ] change-and ;
 | |
| 
 | |
| : tautology? ( partition -- ? )
 | |
|     {
 | |
|         [ [ simples>> ] [ not-simples>> ] bi intersects? ]
 | |
|         [ other>> t swap member? ]
 | |
|     } 1|| ;
 | |
| 
 | |
| : make-or-class ( partition -- and-class )
 | |
|     answer-ands repartition
 | |
|     [ f swap remove ] change-other
 | |
|     dup tautology?
 | |
|     [ drop t ]
 | |
|     [ filter-integers class-partition>sequence members f or-class sequence>instance ] if ;
 | |
| 
 | |
| : <or-class> ( seq -- class )
 | |
|     dup or-class flatten partition-classes
 | |
|     dup not-integers>> length {
 | |
|         { 0 [ nip make-or-class ] }
 | |
|         { 1 [
 | |
|             not-integers>> first
 | |
|             [ class>> '[ _ swap class-member? ] any? ] keep or
 | |
|         ] }
 | |
|         [ 3drop t ]
 | |
|     } case ;
 | |
| 
 | |
| GENERIC: <not-class> ( class -- inverse )
 | |
| 
 | |
| M: object <not-class>
 | |
|     not-class boa ;
 | |
| 
 | |
| M: not-class <not-class>
 | |
|     class>> ;
 | |
| 
 | |
| M: and-class <not-class>
 | |
|     seq>> [ <not-class> ] map <or-class> ;
 | |
| 
 | |
| M: or-class <not-class>
 | |
|     seq>> [ <not-class> ] map <and-class> ;
 | |
| 
 | |
| M: t <not-class> drop f ;
 | |
| M: f <not-class> drop t ;
 | |
| 
 | |
| : <minus-class> ( a b -- a-b )
 | |
|     <not-class> 2array <and-class> ;
 | |
| 
 | |
| : <sym-diff-class> ( a b -- a~b )
 | |
|     2array [ <or-class> ] [ <and-class> ] bi <minus-class> ;
 | |
| 
 | |
| M: primitive-class class-member?
 | |
|     class>> class-member? ; inline
 | |
| 
 | |
| TUPLE: condition question yes no ;
 | |
| C: <condition> condition
 | |
| 
 | |
| GENERIC# answer 2 ( class from to -- new-class )
 | |
| 
 | |
| M:: object answer ( class from to -- new-class )
 | |
|     class from = to class ? ;
 | |
| 
 | |
| : replace-compound ( class from to -- seq )
 | |
|     [ seq>> ] 2dip '[ _ _ answer ] map ;
 | |
| 
 | |
| M: and-class answer
 | |
|     replace-compound <and-class> ;
 | |
| 
 | |
| M: or-class answer
 | |
|     replace-compound <or-class> ;
 | |
| 
 | |
| M: not-class answer
 | |
|     [ class>> ] 2dip answer <not-class> ;
 | |
| 
 | |
| GENERIC# substitute 1 ( class from to -- new-class )
 | |
| M: object substitute answer ;
 | |
| M: not-class substitute [ <not-class> ] bi@ answer ;
 | |
| 
 | |
| : assoc-answer ( table question answer -- new-table )
 | |
|     '[ _ _ substitute ] assoc-map sift-values ;
 | |
| 
 | |
| : assoc-answers ( table questions answer -- new-table )
 | |
|     '[ _ assoc-answer ] each ;
 | |
| 
 | |
| DEFER: make-condition
 | |
| 
 | |
| : (make-condition) ( table questions question -- condition )
 | |
|     [ 2nip ]
 | |
|     [ swap [ t assoc-answer ] dip make-condition ]
 | |
|     [ swap [ f assoc-answer ] dip make-condition ] 3tri
 | |
|     2dup = [ 2nip ] [ <condition> ] if ;
 | |
| 
 | |
| : make-condition ( table questions -- condition )
 | |
|     [ keys ] [ unclip (make-condition) ] if-empty ;
 | |
| 
 | |
| GENERIC: class>questions ( class -- questions )
 | |
| : compound-questions ( class -- questions ) seq>> [ class>questions ] gather ;
 | |
| M: or-class class>questions compound-questions ;
 | |
| M: and-class class>questions compound-questions ;
 | |
| M: not-class class>questions class>> class>questions ;
 | |
| M: object class>questions 1array ;
 | |
| 
 | |
| : table>questions ( table -- questions )
 | |
|     values [ class>questions ] gather >array t swap remove ;
 | |
| 
 | |
| : table>condition ( table -- condition )
 | |
|     ! input table is state => class
 | |
|     >alist dup table>questions make-condition ;
 | |
| 
 | |
| : condition-map ( condition quot: ( obj -- obj' ) -- new-condition )
 | |
|     over condition? [
 | |
|         [ [ question>> ] [ yes>> ] [ no>> ] tri ] dip
 | |
|         '[ _ condition-map ] bi@ <condition>
 | |
|     ] [ call ] if ; inline recursive
 | |
| 
 | |
| : condition-states ( condition -- states )
 | |
|     dup condition? [
 | |
|         [ yes>> ] [ no>> ] bi
 | |
|         [ condition-states ] bi@ union
 | |
|     ] [ 1array ] if ;
 | |
| 
 | |
| : condition-at ( condition assoc -- new-condition )
 | |
|     '[ _ at ] condition-map ;
 |