DECORATE can now handle jump statements

break and continue were added but are not yet useable anywhere
This was made general enough so that loops and switch statements that accept breaks/continues can be done without much difficulty as well as goto statements with explicit labels if those are ever wanted
This commit is contained in:
Leonard2 2016-07-26 23:57:26 +02:00 committed by Christoph Oelckers
parent dfed6ac1fb
commit c4eafc1c38
3 changed files with 121 additions and 22 deletions

View file

@ -50,6 +50,7 @@
#define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p)
class VMFunctionBuilder; class VMFunctionBuilder;
class FxJumpStatement;
//========================================================================== //==========================================================================
// //
@ -59,21 +60,15 @@ class VMFunctionBuilder;
struct FCompileContext struct FCompileContext
{ {
PClassActor *cls; TArray<FxJumpStatement *> Jumps;
PClassActor *Class;
FCompileContext(PClassActor *_cls = NULL) FCompileContext(PClassActor *cls = nullptr);
{
cls = _cls;
}
PSymbol *FindInClass(FName identifier) PSymbol *FindInClass(FName identifier);
{ PSymbol *FindGlobal(FName identifier);
return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL;
} void HandleJumps(int token, FxExpression *handler);
PSymbol *FindGlobal(FName identifier)
{
return GlobalSymbols.FindSymbol(identifier, true);
}
}; };
//========================================================================== //==========================================================================
@ -212,6 +207,8 @@ public:
virtual ExpEmit Emit(VMFunctionBuilder *build); virtual ExpEmit Emit(VMFunctionBuilder *build);
TArray<FxJumpStatement *> JumpAddresses;
FScriptPosition ScriptPosition; FScriptPosition ScriptPosition;
PType *ValueType; PType *ValueType;
@ -930,6 +927,24 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
//==========================================================================
//
// FxJumpStatement
//
//==========================================================================
class FxJumpStatement : public FxExpression
{
public:
FxJumpStatement(int token, const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
int Token;
size_t Address;
FxExpression *AddressResolver;
};
//========================================================================== //==========================================================================
// //
// FxReturnStatement // FxReturnStatement

View file

@ -85,6 +85,45 @@ static const FLOP FxFlops[] =
{ NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } },
}; };
//==========================================================================
//
// FCompileContext
//
//==========================================================================
FCompileContext::FCompileContext(PClassActor *cls) : Class(cls)
{
}
PSymbol *FCompileContext::FindInClass(FName identifier)
{
return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr;
}
PSymbol *FCompileContext::FindGlobal(FName identifier)
{
return GlobalSymbols.FindSymbol(identifier, true);
}
void FCompileContext::HandleJumps(int token, FxExpression *handler)
{
for (unsigned int i = 0; i < Jumps.Size(); i++)
{
if (Jumps[i]->Token == token)
{
Jumps[i]->AddressResolver = handler;
handler->JumpAddresses.Push(Jumps[i]);
Jumps.Delete(i);
i--;
}
}
}
//==========================================================================
//
// ExpEmit
//
//==========================================================================
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
{ {
@ -2838,14 +2877,14 @@ FxSelf::FxSelf(const FScriptPosition &pos)
FxExpression *FxSelf::Resolve(FCompileContext& ctx) FxExpression *FxSelf::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (!ctx.cls) if (!ctx.Class)
{ {
// can't really happen with DECORATE's expression evaluator. // can't really happen with DECORATE's expression evaluator.
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
delete this; delete this;
return NULL; return NULL;
} }
ValueType = ctx.cls; ValueType = ctx.Class;
ValueType = NewPointer(RUNTIME_CLASS(DObject)); ValueType = NewPointer(RUNTIME_CLASS(DObject));
return this; return this;
} }
@ -3818,6 +3857,39 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
return ExpEmit(); return ExpEmit();
} }
//==========================================================================
//
// FxJumpStatement
//
//==========================================================================
FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos)
: FxExpression(pos), Token(token), AddressResolver(nullptr)
{
ValueType = TypeVoid;
}
FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
ctx.Jumps.Push(this);
return this;
}
ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build)
{
if (AddressResolver == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Jump statement %s has nowhere to go!", FScanner::TokenName(Token));
}
Address = build->Emit(OP_JMP, 0);
return ExpEmit();
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -4008,19 +4080,19 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (ctx.cls->NumOwnedStates == 0) if (ctx.Class->NumOwnedStates == 0)
{ {
// This can't really happen // This can't really happen
assert(false); assert(false);
} }
if (ctx.cls->NumOwnedStates <= index) if (ctx.Class->NumOwnedStates <= index)
{ {
ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d",
ctx.cls->TypeName.GetChars(), index); ctx.Class->TypeName.GetChars(), index);
delete this; delete this;
return NULL; return NULL;
} }
FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition); FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition);
delete this; delete this;
return x; return x;
} }
@ -4068,7 +4140,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
} }
else if (names[0] == NAME_Super) else if (names[0] == NAME_Super)
{ {
scope = dyn_cast<PClassActor>(ctx.cls->ParentClass); scope = dyn_cast<PClassActor>(ctx.Class->ParentClass);
} }
else else
{ {
@ -4079,9 +4151,9 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
delete this; delete this;
return NULL; return NULL;
} }
else if (!scope->IsDescendantOf(ctx.cls)) else if (!scope->IsDescendantOf(ctx.Class))
{ {
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars()); ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars());
delete this; delete this;
return NULL; return NULL;
} }

View file

@ -529,6 +529,18 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
sc.MustGetString(); sc.MustGetString();
add = new FxReturnStatement(retexp, sc); add = new FxReturnStatement(retexp, sc);
} }
else if (sc.Compare("break"))
{
add = new FxJumpStatement(TK_Break, sc);
sc.MustGetStringName(";");
sc.MustGetString();
}
else if (sc.Compare("continue"))
{
add = new FxJumpStatement(TK_Continue, sc);
sc.MustGetStringName(";");
sc.MustGetString();
}
else else
{ // Handle a regular action function call { // Handle a regular action function call
add = ParseAction(sc, state, statestring, bag); add = ParseAction(sc, state, statestring, bag);