added class pointer casts. Due to grammar problems the type has to be put into parentheses to get the class token out of the global parsing namespace:

class<Actor> myclass = (class<Actor>)(GetClass());
This commit is contained in:
Christoph Oelckers 2016-11-17 20:31:53 +01:00
parent 022228d8a9
commit 3bcd85eb8a
8 changed files with 167 additions and 0 deletions

View File

@ -683,6 +683,7 @@ xx(BuiltinFindMultiNameState)
xx(BuiltinFindSingleNameState)
xx(BuiltinHandleRuntimeState)
xx(BuiltinGetDefault)
xx(BuiltinClassCast)
xx(Damage)
// basic type names

View File

@ -8382,6 +8382,107 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
return dest;
}
//==========================================================================
//
//==========================================================================
FxClassPtrCast::FxClassPtrCast(PClass *dtype, FxExpression *x)
: FxExpression(EFX_ClassPtrCast, x->ScriptPosition)
{
ValueType = NewClassPointer(dtype);
desttype = dtype;
basex = x;
}
//==========================================================================
//
//
//
//==========================================================================
FxClassPtrCast::~FxClassPtrCast()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
if (basex->ValueType == TypeNullPtr)
{
basex->ValueType = ValueType;
auto x = basex;
basex = nullptr;
delete this;
return x;
}
auto to = static_cast<PClassPointer *>(ValueType);
if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer))
{
auto from = static_cast<PClassPointer *>(basex->ValueType);
// Downcast is always ok.
if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction))
{
basex->ValueType = to;
auto x = basex;
basex = nullptr;
delete this;
return x;
}
// Upcast needs a runtime check.
else if (to->ClassRestriction->IsDescendantOf(from->ClassRestriction))
{
return this;
}
}
// Everything else is an error.
ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName());
delete this;
return nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
int BuiltinClassCast(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
{
PARAM_PROLOGUE;
PARAM_CLASS(from, DObject);
PARAM_CLASS(to, DObject);
ACTION_RETURN_OBJECT(from->IsDescendantOf(to) ? from : nullptr);
}
ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
{
ExpEmit clsname = basex->Emit(build);
build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype, ATAG_OBJECT));
VMFunction *callfunc;
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
clsname.Free(build);
ExpEmit dest(build, REGT_POINTER);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
return dest;
}
//==========================================================================
//
// Symbolic state labels.

View File

@ -258,6 +258,7 @@ enum EFxType
EFX_JumpStatement,
EFX_ReturnStatement,
EFX_ClassTypeCast,
EFX_ClassPtrCast,
EFX_StateByIndex,
EFX_RuntimeStateIndex,
EFX_MultiNameState,
@ -1668,6 +1669,25 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxClassPtrCast : public FxExpression
{
PClass *desttype;
FxExpression *basex;
public:
FxClassPtrCast(PClass *dtype, FxExpression *x);
~FxClassPtrCast();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// Only used to resolve the old jump by index feature of DECORATE

View File

@ -585,6 +585,16 @@ static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node)
out.Close();
}
static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ClassCast *enode = (ZCC_ClassCast *)node;
assert(enode->Operation == PEX_ClassCast);
out.Open("expr-class-cast");
out.AddName(enode->ClassName);
PrintNodes(out, enode->Parameters, false);
out.Close();
}
static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node;
@ -913,6 +923,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *
PrintPropertyStmt,
PrintVectorInitializer,
PrintDeclFlags,
PrintExprClassCast,
};
FString ZCC_PrintAST(ZCC_TreeNode *root)

View File

@ -1080,6 +1080,14 @@ primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function ca
expr->Parameters = B;
X = expr;
}
primary(X) ::= LPAREN CLASS LT IDENTIFIER(A) GT RPAREN LPAREN func_expr_list(B) RPAREN. [DOT] // class type cast
{
NEW_AST_NODE(ClassCast, expr, A);
expr->Operation = PEX_ClassCast;
expr->ClassName = ENamedName(A.Int);
expr->Parameters = B;
X = expr;
}
primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access
{
NEW_AST_NODE(ExprBinary, expr, B);

View File

@ -2766,6 +2766,24 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
break;
}
case AST_ClassCast:
{
auto cc = static_cast<ZCC_ClassCast *>(ast);
if (cc->Parameters == nullptr || cc->Parameters->SiblingNext != cc->Parameters)
{
Error(cc, "Class type cast requires exactly one parameter");
return new FxNop(*ast); // return something so that the compiler can continue.
}
auto cls = PClass::FindClass(cc->ClassName);
if (cls == nullptr)
{
Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars());
return new FxNop(*ast); // return something so that the compiler can continue.
}
return new FxClassPtrCast(cls, ConvertNode(cc->Parameters));
}
case AST_ExprMemberAccess:
{
auto memaccess = static_cast<ZCC_ExprMemberAccess *>(ast);

View File

@ -8,6 +8,7 @@ xx(ConstValue, TK_Const)
xx(FuncCall, '(')
xx(ArrayAccess, TK_Array)
xx(MemberAccess, '.')
xx(ClassCast, TK_Class)
xx(TypeRef, TK_Class)
xx(Vector, TK_Vector2)

View File

@ -102,6 +102,7 @@ enum EZCCTreeNodeType
AST_PropertyStmt,
AST_VectorValue,
AST_DeclFlags,
AST_ClassCast,
NUM_AST_NODE_TYPES
};
@ -366,6 +367,12 @@ struct ZCC_ExprFuncCall : ZCC_Expression
ZCC_FuncParm *Parameters;
};
struct ZCC_ClassCast : ZCC_Expression
{
ENamedName ClassName;
ZCC_FuncParm *Parameters;
};
struct ZCC_ExprMemberAccess : ZCC_Expression
{
ZCC_Expression *Left;