#!/usr/bin/env janet (import ./grammar/php :as php) (import ./grammar/janet :as janet) (defn read-from-file [file-path] "Read a file from string filepath" (let [f (file/open file-path :r) content (file/read f :all)] (file/close f) content)) (defn write-to-file [file-path content] "Append to file from string filepath" (let [f (file/open file-path :w)] (file/write f content) (file/flush f) (file/close f) content)) (defn htmlspecialchars "Convert html special chars from a string" [value] (string/replace-all "\"" """ (string/replace-all "'" "'" (string/replace-all "<" "<" (string/replace-all ">" ">" (string/replace-all "&" "&" value)))))) (def md-to-ast "A custom markdown flavored grammar" ~{ # Symbole :end-of-line (* (? "\r") "\n") :space "\u0020" :tab (+ "\u0009" (4 :space)) :code-block-tag "```" :list-item-starter (+ "*" "-") :italic-tag "*" :bold-tag "**" :stroke-tag "~~" :code-line-tag "`" :rich-text-tag (+ :italic-tag :bold-tag :stroke-tag :code-line-tag) :basic-text (some (if-not (+ :end-of-line :code-line-tag :stroke-tag :bold-tag :italic-tag) 1)) :c-basic-text (cmt (<- :basic-text),|[:text $0]) :bold (cmt (* :bold-tag :rich-text :bold-tag),|[:bold $0 $&]) :italic (cmt (* :italic-tag :rich-text :italic-tag),|[:italic $0 $&]) :stroke (cmt (* :stroke-tag :rich-text :stroke-tag),|[:stroke $0 $&]) :code-line (cmt (* :code-line-tag (<- :rich-text) :code-line-tag),|[:code-line $0 $&]) :rich-text (cmt (some (+ :code-line :bold :italic :stroke :c-basic-text)),|(map (fn [arg] [(get arg 0) (get arg 1)]) $&)) :line (cmt (* :rich-text :end-of-line),|[:line $0]) # Block :heading (cmt (* (<- (between 1 6 "#")) :space (<- :basic-text)),|[:heading (length $0) $1]) :hr (cmt (* (at-least 3 (+ "-" "_" "*")) :end-of-line),|[:hr]) :code-block (cmt (* :code-block-tag (? (<- :basic-text)) :end-of-line (<- (some (if-not :code-block-tag 1))) :code-block-tag),|[:code-block $0 $1]) :quote (cmt (* ">" :space (? :rich-text)),|[:quote $0]) :list-item (cmt (* (<- (? (between 0 2 :tab))) :list-item-starter :space :rich-text),|[:list-item (/ (length $0) 4) $1]) :list (cmt (some (* :list-item (? :end-of-line))),|[:list $&]) :block (+ :heading :hr :code-block :quote :list :line :end-of-line) :main (some (* :block (? :end-of-line)))}) (defn code-ast-to-html [ast] (string/join (map |(match $0 [:single-line-comment value] (string "" (htmlspecialchars value) "") [:multi-line-comment value] (string "" (htmlspecialchars value) "") [:string value] (string "" (htmlspecialchars value) "") [:variable value] (string "" (htmlspecialchars value) "") [:return-type value] (string "" (htmlspecialchars value) "") [:keyword value] (string "" (htmlspecialchars value) "") [:other value] (htmlspecialchars value) _ (error (string "Invalid symbol: " (get $0 0)))) ast) "")) (defn ast-to-html "Convert an AST to html" [ast] (defn to-codeblock [lang value] (string "
" (code-ast-to-html (peg/match (eval-string (string lang "/to-ast")) value)) "
")) (defn to-codeline [value] (string "" (ast-to-html value) "")) (defn to-heading [level value] (string "" (htmlspecialchars value) "")) (defn to-quote [value] (string "
" (ast-to-html value) "
")) (defn to-line [value] (string "

" (ast-to-html value) "

")) (defn to-italic [value] (string "" (ast-to-html value) "")) (defn to-bold [value] (string "" (ast-to-html value) "")) (defn to-stroke [value] (string "" (ast-to-html value) "")) (string/join (map |(match $0 [:code-block lang value] (to-codeblock lang value) [:heading level value] (to-heading level value) [:quote value] (to-quote value) [:hr] "
" [:line value] (to-line value) [:text value] (htmlspecialchars value) [:italic value] (to-italic value) [:stroke value] (to-stroke value) [:bold value] (to-bold value) [:code-line value] (to-codeline value) _ (error (string "Invalid symbol: " (get $0 0)))) ast) "")) (defn pp-ast "Pretty prints the Mardown AST (as provided by (peg/match md-to-ast))" [ast] (if ast (do (print "[") (map |(printf "\t%q" $0) ast) (print "]")))) (defn main [bin & args] (pp-ast (peg/match md-to-ast (read-from-file "raw/~blog/blog.md"))) (write-to-file "test4.html" (string (read-from-file "partial-template/header.html") (ast-to-html (peg/match md-to-ast (read-from-file "raw/~blog/blog.md"))) (read-from-file "partial-template/footer.html"))))