2018-05-09 01:43:07 +03:00
(private fmt-internal)
(hidden fmt-internal)
2017-12-26 21:38:48 +03:00
(defdynamic fmt-internal [s args]
(let [idx (String.index-of s \%)
2018-05-20 10:57:51 +03:00
len (String.length s)]
2017-12-30 17:19:43 +03:00
(if (= idx -1)
2018-01-15 14:04:12 +03:00
(list 'copy s) ; no more splits found, just return string
2017-12-30 16:45:27 +03:00
(if (= \% (String.char-at s (inc idx))) ; this is an escaped %
2018-05-20 07:04:47 +03:00
(list 'StringCopy.append
2018-01-15 14:04:12 +03:00
(list 'copy "%")
(fmt-internal (String.substring s (+ idx 2) len) args))
2018-05-20 10:57:51 +03:00
(if (= 0 (length args)) ; we need to insert something, but have nothing
2017-12-30 17:19:43 +03:00
(macro-error "error in format string: not enough arguments to format string")
2017-12-30 16:45:27 +03:00
; okay, this is the meat:
; get the next % after our escaper
(let [next (String.index-of (String.substring s (inc idx) len) \%)]
2017-12-30 20:21:59 +03:00
(if (= -1 next)
2018-05-20 10:57:51 +03:00
(if (< 1 (length args))
2017-12-30 17:19:43 +03:00
(macro-error "error in format string: too many arguments to format string")
2017-12-30 22:16:31 +03:00
(list 'format s (car args)))
2017-12-30 17:04:01 +03:00
(let [slice (String.substring s 0 (+ (inc idx) next))]
2018-05-20 07:04:47 +03:00
(list 'StringCopy.append (list 'format slice (car args))
(fmt-internal (String.substring s (+ (inc idx) next) len)
(cdr args)))))))))))
2017-12-26 21:38:48 +03:00
2018-05-09 01:43:07 +03:00
(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).")
2017-12-30 17:04:01 +03:00
(defmacro fmt [s :rest args]
2017-12-26 21:38:48 +03:00
(fmt-internal s args))