aboutsummaryrefslogtreecommitdiffstats
path: root/alv-lib/array.moon
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-03-18 11:47:22 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-18 12:06:18 +0000
commitb6cbc69461dc054019f50f8971704f6ef9de63ab (patch)
treed2b8942b780f668ccbe57b52dd8d65f61613e935 /alv-lib/array.moon
parentbuiltins: switch takes single array as value (diff)
downloadalive-wip.tar.gz
alive-wip.zip
language: [array] and {struct} literalswip
Diffstat (limited to 'alv-lib/array.moon')
-rw-r--r--alv-lib/array.moon295
1 files changed, 295 insertions, 0 deletions
diff --git a/alv-lib/array.moon b/alv-lib/array.moon
new file mode 100644
index 0000000..bbc1cbd
--- /dev/null
+++ b/alv-lib/array.moon
@@ -0,0 +1,295 @@
+import Array, Op, PureOp, Builtin, RTNode, Constant, Error, const, any, T from require 'alv.base'
+import Cell, Tag, Dummy from require 'alv.ast'
+builtins = require 'alv.builtins'
+
+unpack or= table.unpack
+
+get = Constant.meta
+ meta:
+ name: 'get'
+ summary: "Index into an array."
+ examples: { '(get array i)' }
+ description: "Get the value at index `i` (starting at 0).
+
+`i` has to be a constant expression."
+
+ value: class extends PureOp
+ pattern: any! + const.num
+ type: (inputs) =>
+ { array, i } = inputs
+ array\type!\get i.result!
+
+ tick: =>
+ { array, i } = @unwrap_all!
+ @out\set array[i + 1]
+
+set = Constant.meta
+ meta:
+ name: 'set'
+ summary: "Update a value in an array."
+ examples: { '(set array i val)' }
+ description: "Set the value for `i` to `val`.
+
+`i` has to be a constant expression. This is a pure op, so at most one of
+`array` and `val` may be a !-stream."
+
+ value: class extends PureOp
+ pattern: any! + const.num + any!
+ type: (inputs) =>
+ { array, i, val } = inputs
+ type = array\type!
+ expected = type\get i.result!
+
+ if expected ~= val\type!
+ msg = string.format "expected value of type %s, not %s",
+ expected, val\type!
+ error Error 'argument', msg
+
+ type
+
+ tick: =>
+ { array, key, val } = @unwrap_all!
+
+ array = [v for v in *array]
+ array[key + 1] = val
+
+ @out\set array
+
+head = Constant.meta
+ meta:
+ name: 'head'
+ summary: "Get the first element from an array."
+ examples: { '(head array)' }
+
+ value: class extends PureOp
+ pattern: any!*1
+ type: (inputs) =>
+ type = inputs[1]\type!
+
+ assert type.__class == Array, Error 'argument', "expected an Array"
+ assert type.size > 0, Error 'argument', "cannot get head of empty Array"
+
+ type.type
+
+ tick: =>
+ { array } = @unwrap_all!
+ @out\set array[1]
+
+tail = Constant.meta
+ meta:
+ name: 'tail'
+ summary: "Get everything except the first element from an array."
+ examples: { '(tail array)' }
+
+ value: class extends PureOp
+ pattern: any!*1
+ type: (inputs) =>
+ type = inputs[1]\type!
+
+ assert type.__class == Array, Error 'argument', "expected an Array"
+ assert type.size > 0, Error 'argument', "cannot get tail of empty Array"
+
+ Array type.size - 1, type.type
+
+ tick: =>
+ { array } = @unwrap_all!
+ @out\set [v for v in *array[2,]]
+
+prepend = Constant.meta
+ meta:
+ name: 'prepend'
+ summary: "Prepend a new value at the start of an array."
+ examples: { '(prepend array val)' }
+ description: "Prepend `val` to `array` at index `0`, moving other values back.
+
+This is a pure op, so at most one of `array` and `val` may be a !-stream."
+
+ value: class extends PureOp
+ pattern: any! + any!
+ type: (inputs) =>
+ { array, val } = inputs
+ type = array\type!
+
+ if val\type! ~= type.type
+ msg = string.format "expected value of type %s, not %s",
+ type.type, val\type!
+ error Error 'argument', msg
+
+ Array type.size + 1, type.type
+
+ tick: =>
+ { array, val } = @unwrap_all!
+
+ array = [v for v in *array]
+ table.insert array, 1, val
+
+ @out\set array
+
+insert = Constant.meta
+ meta:
+ name: 'insert'
+ summary: "Insert a new value into an array."
+ examples: { '(insert array i val)' }
+ description: "Insert `val` into `array` at `i`, moving other values back if
+necessary.
+
+`i` has to be a constant expression. This is a pure op, so at most one of
+`array` and `val` may be a !-stream."
+
+ value: class extends PureOp
+ pattern: any! + const.num + any!
+ type: (inputs) =>
+ { array, i, val } = inputs
+ type = array\type!
+ i = i.result!
+
+ if i > type.size or i < 0
+ error Error 'argument', "index '#{i}' out of range!"
+ if val\type! ~= type.type
+ msg = string.format "expected value of type %s, not %s",
+ type.type, val\type!
+ error Error 'argument', msg
+
+ Array type.size + 1, type.type
+
+ tick: =>
+ { array, i, val } = @unwrap_all!
+
+ array = [v for v in *array]
+ table.insert array, i + 1, val
+
+ @out\set array
+
+remove = Constant.meta
+ meta:
+ name: 'remove'
+ summary: "Remove a value from an Array."
+ examples: { '(remove array i)' }
+ description: "Removes the value at index `i` from `array`.
+
+`i` has to be a constant expression."
+
+ value: class extends PureOp
+ pattern: any! + const.num
+ type: (inputs) =>
+ { array, i } = inputs
+ type = array\type!
+
+ -- check index range
+ type\get i.result!
+
+ Array type.size - 1, type.type
+
+ tick: =>
+ { array, i, val } = @unwrap_all!
+
+ array = [v for v in *array]
+ table.remove array, i + 1
+
+ @out\set array
+
+size = Constant.meta
+ meta:
+ name: 'size'
+ summary: "Get the size of an array."
+ examples: { '(size array)' }
+
+ value: class extends Op
+ setup: (inputs) =>
+ super {}
+
+ assert #inputs == 1, Error 'argument', "expected exactly one argument"
+ type = inputs[1]\type!
+ assert type.__class == Array, Error 'argument', "expected an Array"
+
+ @out = Constant.num type.size
+
+concat = Constant.meta
+ meta:
+ name: 'concat'
+ summary: "Concatenate Arrays."
+ examples: { '(concat arr1 arr2 [arr3…])' }
+
+ value: class extends PureOp
+ pattern: any!\rep 2
+ type: (inputs) =>
+ size = 0
+ type = inputs[1]\type!.type
+
+ for input in *inputs
+ array = input\type!
+
+ if array.type ~= type
+ msg = string.format "Cannot concatenate different arrays %s, %s",
+ inputs[1]\type!, array
+ error Error 'argument', msg
+
+ size += array.size
+
+ Array size, type
+
+ tick: =>
+ arrays = @unwrap_all!
+ out = {}
+
+ for array in *arrays
+ for val in *array
+ table.insert out, val
+
+ @out\set out
+
+array_constr = builtins!\get('mkarray').result
+map = Constant.meta
+ meta:
+ name: 'map'
+ summary: "Apply an function to each value in an array."
+ examples: { '(map array fn)' }
+ description: "
+Invokes `fn` once for each element in `array` and returns an array of the results.
+`fn` must take one argument and return the same type consistently."
+
+ value: class extends Builtin
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 2, "'map' takes exactly two arguments"
+ tail = [L\push t\eval, scope for t in *tail]
+ { array, fn } = tail
+
+ assert fn\type! == T.fndef, "fn has to be a fndef"
+
+ array_type = array\type!
+ assert array_type.__class == Array, Error 'argument', "expected an Array"
+
+ invocations = for i=1, array_type.size
+ tag_o = @tag\clone Tag.parse tostring i
+ tag_i = @tag\clone tag_o
+ Cell tag_o, {
+ Dummy fn\make_ref!
+ Cell tag_i, {
+ Dummy.literal T.opdef, get!
+ Dummy array\make_ref!
+ Constant.num i-1
+ }
+ }
+
+ tag = @tag\clone Tag.parse '-1'
+ inner = Cell tag, {
+ Dummy.literal T.opdef, array_constr
+ unpack invocations
+ }
+
+ node = inner\eval scope
+ super RTNode children: { array, fn, node }, result: node.result
+
+Constant.meta
+ meta:
+ name: 'array'
+ summary: "Utilities for dealing with arrays."
+
+ value:
+ :get, :set
+ :head, :tail, :prepend
+ :insert, :remove
+ :map
+
+ :size, :concat