(defn parse-dot
[[_ target & [m-or-f & args] :as form] env]
(when-not (>= (count form) 3)
(throw (ex-info (str "Wrong number of args to ., had: " (dec (count form)))
(merge {:form form}
(-source-info form env)))))
(let [[m-or-f field?] (if (and (symbol? m-or-f)
(= \- (first (name m-or-f))))
[(-> m-or-f name (subs 1) symbol) true]
[(if args (cons m-or-f args) m-or-f) false])
target-expr (analyze-form target (ctx env :ctx/expr))
call? (and (not field?) (seq? m-or-f))]
(when (and call? (not (symbol? (first m-or-f))))
(throw (ex-info (str "Method name must be a symbol, had: " (class (first m-or-f)))
(merge {:form form
:method m-or-f}
(-source-info form env)))))
(merge {:form form
:env env
:target target-expr}
(cond
call?
{:op :host-call
:method (symbol (name (first m-or-f)))
:args (mapv (analyze-in-env (ctx env :ctx/expr)) (next m-or-f))
:children [:target :args]}
field?
{:op :host-field
:assignable? true
:field (symbol (name m-or-f))
:children [:target]}
:else
{:op :host-interop ;; either field access or no-args method call
:assignable? true
:m-or-f (symbol (name m-or-f))
:children [:target]}))))