🐐 Array slicing
This commit is contained in:
@@ -847,6 +847,49 @@ class ArrayIndex(Node):
|
||||
return vtable, lst[i - 1]
|
||||
|
||||
|
||||
def _to_index_int(val):
|
||||
if isinstance(val, ValInt):
|
||||
return val.value()
|
||||
if isinstance(val, ValFrac) and val.value().denominator == 1:
|
||||
return val.value().numerator
|
||||
raise CentvrionError("Array index must be a number")
|
||||
|
||||
|
||||
class ArraySlice(Node):
|
||||
def __init__(self, array, from_index, to_index) -> None:
|
||||
self.array = array
|
||||
self.from_index = from_index
|
||||
self.to_index = to_index
|
||||
|
||||
def __eq__(self, other):
|
||||
return (type(self) == type(other)
|
||||
and self.array == other.array
|
||||
and self.from_index == other.from_index
|
||||
and self.to_index == other.to_index)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ArraySlice({self.array!r}, {self.from_index!r}, {self.to_index!r})"
|
||||
|
||||
def print(self):
|
||||
return f"{self.array.print()}[{self.from_index.print()} VSQVE {self.to_index.print()}]"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, array = self.array.eval(vtable)
|
||||
vtable, from_val = self.from_index.eval(vtable)
|
||||
vtable, to_val = self.to_index.eval(vtable)
|
||||
if not isinstance(array, ValList):
|
||||
raise CentvrionError("Cannot slice a non-array value")
|
||||
from_int = _to_index_int(from_val)
|
||||
to_int = _to_index_int(to_val)
|
||||
lst = array.value()
|
||||
if from_int < 1 or to_int > len(lst) or from_int > to_int:
|
||||
raise CentvrionError(
|
||||
f"Slice [{from_int} VSQVE {to_int}] out of range"
|
||||
f" for array of length {len(lst)}"
|
||||
)
|
||||
return vtable, ValList(lst[from_int - 1 : to_int])
|
||||
|
||||
|
||||
class SiStatement(Node):
|
||||
def __init__(self, test, statements, else_part) -> None:
|
||||
self.test = test
|
||||
|
||||
@@ -2,7 +2,7 @@ from centvrion.errors import CentvrionError
|
||||
from centvrion.ast_nodes import (
|
||||
String, InterpolatedString, Numeral, Fractio, Bool, Nullus, ID,
|
||||
BinOp, UnaryMinus, UnaryNot,
|
||||
ArrayIndex, DataArray, DataRangeArray, DataDict,
|
||||
ArrayIndex, ArraySlice, DataArray, DataRangeArray, DataDict,
|
||||
BuiltIn, Invoca, Fvnctio,
|
||||
num_to_int, frac_to_fraction,
|
||||
)
|
||||
@@ -120,6 +120,15 @@ def emit_expr(node, ctx):
|
||||
tmp = ctx.fresh_tmp()
|
||||
return arr_lines + idx_lines + [f"CentValue {tmp} = cent_list_index({arr_var}, {idx_var});"], tmp
|
||||
|
||||
if isinstance(node, ArraySlice):
|
||||
arr_lines, arr_var = emit_expr(node.array, ctx)
|
||||
lo_lines, lo_var = emit_expr(node.from_index, ctx)
|
||||
hi_lines, hi_var = emit_expr(node.to_index, ctx)
|
||||
tmp = ctx.fresh_tmp()
|
||||
return arr_lines + lo_lines + hi_lines + [
|
||||
f"CentValue {tmp} = cent_list_slice({arr_var}, {lo_var}, {hi_var});"
|
||||
], tmp
|
||||
|
||||
if isinstance(node, DataArray):
|
||||
lines = []
|
||||
tmp = ctx.fresh_tmp()
|
||||
|
||||
@@ -735,6 +735,22 @@ CentValue cent_list_index(CentValue lst, CentValue idx) {
|
||||
return lst.lval.items[i - 1];
|
||||
}
|
||||
|
||||
CentValue cent_list_slice(CentValue lst, CentValue lo, CentValue hi) {
|
||||
if (lst.type != CENT_LIST)
|
||||
cent_type_error("slice requires a list");
|
||||
if (lo.type != CENT_INT || hi.type != CENT_INT)
|
||||
cent_type_error("slice indices must be integers");
|
||||
long from = lo.ival;
|
||||
long to = hi.ival;
|
||||
if (from < 1 || to > lst.lval.len || from > to)
|
||||
cent_runtime_error("slice out of range");
|
||||
int len = (int)(to - from + 1);
|
||||
CentValue result = cent_list_new(len);
|
||||
for (long j = from; j <= to; j++)
|
||||
cent_list_push(&result, lst.lval.items[j - 1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
void cent_list_index_set(CentValue *lst, CentValue idx, CentValue v) {
|
||||
if (lst->type == CENT_DICT) {
|
||||
cent_dict_set(lst, idx, v);
|
||||
|
||||
@@ -234,6 +234,7 @@ void cent_adivnge(CentValue path, CentValue content); /* ADIVNGE */
|
||||
CentValue cent_list_new(int cap);
|
||||
void cent_list_push(CentValue *lst, CentValue v);
|
||||
CentValue cent_list_index(CentValue lst, CentValue idx); /* 1-based */
|
||||
CentValue cent_list_slice(CentValue lst, CentValue lo, CentValue hi); /* 1-based, inclusive */
|
||||
void cent_list_index_set(CentValue *lst, CentValue idx, CentValue v);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
@@ -326,6 +326,10 @@ class Parser():
|
||||
def array_index(tokens):
|
||||
return ast_nodes.ArrayIndex(tokens[0], tokens[2])
|
||||
|
||||
@self.pg.production('expression : expression SYMBOL_LBRACKET expression KEYWORD_VSQVE expression SYMBOL_RBRACKET', precedence='INDEX')
|
||||
def array_slice(tokens):
|
||||
return ast_nodes.ArraySlice(tokens[0], tokens[2], tokens[4])
|
||||
|
||||
# ids
|
||||
@self.pg.production('ids : SYMBOL_LPARENS id_list')
|
||||
def ids(tokens):
|
||||
|
||||
Reference in New Issue
Block a user