forked from Mirrors/openclonk
Add array slicing syntax ary[begin:end]
... which evaluates to a copy of the elements with indices in the range [begin,end), where either index might be omitted, defaulting to 0 or the length of the string respectivelystable-5.1
parent
a3a643bb5e
commit
adc278dc57
|
@ -132,6 +132,7 @@ enum C4AulBCCType
|
|||
{
|
||||
AB_ARRAYA_R, // array access
|
||||
AB_ARRAYA_V, // not creating a reference
|
||||
AB_ARRAY_SLICE, // array slicing
|
||||
AB_VARN_R, // a named var
|
||||
AB_VARN_V,
|
||||
AB_PARN_R, // a named parameter
|
||||
|
|
|
@ -591,6 +591,26 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_ARRAY_SLICE:
|
||||
{
|
||||
C4Value &Array = pCurVal[-2];
|
||||
C4Value &StartIndex = pCurVal[-1];
|
||||
C4Value &EndIndex = pCurVal[0];
|
||||
|
||||
// Typcheck
|
||||
if (!Array.ConvertTo(C4V_Array) || Array.GetType() == C4V_Any)
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: can't access %s as an array!", Array.GetTypeName()).getData());
|
||||
if (!StartIndex.ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: start index of type %s, int expected!", StartIndex.GetTypeName()).getData());
|
||||
if (!EndIndex.ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: end index of type %s, int expected!", EndIndex.GetTypeName()).getData());
|
||||
|
||||
Array.SetArray(Array.GetData().Array->GetSlice(StartIndex._getInt(), EndIndex._getInt()));
|
||||
|
||||
// Remove both indices
|
||||
PopValues(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case AB_STACK:
|
||||
if (pCPos->Par.i < 0)
|
||||
|
|
|
@ -833,6 +833,7 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
{
|
||||
case AB_ARRAYA_R: return "ARRAYA_R"; // array access
|
||||
case AB_ARRAYA_V: return "ARRAYA_V"; // not creating a reference
|
||||
case AB_ARRAY_SLICE: return "ARRAY_SLICE";
|
||||
case AB_VARN_R: return "VARN_R"; // a named var
|
||||
case AB_VARN_V: return "VARN_V";
|
||||
case AB_PARN_R: return "PARN_R"; // a named parameter
|
||||
|
@ -1103,6 +1104,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
iStack-=X-1;
|
||||
break;
|
||||
|
||||
case AB_ARRAY_SLICE:
|
||||
case AB_PROPSET:
|
||||
iStack -= 2;
|
||||
break;
|
||||
|
@ -1940,7 +1942,7 @@ int C4AulParseState::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * p
|
|||
{
|
||||
case AB_INT: from = (a->CPos-1)->Par.i ? C4V_Int : C4V_Any; break;
|
||||
case AB_STRING: from = C4V_String; break;
|
||||
case AB_ARRAY: from = C4V_Array; break;
|
||||
case AB_ARRAY: case AB_ARRAY_SLICE: from = C4V_Array; break;
|
||||
case AB_BOOL: from = C4V_Bool; break;
|
||||
// case AB_UNOP: case AB_BINOP: from = C4ScriptOpMap[(a->CPos-1)->Par.i].RetType; break;
|
||||
case AB_FUNC:
|
||||
|
@ -2594,11 +2596,37 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
}
|
||||
case ATT_BOPEN2:
|
||||
{
|
||||
// Access the array
|
||||
// parse either [index], or [start:end] in which case either index is optional
|
||||
Shift();
|
||||
Parse_Expression();
|
||||
Match(ATT_BCLOSE2);
|
||||
AddBCC(AB_ARRAYA_R);
|
||||
if (TokenType == ATT_COLON)
|
||||
AddBCC(AB_INT, 0); // slice with first index missing -> implicit start index zero
|
||||
else
|
||||
Parse_Expression();
|
||||
|
||||
if (TokenType == ATT_BCLOSE2)
|
||||
{
|
||||
Shift();
|
||||
AddBCC(AB_ARRAYA_R);
|
||||
}
|
||||
else if (TokenType == ATT_COLON)
|
||||
{
|
||||
Shift();
|
||||
if (TokenType == ATT_BCLOSE2)
|
||||
{
|
||||
Shift();
|
||||
AddBCC(AB_INT, INT_MAX); // second index missing -> implicit end index GetLength()
|
||||
}
|
||||
else
|
||||
{
|
||||
Parse_Expression();
|
||||
Match(ATT_BCLOSE2);
|
||||
}
|
||||
AddBCC(AB_ARRAY_SLICE);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnexpectedToken("']' or ':'");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATT_CALL:
|
||||
|
|
|
@ -253,6 +253,30 @@ C4ValueArray * C4ValueArray::IncRef()
|
|||
return this;
|
||||
}
|
||||
|
||||
C4ValueArray * C4ValueArray::GetSlice(int32_t startIndex, int32_t endIndex)
|
||||
{
|
||||
// adjust indices so that the default end index works and that negative numbers count backwards from the end of the string
|
||||
if (startIndex > iSize) startIndex = iSize;
|
||||
else if (startIndex < -iSize) throw new C4AulExecError(NULL, "Array slice: invalid start index");
|
||||
else if (startIndex < 0) startIndex += iSize;
|
||||
|
||||
if (endIndex > iSize) endIndex = iSize;
|
||||
else if (endIndex < -iSize) throw new C4AulExecError(NULL, "Array slice: invalid end index");
|
||||
else if (endIndex < 0) endIndex += iSize;
|
||||
|
||||
if (startIndex == 0 && endIndex == iSize)
|
||||
{
|
||||
return IncRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
C4ValueArray* NewArray = new C4ValueArray(std::max(0, endIndex - startIndex));
|
||||
for (int i = startIndex; i < endIndex; ++i)
|
||||
NewArray->pData[i - startIndex] = pData[i];
|
||||
return NewArray;
|
||||
}
|
||||
}
|
||||
|
||||
C4ValueArray * C4ValueArray::SetLength(int32_t size)
|
||||
{
|
||||
if (iRefCnt > 1)
|
||||
|
|
|
@ -81,6 +81,8 @@ public:
|
|||
// Add Reference, return self or new copy if necessary
|
||||
C4ValueArray * IncRef();
|
||||
C4ValueArray * IncElementRef();
|
||||
// Return sub-array [startIndex, endIndex), or reference for [0, iSize)
|
||||
C4ValueArray * GetSlice(int32_t startIndex, int32_t endIndex);
|
||||
// Change length, return self or new copy if necessary
|
||||
C4ValueArray * SetLength(int32_t size);
|
||||
void DecRef();
|
||||
|
|
Loading…
Reference in New Issue