Implemented a call check between ui/play/data

This commit is contained in:
ZZYZX 2017-02-17 23:02:43 +02:00
parent a2f3d8511d
commit 3056570ea9
2 changed files with 42 additions and 14 deletions

View file

@ -7662,7 +7662,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
if (ctx.Class == nullptr) if (ctx.Class == nullptr)
{ {
// There's no way that a member function call can resolve to a constant so abort right away. // There's no way that a member function call can resolve to a constant so abort right away.
ScriptPosition.Message(MSG_ERROR, "Expression is not constant."); ScriptPosition.Message(MSG_ERROR, "Expression is not constant");
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7671,7 +7671,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (a == nullptr) if (a == nullptr)
{ {
ScriptPosition.Message(MSG_ERROR, "Empty function argument."); ScriptPosition.Message(MSG_ERROR, "Empty function argument");
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7762,7 +7762,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (ArgList.Size() > 0) if (ArgList.Size() > 0)
{ {
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7806,7 +7806,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (ArgList.Size() > 0) if (ArgList.Size() > 0)
{ {
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7900,7 +7900,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (ArgList.Size() > 0) if (ArgList.Size() > 0)
{ {
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7960,7 +7960,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{ {
if (ArgList.Size() > 0) if (ArgList.Size() > 0)
{ {
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7973,7 +7973,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
} }
else else
{ {
ScriptPosition.Message(MSG_ERROR, "Left hand side of %s must point to a class object\n", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Left hand side of %s must point to a class object", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -7989,7 +7989,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
} }
else else
{ {
ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -8007,7 +8007,7 @@ isresolved:
if (afd == nullptr) if (afd == nullptr)
{ {
ScriptPosition.Message(MSG_ERROR, "Unknown function %s\n", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Unknown function %s", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -8016,11 +8016,31 @@ isresolved:
{ {
// Cannot be made writable so we cannot use its methods. // Cannot be made writable so we cannot use its methods.
// [ZZ] Why this esoteric message? // [ZZ] Why this esoteric message?
ScriptPosition.Message(MSG_ERROR, "Readonly struct on left hand side of %s not allowed\n", MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Readonly struct on left hand side of %s not allowed", MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
// [ZZ] if self is a struct or a class member, check if it's valid to call this function at all.
// implement more magic
if (Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StructMember)
{
FxStructMember* pmember = (FxStructMember*)Self;
int outerflags = 0;
if (ctx.Function)
outerflags = ctx.Function->Variants[0].Flags;
int innerflags = afd->Variants[0].Flags;
if (FScopeBarrier::SideFromFlags(innerflags) == FScopeBarrier::Side_PlainData)
innerflags = FScopeBarrier::ChangeSideInFlags(innerflags, pmember->BarrierSide);
FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars());
if (!scopeBarrier.callable)
{
ScriptPosition.Message(MSG_ERROR, "%s", scopeBarrier.callerror.GetChars());
delete this;
return nullptr;
}
}
if (staticonly && (afd->Variants[0].Flags & VARF_Method)) if (staticonly && (afd->Variants[0].Flags & VARF_Method))
{ {
if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual))
@ -8029,14 +8049,14 @@ isresolved:
auto ccls = dyn_cast<PClass>(cls); auto ccls = dyn_cast<PClass>(cls);
if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls))
{ {
ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
else else
{ {
// Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.) // Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.)
ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented", cls->TypeName.GetChars(), MethodName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }
@ -8064,7 +8084,7 @@ isresolved:
// Functions with no Actor usage may not be called through a pointer because they will lose their context. // Functions with no Actor usage may not be called through a pointer because they will lose their context.
if (!(afd->Variants[0].UseFlags & SUF_ACTOR)) if (!(afd->Variants[0].UseFlags & SUF_ACTOR))
{ {
ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object\n", afd->SymbolName.GetChars()); ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object", afd->SymbolName.GetChars());
delete this; delete this;
return nullptr; return nullptr;
} }

View file

@ -132,6 +132,14 @@ struct FScopeBarrier
} }
} }
// this modifies VARF_ flags and sets the side properly.
static int ChangeSideInFlags(int flags, int side)
{
flags &= ~(VARF_UI | VARF_Play);
flags |= FlagsFromSide(side);
return flags;
}
FScopeBarrier() FScopeBarrier()
{ {
sidefrom = -1; sidefrom = -1;
@ -203,7 +211,7 @@ struct FScopeBarrier
if (callable && (sidefrom != sideto) && !(flags2 & VARF_ReadOnly)) // readonly on methods is used for plain data stuff that can be called from ui/play context. if (callable && (sidefrom != sideto) && !(flags2 & VARF_ReadOnly)) // readonly on methods is used for plain data stuff that can be called from ui/play context.
{ {
callable = false; callable = false;
callerror.Format("Can't call %s field %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom)); callerror.Format("Can't call %s function %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom));
} }
} }
}; };