interpolate: allow mixing of named variables and stack arguments.

db4
John Benediktsson 2015-04-18 17:18:37 -07:00
parent 1ce1e2d27e
commit ce491a5aa1
3 changed files with 82 additions and 38 deletions

View File

@ -1,10 +1,24 @@
USING: help.markup help.syntax math strings ; USING: help.markup help.syntax io math strings ;
IN: interpolate IN: interpolate
HELP: ninterpolate HELP: interpolate.
{ $values { "str" string } { "n" integer } } { $values { "str" string } }
{ $description "Assigns stack arguments to numbered variables for string interpolation." } { $description "String interpolation using named variables and/or stack arguments, writing to the " { $link output-stream } "." }
{ $examples { $examples
{ $example "USING: interpolate ;" "\"Bob\" \"Alice\" \"Hi ${0}, it's ${1}.\" 2 ninterpolate" "Hi Bob, it's Alice." } { $example
} "USING: interpolate ;"
{ $see-also interpolate } ; "\"Bob\" \"Alice\" \"Hi ${0}, it's ${1}.\" interpolate."
"Hi Bob, it's Alice."
}
{ $example
"USING: interpolate namespaces ;"
"\"Fred\" \"name\" [ \"Hi ${name}\" interpolate. ] with-variable"
"Hi Fred"
}
} ;
HELP: interpolate
{ $values { "str" string } { "newstr" string } }
{ $description "String interpolation using named variables and/or stack arguments, captured as a " { $link string } "." } ;
{ interpolate interpolate. } related-words

View File

@ -3,21 +3,30 @@
USING: interpolate io.streams.string namespaces tools.test locals ; USING: interpolate io.streams.string namespaces tools.test locals ;
IN: interpolate.tests IN: interpolate.tests
[ "Hello, Jane." ] [ { "A B" } [ "A" "B" "${0} ${1}" interpolate ] unit-test
{ "B A" } [ "A" "B" "${1} ${0}" interpolate ] unit-test
{ "C A" } [ "A" "B" "C" "${2} ${0}" interpolate ] unit-test
{ "Hello, Jane." } [
"Jane" "name" set "Jane" "name" set
[ "Hello, ${name}." interpolate ] with-string-writer "Hello, ${name}." interpolate
] unit-test ] unit-test
[ "Sup Dawg, we heard you liked rims, so we put rims on your rims so you can roll while you roll." ] [ { "Mr. John" } [
"John" "name" set
"Mr." "${0} ${name}" interpolate
] unit-test
{ "Sup Dawg, we heard you liked rims, so we put rims on your rims so you can roll while you roll." } [
"Dawg" "name" set "Dawg" "name" set
"rims" "noun" set "rims" "noun" set
"roll" "verb" set "roll" "verb" set
[ "Sup ${name}, we heard you liked ${noun}, so we put ${noun} on your ${noun} so you can ${verb} while you ${verb}." interpolate ] with-string-writer "Sup ${name}, we heard you liked ${noun}, so we put ${noun} on your ${noun} so you can ${verb} while you ${verb}." interpolate
] unit-test ] unit-test
[ "Oops, I accidentally the whole economy..." ] [ { "Oops, I accidentally the whole economy..." } [
[let [let
"economy" :> noun "economy" :> noun
[ I[ Oops, I accidentally the whole ${noun}...]I ] with-string-writer "accidentally" [ I[ Oops, I ${0} the whole ${noun}...]I ] with-string-writer
] ]
] unit-test ] unit-test

View File

@ -1,50 +1,71 @@
! Copyright (C) 2008, 2009 Slava Pestov. ! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays fry hashtables io kernel macros make USING: accessors fry generalizations io io.streams.string kernel
math.parser multiline namespaces present sequences locals macros make math math.order math.parser multiline
sequences.generalizations splitting strings vocabs.parser ; namespaces present sequences splitting strings vocabs.parser ;
IN: interpolate IN: interpolate
<PRIVATE <PRIVATE
TUPLE: interpolate-var name ; TUPLE: named-var name ;
: (parse-interpolate) ( string -- ) TUPLE: stack-var n ;
: (parse-interpolate) ( str -- )
[ [
"${" split1-slice [ >string , ] [ "${" split1-slice [
[ >string , ] unless-empty
] [
[ [
"}" split1-slice "}" split1-slice
[ >string interpolate-var boa , ] [
>string dup string>number
[ stack-var boa ] [ named-var boa ] ?if ,
]
[ (parse-interpolate) ] bi* [ (parse-interpolate) ] bi*
] when* ] when*
] bi* ] bi*
] unless-empty ; ] unless-empty ;
: parse-interpolate ( string -- seq ) : parse-interpolate ( str -- seq )
[ (parse-interpolate) ] { } make ; [ (parse-interpolate) ] { } make ;
: (interpolate) ( string quot -- quot' ) : max-stack-var ( seq -- n/f )
[ parse-interpolate ] dip '[ f [
dup interpolate-var? dup stack-var? [ n>> [ or ] keep max ] [ drop ] if
[ name>> @ '[ _ @ present write ] ] ] reduce ;
[ '[ _ write ] ]
if :: interpolate-quot ( str quot -- quot' )
] map [ ] join ; inline str parse-interpolate :> args
args max-stack-var :> vars
args [
dup named-var? [
name>> quot call '[ _ @ present write ]
] [
dup stack-var? [
n>> vars swap - 1 + '[ _ npick present write ]
] [
'[ _ write ]
] if
] if
] map concat
vars [
1 + '[ _ ndrop ] append
] when* ; inline
PRIVATE> PRIVATE>
MACRO: interpolate ( string -- ) MACRO: interpolate. ( str -- )
[ [ get ] ] (interpolate) ; [ [ get ] ] interpolate-quot ;
: interpolate-locals ( string -- quot ) : interpolate ( str -- newstr )
[ search [ ] ] (interpolate) ; [ interpolate. ] with-string-writer ; inline
: interpolate-locals ( str -- quot )
[ dup search [ [ ] ] [ [ get ] ] ?if ] interpolate-quot ;
SYNTAX: I[ SYNTAX: I[
"]I" parse-multiline-string "]I" parse-multiline-string
interpolate-locals append! ; interpolate-locals append! ;
MACRO: ninterpolate ( str n -- quot )
swap '[
_ narray [ number>string swap 2array ] map-index
>hashtable [ _ interpolate ] with-variables
] ;