diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-08-20 12:13:45 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:24:49 +0000 |
| commit | 2fe2873a4efa6501b3cb5bbd69497d630850da28 (patch) | |
| tree | 8819548e69f211a4a19dd2921e3d6180fe727ca2 | |
| parent | implement (set) as per spec (diff) | |
| download | alive-2fe2873a4efa6501b3cb5bbd69497d630850da28.tar.gz alive-2fe2873a4efa6501b3cb5bbd69497d630850da28.zip | |
dirty (insert) implementation
| -rw-r--r-- | alv/builtins.moon | 107 | ||||
| -rw-r--r-- | spec/lang/array_spec.moon | 2 | ||||
| -rw-r--r-- | spec/lang/struct_spec.moon | 2 |
3 files changed, 94 insertions, 17 deletions
diff --git a/alv/builtins.moon b/alv/builtins.moon index 9610b5f..f336440 100644 --- a/alv/builtins.moon +++ b/alv/builtins.moon @@ -467,7 +467,10 @@ array = Constant.meta name: 'array' summary: "Construct an array." examples: { '(array a b c…)' } - description: "Produces an array of values." + description: "Produces an array of values. + +`a`, `b`, `c`… have to be values of the same type. +This is a pure op, so at most one !-stream input is allowed." value: do any = sig! / evt! @@ -485,7 +488,10 @@ struct = Constant.meta name: 'struct' summary: "Construct an struct." examples: { '(struct key1 val1 [key2 val2…])' } - description: "Produces an struct of values." + description: "Produces a struct of values. + +`key1`, `key2`, … have to be constant expressions. +This is a pure op, so at most one !-stream input is allowed." value: do key = const.str / const.sym @@ -505,15 +511,34 @@ get = Constant.meta meta: name: 'get' summary: "Index into Arrays and Structs." - examples: { '(get val key [key2…])' } + examples: { '(get array [key])', '(get struct key [key2…])' } + description: "Get the value for `key`. + +For arrays, `key` can be omitted to peek at the last element in the array. +If multiple keys are specified, they are used to recursively index, i.e. + + (get struct 'a' 0 'note') + +is equivalent to + + (get (get (get struct 'a') 0) 'note') +" value: class extends Op - pattern = (sig! / evt!) + (const.str / const.sym / const.num)*0 + pattern = (sig! / evt!) + (const.str / const.sym / const.num)^0 setup: (inputs) => { val, keys } = pattern\match inputs super val: Input.hot val - @state = [key.result! for key in *keys] + val_type = @inputs.val\type! + + if #keys > 0 + @state = [key.result! for key in *keys] + elseif val_type.__class == Array + assert val_type.size > 0, Error 'argument', "cannot (get) from empty Array" + @state = { val_type.size - 1 } + else + error Error 'argument', "missing key" type = val\type! for key in *@state @@ -535,8 +560,12 @@ get = Constant.meta set = Constant.meta meta: name: 'set' - summary: "Update Arrays and Structs." - examples: { '(set val key new-val)' } + summary: "Update values in Arrays and Structs." + examples: { '(set array key val)', '(set struct key val)' } + description: "Set the value for `key` to `val`. + +`key` has to be a constant expression. This is a pure op, so at most one of +`array`/`struct` and `val` may be a !-stream." value: class extends PureOp pattern: (sig! / evt!) + (const.str / const.sym / const.num) + (sig! / evt!) @@ -545,25 +574,73 @@ set = Constant.meta setup: (...) => super ... - { val, key, new_val } = @inputs + { comp, key, val } = @inputs - expected_val_typ = val\type!\get key! - got_val_typ = new_val\type! + expected_val_typ = comp\type!\get key! + got_val_typ = val\type! if expected_val_typ ~= got_val_typ msg = string.format "expected value for key '%s' to be %s, not %s", key!, expected_val_typ, got_val_typ error Error 'argument', msg tick: => - { val, key, new_val } = @unwrap_all! + { comp, key, val } = @unwrap_all! if type(key) == 'number' key = key + 1 - val = {k,v for k,v in pairs val} - val[key] = new_val + comp = {k,v for k,v in pairs comp} + comp[key] = val - @out\set val + @out\set comp + +insert = Constant.meta + meta: + name: 'insert' + summary: "Insert new values into Arrays and Structs." + examples: { '(insert array key val)', '(insert struct key val)' } + description: "Insert `val` into `array`/`struct` at `key`. + +`key` has to be a constant expression. This is a pure op, so at most one of +`array`/`struct` and `val` may be a !-stream." + + value: class extends PureOp + pattern: (sig! / evt!) + -(const.str / const.sym / const.num) + (sig! / evt!) + type: (inputs) => + { comp, key, val } = inputs + before = comp\type! + + if before.__class == Array + Array before.size + 1, before.type + else + types = {k,v for k,v in pairs before.types} + types[key\const!!] = val\type! + Struct types + + setup: (...) => + super ... + + { comp, key, val } = @inputs + before = comp\type! + key = key! + if before.__class == Array and (key > before.size or key < 0) + error Error 'argument', "index '#{key}' out of range!" + else if before.__class == Struct and before.types[key] + msg = string.format "key '%s' already exists in value of type %s", + key, before + error Error 'argument', msg + + tick: => + { comp, key, val } = @unwrap_all! + + comp = {k,v for k,v in pairs comp} + + if type(key) == 'number' + table.insert comp, key + 1, val + else + comp[key] = val + + @out\set comp loop = Constant.meta meta: @@ -663,7 +740,7 @@ Scope.from_table { '!': to_evt :array, :struct - :get, :set + :get, :set, :insert :loop, :recur diff --git a/spec/lang/array_spec.moon b/spec/lang/array_spec.moon index 25c0167..2dd2894 100644 --- a/spec/lang/array_spec.moon +++ b/spec/lang/array_spec.moon @@ -83,7 +83,7 @@ describe "array", -> assert.is.true rt\is_const! assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result - rt = COPILOT\eval_once '(insert (array "a" "b") 1 "c")' + rt = COPILOT\eval_once '(insert (array "a" "b") 2 "c")' assert.is.true rt\is_const! assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result diff --git a/spec/lang/struct_spec.moon b/spec/lang/struct_spec.moon index aa7b689..9d2286e 100644 --- a/spec/lang/struct_spec.moon +++ b/spec/lang/struct_spec.moon @@ -38,7 +38,7 @@ describe "struct", -> it "doesn't clobber existing members", -> err = assert.has.error -> COPILOT\eval_once '(insert (struct "a" 1) "a" 2)' - assert.matches "TBD", err + assert.matches "key 'a' already exists in value of type {a: num}", err describe "(remove)", -> it "can remove members", -> |
