Skip to content

Instantly share code, notes, and snippets.

@jnpn
Last active July 18, 2019 17:57
Show Gist options
  • Save jnpn/a91379550ade745df25f4f8d92efc4ee to your computer and use it in GitHub Desktop.
Save jnpn/a91379550ade745df25f4f8d92efc4ee to your computer and use it in GitHub Desktop.
Attempt at bringing f-string in elisp.
;; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with C-x C-f and enter text in its buffer.
;;
;;; Attempt at bringing f-string in elisp.
;;; (@f "{a} = {b}")
;;; ->
;;; (let ((a~ a)
;;; (b~ b))
;;; (concatenate 'string a~ " = " b~))
(setq lexical-binding t)
(defun re-find-all (s r z)
(let ((m (string-match r s z)))
(if m
(let* ((n (match-string-no-properties 0 s))
(l (length n)))
(cons (list n m l) (re-find-all s r (1+ m))))
'())))
;;+test: (re-find-all "xxx @f @@b yyy @c zzz" "\\(@[^ ]+\\)" 0)
;;+test: (re-find-all "xxx {f} {b} yyy {c} zzz" "\\({[^ }]+}\\)" 0)
(defun split-at* (s z ps)
"
s... ((s b d) ...)
"
(if (null ps)
(list (substring-no-properties s z))
(cons (substring-no-properties s z (cadr (car ps)))
(split-at* s (+ (cadr (car ps)) (caddr (car ps))) (cdr ps)))))
(defvar *fstring-re* "\\({[^ }]+}\\)")
(defvar *fstring-stripper* (lambda (s) (substring-no-properties s 1 (1- (length s)))))
;;+test: (funcall *fstring-stripper* "{f}")
(defun parse-fstring (fstring)
(let* ((parsed (re-find-all fstring *fstring-re* 0)))
(list (cons :bindings parsed)
(cons :chunks (split-at* fstring 0 parsed)))))
(defmacro comment (f)
`(progn
,f))
;;+test: (-zip '(1 2 3) '(a b c))
;;+test: (-zip-with #'list '(1 2 3) '(a b c))
;;+test: (-zip-pair '(1 2 3) '(a b c))
(defmacro @f (s)
(let* ((parsed (parse-fstring s))
(bindings (mapcar (lambda (b) (funcall *fstring-stripper* (car b)))
(cdr (assoc :bindings parsed))))
(chunks (cdr (assoc :chunks parsed)))
(names (mapcar #'gensym bindings))
(bindings (mapcar #'intern bindings))
(filled-chunks (-interleave-rest chunks names)))
`(let ,(-zip-with (lambda (a b) (list a (list 'format "%s" b))) names bindings)
(funcall #'concatenate 'string ,@filled-chunks))))
(defun -interleave-rest (a b)
"because -interleave drops too early"
(cond ((null a) b)
((null b) a)
(t (cons (car a) (-interleave-rest b (cdr a))))))
(-interleave-rest '(1 2 3) '(a b c d))
;;+test: (format "%s" 1)
(defun test ()
(let ((f 1)
(g 2))
(@f "{f} = {g}")))
(test)
(defun test-0 ()
(let ((f 1)
(g 2))
(@f "")))
(test-0)
(defun test-1 ()
(let ((f 1)
(g 2))
(@f "(Formatted {f} = {g})")))
(test-1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment