diff --git a/polymod/hscript/_internal/Expr.hx b/polymod/hscript/_internal/Expr.hx index c139d622..844beafe 100644 --- a/polymod/hscript/_internal/Expr.hx +++ b/polymod/hscript/_internal/Expr.hx @@ -180,6 +180,7 @@ enum Error EClassInvalidSuper; // Accessing "super" in a parentless class EScriptThrow(v:Dynamic); // Script called "throw" EScriptCallThrow(v:Dynamic); // Script called a function which threw + EInvalidAccessorCombination(accessors:Array); // Fallback error type. ECustom(msg:String); } diff --git a/polymod/hscript/_internal/Parser.hx b/polymod/hscript/_internal/Parser.hx index f333f5fd..6b14c0d7 100644 --- a/polymod/hscript/_internal/Parser.hx +++ b/polymod/hscript/_internal/Parser.hx @@ -1663,9 +1663,17 @@ class Parser case "override": access.push(AOverride); case "public": - access.push(APublic); + // Throw an error if the user tries declaring a variable as public when it's already been declared private. + if (access.contains(APrivate)) + error(ECustom("Conflicting access modifier public"), currentPos, currentPos); + else if (!access.contains(APublic)) + access.push(APublic); case "private": - access.push(APrivate); + // Throw an error if the user tries declaring a variable as private when it's already been declared public. + if (access.contains(APublic)) + error(ECustom("Conflicting access modifier private"), currentPos, currentPos); + else if (!access.contains(APrivate)) + access.push(APrivate); case "inline": access.push(AInline); case "static": @@ -1673,6 +1681,11 @@ class Parser case "macro": access.push(AMacro); case "function": + if (access.contains(AOverride) && access.contains(AStatic)) + { + error(EInvalidAccessorCombination(['override', 'static']), currentPos, currentPos); + } + var name = getIdent(); var inf = parseFunctionDecl(); maybe(TSemicolon); @@ -1713,6 +1726,13 @@ class Parser else ensure(TSemicolon); + #if POLYMOD_STRICT_SYNTAX + if (access.contains(AInline) && !access.contains(AStatic)) + { + error(ECustom('Invalid modifier: inline on non-static variable'), currentPos, currentPos); + } + #end + return { name: name, meta: meta, diff --git a/polymod/hscript/_internal/PolymodScriptClass.hx b/polymod/hscript/_internal/PolymodScriptClass.hx index 62577ea6..69297312 100644 --- a/polymod/hscript/_internal/PolymodScriptClass.hx +++ b/polymod/hscript/_internal/PolymodScriptClass.hx @@ -181,6 +181,11 @@ class PolymodScriptClass Polymod.error(SCRIPT_PARSE_FAILED, 'Error while parsing class ${path}#${errLine}: EClassUnresolvedSuperclass' + '\n' + 'Unresolved superclass "${cls}", ${reason}', SCRIPT_RUNTIME); return false; + case EInvalidAccessorCombination(accessors): + Polymod.error( + SCRIPT_PARSE_FAILED, + 'Error while parsing function ${path}#${errLine}: EInvalidAccessorCombination' + '\n' + 'Invalid modifier combination: ${accessors.join(' + ')}', SCRIPT_RUNTIME); + return false; default: Polymod.error(SCRIPT_PARSE_FAILED, 'Error while parsing script ${path}#${errLine}: ' + '\n' + 'An unknown error occurred: ${err}', SCRIPT_RUNTIME); return false; @@ -568,7 +573,6 @@ class PolymodScriptClass superClass = Type.createInstance(clsToCreate, args); } - // Throw an error if the script class has an instance field with the same name as one from the super class. for (f in _c.fields) { switch (f.kind) @@ -576,10 +580,39 @@ class PolymodScriptClass case KVar(v): if (!f.access.contains(AStatic) && superHasField(f.name)) { - throw 'Redefinition of variable "${f.name}" from superclass not allowed'; + // Throw an error if the script class has an instance field with the same name as one from the super class. + throw 'Redefinition of variable "${f.name}" from superclass not allowed.'; } + case KFunction(fn): + #if POLYMOD_STRICT_SYNTAX + if (f.access.contains(AOverride) && !superHasField(f.name)) + { + // Throw an error if a function is declared overwritten but isn't overriding anything. + throw "Field " + f.name + " is declared 'override' but doesn't override any field."; + } + else if (!f.access.contains(AOverride) && superHasField(f.name)) + { + var superClassPackage:String = ''; + if (superClass is PolymodScriptClass) + { + superClassPackage = Util.getFullClassName((cast superClass : PolymodScriptClass)._c); + } + else + { + // TODO: Fetch entire package name? + superClassPackage = Util.getTypeNameOf(superClass); + } - case _: + // Throw an error if a function is overriden but doesn't have the override accessor. + throw "Field " + f.name + " should be declared with 'override' since it is inherited from superclass " + superClassPackage + '.'; + } + else if (f.access.contains(AOverride) && superClass == null) + { + // Throw an error if the override accessor is used with no super class. + throw "Invalid modifier: override on field" + f.name + " of class that has no parent."; + } + #end + default: } } } diff --git a/polymod/hscript/_internal/Printer.hx b/polymod/hscript/_internal/Printer.hx index b1ddc2d8..f8cc68b5 100644 --- a/polymod/hscript/_internal/Printer.hx +++ b/polymod/hscript/_internal/Printer.hx @@ -746,6 +746,7 @@ class Printer // TODO: Do we need to distinguish these? case EScriptCallThrow(v): 'Script threw an exception:\n$v'; case EScriptThrow(v): 'User script threw an exception:\n$v'; + case EInvalidAccessorCombination(accessors): 'Invalid modifier combination: ${accessors.join(' + ')}'; case ECustom(msg): msg; }; #if hscriptPos