Skip to content

Commit

Permalink
feat(zscript): option 'OLD_ARRAY_TYPECASTING' to use old array type h…
Browse files Browse the repository at this point in the history
…andling
  • Loading branch information
EmilyV99 committed May 3, 2024
1 parent d892403 commit d7555bf
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 47 deletions.
16 changes: 15 additions & 1 deletion src/dialog/compilesetting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ void CompileSettingsDlg::load()
dd_cfg[1] = zc_get_config("Compiler","HEADER_GUARD",1,App::zscript);
dd_cfg[2] = zc_get_config("Compiler","WARN_DEPRECATED",0,App::zscript);
dd_cfg[3] = zc_get_config("Compiler","ON_MISSING_RETURN",2,App::zscript);
old_compat_array_typecast = compat_array_typecast = zc_get_config("Compiler","OLD_ARRAY_TYPECASTING",0,App::zscript);
old_timeout_secs = timeout_secs = zc_get_config("Compiler","compiler_timeout",30,App::zscript);
memcpy(old_dd_cfg,dd_cfg,sizeof(dd_cfg));

Expand Down Expand Up @@ -84,6 +85,8 @@ void CompileSettingsDlg::save()
zc_set_config("Compiler","WARN_DEPRECATED",dd_cfg[2],App::zscript);
if(dd_cfg[3] != old_dd_cfg[3])
zc_set_config("Compiler","ON_MISSING_RETURN",dd_cfg[3],App::zscript);
if(compat_array_typecast != old_compat_array_typecast)
zc_set_config("Compiler","OLD_ARRAY_TYPECASTING",compat_array_typecast,App::zscript);
if(timeout_secs != old_timeout_secs)
zc_set_config("Compiler","compiler_timeout",timeout_secs,App::zscript);
run_str[20] = 0;
Expand Down Expand Up @@ -208,7 +211,18 @@ std::shared_ptr<GUI::Widget> CompileSettingsDlg::view()
{
timeout_secs = val;
}),
INFOBTN("The time ZQ waits before the parser 'times out'. 0 for no timeout.")
INFOBTN("The time ZQ waits before the parser 'times out'. 0 for no timeout."),
//
Checkbox(colSpan = 2, hAlign = 1.0,
text = "Old Array Typecasting",
boxPlacement = GUI::Checkbox::boxPlacement::RIGHT,
checked = compat_array_typecast,
onToggleFunc = [&](bool state)
{
compat_array_typecast = state;
}),
INFOBTN("If arrays should use the old non-strict typing, or not."
"\nNOTE: Old typing may have some bugs, upgrading to new typing is recommended.")
),
Label(text = "Include Paths", hAlign = 0.0),
TextField(
Expand Down
1 change: 1 addition & 0 deletions src/dialog/compilesetting.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class CompileSettingsDlg: public GUI::Dialog<CompileSettingsDlg>
char include_str[MAX_INCLUDE_PATH_CHARS];
byte qst_cfg[4];
word timeout_secs, old_timeout_secs;
bool compat_array_typecast, old_compat_array_typecast;

void load();
void save();
Expand Down
4 changes: 2 additions & 2 deletions src/parser/ASTVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ void RecursiveVisitor::visitFunctionInternals(ZScript::Program& program)
void RecursiveVisitor::checkCast(
DataType const& sourceType, DataType const& targetType, AST* node, bool twoWay)
{
if (sourceType.canCastTo(targetType)) return;
if (twoWay && targetType.canCastTo(sourceType)) return;
if (sourceType.canCastTo(targetType, scope)) return;
if (twoWay && targetType.canCastTo(sourceType, scope)) return;
handleError(
CompileError::IllegalCast(
node, sourceType.getName(), targetType.getName()));
Expand Down
8 changes: 4 additions & 4 deletions src/parser/RegistrationVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ void RegistrationVisitor::caseDataDeclExtraArray(ASTDataDeclExtraArray& host, vo
ASTExpr& size = **it;

// Make sure each size can cast to float.
if (!size.getReadType(scope, this)->canCastTo(DataType::FLOAT))
if (!size.getReadType(scope, this)->canCastTo(DataType::FLOAT, scope))
{
handleError(CompileError::NonIntegerArraySize(&host));
return;
Expand Down Expand Up @@ -1113,15 +1113,15 @@ void RegistrationVisitor::caseExprCall(ASTExprCall& host, void* param)
handleError(CompileError::NoClass(&host, identifier->asString()));
return;
}
functions = lookupConstructors(*user_class, parameterTypes);
functions = lookupConstructors(*user_class, parameterTypes, scope);
}
else
{
if(identifier->components.size() == 1 && parsing_user_class > puc_vars)
{
user_class = &scope->getClass()->user_class;
if(parsing_user_class == puc_construct && identifier->components[0] == user_class->getName())
functions = lookupConstructors(*user_class, parameterTypes);
functions = lookupConstructors(*user_class, parameterTypes, scope);
if(!functions.size())
functions = lookupFunctions(*scope, identifier->components[0], parameterTypes, identifier->noUsing, true);
}
Expand All @@ -1131,7 +1131,7 @@ void RegistrationVisitor::caseExprCall(ASTExprCall& host, void* param)
}
else if(user_class)
{
functions = lookupClassFuncs(*user_class, arrow->right->getValue(), parameterTypes);
functions = lookupClassFuncs(*user_class, arrow->right->getValue(), parameterTypes, scope);
}
else functions = lookupFunctions(arrow->leftClass->getScope(), arrow->right->getValue(), parameterTypes, true); //Never `using` arrow functions

Expand Down
31 changes: 16 additions & 15 deletions src/parser/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ vector<Function*> ZScript::lookupFunctions(Scope& scope, string const& name, vec
foundFile = true;
vector<Function*> currentFunctions = current->getLocalFunctions(name);
if (!skipParamCheck)
trimBadFunctions(currentFunctions, parameterTypes, !isClass);
trimBadFunctions(currentFunctions, parameterTypes, &scope, !isClass);
functions.insert(currentFunctions.begin(), currentFunctions.end());
}
if(!noUsing)
Expand All @@ -534,7 +534,7 @@ vector<Function*> ZScript::lookupFunctions(Scope& scope, string const& name, vec
NamespaceScope* nsscope = *it;
vector<Function*> currentFunctions = nsscope->getLocalFunctions(name);
if (!skipParamCheck)
trimBadFunctions(currentFunctions, parameterTypes, !isClass);
trimBadFunctions(currentFunctions, parameterTypes, &scope, !isClass);
functions.insert(currentFunctions.begin(), currentFunctions.end());
}
current = &scope;
Expand Down Expand Up @@ -569,7 +569,7 @@ vector<Function*> ZScript::lookupFunctions(
if(current.isFile()) foundFile = true;
vector<Function*> currentFunctions = current.getLocalFunctions(name);
if (!skipParamCheck)
trimBadFunctions(currentFunctions, parameterTypes, !isClass);
trimBadFunctions(currentFunctions, parameterTypes, &scope, !isClass);
functions.insert(functions.end(),
currentFunctions.begin(), currentFunctions.end());
}
Expand All @@ -582,7 +582,7 @@ vector<Function*> ZScript::lookupFunctions(
Scope& current = **it;
vector<Function*> currentFunctions = current.getLocalFunctions(name);
if (!skipParamCheck)
trimBadFunctions(currentFunctions, parameterTypes, !isClass);
trimBadFunctions(currentFunctions, parameterTypes, &scope, !isClass);
functions.insert(functions.end(),
currentFunctions.begin(), currentFunctions.end());
}
Expand Down Expand Up @@ -675,17 +675,17 @@ UserClass* ZScript::lookupClass(Scope& scope, vector<string> const& names,
return nullptr;
}

vector<Function*> ZScript::lookupConstructors(UserClass const& user_class, vector<DataType const*> const& parameterTypes)
vector<Function*> ZScript::lookupConstructors(UserClass const& user_class, vector<DataType const*> const& parameterTypes, Scope const* scope)
{
vector<Function*> functions = user_class.getScope().getConstructors();
trimBadFunctions(functions, parameterTypes, false);
trimBadFunctions(functions, parameterTypes, scope, false);
return functions;
}
vector<Function*> ZScript::lookupClassFuncs(UserClass const& user_class,
std::string const& name, vector<DataType const*> const& parameterTypes)
std::string const& name, vector<DataType const*> const& parameterTypes, Scope const* scope)
{
vector<Function*> functions = user_class.getScope().getLocalFunctions(name);
trimBadFunctions(functions, parameterTypes, false);
trimBadFunctions(functions, parameterTypes, scope, false);
for (vector<Function*>::iterator it = functions.begin();
it != functions.end();)
{
Expand Down Expand Up @@ -716,7 +716,8 @@ static int applyTemplateTypes(
Function* function,
std::vector<DataType const *> const &parameter_types,
size_t num_params,
Function** out_resolved_function)
Function** out_resolved_function,
Scope const* parent_scope)
{
auto resolved_params = function->paramTypes;
bool found_template_type = false;
Expand Down Expand Up @@ -752,7 +753,7 @@ static int applyTemplateTypes(
continue;
}

if (!el_type->canCastTo(*bound_t))
if (!el_type->canCastTo(*bound_t, parent_scope))
return APPLY_TEMPLATE_RET_UNSATISFIABLE;

resolved_params[i] = parameter_types[i];
Expand Down Expand Up @@ -789,7 +790,7 @@ static int applyTemplateTypes(
continue;
}

if (!el_type->canCastTo(*bound_t))
if (!el_type->canCastTo(*bound_t, parent_scope))
return APPLY_TEMPLATE_RET_UNSATISFIABLE;

varg_basety = parameter_types[i];
Expand Down Expand Up @@ -826,7 +827,7 @@ static int applyTemplateTypes(
return APPLY_TEMPLATE_RET_APPLIED;
}

inline void ZScript::trimBadFunctions(std::vector<Function*>& functions, std::vector<DataType const*> const& parameterTypes, bool trimClasses)
inline void ZScript::trimBadFunctions(std::vector<Function*>& functions, std::vector<DataType const*> const& parameterTypes, Scope const* parent_scope, bool trimClasses)
{
bool any_from_type_template = false;

Expand Down Expand Up @@ -897,7 +898,7 @@ inline void ZScript::trimBadFunctions(std::vector<Function*>& functions, std::ve
else
{
Function* resolved_function = nullptr;
int apply_ret = applyTemplateTypes(function, parameterTypes, lowsize, &resolved_function);
int apply_ret = applyTemplateTypes(function, parameterTypes, lowsize, &resolved_function, parent_scope);
if (apply_ret == APPLY_TEMPLATE_RET_UNSATISFIABLE)
{
it = functions.erase(it);
Expand All @@ -912,7 +913,7 @@ inline void ZScript::trimBadFunctions(std::vector<Function*>& functions, std::ve

for (size_t i = 0; i < lowsize; ++i)
{
if (!parameterTypes[i]->canCastTo(*function->paramTypes[i]))
if (!parameterTypes[i]->canCastTo(*function->paramTypes[i], parent_scope))
{
parametersMatch = false;
break;
Expand All @@ -923,7 +924,7 @@ inline void ZScript::trimBadFunctions(std::vector<Function*>& functions, std::ve
auto& vargty = static_cast<DataTypeArray const*>(function->paramTypes.back())->getElementType();
for(size_t i = lowsize; i < targetSize; ++i)
{
if(!parameterTypes[i]->canCastTo(vargty))
if(!parameterTypes[i]->canCastTo(vargty, parent_scope))
{
parametersMatch = false;
break;
Expand Down
6 changes: 3 additions & 3 deletions src/parser/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,10 @@ namespace ZScript
UserClass* lookupClass(Scope& scope, std::string const& name, bool noUsing);
UserClass* lookupClass(Scope& scope, std::vector<std::string> const& names,
std::vector<std::string> const& delimiters, bool noUsing);
std::vector<Function*> lookupConstructors(UserClass const& user_class, std::vector<DataType const*> const& parameterTypes);
std::vector<Function*> lookupConstructors(UserClass const& user_class, std::vector<DataType const*> const& parameterTypes, Scope const* scope);
std::vector<Function*> lookupClassFuncs(UserClass const& user_class,
std::string const& name, std::vector<DataType const*> const& parameterTypes);
inline void trimBadFunctions(std::vector<Function*>& functions, std::vector<DataType const*> const& parameterTypes, bool trimClasses = true);
std::string const& name, std::vector<DataType const*> const& parameterTypes, Scope const* scope);
inline void trimBadFunctions(std::vector<Function*>& functions, std::vector<DataType const*> const& parameterTypes, Scope const* scope, bool trimClasses = true);

// Resolve an option value under the scope. Will only return empty if
// the provided option is invalid. If the option is valid but not set,
Expand Down
10 changes: 5 additions & 5 deletions src/parser/SemanticAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ void SemanticAnalyzer::caseDataDeclExtraArray(
ASTExpr& size = **it;

// Make sure each size can cast to float.
if (!size.getReadType(scope, this)->canCastTo(DataType::FLOAT))
if (!size.getReadType(scope, this)->canCastTo(DataType::FLOAT, scope))
{
handleError(CompileError::NonIntegerArraySize(&host));
return;
Expand Down Expand Up @@ -1475,15 +1475,15 @@ void SemanticAnalyzer::caseExprCall(ASTExprCall& host, void* param)
handleError(CompileError::NoClass(&host, identifier->asString()));
return;
}
functions = lookupConstructors(*user_class, parameterTypes);
functions = lookupConstructors(*user_class, parameterTypes, scope);
}
else
{
if(identifier->components.size() == 1 && parsing_user_class > puc_vars)
{
user_class = &scope->getClass()->user_class;
if(parsing_user_class == puc_construct && identifier->components[0] == user_class->getName())
functions = lookupConstructors(*user_class, parameterTypes);
functions = lookupConstructors(*user_class, parameterTypes, scope);
if(!functions.size())
functions = lookupFunctions(*scope, identifier->components[0], parameterTypes, identifier->noUsing, true);
}
Expand All @@ -1493,7 +1493,7 @@ void SemanticAnalyzer::caseExprCall(ASTExprCall& host, void* param)
}
else if(user_class)
{
functions = lookupClassFuncs(*user_class, arrow->right->getValue(), parameterTypes);
functions = lookupClassFuncs(*user_class, arrow->right->getValue(), parameterTypes, scope);
}
else functions = lookupFunctions(arrow->leftClass->getScope(), arrow->right->getValue(), parameterTypes, true); //Never `using` arrow functions

Expand Down Expand Up @@ -2004,7 +2004,7 @@ void SemanticAnalyzer::caseArrayLiteral(ASTArrayLiteral& host, void*)

// I think this should accept only exactly matching types. A future
// change could modify this to accept the base type of two related types.
if (!type->canCastTo(*node_type) || !node_type->canCastTo(*type))
if (!type->canCastTo(*node_type, scope) || !node_type->canCastTo(*type, scope))
{
type = nullptr;
break;
Expand Down
33 changes: 24 additions & 9 deletions src/parser/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,19 +271,24 @@ int32_t DataTypeSimple::selfCompare(DataType const& rhs) const
return simpleId - o.simpleId;
}

bool DataTypeSimple::canCastTo(DataType const& target) const
bool DataTypeSimple::canCastTo(DataType const& target, Scope const* scope) const
{
if (isVoid() || target.isVoid()) return false;
if (isUntyped() || target.isUntyped()) return true;
if (target.isArray()) return false;
if (target.isArray())
{
if(*lookupOption(scope, CompileOption::OPT_OLD_ARRAY_TYPECASTING) != 0)
return canCastTo(static_cast<DataTypeArray const*>(&target)->getBaseType(), scope);
return false;
}
if (simpleId == ZTID_CHAR || simpleId == ZTID_LONG)
return FLOAT.canCastTo(target); //Char/Long cast the same as float.
return FLOAT.canCastTo(target, scope); //Char/Long cast the same as float.

if (DataTypeSimple const* t =
dynamic_cast<DataTypeSimple const*>(&target))
{
if (t->simpleId == ZTID_CHAR || t->simpleId == ZTID_LONG)
return canCastTo(FLOAT); //Char/Long cast the same as float.
return canCastTo(FLOAT, scope); //Char/Long cast the same as float.
if (simpleId == ZTID_UNTYPED || t->simpleId == ZTID_UNTYPED)
return true;
if (simpleId == ZTID_VOID || t->simpleId == ZTID_VOID)
Expand Down Expand Up @@ -322,14 +327,19 @@ DataType const* DataTypeSimpleConst::baseType(Scope& scope, CompileErrorHandler*
////////////////////////////////////////////////////////////////
// DataTypeArray

bool DataTypeArray::canCastTo(DataType const& target) const
bool DataTypeArray::canCastTo(DataType const& target, Scope const* scope) const
{
if (target.isVoid()) return false;
if (target.isUntyped()) return true;
if (!target.isArray()) return false;
if (!target.isArray())
{
if(*lookupOption(scope, CompileOption::OPT_OLD_ARRAY_TYPECASTING) != 0)
return getBaseType().canCastTo(target, scope);
return false;
}
DataTypeArray const* targ_arr = static_cast<DataTypeArray const*>(&target);

return getElementType().canCastTo(targ_arr->getElementType());
return getElementType().canCastTo(targ_arr->getElementType(), scope);
}

int32_t DataTypeArray::selfCompare(DataType const& rhs) const
Expand Down Expand Up @@ -386,11 +396,16 @@ bool DataTypeCustom::canHoldObject() const {
return true;
}

bool DataTypeCustom::canCastTo(DataType const& target) const
bool DataTypeCustom::canCastTo(DataType const& target, Scope const* scope) const
{
if (target.isVoid()) return false;
if (target.isUntyped()) return true;
if (target.isArray()) return false;
if (target.isArray())
{
if(*lookupOption(scope, CompileOption::OPT_OLD_ARRAY_TYPECASTING) != 0)
return canCastTo(static_cast<DataTypeArray const*>(&target)->getBaseType(), scope);
return false;
}

if(!isClass() && !isUsrClass())
{
Expand Down
10 changes: 5 additions & 5 deletions src/parser/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ namespace ZScript
virtual DataType const* baseType(ZScript::Scope& scope, CompileErrorHandler* errorHandler) const = 0;
// Basics
virtual std::string getName() const = 0;
virtual bool canCastTo(DataType const& target) const = 0;
virtual bool canCastTo(DataType const& target, Scope const* scope) const = 0;
virtual bool canBeGlobal() const {return true;}
virtual bool canHoldObject() const {return getScriptObjectTypeId() != script_object_type::none;}
virtual bool isObject() const {return getScriptObjectTypeId() != script_object_type::none;}
Expand Down Expand Up @@ -310,7 +310,7 @@ namespace ZScript

virtual std::string getName() const;
ASTExprIdentifier const* getIdentifier() const {return iden;}
virtual bool canCastTo(DataType const& target) const {return false;}
virtual bool canCastTo(DataType const& target, Scope const* scope) const {return false;}

private:
ASTExprIdentifier* iden;
Expand All @@ -327,7 +327,7 @@ namespace ZScript
int unique_type_id() const { return 2; }

virtual std::string getName() const {return name;}
virtual bool canCastTo(DataType const& target) const;
virtual bool canCastTo(DataType const& target, Scope const* scope) const;
virtual bool canBeGlobal() const;
virtual bool isConstant() const {return false;}
virtual bool isUntyped() const {return simpleId == ZTID_UNTYPED;}
Expand Down Expand Up @@ -373,7 +373,7 @@ namespace ZScript

virtual std::string getName() const {
return elementType.getName() + "[]";}
virtual bool canCastTo(DataType const& target) const;
virtual bool canCastTo(DataType const& target, Scope const* scope) const;
virtual bool canBeGlobal() const {return true;}
virtual bool canHoldObject() const {return elementType.canHoldObject();}
virtual bool isObject() const {return false;} //arrays themselves are not objects
Expand Down Expand Up @@ -425,7 +425,7 @@ namespace ZScript
}
virtual UserClass* getUsrClass() const {return user_class;}
virtual std::string getName() const {return name;}
virtual bool canCastTo(DataType const& target) const;
virtual bool canCastTo(DataType const& target, Scope const* scope) const;
int32_t getCustomId() const {return id;}
virtual DataType const* baseType(ZScript::Scope& scope, CompileErrorHandler* errorHandler) const;

Expand Down

0 comments on commit d7555bf

Please sign in to comment.