mnt.janet (4097B)
1 (defn- from-pairs-check [ps] 2 (def ret @{}) 3 (each [k v] ps 4 (if (has-key? ret k) 5 (error (string/format "Duplicate key: '%s'" k)) 6 (put ret k v))) 7 ret) 8 9 (def peg 10 (peg/compile 11 ~{:location (% (* (constant "at [") (line) (constant ":") (/ (column) ,dec) (constant "]: "))) 12 13 :invalid_key_start (+ "- " "> " ": " "[" "{" "#") 14 15 :check_indent (+ (error (* " " (% (* :location 16 (constant "Invalid indentation, try ") 17 (backref :indent) 18 (constant " spaces"))))) true) 19 :check_eof (+ (error (* 1 (% (* :location 20 (constant "Stray characters at the end of file"))))) true) 21 :check_key_start (+ (error (* (<- :invalid_key_start :key_start) 22 (% (* :location 23 (constant "Keys cannot start with: '") 24 (backref :key_start) 25 (constant "'"))))) true) 26 :check_key_end (+ (error (* "\n" (% (* :location 27 (constant "Keys can't contain newlines"))))) true) 28 29 :indent_init (only-tags (constant 0 :indent)) 30 :indent_save (only-tags (* (/ (column) ,dec :indent) (constant false :indent_new))) 31 :indent_saved (lenprefix (backref :indent) " ") 32 :indent_if_new (* (backmatch :indent_new) :indent_saved) 33 :indent_set_new (only-tags (constant "" :indent_new)) 34 :indent_inc (only-tags (/ (backref :indent) ,inc :indent)) 35 :indent (+ (* :indent_if_new (any " ") :indent_save) :indent_saved) 36 37 :value (* " " (<- (to (+ "\n" -1 ))) (+ -1 (some "\n"))) 38 :key (* :check_indent :check_key_start (<- (to (+ "\n" (* (any " ") ":")))) :check_key_end (any " ")) 39 :map (group (* :indent :key ":" (+ (* -1 :empty) :value (unref (* (some "\n") :indent_inc :any))))) 40 :maps (/ (group (unref (* :indent_set_new :map (any (+ :comment :map))))) ,from-pairs-check) 41 42 :string (* :indent ">" :value) 43 :strings (% (unref (* :indent_set_new :string (any (+ :comment (* (constant "\n") :string)))))) 44 45 :list (* :indent "-" :value) 46 :lists (group (unref (* :indent_set_new :list (any (+ :comment :list))))) 47 48 :comment (* (any " ") "#" (to (+ "\n" -1)) (? "\n")) 49 :comments (any :comment) 50 51 :empty (constant "") 52 53 :any (* :comments (+ :strings :lists :maps :empty)) 54 55 :main (* :indent_init :comments :maps :check_eof) 56 })) 57 58 (defn parse [str] 59 (if-let [matched (peg/match peg str)] 60 (matched 0) 61 (error "Unable to parse the string as minimal nested text"))) 62 63 (defn parsefile [path] 64 (def f (file/open path :rn)) 65 (def p (parse (file/read f :all))) 66 (file/close f) 67 p) 68 69 (defn- print_mnt [buf indent &opt key sep value] 70 (buffer/push-string buf (string 71 (string/repeat " " indent) 72 (if (nil? key) "" key) 73 (if (nil? sep) ":" sep) 74 ;(if (nil? value) [] [" " value]) 75 "\n"))) 76 77 (defn unparse [dict &opt opt_dif opt_cur] 78 (if (not (dictionary? dict)) 79 (error "The first argument to unparse must be a table")) 80 81 (def cur (if (nil? opt_cur) 0 opt_cur)) 82 (def dif (if (nil? opt_dif) 2 opt_dif)) 83 (def nxt (+ cur dif)) 84 (def buf @"") 85 (loop [[key val] :pairs dict] 86 (if (not (string? key)) 87 (error "The keys in the table can only be strings")) 88 (cond 89 (dictionary? val) 90 (do 91 (print_mnt buf cur key) 92 (buffer/push-string buf (unparse val dif nxt))) 93 (array? val) 94 (do 95 (print_mnt buf cur key) 96 (each el val 97 (print_mnt buf nxt nil "-" el))) 98 (string? val) 99 (if (nil? (string/find "\n" val)) 100 (print_mnt buf cur key ":" val) 101 (do 102 (print_mnt buf cur key) 103 (each el (string/split "\n" val) 104 (print_mnt buf nxt nil ">" el)))) 105 (error "The table can only contain strings, arrays and tables"))) 106 (buffer/popn buf 1))