diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0cd1a8d31d..9191c60c00 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1671,7 +1671,7 @@ int PPointer::GetStoreOp() const int PPointer::GetLoadOp() const { - return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP; + return (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; } //========================================================================== diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f3cf4867ee..f78dcdff6c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -229,6 +229,31 @@ static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::Na // //========================================================================== +static bool AreCompatiblePointerTypes(PType *dest, PType *source) +{ + if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer))) + { + // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. + auto fromtype = static_cast(source); + auto totype = static_cast(dest); + if (fromtype == nullptr) return true; + if (fromtype == totype) return true; + if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + auto fromcls = static_cast(fromtype->PointedType); + auto tocls = static_cast(totype->PointedType); + return (fromcls->IsDescendantOf(tocls)); + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + ExpEmit FxExpression::Emit (VMFunctionBuilder *build) { ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); @@ -1174,21 +1199,9 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) if (fromtype->IsDescendantOf(totype)) goto basereturn; } } - else if (ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + else if (AreCompatiblePointerTypes(ValueType, basex->ValueType)) { - // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. - if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) - { - auto fromtype = static_cast(basex->ValueType); - auto totype = static_cast(ValueType); - if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - - auto fromcls = static_cast(fromtype->PointedType); - auto tocls = static_cast(totype->PointedType); - if (fromcls->IsDescendantOf(tocls)) goto basereturn; - } - } + goto basereturn; } // todo: pointers to class objects. // All other types are only compatible to themselves and have already been handled above by the equality check. @@ -1201,9 +1214,9 @@ errormsg: basereturn: auto x = basex; + x->ValueType = ValueType; basex = nullptr; delete this; - x->ValueType = ValueType; return x; } @@ -1996,14 +2009,21 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) ValueType = TypeFloat64; } } - else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType) + else if (left->ValueType->GetRegType() == REGT_POINTER) { - ValueType = left->ValueType; + if (left->ValueType == right->ValueType || right->ValueType == TypeNullPtr || left->ValueType == TypeNullPtr || + AreCompatiblePointerTypes(left->ValueType, right->ValueType)) + { + // pointers can only be compared for equality. + assert(Operator == TK_Eq || Operator == TK_Neq); + ValueType = TypeBool; + } } else { ValueType = TypeVoid; } + assert(ValueType > nullptr && ValueType < (PType*)0xfffffffffffffff); if (castnumeric) { @@ -4191,70 +4211,75 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) SAFE_RESOLVE(Object, ctx); - if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PSymbolTable *symtbl; - PClass *cls = static_cast(Object->ValueType)->ClassRestriction; - if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) + auto ptype = static_cast(Object->ValueType)->PointedType; + + if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + PClass *cls = static_cast(ptype); + if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); - newex = FxConstant::MakeConstant(sym, ScriptPosition); - } - else if (sym->IsKindOf(RUNTIME_CLASS(PField))) - { - PField *vsym = static_cast(sym); - - // We have 4 cases to consider here: - // 1. The symbol is a static/meta member (not implemented yet) which is always accessible. - // 2. This is a static function - // 3. This is an action function with a restricted self pointer - // 4. This is a normal member or unrestricted action function. - if (vsym->Flags & VARF_Deprecated) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { - ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars()); + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); + newex = FxConstant::MakeConstant(sym, ScriptPosition); } - if ((vsym->Flags & VARF_Private) && symtbl != &ctx.Class->Symbols) + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { - ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars()); + PField *vsym = static_cast(sym); + + // We have 4 cases to consider here: + // 1. The symbol is a static/meta member (not implemented yet) which is always accessible. + // 2. This is a static function + // 3. This is an action function with a restricted self pointer + // 4. This is a normal member or unrestricted action function. + if (vsym->Flags & VARF_Deprecated) + { + ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars()); + } + if ((vsym->Flags & VARF_Private) && symtbl != &ctx.Class->Symbols) + { + ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars()); + delete this; + return nullptr; + } + + if (vsym->Flags & VARF_Static) + { + // todo. For now these cannot be defined so let's just exit. + ScriptPosition.Message(MSG_ERROR, "Static members not implemented yet."); + delete this; + return nullptr; + } + auto x = new FxClassMember(Object, vsym, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); delete this; return nullptr; } - - if (vsym->Flags & VARF_Static) - { - // todo. For now these cannot be defined so let's just exit. - ScriptPosition.Message(MSG_ERROR, "Static members not implemented yet."); - delete this; - return nullptr; - } - auto x = new FxClassMember(Object, vsym, ScriptPosition); - delete this; - return x->Resolve(ctx); } else { - ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); delete this; return nullptr; } } - else + else if (ptype->IsA(RUNTIME_CLASS(PStruct))) { - ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); - delete this; - return nullptr; + // todo } } else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct))) { // todo } - else if (Object->ValueType->IsA(RUNTIME_CLASS(PPointer))) - { - // todo - } ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars()); delete this; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 0348468a92..32dc4bfbf1 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -380,7 +380,7 @@ public: isresolved = true; } - FxConstant(nullptr_t *nullp, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(const FScriptPosition &pos) : FxExpression(pos) { value.pointer = nullptr; ValueType = value.Type = TypeNullPtr; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4705948973..260cc64088 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -636,7 +636,7 @@ void InitThingdef() // Define some member variables we feel like exposing to the user PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PType *array5 = NewArray(TypeSInt32, 5); - PType *TypeActor = NewClassPointer(RUNTIME_CLASS(AActor)); + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha))); symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw))); symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args))); diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 42c3014c13..eeeba6295a 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1450,6 +1450,14 @@ constant(X) ::= TRUE(A). NEW_INTCONST_NODE(boolconst, TypeBool, true, A); X = boolconst; } +constant(X) ::= NULLPTR(A). +{ + NEW_AST_NODE(ExprConstant, nullptrconst, A); + nullptrconst->Operation = PEX_ConstValue; + nullptrconst->Type = TypeNullPtr; + nullptrconst->StringVal = nullptr; + X = nullptrconst; +} /************ Statements ************/ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index a91d27a4ee..06c08f6811 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1462,6 +1462,10 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) { return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } + if (type->IsKindOf(RUNTIME_CLASS(PClass))) + { + return NewPointer(type); + } return type; } return TypeError; @@ -2353,6 +2357,8 @@ static FxExpression *ModifyAssign(FxBinary *operation, FxExpression *left) FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) { + if (ast == nullptr) return nullptr; + // Note: Do not call 'Simplify' here because that function tends to destroy identifiers due to lack of context in which to resolve them. // The Fx nodes created here will be better suited for that. switch (ast->NodeType) @@ -2436,6 +2442,10 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) { return new FxConstant(*cnst->StringVal, *ast); } + else if (cnst->Type == TypeNullPtr) + { + return new FxConstant(*ast); + } else { // can there be other types? diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 222e8e6c53..7d4edf78a3 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -154,7 +154,7 @@ static void InitTokenMap() TOKENDEF (TK_Out, ZCC_OUT); TOKENDEF (TK_Optional, ZCC_OPTIONAL); TOKENDEF (TK_Super, ZCC_SUPER); - TOKENDEF (TK_Null, ZCC_NULL); + TOKENDEF (TK_Null, ZCC_NULLPTR); TOKENDEF (TK_Self, ZCC_SELF); TOKENDEF ('~', ZCC_TILDE); TOKENDEF ('!', ZCC_BANG);