diff options
| author | s-ol <s+removethis@s-ol.nu> | 2025-09-14 10:12:13 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-09-14 15:36:21 +0000 |
| commit | 06c239e4f44849a3e4c8317194caacbcc47fc2d4 (patch) | |
| tree | 491c8c5f9e3ad4351aa55951a0d7c70cd8686087 | |
| parent | expose Tag to Ops (diff) | |
| download | alive-06c239e4f44849a3e4c8317194caacbcc47fc2d4.tar.gz alive-06c239e4f44849a3e4c8317194caacbcc47fc2d4.zip | |
de/fn, loop parameter lists use square brackets
| -rw-r--r-- | alv/builtins.moon | 16 | ||||
| -rw-r--r-- | alv/cell.moon | 14 | ||||
| -rw-r--r-- | docs/reference/03-3_functions.md | 8 | ||||
| -rw-r--r-- | docs/reference/03-4_dynamic-symbols.md | 4 | ||||
| -rw-r--r-- | docs/reference/03-5_loops.md | 4 | ||||
| -rw-r--r-- | docs/reference/03-6_modules-and-loading.md | 2 | ||||
| -rw-r--r-- | spec/lib/array_spec.moon | 23 | ||||
| -rw-r--r-- | spec/lib/builtins/fn_spec.moon | 20 | ||||
| -rw-r--r-- | spec/lib/struct_spec.moon | 9 |
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)' |
