# Operations corresponding to indexing of tables, vectors, strings,
# and "any" values.

op IndexVecBoolSelect
classes VVV VCV
op-types V V V
set-type $$
eval	if ( $1->Size() != $2->Size() )
		ERROR("size mismatch, boolean index and vector");
	else
		{
		auto vt = cast_intrusive<VectorType>(Z_TYPE);
		auto v2 = $1;
		auto v3 = $2;
		auto v = vector_bool_select(std::move(vt), v2, v3);
		Unref($$);
		$$ = v.release();
		}

op IndexVecIntSelect
classes VVV VCV
op-types V V V
set-type $$
eval	auto vt = cast_intrusive<VectorType>(Z_TYPE);
	auto v2 = $1;
	auto v3 = $2;
	auto v = vector_int_select(std::move(vt), v2, v3);
	Unref($$);
	$$ = v.release();

op Index
class VVL
custom-method return CompileIndex(n1, n2, l, false);
no-eval

op Index
class VCL
custom-method return CompileIndex(n, c, l, false);
no-eval

op WhenIndex
class VVL
custom-method return CompileIndex(n1, n2, l, true);
no-eval

op WhenIndex
class VCL
custom-method return CompileIndex(n, c, l, true);
no-eval

internal-op Index-Vec
class VVV
op-types X V I
eval	EvalIndexVec($$, $1, $2)

macro EvalIndexVec(lhs, rhs_vec, index)
	auto& vv = rhs_vec->RawVec();
	zeek_int_t ind = index;
	if ( ind < 0 )
		ind += vv.size();
	if ( ind < 0 || ind >= int(vv.size()) )
		ERROR("no such index");
	AssignTarget(lhs, CopyVal(*(vv[ind])))

internal-op Index-VecC
class VVi
op-types X V I
eval	EvalIndexVec($$, $1, $2)

internal-op Index-Any-Vec
class VVV
op-types X V I
eval	EvalIndexAnyVec($$, $1, $2)

macro EvalIndexAnyVec(lhs, vec, index)
	auto vv = vec;
	zeek_int_t ind = index;
	if ( ind < 0 )
		ind += vv->Size();
	if ( ind < 0 || ind >= int(vv->Size()) )
		ERROR("no such index");
	AssignTarget(lhs, ZVal(vv->ValAt(ind).release()))

internal-op Index-Any-VecC
class VVi
op-types X V I
eval	EvalIndexAnyVec($$, $1, $2)

macro WhenIndexResCheck(vec)
	if ( vec && IndexExprWhen::evaluating > 0 )
		IndexExprWhen::results.push_back({NewRef{}, vec});

internal-op When-Index-Vec
class VVV
op-types X V I
eval	EvalIndexAnyVec($$, $1, $2)
	WhenIndexResCheck($$.AsVector())

internal-op When-Index-VecC
class VVi
op-types X V I
eval	EvalIndexAnyVec($$, $1, $2)
	WhenIndexResCheck($$.AsVector())

macro EvalVecSlice(lhs, vv)
	auto vec = vv;
	auto v = index_slice(vec, indices.get());
	Unref(lhs);
	lhs = v.release();

internal-op Index-Vec-Slice
class VV
op-types V V
eval	auto indices = Z_AUX->ToListVal(frame);
	EvalVecSlice($$, $1)

internal-op When-Index-Vec-Slice
class VV
op-types V V
eval	auto indices = Z_AUX->ToListVal(frame);
	EvalVecSlice($$, $1)
	WhenIndexResCheck($$)

internal-op Table-Index
class VV
eval	auto indices = Z_AUX->ToListVal(frame);
	EvalTableIndex($1, indices)
	if ( v )
		AssignTarget($$, BuildVal(v, Z_TYPE))

internal-op Table-PatStr-Index
classes VVV VVC
op-types X T S
eval	auto vec = ZVal($1->LookupPattern({NewRef{}, $2}));
	ZVal::DeleteManagedType($$);
	$$ = vec;

internal-op When-Table-Index
class VV
eval	auto indices = Z_AUX->ToListVal(frame);
	EvalTableIndex($1, indices)
	if ( v )
		{
		if ( IndexExprWhen::evaluating > 0 )
			IndexExprWhen::results.emplace_back(v);
		AssignTarget($$, BuildVal(v, Z_TYPE))
		}

macro EvalTableIndex(tbl, index)
	auto v = tbl.AsTable()->FindOrDefault(index);
	if ( ! v )
		ERROR("no such index");

internal-op When-PatStr-Index
class VV
op-types X T
eval	auto indices = Z_AUX->ToListVal(frame);
	auto arg0 = indices->Idx(0);
	auto v = $1->LookupPattern({NewRef{}, arg0->AsStringVal()});
	if ( IndexExprWhen::evaluating > 0 )
		IndexExprWhen::results.emplace_back(v);
	AssignTarget($$, BuildVal(v, Z_TYPE))

internal-assignment-op Table-Index1
classes VVV VVC
assign-val v
eval	EvalTableIndex($1, $2.ToVal(Z_TYPE))
# No AssignTarget needed, as this is an assignment-op

# This version is for a variable v3.
internal-op Index-String
class VVV
op-types S S I
eval	EvalIndexString($$, $1, $2)

macro EvalIndexString(lhs, s, index)
	auto str = s->AsString();
	auto len = str->Len();
	auto idx = index;
	if ( idx < 0 )
		idx += len;
	auto v = str->GetSubstring(idx, 1);
	Unref(lhs);
	lhs = new StringVal(v ? v : new String(""));

# This version is for a constant v3.
internal-op Index-StringC
class VVi
op-types S S I
eval	EvalIndexString($$, $1, $2)

internal-op Index-String-Slice
class VV
op-types S S
eval	auto str = $1->AsString();
	auto indices = Z_AUX->ToListVal(frame);
	auto slice = index_string(str, indices.get());
	Unref($$);
	$$ = new StringVal(slice->ToStdString());

op AnyIndex
class VVi
op-types X a I
set-type $$
eval	auto lv = $1->AsListVal();
	if ( $2 < 0 || $2 >= lv->Length() )
		reporter->InternalError("bad \"any\" element index");
	ValPtr elem = lv->Idx($2);
	if ( CheckAnyType(elem->GetType(), Z_TYPE, Z_LOC) )
		AssignTarget($$, BuildVal(elem, Z_TYPE))
	else
		ZAM_error = true;
