From 2df1921c9abf756eb2bcb9e99f8ba02eae1a8c53 Mon Sep 17 00:00:00 2001 From: Arun Isaac Date: Tue, 23 Feb 2021 23:04:30 +0530 Subject: Initial commit --- generate-cwl/yaml.scm | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 generate-cwl/yaml.scm (limited to 'generate-cwl/yaml.scm') diff --git a/generate-cwl/yaml.scm b/generate-cwl/yaml.scm new file mode 100644 index 0000000..f4691ca --- /dev/null +++ b/generate-cwl/yaml.scm @@ -0,0 +1,85 @@ +;; +;; scm->yaml +;; +;; This file implements a library to convert a scm tree to yaml. + +(define-module (generate-cwl yaml) + #:use-module (ice-9 match) + #:export (scm->yaml)) + +(define (kebab->camel string) + "Convert STRING from kebab case to CAMEL case." + (match (string-split string #\-) + ((head tail ...) + (string-concatenate + (cons head (map string-titlecase tail)))))) + +(define (display-atom atom port) + "Display ATOM in PORT converting from kebab case to camel case if +ATOM is a symbol." + (cond + ((symbol? atom) + (display (string->symbol (kebab->camel (symbol->string atom))) port)) + ((number? atom) + (display atom port)) + ((string? atom) + ;; Escape string with double quotes if + ;; - every character is a digit or period, and the unescaped + ;; string can therefore be misinterpreted as a number + ;; - string contains the colon character + (if (or (string-every (char-set-union char-set:digit (char-set #\.)) atom) + (string-any #\: atom)) + (write atom port) + (display atom port))) + ((boolean? atom) + (display (if atom "true" "false") port)) + (else (error "Unknown atom" atom)))) + +(define (indent-level port level) + "Emit whitespaces to PORT corresponding to nesting LEVEL." + (display (make-string (* 2 level) #\space) port)) + +(define (display-array-element element port level) + "Display array ELEMENT to PORT at nesting LEVEL." + (display "- " port) + (scm->yaml element port (1+ level))) + +(define (display-dictionary-entry entry port level) + "Display dictionary ENTRY to PORT at nesting LEVEL." + (match entry + ((key . value) + (display-atom key port) + (display ":" port) + (match value + ((or #(_ ...) + ((_ . _) (_ . _) ...)) + (newline port) + (indent-level port (1+ level)) + (scm->yaml value port (1+ level))) + (_ (display " " port) + (scm->yaml value port level)))))) + +(define* (scm->yaml scm #:optional (port (current-output-port)) (level 0)) + "Convert SCM, an S-expression tree, to YAML and display to +PORT. LEVEL is an internal recursion variable." + (match scm + (#(head tail ...) + (display-array-element head port level) + (for-each (lambda (element) + (indent-level port level) + (display-array-element element port level)) + tail)) + (#() + (display "[]" port)) + ((head tail ...) + (display-dictionary-entry head port level) + (for-each (lambda (entry) + (indent-level port level) + (display-dictionary-entry entry port level)) + tail)) + (() + (display "{}" port) + (newline port)) + (symbol + (display-atom symbol port) + (newline port)))) -- cgit v1.2.3