instow

:)
git clone https://git.sr.ht/~ashymad/instow
Log | Files | Refs | LICENSE

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))