- added 'foreach' loop to ZScript.
Syntax:
foreach(variable : array)
{
}
the variable's type is automatically deducted.
This commit is contained in:
parent
4994e114c8
commit
29b4418c3a
8 changed files with 173 additions and 24 deletions
|
|
@ -7310,8 +7310,8 @@ FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index)
|
||||
:FxExpression(EFX_ArrayElement, base->ScriptPosition)
|
||||
FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index, bool nob)
|
||||
:FxExpression(EFX_ArrayElement, base->ScriptPosition), noboundscheck(nob)
|
||||
{
|
||||
Array=base;
|
||||
index = _index;
|
||||
|
|
@ -7594,18 +7594,21 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|||
else
|
||||
{
|
||||
ExpEmit indexv(index->Emit(build));
|
||||
if (SizeAddr != ~0u || nestedarray)
|
||||
if (!noboundscheck) // this is 'foreach' which is known to be inside the bounds.
|
||||
{
|
||||
build->Emit(OP_BOUND_R, indexv.RegNum, bound.RegNum);
|
||||
bound.Free(build);
|
||||
}
|
||||
else if (arraytype->ElementCount > 65535)
|
||||
{
|
||||
build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
||||
if (SizeAddr != ~0u || nestedarray)
|
||||
{
|
||||
build->Emit(OP_BOUND_R, indexv.RegNum, bound.RegNum);
|
||||
bound.Free(build);
|
||||
}
|
||||
else if (arraytype->ElementCount > 65535)
|
||||
{
|
||||
build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (!start.Konst)
|
||||
|
|
@ -8338,7 +8341,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
else if (Self->IsVector())
|
||||
{
|
||||
// handle builtins: Vectors got 5.
|
||||
if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Unit || MethodName == NAME_Angle)
|
||||
if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Sum || MethodName == NAME_Unit || MethodName == NAME_Angle)
|
||||
{
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
|
|
@ -10655,6 +10658,77 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
|
|||
return ExpEmit();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxForLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Array != nullptr) Array->NeedResult = false;
|
||||
if (Array2 != nullptr) Array2->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxForEachLoop::~FxForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(Array);
|
||||
SAFE_DELETE(Array2);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Array, ctx);
|
||||
SAFE_RESOLVE(Array2, ctx);
|
||||
|
||||
// Instead of writing a new code generator for this, convert this into
|
||||
//
|
||||
// int @size = array.Size();
|
||||
// for(int @i = 0; @i < @size; @i++)
|
||||
// {
|
||||
// let var = array[i];
|
||||
// body
|
||||
// }
|
||||
// and let the existing 'for' loop code sort out the rest.
|
||||
|
||||
FName sizevar = "@size";
|
||||
FName itvar = "@i";
|
||||
FArgumentList al;
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, al, ScriptPosition);
|
||||
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
|
||||
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
|
||||
block->Add(size);
|
||||
block->Add(it);
|
||||
|
||||
auto cit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto csiz = new FxLocalVariable(size, ScriptPosition);
|
||||
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
|
||||
|
||||
auto iit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto bump = new FxPreIncrDecr(iit, TK_Incr);
|
||||
|
||||
auto ait = new FxLocalVariable(it, ScriptPosition);
|
||||
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
|
||||
|
||||
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
|
||||
auto body = new FxCompoundStatement(ScriptPosition);
|
||||
body->Add(assign);
|
||||
body->Add(Code);
|
||||
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
|
||||
block->Add(forloop);
|
||||
Array2 = Array = nullptr;
|
||||
Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxJumpStatement
|
||||
|
|
@ -11221,14 +11295,23 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
|
|||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
SAFE_RESOLVE_OPT(Init, ctx);
|
||||
if (Init->ValueType->RegType == REGT_NIL)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
SAFE_RESOLVE(Init, ctx);
|
||||
ValueType = Init->ValueType;
|
||||
if (ValueType->RegType == REGT_NIL)
|
||||
{
|
||||
if (Init->IsStruct())
|
||||
{
|
||||
ValueType = NewPointer(ValueType);
|
||||
Init = new FxTypeCast(Init, ValueType, false);
|
||||
SAFE_RESOLVE(Init, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// check for undersized ints and floats. These are not allowed as local variables.
|
||||
if (IsInteger() && ValueType->Align < sizeof(int)) ValueType = TypeSInt32;
|
||||
else if (IsFloat() && ValueType->Align < sizeof(double)) ValueType = TypeFloat64;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue