.. figure:: logo.png :align: center http://www.bardolph.org .. index:: single: array .. _array: ****** 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: .. code-block:: lightbulb 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. .. code-block:: lightbulb 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: .. code-block:: lightbulb 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. .. code-block:: lightbulb 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: .. code-block:: lightbulb 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. .. code-block: lightbulb declare array[5][5][5] assign matrix array[4] assign matrix[0][0] 100 assign vector array[4][2] assign vector[0] 200 .. index:: array; iterating over Iterating Over an Array ======================= To iterate over a specific range, use the ``repeat`` ``with`` construct: .. code-block:: lightbulb 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: .. code-block:: lightbulb 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: .. code-block:: lightbulb 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 .. index:: array; as a parameter 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: .. code-block:: lightbulb 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: .. code-block:: lightbulb 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: .. code-block:: lightbulb declare a[5] can be accomplished with: .. code-block:: python OpCode.ARRAY, "a", 5 If the array already exists, its dimensionality is increased accoringly. So, to have v[3][4]: .. code-block:: python 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: .. code-block:: python OpCode.DEREF, "v", 1 OpCode.INDEX, name, index ^^^^^^^^^^^^^^^^^^^^^^^^^ Positions the named array at the given index, typically: .. code-block:: python 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: .. code-block:: lightbulb assign a[3] 5 would yield: .. code-block:: python OpCode.DEREF, "a", 3 OpCode.MOVEQ 5, "a" Conversely, referencing an array element: .. code-block:: lightbulb assign x a[2] can be done with: .. code-block:: python OpCode.DEREF, "a", 2 OpCode.MOV, "a", "x" Multi-dimensional arrays are handled with a ``DEREF``, followed by multiple ``INDEX`` instructions: .. code-block:: lightbulb assign x v[2][3] can be done with: .. code-block:: python OpCode.DEREF, "a", 2 OpCode.INDEX, "a", 3 OpCode.MOVEQ, "a", "x" Use Case: 1D Assignment ----------------------- Script: .. code-block:: lightbulb declare v[5] assign v[3] 20 VM code: .. code-block:: python OpCode.ARRAY, "v", 5 OpCode.DEREF, "v", 2 OpCode.MOVEQ, 10, "v" Use Case: 1D Read ----------------- Script: .. code-block:: lightbulb declare v[5] assign v[2] 10 ... hue v[2] VM code: .. code-block:: python 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: .. code-block:: lightbulb declare a[10][5] assign a[3][4] 200 VM code: .. code-block:: python 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: .. code-block:: lightbulb declare a[10][5] assign a[5][2] 100 ... hue a[5][2] VM code: .. code-block:: python 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: .. code-block:: lightbulb declare v[10] assign v[5] 100 assign v_ref v hue v_ref[5] assign 10 v_ref[6] VM code: .. code-block:: python 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: .. code-block:: lightbulb declare a[5][7] assign a[2][5] 100 ... assign a_ref a[2] ... hue a_ref[5] VM code: .. code-block:: python 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: .. code-block:: lightbulb declare a[5][7] assign a[2][5] 100 ... assign a_ref a[2] ... hue a[3][3] hue a_ref[5] VM code: .. code-block:: python 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: .. code-block:: lightbulb 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: .. code-block:: python 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: .. code-block:: lightbulb 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: .. code-block:: python 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: .. code-block:: lightbulb declare a[5] assign a[2] 3 assign a[a[2]] 4 VM code: .. code-block:: python 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: .. code-block:: lightbulb declare v[10] repeat in v as i hue v[i] Use Case: Loop over 2D Array ---------------------------- Script: .. code-block:: lightbulb 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]