
Arrays
An array is set up with the declare
keyword. After it has been declared,
the elements can be accessed with numerical subscripts. The language
specification allows for arrays to have an arbitrary number of dimensions.
The size and dimension of an array are static and set when the
array is declared. For example, to declare a one-dimensional array:
declare vector[5]
In this example, the array named vector has 5 elements and can be accessed with subscripts from 0 to 4.
Once an array is declared, it can be written with assign
and read wherever
any other variable is allowed.
declare hues[10]
assign hues[5] 120
hue hues[5]
Accessing an array with a subscript that is negative or outside the bounds of its size will cause an error to be logged, but in most cases, the virtual machine will make an attempt to provide a reasonable default. If the subscript is a floating-point value, the fraction will be truncated to yield an integer.
To declare a multi-dimensional array, use a series of square brackets, each with a size. For example:
declare colors[8][4][9]
assign colors[1][3][8] 100
Within the declaration, the size of the array can be calculated at run-tme. However, after an arrary has been declared, its size may not be changed. As with other features of the language, numerical expressions need to be in curly braces.
declare hue_segment[{hue / 10}]
assign array_size {24 * 60}
declare day[array_size]
Assigning an array to a variable creates an alias and does not make a copy:
declare mat[3]
assign mat[0] 100
assign mat2 mat
assign mat2[0] 200
# This will print 200
print mat[0]
When an array is partially subscripted, the result is itself an array with a reduced dimension.
Iterating Over an Array
To iterate over a specific range, use the repeat
with
construct:
declare vector[5]
repeat with i from 1 to 3
assign vector[i] {i * 2}
To iterate over all of the elements in an array, use a repaeat
in
as
clause:
declare hues[3]
repeat in hues as i begin
assign hues[i] {i * 120}
end
A similar construct can be used for multi-dimensional arrays:
declare colors[5][4]
repeat in colors as color_num
repeat in colors[color_num] as setting_num
assign colors[color_num][setting_num] 100
repeat in colors[0] as setting_num
assign colors[0][setting_num] 200
declare matrix[6][5][3]
repeat in matrix as i
repeat in matrix[i] as j
repeat in matrix[i][j] as k
assign matrix[i][j][k] 500
Arrays as Parameters
When an array is passed into a routine, it needs to be declared as such in the routine’s definition. This is done with a pair of square brackets for each dimension. For example:
define sum_array with arr[][] begin
assign sum 0
repeat with i from 0 to 4 begin
repeat with j from 0 to 9 begin
assign sum {sum + arr[i][j]
end
end
end
declare matrix[5][10]
# ...some code here fills the "matrix" array with data.
println [sum_array matrix]
The code using the array can also be written without explicitly giving the lengths of each dimension:
define sum_array with arr[][] begin
assign sum 0
repeat in arr as i begin
repeat in arr[i] as j begin
assign sum {sum + arr[i][j]}
end
end
end
Design Overview
Support for arrays is accomplished with a couple of new instructions and new handling of certain types of parameters passed into to move-related instructions.
New VM Instructions
OpCode.ARRAY, name, size
Declares an array with the given name and size.
For example, this script:
declare a[5]
can be accomplished with:
OpCode.ARRAY, "a", 5
If the array already exists, its dimensionality is increased accoringly. So, to have v[3][4]:
OpCode.ARRAY, "v", 3
OpCode.ARRAY, "v", 4
OpCode.DEREF, name
Resets the indexing of the named array and positions it at the value provided in the second parameter:
OpCode.DEREF, "v", 1
OpCode.INDEX, name, index
Positions the named array at the given index, typically:
OpCode.DEREF "a", 1
OpCode.INDEX, "a", 2
Instructions With New Parameter Types
When an array is part of move instruction, it utilizes whatever address it got
in the last INDEX
or DEREF
instruction. For example:
assign a[3] 5
would yield:
OpCode.DEREF, "a", 3
OpCode.MOVEQ 5, "a"
Conversely, referencing an array element:
assign x a[2]
can be done with:
OpCode.DEREF, "a", 2
OpCode.MOV, "a", "x"
Multi-dimensional arrays are handled with a DEREF
, followed by multiple
INDEX
instructions:
assign x v[2][3]
can be done with:
OpCode.DEREF, "a", 2
OpCode.INDEX, "a", 3
OpCode.MOVEQ, "a", "x"
Use Case: 1D Assignment
Script:
declare v[5]
assign v[3] 20
VM code:
OpCode.ARRAY, "v", 5
OpCode.DEREF, "v", 2
OpCode.MOVEQ, 10, "v"
Use Case: 1D Read
Script:
declare v[5]
assign v[2] 10
...
hue v[2]
VM code:
OpCode.ARRAY, "v", 5
OpCode.DEREF, "v", 2
OpCode.MOVEQ, 10, "v"
...
Opcode.DEREF, "v", 2
OpCode.MOVE, "v", Register.HUE
Use Case: 2D Assignment
This use case also covers arrays with dimensions of 3 and above.
Script:
declare a[10][5]
assign a[3][4] 200
VM code:
OpCode.ARRAY, "a", 10
OpCode.ARRAY, "a", 5
OpCode.DEREF, "a", 3
OpCode.INDEX, "a", 4
OpCode.MOVEQ, 200, "a"
Use Case: 2D Read
This use case also covers arrays with dimensions of 3 and above.
Script:
declare a[10][5]
assign a[5][2] 100
...
hue a[5][2]
VM code:
OpCode.ARRAY, "a", 10
OpCode.ARRAY, "a", 5
OpCode.DEREF, "a", 5
OpCode.INDEX, "a", 2
OpCode.MOVEQ, 100, "a"
...
OpCode.DEREF, "a", 5
OpCode.INDEX, "a", 2
OpCode.MOVE, "a", Register.HUE
Use Case: Assign Array to Variable
Script:
declare v[10]
assign v[5] 100
assign v_ref v
hue v_ref[5]
assign 10 v_ref[6]
VM code:
OpCode.ARRAY, "v", 10
OpCode.DEREF, "v", 5
OpCode.MOVEQ, 100, "v"
OpCode.DEREF, "v", None
OpCode.MOVE, "v", "v_ref"
OpCode.DEREF, "v_ref", 5
OpCode.MOVE, "v_ref", Register.HUE
OpCode.DEREF, "v_ref", 6
OpCode.MOVEQ, 10 "v_ref"
Use Case: Assign Partially-Dereferenced Array to Variable
Script:
declare a[5][7]
assign a[2][5] 100
...
assign a_ref a[2]
...
hue a_ref[5]
VM code:
OpCode.ARRAY, "a", 5
OpCode.ARRAY, "a", 7
OpCode.DEREF, "a", 2
OpCode.INDEX, "a", 5
OpCode.MOVEQ, 100, "a"
...
OpCode.DEREF, "a", 2
OpCode.MOVE, "a", "a_ref"
...
OpCode.DEREF, "a_ref", 5
OpCode.MOVE, "a_ref", Register.HUE
Problem: Assign Partially-Dereferenced Array to Variable
Script:
declare a[5][7]
assign a[2][5] 100
...
assign a_ref a[2]
...
hue a[3][3]
hue a_ref[5]
VM code:
OpCode.ARRAY, "a", 5
OpCode.ARRAY, "a", 7
OpCode.DEREF, "a", 2
OpCode.INDEX, "a", 5
OpCode.MOVEQ, 100, "a"
...
OpCode.DEREF, "a", 2
OpCode.MOVE, "a", "a_ref"
...
OpCode.DEREF, "a", 3
OpCode.INDEX, "a", 3
OpCode.MOVE, "a", Register.HUE
OpCode.DEREF, "a_ref", 5
OpCode.MOVE, "a_ref", Register.HUE
Use Case: Array as Parameter
Script:
define fn with v[] begin
assign v[7] 9
return v[5]
end
declare arr[10]
assign arr[5] 250
hue [fn arr]
VM code:
OpCode.ROUTINE, "fn"
OpCode.DEREF, "v", 7
OpCode.MOVEQ, 9, "v"
OpCode.DEREF, "v", 5
OpCode.MOVE, "v", Register.RESULT
OpCode.RETURN
OpCode.ARRAY, "arr", 10
OpCode.DEREF, "arr", 5
Opcode.MOVEQ, 250, "arr"
OpCode.CTX
OpCode.DEREF, "arr", None
OpCode.PARAM, "v", "arr"
OpCode.JSR, "fn"
OpCode.END_CTX
Use Case: Partially-Dereferenced Array as a Parameter
Script:
define fn with v[] begin
assign v[6] 7
return v[5]
end
declare arr[5][7]
assign arr[2][5] 100
hue [fn arr[5]]
VM code:
OpCode.ROUTINE, "fn"
OpCode.DEREF, "v", 6
OpCode.MOVE, 7, "v"
OpCode.DEREF, "v", 5
OpCode.MOVE, "v", Register.RESULT
OpCode.RETURN
OpCode.ARRAY, "arr", 5
OpCode.ARRAY, "arr", 7
OpCode.DEREF, "arr", 2
OpCode.INDEX, "arr", 5
OpCode.MOVEQ, 100, "arr"
OpCode.CTX
OpCode.DEREF, "arr", 5
OpCode.PARAM, "v", "arr"
OpCode.JSR, "fn"
OpCode.END_CTX
OpCode.MOVE, Register.RESULT, Register.HUE
Use Case: Nesting
Script:
declare a[5]
assign a[2] 3
assign a[a[2]] 4
VM code:
OpCode.ARRAY, "a", 5
OpCode.DEREF, "a", 2
OpCode.MOVEQ, 3, "a"
OpCode.DEREF, "a", 2
OpCode.MOVE, "a", Register.RESULT # rvalue
OpCode.DEREF, "a", Register.RESULT
OpCode.MOVEQ, "4", "a"
Use Case: Loop over 1D Array
Script:
declare v[10]
repeat in v as i
hue v[i]
Use Case: Loop over 2D Array
Script:
declare m[5][10]
repeat in m as i
repeat in m[i] as j
assign m[i][j] 0
repeat in m as i
repeat in m[i] as j
hue m[i][j]