- added automatic type deduction capabilities for local variables. If you type 'let variable = value;' the type of 'variable' will be deduced from the given value. This is mostly of interest for type casting pointers, because 'let p = Classtype(objectvar);' does not require writing the class type name twice.

This commit is contained in:
Christoph Oelckers 2016-12-05 13:24:42 +01:00
parent 67bdac5227
commit f722967abe
10 changed files with 42 additions and 3 deletions

View file

@ -9964,17 +9964,43 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
delete this;
return nullptr;
}
if (ValueType->RegType == REGT_NIL)
if (ValueType->RegType == REGT_NIL && ValueType != TypeAuto)
{
auto sfunc = static_cast<VMScriptFunction *>(ctx.Function->Variants[0].Implementation);
StackOffset = sfunc->AllocExtraStack(ValueType);
// Todo: Process the compound initializer once implemented.
if (Init != nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars());
delete this;
return nullptr;
}
}
else
else if (ValueType !=TypeAuto)
{
if (Init) Init = new FxTypeCast(Init, ValueType, false);
SAFE_RESOLVE_OPT(Init, ctx);
}
else
{
if (Init == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Automatic type deduction requires an initializer for variable %s", Name.GetChars());
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;
}
ValueType = Init->ValueType;
// 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;
}
if (Name != NAME_None)
{
for (auto l : ctx.Block->LocalVars)

View file

@ -704,6 +704,7 @@ type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; }
type_name1(X) ::= SOUND(T). { X.Int = ZCC_Sound; X.SourceLoc = T.SourceLoc; }
type_name1(X) ::= STATE(T). { X.Int = ZCC_State; X.SourceLoc = T.SourceLoc; }
type_name1(X) ::= COLOR(T). { X.Int = ZCC_Color; X.SourceLoc = T.SourceLoc; }
type_name1(X) ::= LET(T). { X.Int = ZCC_Let; X.SourceLoc = T.SourceLoc; }
type_name(X) ::= type_name1(A).
{

View file

@ -1449,6 +1449,10 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
retval = TypeSound;
break;
case ZCC_Let:
retval = TypeAuto;
break;
case ZCC_UserType:
// statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too?
switch (btype->UserType->Id)

View file

@ -201,6 +201,7 @@ static void InitTokenMap()
TOKENDEF2(TK_State, ZCC_STATE, NAME_State);
TOKENDEF2(TK_Color, ZCC_COLOR, NAME_Color);
TOKENDEF2(TK_Sound, ZCC_SOUND, NAME_Sound);
TOKENDEF2(TK_Let, ZCC_LET, NAME_let);
TOKENDEF (TK_Identifier, ZCC_IDENTIFIER);
TOKENDEF (TK_StringConst, ZCC_STRCONST);

View file

@ -131,6 +131,7 @@ enum EZCCBuiltinType
ZCC_Sound,
ZCC_UserType,
ZCC_Let,
ZCC_NUM_BUILT_IN_TYPES
};