From d720bcd8aa948fb58087ca9c11a8c8c5ab52db4b Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Sat, 10 Aug 2024 12:30:07 +0200 Subject: Start cook parsing --- cook/parse.scm | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cook/parse.sld | 10 ++++ 2 files changed, 153 insertions(+) create mode 100644 cook/parse.scm create mode 100644 cook/parse.sld diff --git a/cook/parse.scm b/cook/parse.scm new file mode 100644 index 0000000..8403221 --- /dev/null +++ b/cook/parse.scm @@ -0,0 +1,143 @@ +(import (srfi 1) + (srfi 9) + (srfi 69) + (chibi char-set ascii) + (chibi char-set) + (chibi parse) + (chibi regexp) + (chibi parse common)) +#| +https://github.com/cooklang/spec/blob/main/EBNF.md +|# +(define-record-type + (make-amount quantity unit) + amount? + (quantity amount-quantity) + (unit amount-unit)) + +(define-record-type + (make-component name amount) + component? + (name component-name) + (amount component-amount)) + +(define-record-type + (make-ingredient name amount) + ingredient? + (name ingredient-name) + (amount ingredient-amount)) + +(define (component->ingredient comp) + (make-ingredient (component-name comp) (component-amount comp))) + +(define-record-type + (make-cookware name amount) + cookware? + (name cookware-name) + (amount cookware-amount)) + +(define (component->cookware comp) + (make-cookware (component-name comp) (component-amount comp))) + +(define-record-type + (make-timer name amount) + timer? + (name timer-name) + (amount timer-amount)) + +(define (component->timer comp) + (make-timer (component-name comp) (component-amount comp))) + +(define-record-type + (make-metadata-line key value) + metadata-line? + (key metadata-line-key) + (value metadata-line-value)) + +(define-record-type + (make-step elements) + step? + (elements step-elements)) + +(define (metadata-line-list->hash-table meta-lines) + (let ((metadata (make-hash-table))) + (for-each (lambda (line) + (hash-table-set! metadata + (metadata-line-key line) + (metadata-line-value line))) + meta-lines) + metadata)) + + +(define newline-chars (char-set #\x000A #\x000D #\x0085 #\x2028 #\x2029)) +(define punctuation-chars (char-set #\. #\{ #\})) ;; TODO: do it right +(define word-chars (char-set-difference char-set:full + punctuation-chars + char-set:whitespace)) +(define text-chars (char-set-difference char-set:full + (char-set #\@ #\# #\~) + newline-chars)) +(define unit-chars (char-set-difference text-chars (char-set #\}))) +(define component-chars (char-set-difference text-chars (char-set #\{ #\}))) +(define quantity-chars (char-set-difference text-chars (char-set #\} #\%))) +(define metadata-chars (char-set-difference text-chars (char-set #\:))) + +(define-grammar cook + (newline ((+ ,newline-chars))) + (whitespace ((+ ,char-set:whitespace))) + + (text-item ((: (=> c (+ ,text-chars))) + (list->string c))) + + (comment ((: "--" (=> c (+ ,text-chars)) ,newline) + (list->string c)) + ((: "[-" (=> c (* any)) "-]") + (list->string c))) + + (word ((=> w (+ ,word-chars)) + (list->string w))) + (unit ((=> u (+ ,unit-chars)) + (list->string u))) + (quantity ((=> q (+ ,quantity-chars)) + (list->string q))) + (meta-key ((=> k (+ ,metadata-chars)) + (list->string k))) + + (amount ((: (=> q ,quantity) "%" (=> u ,unit)) + (make-amount q u)) + ((=> q ,quantity) + (make-amount q #f))) + + (no-word-component ((: (=> x (? ,component-chars)) + "{" (? (=> a ,amount)) "}") + (make-component (list->string x) a))) + (component ((: (=> x (+ ,word)) (? (:"{" (=> a ,amount) "}"))) + (make-component x a)) + ((: (=> x (+ ,component-chars)) "{" (? (=> a ,amount)) "}") + (make-component (list->string x) a))) + + (timer ((: "~" (=> c (or ,component ,no-word-component))) + (component->timer c))) + (cookware ((: "#" (=> c ,component)) + (component->cookware c))) + (ingredient ((: "@" (=> c ,component)) + (component->ingredient c))) + + (step ((: (=> s (+ (or ,ingredient + ,cookware + ,timer + ,text-item))) + ,newline) + (make-step s))) + + (metadata ((: bol ">>" (* ,whitespace) + (=> k ,meta-key) + (* ,whitespace) ":" (* ,whitespace) + (=> v ,text-item) (* ,whitespace) ,newline) + (make-metadata-line k v))) + + (recipe ((* (or (=> m (+ ,metadata)) (=> s (+ ,step)))) + (list 'recipe (metadata-line-list->hash-table m) s)))) + +(define (parse-cook str) + (parse-fully recipe str)) diff --git a/cook/parse.sld b/cook/parse.sld new file mode 100644 index 0000000..9f4eaa3 --- /dev/null +++ b/cook/parse.sld @@ -0,0 +1,10 @@ +(define-library (cook parse) + (export parse-cook) + (import (srfi 1) + (srfi 9) + (srfi 69) + (chibi char-set ascii) + (chibi char-set) + (chibi parse) + (chibi regexp)) + (include "parse.scm")) -- cgit v1.2.3