#!/usr/bin/env janet # need to get comment, link, doctag, string literal/regexp, other literal, keyword identifier? # based on https://github.com/php/php-langspec/blob/ca697b43031efd70b5306d29b74e1190e7eacac8/spec/19-grammar.md (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 pp-ast "Pretty prints the PHP AST (as provided by (peg/match php-to-ast))" [ast] (if ast (do (print "[") (map |(printf "\t%q" $0) ast) (print "]")))) (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 php-to-ast "A custom markdown flavored grammar" ~{ :end-of-line (* (? "\r") "\n") :single-line-comment (cmt (<- (* (+ "//" "#") (some (if-not :end-of-line 1)))),|[:single-line-comment (string/join $&)]) :multi-line-comment (cmt (<- (* "/*" (some (if-not "*/" 1)) "*/")),|[:multi-line-comment (string/join $&)]) :comment (+ :single-line-comment :multi-line-comment) :string (cmt (<- (* "\"" (some (if-not "\"" 1)) "\"")),|[:string (string/join $&)]) :name-non-digit (+ :a "_") :name (some (+ :name-non-digit (range "\x80\xFF"))) :variable (cmt (<- (* "$" :name)),|[:variable (string/join $&)]) :scalar-type (+ "bool" "float" "int" "string") :base-type (+ "array" "callable" "iterable" :scalar-type) :return-type (cmt (<- (+ :base-type "void")),|[:return-type $0]) :keyword (cmt (<- (+ "abstract" "and" "array" "as" "break" "callable" "case" "catch" "class" "clone" "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif" "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile" "eval" "exit" "extends" "final" "finally" "for" "foreach" "function" "fn" "global" "goto" "if" "implements" "include" "include_once" "instanceof" "insteadof" "interface" "isset" "list" "namespace" "new" "or" "print" "private" "protected" "public" "require" "require_once" "return" "static" "switch" "throw" "trait" "try" "unset" "use" "var" "while" "xor" "yield" "yield from")),|[:keyword $0]) :other (cmt (<- (if-not :comment 1)),|[:other (string/join $&)]) :main (some (+ :comment :string :variable :return-type :keyword :other))}) (defn 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 main [bin & args] # (pp-ast (peg/match php-to-ast (read-from-file "sample.php")))) (write-to-file "php.html" (string "
" (ast-to-html (peg/match php-to-ast (read-from-file "sample.php"))) "
")))