aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alv/builtins.moon16
-rw-r--r--alv/cell.moon14
-rw-r--r--docs/reference/03-3_functions.md8
-rw-r--r--docs/reference/03-4_dynamic-symbols.md4
-rw-r--r--docs/reference/03-5_loops.md4
-rw-r--r--docs/reference/03-6_modules-and-loading.md2
-rw-r--r--spec/lib/array_spec.moon23
-rw-r--r--spec/lib/builtins/fn_spec.moon20
-rw-r--r--spec/lib/struct_spec.moon9
9 files changed, 63 insertions, 37 deletions
diff --git a/alv/builtins.moon b/alv/builtins.moon
index 84978f1..6e36c7e 100644
--- a/alv/builtins.moon
+++ b/alv/builtins.moon
@@ -12,7 +12,7 @@ import
import Constant from require 'alv.result'
import Error from require 'alv.error'
import RTNode from require 'alv.rtnode'
-import Cell from require 'alv.cell'
+import Cell, ArrayCell from require 'alv.cell'
import Dummy from require 'alv.dummy'
import Scope from require 'alv.scope'
import Tag from require 'alv.tag'
@@ -194,7 +194,7 @@ fn = Constant.meta
meta:
name: 'fn'
summary: "Declare a function."
- examples: { '(fn (p1 [p2…]) body-expr)' }
+ examples: { '(fn [p1 p2…] body-expr)' }
description: "
The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
function is invoked."
@@ -205,7 +205,7 @@ function is invoked."
assert #tail == 2, "'fn' takes exactly two arguments"
{ params, body } = tail
- assert params.__class == Cell, "'fn's first argument has to be an expression"
+ assert params.__class == ArrayCell, "'fn's first argument has to be a [parmeter list]"
param_symbols = for param in *params.children
assert param.type == T.sym, "function parameter declaration has to be a symbol"
param
@@ -220,7 +220,7 @@ defn = Constant.meta
meta:
name: 'defn'
summary: "Define a function."
- examples: { '(defn name-sym (p1 [p2…]) body-expr)' }
+ examples: { '(defn name-sym [p1 p2…] body-expr)' }
description: "
Declare a function and define it as `name-sym` in the current scope.
The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
@@ -233,7 +233,7 @@ function is invoked."
{ name, params, body } = tail
name = name\unwrap T.sym
- assert params.__class == Cell, "'defn's second argument has to be an expression"
+ assert params.__class == ArrayCell, "'defn's second argument has to be a [parameter list]"
param_symbols = for param in *params.children
assert param.type == T.sym, "function parameter declaration has to be a symbol"
param
@@ -636,7 +636,7 @@ loop = Constant.meta
meta:
name: 'loop'
summary: "Loop on arbitrary data via recursion."
- examples: { '(loop (k1 v1 [k2 v2…]) body)' }
+ examples: { '(loop [k1 v1 [k2 v2…]] body)' }
description: "
Defines a recursive loop function `*recur*` with parameters `k1`, `k2`, … and
function body `body`, then invokes it immediately with arguments `v1`, `v2`, …
@@ -644,7 +644,7 @@ function body `body`, then invokes it immediately with arguments `v1`, `v2`, …
Inside the `body`, `(recur)` is used to recursively restart loop evaluation
with a different set of arguments, e.g. to sum the first `5` integers:
- (loop (n 5)
+ (loop [n 5]
(if (= n 0)
0
(+ n (recur (n - 1)))))"
@@ -655,7 +655,7 @@ with a different set of arguments, e.g. to sum the first `5` integers:
assert #tail == 2, "'loop' takes exactly two arguments"
{ binds, body } = tail
- assert binds.__class == Cell, "loops bindings have to be an cell"
+ assert binds.__class == ArrayCell, "loops bindings have to be a [parameter list]"
assert #binds.children % 2 == 0, "key without binding in loop binding"
names = {}
diff --git a/alv/cell.moon b/alv/cell.moon
index 8d1e5f6..989d4ad 100644
--- a/alv/cell.moon
+++ b/alv/cell.moon
@@ -190,9 +190,11 @@ class ArrayCell extends RootCell
tail: => @children
stringify: => '[' .. super! .. ']'
- new: (...) =>
- Cell.__init @, ...
+ eval: (...) =>
assert #@children > 0, Error 'syntax', "array literal can't be empty"
+ super ...
+
+ new: (...) => Cell.__init @, ...
--- @type StructCell
class StructCell extends RootCell
@@ -200,10 +202,12 @@ class StructCell extends RootCell
tail: => @children
stringify: => '{' .. super! .. '}'
- new: (...) =>
- Cell.__init @, ...
+ eval: (...) =>
assert #@children > 0, Error 'syntax', "struct literal can't be empty"
- assert #@children % 2 == 0, Error 'syntax', "struct literal can't have uneven number values"
+ assert #@children % 2 == 0, Error 'syntax', "struct literal must have even number of values"
+ super ...
+
+ new: (...) => Cell.__init @, ...
--- @type TemplateString
class TemplateString extends Cell
diff --git a/docs/reference/03-3_functions.md b/docs/reference/03-3_functions.md
index 6715eb7..4fc32ba 100644
--- a/docs/reference/03-3_functions.md
+++ b/docs/reference/03-3_functions.md
@@ -5,8 +5,7 @@ code, amongst other things:
(import* math)
(def add-and-trace
- (fn
- (a b)
+ (fn [a b]
(trace (+ a b))))
(add-and-trace 1 2)
@@ -29,8 +28,7 @@ example is equivalent to the following:
(import* math)
(def add-and-trace
- (fn
- (a b)
+ (fn [a b]
(trace (+ a b)))
(do
@@ -53,5 +51,5 @@ name, so there is the `defn` shorthand, which combines the `def` and `fn`
builtins into a single expression. Compare this equivalent definition of the
`add-and-trace` function:
- (defn add-and-trace (a b)
+ (defn add-and-trace [a b]
(trace (+ a b)))
diff --git a/docs/reference/03-4_dynamic-symbols.md b/docs/reference/03-4_dynamic-symbols.md
index eb12a41..fdaa1b9 100644
--- a/docs/reference/03-4_dynamic-symbols.md
+++ b/docs/reference/03-4_dynamic-symbols.md
@@ -8,7 +8,7 @@ then the surrounding scope (the whole file), where the value `"original
message"` is found:
(def hello "original message")
- (defn print-hello () (print hello))
+ (defn print-hello [] (print hello))
(do
(def hello "overwritten message")
@@ -24,7 +24,7 @@ scope that contains the *function definition*, but rather the scope containing
the *function call site*:
(def *hello* "original message")
- (defn print-hello () (print *hello*))
+ (defn print-hello [] (print *hello*))
(do
(def *hello* "overwritten message")
diff --git a/docs/reference/03-5_loops.md b/docs/reference/03-5_loops.md
index aedc4ab..d25fa03 100644
--- a/docs/reference/03-5_loops.md
+++ b/docs/reference/03-5_loops.md
@@ -6,7 +6,7 @@ begins a recursive loop, and [recur][] is used to restart it:
(import* math logic string)
- (loop (n 5)
+ (loop [n 5]
(when (!= n 0)
(print (str "hello #" n))
(recur (- n 1))))
@@ -30,7 +30,7 @@ as follows:
(import* math logic string)
- (defn loop-fn (n)
+ (defn loop-fn [n]
(when (!= n 0)
(print (str "hello #" n))
(loop-fn (- n 1))))
diff --git a/docs/reference/03-6_modules-and-loading.md b/docs/reference/03-6_modules-and-loading.md
index cb53cc1..0f28e7e 100644
--- a/docs/reference/03-6_modules-and-loading.md
+++ b/docs/reference/03-6_modules-and-loading.md
@@ -57,7 +57,7 @@ rather the newly created scope. It can therefore be combined with [def][],
(export
(def a-value 7)
- (defn print-doubled (x) (print (str x " doubled is " (* x 2)))))
+ (defn print-doubled [x] (print (str x " doubled is " (* x 2)))))
`main.alv`
diff --git a/spec/lib/array_spec.moon b/spec/lib/array_spec.moon
index 130138c..dcad2ad 100644
--- a/spec/lib/array_spec.moon
+++ b/spec/lib/array_spec.moon
@@ -6,15 +6,20 @@ describe "array", ->
svec3 = Array 3, T.str
- it "can contain any type", ->
- COPILOT\eval_once '[1 2 3]'
- COPILOT\eval_once '[true false]'
- COPILOT\eval_once '["a"]'
- COPILOT\eval_once '[[1 2] [3 4]]'
-
- it "cannot contain mixed types", ->
- err = assert.has.error -> COPILOT\eval_once '[1 false]'
- assert.matches "argument error: couldn't match arguments", err
+ describe "literal", ->
+ it "can't be empty", ->
+ err = assert.has.error -> COPILOT\eval_once '[]'
+ assert.matches "syntax error: array literal can't be empty", err
+
+ it "can contain any type", ->
+ COPILOT\eval_once '[1 2 3]'
+ COPILOT\eval_once '[true false]'
+ COPILOT\eval_once '["a"]'
+ COPILOT\eval_once '[[1 2] [3 4]]'
+
+ it "cannot contain mixed types", ->
+ err = assert.has.error -> COPILOT\eval_once '[1 false]'
+ assert.matches "argument error: couldn't match arguments", err
describe "(set)", ->
it "can swap values", ->
diff --git a/spec/lib/builtins/fn_spec.moon b/spec/lib/builtins/fn_spec.moon
index af27cf3..337a427 100644
--- a/spec/lib/builtins/fn_spec.moon
+++ b/spec/lib/builtins/fn_spec.moon
@@ -8,18 +8,28 @@ describe "function", ->
rt = COPILOT\eval_once '
(import* math)
- (defn my-plus (a b)
+ (defn my-plus [a b]
(+ a b))
(my-plus 2 3)'
assert.is.true rt\is_const!
assert.is.equal (Constant.num 5), rt.result
+ it "can have empty arguments", ->
+ rt = COPILOT\eval_once '
+ (import* math)
+
+ (defn my-plus []
+ (+ 1 2))
+
+ (my-plus)'
+ assert.is.equal (Constant.num 3), rt.result
+
it "checks argument arity when invoked", ->
err = assert.has.error -> COPILOT\eval_once '
([1]import* math)
- ([2]defn my-plus (a b)
+ ([2]defn my-plus [a b]
([4]+ a b))
([3]my-plus 2)'
@@ -29,7 +39,7 @@ describe "function", ->
err = assert.has.error -> COPILOT\eval_once '
([1]import* math)
- ([2]defn my-plus (a b)
+ ([2]defn my-plus [a b]
([4]+ a b))
([3]my-plus 2 3 4)'
@@ -39,13 +49,13 @@ describe "function", ->
it "can be anonymously invoked", ->
rt = COPILOT\eval_once '
([1]
- ([2]fn (a b) b)
+ ([2]fn [a b] b)
3 4)'
assert.is.equal (Constant.num 4), rt\const!
err = assert.has.error -> COPILOT\eval_once '
([1]
- ([2]fn (a b) b)
+ ([2]fn [a b] b)
3)'
assert.matches "argument error: expected 2 arguments, found 1", err
assert.matches "while invoking function %(unnamed%) at %[1%]", err
diff --git a/spec/lib/struct_spec.moon b/spec/lib/struct_spec.moon
index 94dcc5a..6f740ec 100644
--- a/spec/lib/struct_spec.moon
+++ b/spec/lib/struct_spec.moon
@@ -6,6 +6,15 @@ describe "struct", ->
ab = Struct { a: T.num, b: T.bool }
+ describe "literal", ->
+ it "can't be empty", ->
+ err = assert.has.error -> COPILOT\eval_once '{}'
+ assert.matches "syntax error: struct literal can't be empty", err
+
+ it "can't have uneven args", ->
+ err = assert.has.error -> COPILOT\eval_once '{3}'
+ assert.matches "syntax error: struct literal must have even number of values", err
+
describe "(set)", ->
it "can update values", ->
rt = COPILOT\eval_once '(set {"a" 1 "b" false} "a" 2)'