! Copyright (C) 2009 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: xml xml.state kernel sequences fry assocs xml.data accessors strings make multiline parser namespaces macros sequences.deep generalizations locals words combinators math ; IN: xml.interpolate xml-chunk ] with-variable ; : interpolated-doc ( string -- xml ) t interpolating? [ string>xml ] with-variable ; DEFER: interpolate-sequence : interpolate-attrs ( table attrs -- attrs ) swap '[ dup interpolated? [ var>> _ at ] when ] assoc-map ; : interpolate-tag ( table tag -- tag ) [ nip name>> ] [ attrs>> interpolate-attrs ] [ children>> [ interpolate-sequence ] [ drop f ] if* ] 2tri ; GENERIC: push-item ( item -- ) M: string push-item , ; M: object push-item , ; M: sequence push-item % ; GENERIC: interpolate-item ( table item -- ) M: object interpolate-item nip , ; M: tag interpolate-item interpolate-tag , ; M: interpolated interpolate-item var>> swap at push-item ; : interpolate-sequence ( table seq -- seq ) [ [ interpolate-item ] with each ] { } make ; : interpolate-xml-doc ( table xml -- xml ) (clone) [ interpolate-tag ] change-body ; GENERIC# (each-interpolated) 1 ( item quot -- ) inline M: interpolated (each-interpolated) call ; M: tag (each-interpolated) swap attrs>> values [ interpolated? ] filter swap each ; M: object (each-interpolated) 2drop ; : each-interpolated ( xml quot -- ) '[ _ (each-interpolated) ] deep-each ; inline :: number<-> ( doc -- doc ) 0 :> n! doc [ dup var>> [ n >>var n 1+ n! ] unless drop ] each-interpolated doc ; MACRO: interpolate-xml ( string -- doc ) interpolated-doc number<-> '[ _ interpolate-xml-doc ] ; MACRO: interpolate-chunk ( string -- chunk ) interpolated-chunk number<-> '[ _ interpolate-sequence ] ; : >search-hash ( seq -- hash ) [ dup search ] H{ } map>assoc ; : extract-variables ( xml -- seq ) [ [ var>> , ] each-interpolated ] { } make ; : collect ( accum seq -- accum ) { { [ dup [ ] all? ] [ >search-hash parsed ] } ! locals { [ dup [ not ] all? ] [ ! fry length parsed \ narray parsed \ parsed ] } [ drop "XML interpolation contains both fry and locals" throw ] ! mixed } cond ; : parse-def ( accum delimiter word -- accum ) [ parse-multiline-string [ interpolated-chunk extract-variables collect ] keep parsed ] dip parsed ; PRIVATE> : " \ interpolate-xml parse-def ; parsing : [XML "XML]" \ interpolate-chunk parse-def ; parsing