~subsetpark/ec

70a63e918bad9c3ae7c94cd699e0d4c0cb947774 — Zach Smith 8 months ago b162ab6 v0.2.0
Implement evaluation and environments. Parsing produces symbols which are conditionally evaluated. Quotations contain unevaluated symbols.
M main.janet => main.janet +8 -6
@@ 1,6 1,8 @@
(import /src/calc)
(import /src/print)
(import /src/parser)
(import /src/env)
(import /src/eval)

(use argparse)



@@ 23,7 25,7 @@

(defn- display-help
  []
  (each [k v] (pairs parser/dictionary)
  (each [k v] (pairs env/dictionary)
    (printf "%s: %s" k (string (v :type))))
  "")



@@ 42,8 44,8 @@
(defn- handle-special
  [s special]
  (case (freeze (string/trim special))
    "." (display (calc/peek s))
    "p" (display (calc/pop s))
    "." (display (calc/pop s))
    "p" (display (calc/peek s))
    "s" (display-all (s :data))
    "?" (describe-all (calc/pop s))
    "??" (display-help)))


@@ 53,7 55,7 @@
  (each token input
    (match token
      @[:special patt] (handle-special s patt)
      _ (calc/push s token))))
      _ (eval/eval-and-push s token))))

(defn- prompt
  [s]


@@ 65,10 67,10 @@

(defn repl
  []
  (def s (:new calc/Stack))
  (def s (env/new-env))
  (while true
    (def bak (array/slice (s :data)))
    (try (->> (getline (prompt s) @"" parser/dictionary)
    (try (->> (getline (prompt s) @"" env/dictionary)
              (handle-signal)
              (parser/parse)
              (handle-commands s))

M src/adverbs.janet => src/adverbs.janet +27 -36
@@ 1,4 1,5 @@
(import /src/calc)
(import /src/eval)

(defmacro defadv
  [name arity doc & body]


@@ 8,14 9,6 @@
                    :type ,(keyword name)
                    :fun-ref (fn ,name [stack] ,;body))))

(defn- do-apply
  [stack quotation]
  (if (calc/Quotation*? quotation)
      (do (calc/check-arity stack quotation)
        (each elem (calc/data quotation)
          (calc/push stack elem)))
      (calc/push stack quotation)))

(defadv apply-quotation 1
  ```
  q -- x


@@ 23,9 16,9 @@
  `1 1 (+) apply` is equivalent to `1 1 +`.
  ```
  (let [quotation (calc/pop stack)]
    (do-apply stack quotation)))
    (eval/apply-quotation stack quotation)))

(defadv distribute 0
(defadv map-quotation 2
  ```
  v q -- x
  Insert the contents of quotation `q` in between every element of


@@ 38,23 31,18 @@
                    (calc/quote-wrap q))
        v (calc/pop stack)]

    (defn push-verb []
      (calc/check-arity stack quotation)
      (each verb-elem (calc/data quotation)
        (calc/push stack verb-elem)))

    (if (calc/Quotation*? v)
      (each elem (calc/data v)
        (calc/push stack elem)
        (push-verb))
        (eval/apply-quotation stack quotation))
      (do
        (calc/push stack v)
        (push-verb)))))
        (eval/apply-quotation stack quotation)))))

(defadv wrap-stack 0
  ```
  (x) -- q
  Wrap the entire stack in a quotation. 
  (x) -- v
  Wrap the entire stack in a vector. 
  ```
  (let [v (calc/wrap ;(stack :data))]
    (array/clear (stack :data))


@@ 133,17 121,6 @@
          new-quotation (calc/fill elem unwrapped-shape)]
      (calc/push stack new-quotation))))

(defadv arity 1
  ```
  a -- n
  Pushes the number of stack elements that `a` would consume
  if it were pushed to the stack.
  ```
  (let [elem (calc/pop stack)
        arity (calc/get-arity elem)
        new-elem (calc/make-element arity)]
    (calc/push stack new-elem)))

(defadv shape 1
  ```
  v -- w


@@ 156,16 133,20 @@

(defadv if 3
  ```
  p qt qf -- x
  If `p` = 0, applies `qf`.
  qp qt qf -- x
  If `qp !` = 0, applies `qf`.
     else applies `qt`.
  ```
  (let [qf (calc/pop stack)
        qt (calc/pop stack)
        p (calc/pop stack)]
    (case (p :value)
      0 (do-apply stack qf)
      (do-apply stack qt))))
        qp (calc/pop stack)]

    (eval/apply-quotation stack qp)

    (let [result (calc/pop stack)]
      (case (result :value)
        0 (eval/apply-quotation stack qf)
        (eval/apply-quotation stack qt)))))

(defadv pop 1
  ```


@@ 173,3 154,13 @@
  Pops the top element of the stack.
  ```
  (calc/pop stack))

(defadv dip 2
  ```
  a q --- a
  Pops the quotation `q`, pops `a`, applies `q`, and pushes `a`.
  ```
  (let [q (calc/pop stack)
        a (calc/pop stack)]
    (eval/apply-quotation stack q)
    (calc/push stack a)))

M src/calc.janet => src/calc.janet +36 -40
@@ 1,12 1,13 @@
(use fugue)

(defproto Stack () data {:default @[]})
(defproto Stack ()
  env {}
  data {:default @[]})

(defproto Element ()
  doc {:default ""})

(defproto Number Element
  out-arity {:allocate-value 1})
(defproto Number Element)

(defproto Int Number
  type {:allocate-value :integer}


@@ 16,19 17,19 @@
  type {:allocate-value :float}
  value {:init? true})

(defproto Symbol Element
  value {:init? true}
  quoted? {:default false})

(defproto Operation Element
  type {}
  arity {}
  out-arity {}
  fun-ref {})

(defproto Adverb Element
  type {}
  arity {}
  out-arity {:allocate-value math/inf})
  type {})

(defproto Quotation Element
  out-arity {:allocate-value 1}
  data {:init? true}
  type {:allocate-value :quotation})



@@ 37,6 38,10 @@
  data {:init? true}
  type {:allocate-value :vector})

(defproto Thunk Quotation
  data {:init? true}
  type {:allocate-value :thunk})

(defgeneric get-shape [elem]
  (errorf "Shape error: attempted vector operation on a %s"
          ((table/getproto elem) :_name)))


@@ 44,22 49,8 @@
(defmethod get-shape Number [self] [])
(defmethod get-shape Vector [self] (self :shape))

(defgeneric get-arity [_] 0)
(defmethod get-arity Adverb [a] (a :arity))
(defmethod get-arity Operation [a] (a :arity))
(defmethod get-arity Quotation [q]
  (def arities @[])
  
  (loop [i :range [0 (length (q :data))]]
    (if (zero? i)
      (array/push arities
                  (get-arity (get-in q [:data i])))
      (array/push arities
                  (+ (last arities)
                     (- (get-arity (get-in q [:data i]))
                        (get-in q [:data (dec i) :out-arity]))))))

  (max ;arities))

(defmethod fill Number
  [element shape-to-fill]


@@ 136,39 127,44 @@
  [self]
  (-> (self :data) (last)))

(defmethod size Stack
(defmulti size [Stack]
  [self]
  (-> (self :data) (length)))

(defmulti size [:tuple] [t] (length t))
(defmulti size [_] [_] 0)

(defn check-arity
  [stack elem]
  (let [arity (get-arity elem)]
    (when (> arity (size stack))
      (errorf "Not enough stack: %s has arity %i; stack has size %i"
      (errorf "Not enough stack: %s has arity %i; Stack has size %i"
              (string (elem :type))
              arity
              (size stack)))))

(defmulti push [Stack Operation]
  [self op]
  (check-arity self op)
(declare-open-multi push)

(extend-multi push [Stack Operation]
              [self op]
              (check-arity self op)

  (def buf @[])
  (loop [_ :range [0 (get-arity op)]]
    (array/insert buf 0 (pop self)))
              (def buf @[])
              (loop [_ :range [0 (get-arity op)]]
                (array/insert buf 0 (pop self)))

  (->> (apply-operation op ;buf)
       (make-element)
       (push self)))
              (->> (apply-operation op ;buf)
                   (make-element)
                   (push self)))

(defmulti push [Stack Adverb]
  [self adv]
  (check-arity self adv)
  ((adv :fun-ref) self))
(extend-multi push [Stack Adverb]
              [self adv]
              (check-arity self adv)
              ((adv :fun-ref) self))

(defmulti push [Stack _]
  [self item]
  (array/push (self :data) item))
(extend-multi push [Stack _]
              [self item]
              (array/push (self :data) item))

(defn shape?
  [obj]

M src/compose.janet => src/compose.janet +8 -0
@@ 12,3 12,11 @@
                                   ~(calc/push stack ,word))))))

(defcompose square 1 adverbs/dup operations/mul)

(defcompose abs 1
  (calc/quote-wrap (:new calc/Int 0) operations/lt)
  (calc/quote-wrap (:new calc/Int 0) adverbs/swap operations/sub)
  (calc/quote-wrap)
  adverbs/if)

(defcompose wrap-1 1 (calc/wrap) adverbs/slurp-left)

A src/env.janet => src/env.janet +53 -0
@@ 0,0 1,53 @@
(import /src/calc)
(import /src/operations)
(import /src/adverbs)
(import /src/compose)
(import /src/eval)


(def dictionary @{"+" operations/add
                  "-" operations/sub
                  "*" operations/mul
                  "x" operations/mul
                  "%" operations/div
                  "sqrt" operations/sqrt
                  ">" operations/gt
                  "<" operations/lt
                  ">=" operations/gte
                  "<=" operations/lte
                  "=" operations/eq
                  "cmp" operations/cmp
                  "pow" operations/pow
                  "small" operations/small

                  # Combinators
                  "map" adverbs/map-quotation
                  "apply" adverbs/apply-quotation
                  "i" adverbs/apply-quotation
                  "if" adverbs/if
                  # Stack operations
                  "clear" adverbs/clear-stack
                  "c" adverbs/clear-stack
                  "swap" adverbs/swap
                  "dup" adverbs/dup
                  "pop" adverbs/pop
                  "dip" adverbs/dip
                  # Array logic-bypassing
                  "shape" adverbs/shape
                  # Quotation
                  "wrap-all" adverbs/wrap-stack
                  "fill" adverbs/fill
                  "slurp" adverbs/slurp
                  "slurpl" adverbs/slurp-left
                  "slurpr" adverbs/slurp
                  # Definition
                  "def" eval/define

                  "sqr" compose/square
                  "abs" compose/abs
                  "wrap-1" compose/wrap-1})

(defn new-env
  []
  (let [s (:new calc/Stack)]
    (put s :env (table/setproto @{} dictionary))))

A src/eval.janet => src/eval.janet +62 -0
@@ 0,0 1,62 @@
(use fugue)
(use /src/calc)

(def define (:new Adverb
                  :arity 2
                  :type :define
                  :fun-ref (fn define [stack]
                             (let [sym (pop stack)
                                   q (pop stack)]
                               (match sym
                                 {:value sym-value :quoted? true} (put-in stack [:env sym-value] q))))))


(defn lookup
  ```
  Look up a symbol in a stack 's environment. The symbol might refer
  to an atomic element or to an unevaluated quotation.
  ```
  [stack sym-value]
  (match (get-in stack [:env sym-value])
    # Mark the stored quotation for evaluation by creating a Thunk out
    # of it, which is a Quotation that evaluates its contents when
    # pushed to the stack.
    (q (Quotation? q)) (:new Thunk (q :data))
    nil (errorf "Eval error: unknown word %s" sym-value)
    elem elem))

(defn eval
  ```
  Evaluate an unquoted symbol by looking it up in the stack
  environment; all other types evaluate to themselves.
  ```
  [stack sym]
  (match sym
    {:value sym-value :quoted? false} (lookup stack sym-value)
    _ sym))

(defn apply-quotation
  ```
  Quotation evaluation. Given any potentially unevaluated quotation,
  evaluate and push each element.
  ```
  [stack maybe-quote]
  (match maybe-quote
    (q (Quotation*? q)) (each elem (data q)
                          (->> elem
                               (eval stack)
                               (push stack)))
    not-a-quote (push stack not-a-quote)))

(extend-multi push
              [Stack Thunk]
              [stack thunk]
              (let [evaled (map |(eval stack $) (thunk :data))
                    q (:new Quotation evaled)]
                (apply-quotation stack q)))

(defn eval-and-push
  [stack symbol]
  (->> symbol
       (eval stack)
       (push stack)))

M src/operations.janet => src/operations.janet +27 -25
@@ 1,42 1,44 @@
(import /src/calc)

(defmacro defop
  [name arity out-arity f &opt doc]
  [name arity f &opt doc]
  ~(def ,name (:new calc/Operation
                    :arity ,arity
                    :out-arity ,out-arity
                    :type ,(keyword name)
                    :fun-ref ,f
                    :doc ,doc)))

(defop add 2 +)
(defop sub 2 -)
(defop div 2 /)
(defop mul 2 *)
(defop cmp 2 cmp
  `
  x y -- bool
  Push -1 if x < y;
        0 if x = y;
        1 if x > y.
  `)
(defop pow 2 math/pow)
(defop sqrt 1 math/sqrt)
(defop small 1 |(or (= $ 0) (= $ 1))
  "x -- bool\nPush 1 if x is 0 or 1.")

(defmacro defcmp
  [name arity out-arity cmp]
  ~(defop ,name ,arity ,out-arity
  [name arity cmp]
  ~(defop ,name ,arity
     (fn [x y] (if (,cmp x y) 1 0))
     (string/format
      `
       `
      x y -- bool
      Comparison predicate.
      Push 1 if x %s y;
             else 0.
      ` ,(string cmp))))

(defop add 2 1 +)
(defop sub 2 1 -)
(defop div 2 1 /)
(defop mul 2 1 *)
(defop cmp 2 1 cmp
  `
  x y -- bool
  Push -1 if x < y;
        0 if x = y;
        1 if x > y.
  `)
(defop pow 2 1 math/pow)
(defop sqrt 1 1 math/sqrt)
      `
       ,(string cmp))))

(defcmp lt 2 1 <)
(defcmp gt 2 1 >)
(defcmp lte 2 1 <=)
(defcmp gte 2 1 >=)
(defcmp eq 2 1 =)
(defcmp lt 2 <)
(defcmp gt 2 >)
(defcmp lte 2 <=)
(defcmp gte 2 >=)
(defcmp eq 2 =)

M src/parser.janet => src/parser.janet +7 -42
@@ 1,41 1,4 @@
(import /src/calc)
(import /src/operations)
(import /src/adverbs)
(import /src/compose)

(def dictionary {"+" operations/add
                 "-" operations/sub
                 "*" operations/mul
                 "x" operations/mul
                 "%" operations/div
                 "sqrt" operations/sqrt
                 ">" operations/gt
                 "<" operations/lt
                 ">=" operations/gte
                 "<=" operations/lte
                 "=" operations/eq
                 "cmp" operations/cmp
                 "pow" operations/pow

                 "distribute" adverbs/distribute
                 "/" adverbs/distribute
                 "apply" adverbs/apply-quotation
                 "!" adverbs/apply-quotation
                 "@" adverbs/wrap-stack
                 "swap" adverbs/swap
                 "slurp" adverbs/slurp
                 "slurpl" adverbs/slurp-left
                 "slurpr" adverbs/slurp
                 "clear" adverbs/clear-stack
                 "c" adverbs/clear-stack
                 "fill" adverbs/fill
                 "dup" adverbs/dup
                 "arity" adverbs/arity
                 "shape" adverbs/shape
                 "if" adverbs/if
                 "pop" adverbs/pop

                 "sqr" compose/square})

(defn handle-parens
  [& patt]


@@ 61,11 24,13 @@

(defn handle-word
  [patt]
  (cond (index-of patt ["." "p" "s" "?" "??"])
    [:special patt]
    true
    (or (dictionary patt)
        (errorf "syntax error: unknown word %s" patt))))
  (cond
    (index-of patt ["." "p" "s" "?" "??"]) [:special patt]
    (string/has-prefix? "'" patt) (:new calc/Symbol
                                        (string/slice patt 1)
                                        :quoted? true)
    (:new calc/Symbol patt
          :quoted? false)))

(def- peg (peg/compile
            ~{:main (any (+ :s+ :quotes :vectors :token))

M src/print.janet => src/print.janet +3 -0
@@ 14,6 14,9 @@
(defmulti p [calc/Adverb]
  [a] (string (a :type)))

(defmulti p [calc/Symbol]
  [{:value value}] value)

(varfn join [q] nil)

(defmulti p [calc/Quotation] [q] (join q "(" ")"))

M test-support.janet => test-support.janet +5 -4
@@ 1,4 1,5 @@
(import /src/calc)
(import /src/eval)

(use testament)



@@ 30,7 31,7 @@
                {:value value} value)]
    (is (== val found))))

(defn push-all
  [stack args]
  (each arg args
    (calc/push stack arg)))
(defn eval-all
  [stack tokens]
  (each token tokens
    (eval/eval-and-push stack token)))

D test/arity-checks.janet => test/arity-checks.janet +0 -38
@@ 1,38 0,0 @@
(import /src/calc)

(import /src/operations :prefix "o/")
(import /src/adverbs :prefix "a/")

(use testament)
(use /test-support)

(defn test-arity
  [n elem doc]
  (is (= n (calc/get-arity elem)) doc)
  (let [s (:new calc/Stack)]
    (loop [_ :range [0 n]]
      (calc/push s (:new calc/Int 0)))
    (calc/push s elem)
    (calc/push s a/apply-quotation)))

(deftest get-arity
  (test-arity 2 (quote-wrap o/add)
      "A quoted operation's arity is the operation's arity")
  (test-arity 3 (quote-wrap o/add o/add)
      ```
      A composition of operations' arity is the greatest of the
      individual operations' arities, each adjusted for the out-arity
      of the one prior
      ```)
  (test-arity 2 (quote-wrap o/add 2 o/add)
      "Interposed numbers will reduce the arity of a quotation")
  (test-arity 0 (:new calc/Int 2)
      "A number's arity is 0")
  (test-arity 0 (quote-wrap 2)
      "A quoted number's arity is 0")
  (test-arity 0 (quote-wrap 2 2 2 2)
      "A quoted sequence of numbers is 0")
  (test-arity 0 (quote-wrap 2 2 o/add)
      "A quoted operation is 0 if the quote enough values to fulfill it"))

(run-tests!)

M test/calc.janet => test/calc.janet +13 -7
@@ 44,24 44,30 @@
            @[8 10 12]]]
        (calc/apply-operation o/add m filled)))

(deftest distribute-add
(deftest map-add
  (def s (:new calc/Stack))
  # Initial value
  (calc/push s (:new calc/Int 0))
  # Operands
  (calc/push s (wrap 1 2 3))
  # Operator
  (calc/push s (quote-wrap o/add))
  (calc/push s a/distribute)
  (calc/push s a/map-quotation)
  (pop-and-compare 6 s))

(deftest distribute-multiple-operations
(deftest map-multiple-operations
  (def s (:new calc/Stack))
  (calc/push s (:new calc/Int 0))
  (calc/push s (wrap 1 2 3))
  (calc/push s (quote-wrap 3 o/mul o/add))
  (calc/push s a/distribute)
  (pop-and-compare 18 s))
  (calc/push s (quote-wrap 4 o/mul o/add))
  # 0 [1 2 3]
  # [2 3] 0 1 4 * +
  # [2 3] 4
  # [3] 4 2 4 * +
  # [3] 12
  # 12 3 4 * +
  # 24
  (calc/push s a/map-quotation)
  (pop-and-compare 24 s))

(deftest apply-quotation
  (def s (:new calc/Stack))

A test/env.janet => test/env.janet +45 -0
@@ 0,0 1,45 @@
(import /src/calc)
(import /src/parser)
(import /src/eval)
(import /src/env)

(import /src/operations :prefix "o/")
(import /src/adverbs :prefix "a/")

(use testament)
(use /test-support)

(deftest not-found
  (let [s (env/new-env)]
    (is (thrown? (eval/lookup s "foo")))))

(deftest atom-definition
  (let [s (env/new-env)
        parsed (parser/parse "40 'foo def")]
    (eval-all s parsed)
    (let [lookup (eval/lookup s "foo")]
      (is (calc/Int? lookup))
      (is (= 40 (lookup :value))))))

(deftest quotation-definition
  (let [s (env/new-env)
        parsed (parser/parse "(1 +) 'inc def")]
    (eval-all s parsed)
    (let [lookup (eval/lookup s "inc")]
      (is (calc/Thunk? lookup))
      (let [[one plus] (lookup :data)]
        (is (calc/Int? one))
        (is (= 1 (one :value)))

        (is (calc/Symbol? plus))
        (is (= "+" (plus :value)))))))

(deftest quotation-application
  (let [s (env/new-env)
        parsed (parser/parse "(1 +) 'inc def 10 inc")]
    (eval-all s parsed)
    (let [eleven (calc/peek s)]
      (is (calc/Float? eleven))
      (is (= 11 (eleven :value))))))

(run-tests!)

A test/eval.janet => test/eval.janet +34 -0
@@ 0,0 1,34 @@
(import /src/calc)
(import /src/parser)
(import /src/eval)
(import /src/env)

(import /src/operations :prefix "o/")
(import /src/adverbs :prefix "a/")

(use testament)
(use /test-support)

(deftest pushable
  (let [s (env/new-env)
        parsed (parser/parse "4 5 +")]
    (eval-all s parsed)

    (is (= 1 (length (s :data))))
    (def res (first (s :data)))

    (is (= 9 (res :value)))
    (is (calc/Float? res))))

(deftest push-adverb
  (let [s (env/new-env)
        parsed (parser/parse "0 [1 2 3] (+) map")]
    (eval-all s parsed)

    (is (= 1 (length (s :data))))
    (def res (first (s :data)))

    (is (= 6 (res :value)))
    (is (calc/Float? res))))

(run-tests!)

M test/parser.janet => test/parser.janet +12 -28
@@ 36,33 36,17 @@
    (is (calc/Int? underscored))))

(deftest word
  (let [[add dist] (parser/parse "+ /")]
    (is (= add o/add))
    (is (calc/Operation? add))

    (is (= dist a/distribute))
    (is (calc/Adverb? dist))))

(deftest pushable
  (let [s (:new calc/Stack)
        parsed (parser/parse "4 5 +")]
    (push-all s parsed)

    (is (= 1 (length (s :data))))
    (def res (first (s :data)))

    (is (= 9 (res :value)))
    (is (calc/Float? res))))

(deftest push-adverb
  (let [s (:new calc/Stack)
        parsed (parser/parse "0 [1 2 3] (+) /")]
    (push-all s parsed)

    (is (= 1 (length (s :data))))
    (def res (first (s :data)))

    (is (= 6 (res :value)))
    (is (calc/Float? res))))
  (let [[add i] (parser/parse "+ i")]
    (is (= "+" (add :value)))
    (is (calc/Symbol? add))

    (is (= "i" (i :value)))
    (is (calc/Symbol? i))))

(deftest symbol
  (let [[parsed] (parser/parse "'foo")]
    (is (calc/Symbol? parsed))
    (is (= true (parsed :quoted?)))
    (is (= "foo" (parsed :value)))))

(run-tests!)

M test/regressions.janet => test/regressions.janet +18 -16
@@ 1,6 1,8 @@
(import /src/calc)
(import /src/parser)
(import /src/print)
(import /src/eval)
(import /src/env)

(import /src/operations :prefix "o/")
(import /src/adverbs :prefix "a/")


@@ 10,35 12,35 @@

(deftest regression1
  # [1] 1 + 1 +
  (def s (:new calc/Stack))
  (def s (env/new-env))
  (let [in (parser/parse "[1] 1 + 1 +")]
    (calc/push s (in 0))
    (eval/eval-and-push s (in 0))
    (vec= [1] (calc/peek s))
    (calc/push s (in 1))
    (eval/eval-and-push s (in 1))
    (vec= 1 (calc/peek s))
    (calc/push s (in 2))
    (eval/eval-and-push s (in 2))
    (vec= [2] (calc/peek s))
    (calc/push s (in 3))
    (eval/eval-and-push s (in 3))
    (vec= 1 (calc/peek s))
    (calc/push s (in 4)))
    (eval/eval-and-push s (in 4)))

  (def res (calc/pop s))
  (vec= [3] res))

(deftest regression2
  # [4 5] 6 +  8 +
  (def s (:new calc/Stack))
  (def s (env/new-env))
  (let [in (parser/parse "[4 5] 6 + 8 +")]
    (push-all s in))
    (eval-all s in))

  (def res (calc/pop s))
  (vec= [18 19] res))

(deftest regression3
  # [2 3 4] 1 -
  (def s (:new calc/Stack))
  (def s (env/new-env))
  (let [in (parser/parse "[2 3 4] 1 -")]
    (push-all s in))
    (eval-all s in))

  (def res (calc/pop s))
  (vec= [1 2 3] res))


@@ 46,18 48,18 @@
(deftest regression4
  # ([[1] [2] [3]])> !
  #could not find method :- for 0, or :r- for nil
  (def s (:new calc/Stack))
  (let [in (parser/parse "[[1][2]] !")]
    (push-all s in))
  (def s (env/new-env))
  (let [in (parser/parse "[[1][2]] i")]
    (eval-all s in))
  (while ((complement empty?) (s :data))
    (def inner-q (calc/pop s))
    (is (= [1] (calc/get-shape inner-q)))))

(deftest regression5
  # .[.[2].[4]] [.[2 1] fill] /
  (def s (:new calc/Stack))
  (let [in (parser/parse "[[2][4]] ([2 1] fill) /")]
    (push-all s in))
  (def s (env/new-env))
  (let [in (parser/parse "[[2][4]] ([2 1] fill) map")]
    (eval-all s in))
  # Distribute `[2 1] fill`:
  # Push [2]
  # Push [2 1] fill