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 respectively
stable-5.1
Benjamin Herr 2010-04-05 17:41:36 +02:00
parent a3a643bb5e
commit adc278dc57
5 changed files with 80 additions and 5 deletions

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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();