Two-dimensional array slicing

Uses
- Two-dimensional array indexation
- One-dimensional array slicing

A slice is extracted by using intervals or grids as subscript. If both dimensions are sliced, the result is a two-dimensional array:
s:𝕊, (Array2D(s))[ℕ.nz⧺ℕ.nz⧺ℕ.nz, ℕ.nz⧺ℕ.nz⧺ℕ.nz] : Array2D(s)

If one dimension is slices whereas the other one is indexed with an integer, the result is a one-dimensional array:
s:𝕊, (Array2D(s))[ℕ.nz, ℕ.nz⧺ℕ.nz⧺ℕ.nz] : Array1D(s)
s:𝕊, (Array2D(s))[ℕ.nz⧺ℕ.nz⧺ℕ.nz, ℕ.nz] : Array1D(s)

Interval slices are rewritten to grid slices:
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, slice:ℕ.nz⧺ℕ.nz⧺ℕ.nz, A[i j, slice] ⇒ A[i 1 j, slice]
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, index:ℕ.nz, A[i j, index] ⇒ A[i 1 j, index]
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, slice:ℕ.nz⧺ℕ.nz⧺ℕ.nz, A[slice, i j] ⇒ A[slice, i 1 j]
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, index:ℕ.nz, A[index, i j] ⇒ A[index, i 1 j]

For array terms and grid literals, slices are computed in Pharo code:
s_:𝕊, A:Array2D(s_), i1:ℕ.nz, j1:ℕ.nz, k1:ℕ.nz, i2:ℕ.nz, j2:ℕ.nz, k2:ℕ.nz, A[i1 k1 j1, i2 k2 j2] ⇒ Pharo:"A ensureArrayTerm. i1 ensureNumber. j1 ensureNumber. k1 ensureNumber. i2 ensureNumber. j2 ensureNumber. k2 ensureNumber. A slice: { i1 . j1 . k1 } slice: { i2 . j2 . k2 }"
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, k:ℕ.nz, l:ℕ.nz, A[i k j, l] ⇒ Pharo:"A ensureArrayTerm. i ensureNumber. j ensureNumber. k ensureNumber. l ensureNumber. A slice: { i . j . k } index: l"
s_:𝕊, A:Array2D(s_), i:ℕ.nz, j:ℕ.nz, k:ℕ.nz, l:ℕ.nz, A[l, i k j] ⇒ Pharo:"A ensureArrayTerm. i ensureNumber. j ensureNumber. k ensureNumber. l ensureNumber. A index: l slice: { i . j . k }"

Example

For example a : Array2D(ℕ) with example a ⇒ {[[1, 4, 9], [16, 25, 36], [49, 64, 81]]} we find:
example a[1 2, 1 2] ⇒ {[[1, 4], [16, 25]]}
example a[1 2, 2] ⇒ {[4, 25]}
example a[2, 1 2] ⇒ {[16, 25]}
example a[1 2 3, 1 2 3] ⇒ {[[1, 9], [49, 81]]}
example a[1 2 3, 1] ⇒ {[1, 49]}
example a[3, 1 2 3] ⇒ {[49, 81]}