1 ! Copyright (C) 2009 Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: xml xml.state kernel sequences fry assocs xml.data
4 accessors strings make multiline parser namespaces macros
5 sequences.deep generalizations words combinators
6 math present arrays unicode.categories ;
11 : string>chunk ( string -- chunk )
12 t interpolating? [ string>xml-chunk ] with-variable ;
14 : string>doc ( string -- xml )
15 t interpolating? [ string>xml ] with-variable ;
17 DEFER: interpolate-sequence
19 : interpolate-attrs ( table attrs -- attrs )
22 [ var>> _ at dup [ present ] when ] when
23 ] assoc-map [ nip ] assoc-filter ;
25 : interpolate-tag ( table tag -- tag )
27 [ attrs>> interpolate-attrs ]
28 [ children>> [ interpolate-sequence ] [ drop f ] if* ] 2tri
31 GENERIC: push-item ( item -- )
32 M: string push-item , ;
33 M: xml-data push-item , ;
34 M: object push-item present , ;
36 dup xml-data? [ , ] [ [ push-item ] each ] if ;
37 M: number push-item present , ;
38 M: xml-chunk push-item % ;
40 GENERIC: interpolate-item ( table item -- )
41 M: object interpolate-item nip , ;
42 M: tag interpolate-item interpolate-tag , ;
43 M: interpolated interpolate-item
44 var>> swap at push-item ;
46 : interpolate-sequence ( table seq -- seq )
47 [ [ interpolate-item ] with each ] { } make ;
49 : interpolate-xml-doc ( table xml -- xml )
50 (clone) [ interpolate-tag ] change-body ;
52 : (each-interpolated) ( item quot: ( interpolated -- ) -- )
54 { [ over interpolated? ] [ call ] }
56 [ attrs>> values [ interpolated? ] filter ] dip each
58 { [ over xml? ] [ [ body>> ] dip (each-interpolated) ] }
60 } cond ; inline recursive
62 : each-interpolated ( xml quot -- )
63 '[ _ (each-interpolated) ] deep-each ; inline
65 : number<-> ( doc -- dup )
70 ] each-interpolated drop ;
72 GENERIC: interpolate-xml ( table xml -- xml )
74 M: xml interpolate-xml
77 M: xml-chunk interpolate-xml
78 interpolate-sequence <xml-chunk> ;
80 : >search-hash ( seq -- hash )
81 [ dup search ] H{ } map>assoc ;
83 : extract-variables ( xml -- seq )
84 [ [ var>> , ] each-interpolated ] { } make ;
86 : nenum ( ... n -- assoc )
87 narray <enum> ; inline
89 : collect ( accum variables -- accum ? )
91 { [ dup empty? ] [ drop f ] } ! Just a literal
92 { [ dup [ ] all? ] [ >search-hash parsed t ] } ! locals
93 { [ dup [ not ] all? ] [ length parsed \ nenum parsed t ] } ! fry
94 [ drop "XML interpolation contains both fry and locals" throw ] ! mixed
97 : parse-def ( accum delimiter quot -- accum )
98 [ parse-multiline-string [ blank? ] trim ] dip call
99 [ extract-variables collect ] keep swap
100 [ number<-> parsed ] dip
101 [ \ interpolate-xml parsed ] when ; inline
106 "XML>" [ string>doc ] parse-def ; parsing
109 "XML]" [ string>chunk ] parse-def ; parsing