(private fmt-internal) (hidden fmt-internal) (defdynamic fmt-internal [s args] (let [idx (String.index-of s \%) len (String.count s)] (if (= idx -1) (list 'copy s) ; no more splits found, just return string (if (= \% (String.char-at s (inc idx))) ; this is an escaped % (list 'StringCopy.append (list 'copy "%") (fmt-internal (String.substring s (+ idx 2) len) args)) (if (= 0 (count args)) ; we need to insert something, but have nothing (macro-error "error in format string: not enough arguments to format string") ; okay, this is the meat: ; get the next % after our escaper (let [next (String.index-of (String.substring s (inc idx) len) \%)] (if (= -1 next) (if (< 1 (count args)) (macro-error "error in format string: too many arguments to format string") (list 'format s (car args))) (let [slice (String.substring s 0 (+ (inc idx) next))] (list 'StringCopy.append (list 'format slice (car args)) (fmt-internal (String.substring s (+ (inc idx) next) len) (cdr args))))))))))) (doc fmt "fmt formats a string. It supports all of the string interpolations defined in format of the type that should be interpolated (e.g. %d and %x on integers).") (defmacro fmt [s :rest args] (fmt-internal s args))