From 0c594ea788f31c561a9d617d5c0764f99429599b Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Thu, 8 Jun 2023 23:03:54 -0500 Subject: Rewrite; rename to chicken-scratch --- chicken-scratch.scm | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100755 chicken-scratch.scm (limited to 'chicken-scratch.scm') diff --git a/chicken-scratch.scm b/chicken-scratch.scm new file mode 100755 index 0000000..e47ad67 --- /dev/null +++ b/chicken-scratch.scm @@ -0,0 +1,78 @@ +;;; CHICKEN-SCRATCH --- heredocs for CHICKEN +;; written by Case Duckworth off an idea by evhan +;; Licensed under BSD-3. See COPYING for details. + +;; CHICKEN has "Multiline string constants with embedded expressions" syntax, +;; which is basically shell here-doc syntax but schemier and with a real +;; programming langugage to embed. evhan's beaker tool (which is great, btw) +;; uses this facility to do a quick-and-dirty templating for wiki generation. I +;; realized that I could use the same facility for the same kind of +;; heredoc-style templating I have done in various other SSGs like unk and +;; vienna, but with scheme. Thus, CHICKEN-SCRATCH was born. + +;; USAGE + +;; `expand-string' is the main entry point to this module. It takes a string and +;; returns a string with all #( ... ) forms expanded according to the CHICKEN +;; rules. `expand-port' is a port version of `expand-string'. + +;; To enable truly invisible definitions within the expanded string, the `def' +;; macro is provided which performs a `set!' on its variables, then returns a +;; string guaranteed not to be in the input string, which is then filtered out +;; in the expanded string. + +;; Finally, to enable CHICKEN-SCRATCH to be used in a shebang, if the first line +;; of the input string begins with #!, it's deleted from the input. + +(module chicken-scratch + (expand-string + expand-port + def + %def/replacer) + + (import scheme + (chicken base) + (only (chicken io) + read-string) + (only (chicken irregex) + irregex-replace + irregex-replace/all + irregex-search) + (only (chicken port) + make-concatenated-port) + (only (chicken random) + pseudo-random-real)) + + (define %def/replacer (make-parameter #f)) + + (define (expand-string str) + (parameterize ((%def/replacer (random-string-not-in str))) + (let* ((delim (random-string-not-in str)) + (template (make-concatenated-port + (open-input-string (string-append "#<#" delim "\n")) + (open-input-string (irregex-replace "^#!.*\n" str "")) + (open-input-string (string-append "\n" delim "\n")))) + (expanded (open-output-string)) + (output (begin + (display (eval (read template)) expanded) + (get-output-string expanded)))) + (irregex-replace/all `(seq ,(%def/replacer) (* "\n")) + output + "")))) + + (define (expand-port #!optional port) + (let ((port (or port (current-input-port)))) + (expand-string (read-string #f port)))) + + (define-syntax def + (syntax-rules () + ((def var val) + ;; I think this only works in CHICKEN. + (begin (set! var val) + (%def/replacer))))) + + (define (random-string-not-in str) + (let ((attempt (number->string (pseudo-random-real)))) + (if (irregex-search attempt str) + (random-string-not-in str) + attempt)))) -- cgit 1.4.1-21-gabe81