~subsetpark/ec

603ec2239a258dcb283f48501d47444ca156c546 — Zach Smith 9 months ago 94834b6
Add some documentation
5 files changed, 205 insertions(+), 24 deletions(-)

M README.md
M main.janet
M project.janet
M src/adverbs.janet
M src/operations.janet
M README.md => README.md +90 -1
@@ 6,8 6,97 @@ An RPN calculator with array operations and quotations.
9
(nil)> [3 4 5] 6 x
([18 24 30])> 0 swap
([18 24 30])> [+] /
([18 24 30])> (+) /
(72)> p
72
(nil)> 
```

# Usage 

   ec <expression>: evaluate <expression> as a sequence of
                    ec commands and print the resulting stack.
   ec             : enter interactive (repl) mode.

   ec operates as a RPN desk calculator with quotation
   and vector math functions. Ordinarily, tokens are
   evaluated from left to right as they're pushed onto
   the stack. eg.,

       3 4 +

   will push 3, then 4, then apply the operation +, which
   will pop two elements from the stack, add them, and
   push their sum.

   To quote a sequence of tokens, wrap it in
   parentheses. eg.,

       (3 4 +)

   will push a single quotation containing just those
   three tokens, which can be applied by subsequent
   commands.

   To create a vector, enclose a sequence of numbers or
   other vectors in square brackets. eg.,

       [3 4]

   will create a 1-dimensional vector and push it on the
   stack.

   Vectors can be added to other vectors or individual
   numbers. eg.,
 
       [3 4] 2 +

   will add 2 to each element of [3 4], resulting in
   [5 6].

       [3 4] [2 1] +

   will add matching elements of vectors, resulting in
   [5 5].

   Vectors can be of arbitrary dimension, but must
   contain homogeneous data. eg.,

       [[2 1] [0 0]]

   is a valid vector (of shape [2 2]), but

       [[2] [0 0]]

   is not.

   For a full dictionary listing, enter the special
   command:

     ??

   To get a description of any word, quote it and use the
   special command. eg.,

       (!) ?

   Will print a description of the `apply` adverb.

# Installation

On Arch Linux, install `ec` via AUR:

`yay -S ec`

On other systems, install the [Janet][] language, clone this
repository and build using `jpm`:

```
$ mkdir janet_modules
$ JANET_PATH=janet_modules/ jpm load-lockfile
$ JANET_PATH=janet_modules/ jpm build
$ cp build/ec <somewhere on your path>
```

[Janet]: https://janet-lang.org


M main.janet => main.janet +83 -4
@@ 2,6 2,8 @@
(import /src/print)
(import /src/parser)

(use argparse)

(defn handle-signal
  [input]
  (let [str (string input)]


@@ 105,8 107,85 @@
         (handle-commands s))
    (display-all (s :data))))

(def params
  [```
   A desk calculator with vectors and quotations.

   USAGE:
      ec <expression>: evaluate <expression> as a sequence of
                       ec commands and print the resulting stack.
      ec             : enter interactive (repl) mode.
   
      ec operates as a RPN desk calculator with quotation
      and vector math functions. Ordinarily, tokens are
      evaluated from left to right as they're pushed onto
      the stack. eg.,
   
          3 4 +
   
      will push 3, then 4, then apply the operation +, which
      will pop two elements from the stack, add them, and
      push their sum.
   
      To quote a sequence of tokens, wrap it in
      parentheses. eg.,
   
          (3 4 +)
   
      will push a single quotation containing just those
      three tokens, which can be applied by subsequent
      commands.
   
      To create a vector, enclose a sequence of numbers or
      other vectors in square brackets. eg.,
   
          [3 4]
   
      will create a 1-dimensional vector and push it on the
      stack.
   
      Vectors can be added to other vectors or individual
      numbers. eg.,
    
          [3 4] 2 +
   
      will add 2 to each element of [3 4], resulting in
      [5 6].
   
          [3 4] [2 1] +
   
      will add matching elements of vectors, resulting in
      [5 5].
   
      Vectors can be of arbitrary dimension, but must
      contain homogeneous data. eg.,
   
          [[2 1] [0 0]]
   
      is a valid vector (of shape [2 2]), but
   
          [[2] [0 0]]
   
      is not.
   
      For a full dictionary listing, enter the special
      command:
   
        ??
   
      To get a description of any word, quote it and use the
      special command. eg.,
   
          (!) ?
   
      Will print a description of the `apply` adverb.
   ```
   :default {:kind :accumulate}])

(defn main
  [_cmd & args]
  (if (empty? args)
    (repl)
    (handle-line (string/join args " "))))
  [& _args]
  (let [res (argparse ;params)]
    (when res
      (match (res :default)
        nil (repl)
        inputs (handle-line (string/join inputs " "))))))

M project.janet => project.janet +2 -1
@@ 2,7 2,8 @@
  :name "ec"
  :description "a very good calculator"
  :dependencies ["fugue"
                 "https://github.com/pyrmont/testament"])
                 "argparse"
                 "testament"])

(def *static-build* (= (or (os/getenv "EC_STATIC_BUILD") "0") "1"))


M src/adverbs.janet => src/adverbs.janet +14 -14
@@ 12,7 12,7 @@
  ```
  q -- x
  "Unwrap" a quotation and push its elements onto the stack.
  `1 1 [+] apply` is equivalent to `1 1 +`.
  `1 1 (+) apply` is equivalent to `1 1 +`.
  ```
  (let [quotation (calc/pop stack)]
    (if (calc/Quotation*? quotation)


@@ 84,11 84,11 @@
(defadv slurp 2
  ```
  q a -- q
  If the second element on the stack `q` is a quotation, includes the
  topmost element as the last item in `q`.
  If the second element on the stack `q` is a quotation,
  includes the topmost element as the last item in `q`.

  If either element is a quotation, wraps the two top elements in a
  quotation.
  If either element is a quotation, wraps the two top
  elements in a quotation.
  ```
  (let [elem (calc/pop stack)
        vector (calc/pop stack)


@@ 100,11 100,11 @@
(defadv slurp-left 2
  ```
  a q -- q
  If the topmost element on the stack `q` is a quotation, includes the
  second element as the first item in `q`.
  If the topmost element on the stack `q` is a quotation,
  includes the second element as the first item in `q`.
  
  If either element is a quotation, wraps the two top elements in a
  quotation.
  If either element is a quotation, wraps the two top
  elements in a quotation.
  ```
  (let [vector (calc/pop stack)
        elem (calc/pop stack)


@@ 116,8 116,8 @@
(defadv fill 2
  ```
  a s -- a'
  Given a quotation shape `s`, repeats the element `a` until it has
  that shape.
  Given a quotation shape `s`, recursively repeats the
  element `a` until it has that shape.
  ```
  (let [shape (calc/pop stack)
        elem (calc/pop stack)]


@@ 132,8 132,8 @@
(defadv arity 1
  ```
  a -- n
  Returns the number of stack elements that `a` would consume if it
  were pushed to the stack.
  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)


@@ 143,7 143,7 @@
(defadv shape 1
  ```
  v -- w
  Returns the shape of the vector `v`.
  Pushes the shape of the vector `v`.
  ```
  (let [v (calc/pop stack)
        shape (calc/get-shape v)

M src/operations.janet => src/operations.janet +16 -4
@@ 1,23 1,35 @@
(import /src/calc)

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

(defmacro defcmp
  [name arity out-arity cmp]
  ~(defop ,name ,arity ,out-arity
     (fn [x y] (if (,cmp x y) 1 0))))
     (fn [x y] (if (,cmp x y) 1 0))
     (string/format
      `x y -- p
       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)
(defop cmp 2 1 cmp
  `x y -- p
  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)