peppi 2.1.2

Parser for Slippi replay files
Documentation
(ns peppi-codegen.frame.immutable.mod
  (:require
   [clojure.java.io :as io]
   [peppi-codegen.common :refer :all]
   [peppi-codegen.frame.common :refer :all]))

(defn array-type
  [ty]
  (cond
    (primitive-types ty) ["PrimitiveArray" ty]
    (nil? ty)            "NullArray"
    :else                ty))

(defn struct-field
  [{nm :name, ty :type, ver :version, desc :description}]
  [:struct-field
   {:docstring (field-docstring desc ver)}
   nm
   (cond->> (array-type ty)
     ver (conj ["Option"]))])

(defn tuple-struct-field
  [{ty :type, ver :version, desc :description}]
  [:tuple-struct-field
   {:docstring desc}
   (cond->> (array-type ty)
     ver (conj ["Option"]))])

(defn transpose-one-field-init
  [{idx :index, nm :name, ty :type, ver :version}]
  (let [real-target [:field-get "self" (or nm idx)]
        target (if ver "x" real-target)
        value (if (primitive-types ty)
                [:subscript [:method-call target "values"] "i"]
                [:method-call target "transpose_one" ["i" "version"]])]
    (if ver
      (wrap-map (as-ref real-target) "x" value)
      value)))

(defn transpose-one-fn
  [nm fields]
  (let [ctype (list "transpose" nm)]
    [:fn
     {:visibility "pub"
      :ret ctype}
     "transpose_one"
     [["&self"]
      ["i" "usize"]
      ["version" "Version"]]
     [:block
      [:struct-init ctype (->> fields
                               (filterv :type)
                               (mapv (juxt :name transpose-one-field-init)))]]]))

(defn into-immutable
  [{idx :index, nm :name, ver :version}]
  (let [target [:field-get "x" (or nm idx)]]
    (if ver
      (wrap-map target "x" [:method-call "x" "into" []])
      [:method-call target "into" []])))

(defn mutable
  [ty]
  (list "mutable" ty))

(defmulti struct-decl
  (fn [[nm {:keys [fields]}]]
    (named? fields)))

(defmethod struct-decl true
  [[nm {:keys [description fields]}]]
  [:struct
   {:attrs {:derive ["Debug"]}
    :docstring description}
   nm
   (->> (mapv struct-field fields)
        (append [:struct-field
                 {:docstring "Indicates which indexes are valid (`None` means \"all valid\"). Invalid indexes can occur on frames where a character is absent (ICs or 2v2 games)"}
                 "validity"
                 ["Option" "Bitmap"]]))])

(defmethod struct-decl false
  [[nm {:keys [description fields]}]]
  [:tuple-struct
   {:attrs {:derive ["Debug"]}
    :docstring description}
   nm
   (mapv tuple-struct-field fields)])

(defn struct-impl
  [[nm {:keys [fields]}]]
  [:impl nm [(transpose-one-fn nm fields)]])

(defn struct-from-impl
  [[nm {:keys [fields]}]]
  [:impl
   {:for nm}
   ["From" (mutable nm)]
   [[:fn
     {:ret "Self"}
     "from"
     [["x" (mutable nm)]]
     [:block
      [:struct-init "Self" (cond->> (mapv (juxt :name into-immutable) fields)
                             (named? fields) (append ["validity"
                                                      [:method-call
                                                       [:field-get "x" "validity"]
                                                       "map"
                                                       [[:closure
                                                         [["v"]]
                                                         [[:method-call "v" "into" []]]]]]]))]]]]])

(defn -main []
  (doseq [decl (mapcat (juxt struct-decl struct-impl struct-from-impl) (read-structs))]
    (println (emit-expr decl) "\n")))