Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove CompileErrorException #1758

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
var/ele = 2

/proc/RunTest()
var/o = new
var/o = new /obj
ASSERT(o.ele == 2)
9 changes: 9 additions & 0 deletions DMCompiler/Bytecode/DreamProcOpcode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ public struct DMReference {
public static readonly DMReference Args = new() { RefType = Type.Args };
public static readonly DMReference SuperProc = new() { RefType = Type.SuperProc };
public static readonly DMReference ListIndex = new() { RefType = Type.ListIndex };
public static readonly DMReference Invalid = new() { RefType = Type.Invalid };

public enum Type : byte {
Src,
Expand All @@ -452,6 +453,14 @@ public enum Type : byte {
Field,
SrcField,
SrcProc,

/// <summary>
/// Something went wrong in the creation of this DMReference, and so this reference is not valid
/// </summary>
/// <remarks>
/// Be sure to emit a compiler error before creating
/// </remarks>
Invalid
}

public Type RefType;
Expand Down
41 changes: 5 additions & 36 deletions DMCompiler/Compiler/CompilerError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,40 +114,9 @@ public struct CompilerEmission {
};
}

[Obsolete("This is not a desirable way for the compiler to emit an error. Use CompileAbortException or ForceError() if it needs to be fatal, or an DMCompiler.Emit() otherwise.")]
public class CompileErrorException : Exception {
public CompilerEmission Error;

public CompileErrorException(CompilerEmission error) : base(error.Message) {
Error = error;
}

public CompileErrorException(Location location, string message) : base(message) {
Error = new CompilerEmission(ErrorLevel.Error, location, message);
}

public CompileErrorException(string message) {
Error = new CompilerEmission(ErrorLevel.Error, Location.Unknown, message);
}
}


/// <summary>
/// Represents an internal compiler error that should cause parsing for a particular block to cease. <br/>
/// This should be ideally used for exceptions that are the fault of the compiler itself, <br/>
/// like an abnormal state being reached or something.
/// </summary>
public sealed class CompileAbortException : CompileErrorException {
public CompileAbortException(CompilerEmission error) : base(error) {
}

public CompileAbortException(Location location, string message) : base(location, message) {
}

public CompileAbortException(string message) : base(message) {
}
}

public sealed class UnknownIdentifierException(Location location, string identifierName) : CompileErrorException(location, $"Unknown identifier \"{identifierName}\"") {
public string IdentifierName = identifierName;
// TODO: Find a nicer way to do this
public sealed class UnknownIdentifierException(Location location, string identifier)
: Exception($"Unknown identifier \"{identifier}\" - This message should not be seen") {
public readonly Location Location = location;
public readonly string Identifier = identifier;
}
149 changes: 70 additions & 79 deletions DMCompiler/DM/Builders/DMExpressionBuilder.cs

Large diffs are not rendered by default.

159 changes: 72 additions & 87 deletions DMCompiler/DM/Builders/DMObjectBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
} catch (UnknownIdentifierException e) {
// For step 6
lateProcVarDefs.Add((procStatic.DMObject, procStatic.Proc, procStatic.VarDecl, procStatic.Id, e));
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
} finally {
DMExpressionBuilder.CurrentScopeMode = DMExpressionBuilder.ScopeMode.Normal;
}
Expand Down Expand Up @@ -104,11 +102,13 @@

// The vars these reference were never found, emit their errors
foreach (var lateVarDef in lateVarDefs) {
DMCompiler.Emit(lateVarDef.Item3.Error);
DMCompiler.Emit(WarningCode.ItemDoesntExist, lateVarDef.Item3.Location,
$"Unknown identifier \"{lateVarDef.Item3.Identifier}\"");
}

foreach (var lateVarDef in lateProcVarDefs) {
DMCompiler.Emit(lateVarDef.Item5.Error);
DMCompiler.Emit(WarningCode.ItemDoesntExist, lateVarDef.Item3.Location,
$"Unknown identifier \"{lateVarDef.Item5.Identifier}\"");
}

// Step 7: Create each types' initialization proc (initializes vars that aren't constants)
Expand All @@ -130,11 +130,7 @@

private static void ProcessBlockInner(DMASTBlockInner blockInner, DMObject? currentObject) {
foreach (DMASTStatement statement in blockInner.Statements) {
try {
ProcessStatement(statement, currentObject);
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
}
ProcessStatement(statement, currentObject);
}
}

Expand Down Expand Up @@ -162,8 +158,10 @@
case DMASTObjectVarOverride varOverride:
// parent_type is treated as part of the object definition rather than an actual var override
if (varOverride.VarName == "parent_type") {
if (varOverride.Value is not DMASTConstantPath parentTypePath)
throw new CompileErrorException(varOverride.Location, "Expected a constant path");
if (varOverride.Value is not DMASTConstantPath parentTypePath) {
DMCompiler.Emit(WarningCode.BadExpression, varOverride.Location, "Expected a constant path");
break; // Ignore it
}

var parentType = DMObjectTree.GetDMObject(parentTypePath.Value.Path);

Expand Down Expand Up @@ -194,7 +192,9 @@

break;
}
default: throw new CompileAbortException(statement.Location, "Invalid object statement");
default:
DMCompiler.ForcedError(statement.Location, $"Invalid object statement {statement.GetType()}");
break;
}
}

Expand Down Expand Up @@ -231,11 +231,6 @@
// TODO: no, bad. instance field declarations should have a proc assigned to them.
expression = DMExpression.Create(varObject, varDefinition.IsGlobal ? DMObjectTree.GlobalInitProc : null,
varDefinition.Value, varDefinition.Type);
} catch (UnknownIdentifierException) {
throw; // This should be handled by the calling code
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
return;
} finally {
DMExpressionBuilder.CurrentScopeMode = DMExpressionBuilder.ScopeMode.Normal;
}
Expand All @@ -257,96 +252,82 @@
}
}

try {
// why are we passing the variable ref? we aren't using it after this
SetVariableValue(varObject, ref variable, varDefinition.Location, expression);
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
}
// TODO: why are we passing the variable ref? we aren't using it after this
SetVariableValue(varObject, ref variable, varDefinition.Location, expression);
}

private static void ProcessVarOverride(DMObject? varObject, DMASTObjectVarOverride? varOverride) {
try {
switch (varOverride.VarName) {
// Keep in mind that anything here, by default, affects all objects, even those who don't inherit from /datum
case "tag": {
if (varObject.IsSubtypeOf(DreamPath.Datum)) {
throw new CompileErrorException(varOverride.Location,
"var \"tag\" cannot be set to a value at compile-time");
}

break;
switch (varOverride.VarName) {

Check warning

Code scanning / InspectCode

Dereference of a possibly null reference. Warning

Dereference of a possibly null reference
// Keep in mind that anything here, by default, affects all objects, even those who don't inherit from /datum
case "tag": {
if (varObject.IsSubtypeOf(DreamPath.Datum)) {

Check warning

Code scanning / InspectCode

Dereference of a possibly null reference. Warning

Dereference of a possibly null reference
DMCompiler.Emit(WarningCode.BadExpression, varOverride.Location,
"var \"tag\" cannot be set to a value at compile-time");
}
}

DMVariable? variable;
if (varObject.HasLocalVariable(varOverride.VarName)) {
variable = varObject.GetVariable(varOverride.VarName);
} else if (varObject.HasGlobalVariable(varOverride.VarName)) {
variable = varObject.GetGlobalVariable(varOverride.VarName);
DMCompiler.Emit(WarningCode.StaticOverride, varOverride.Location, $"var \"{varOverride.VarName}\" cannot be overridden - it is a global var");
} else {
throw new UnknownIdentifierException(varOverride.Location, varOverride.VarName);
break;
}
}

OverrideVariableValue(varObject, ref variable, varOverride.Value);
varObject.VariableOverrides[variable.Name] = variable;
} catch (UnknownIdentifierException) {
throw; // Should be handled by calling code
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
DMVariable? variable;
if (varObject.HasLocalVariable(varOverride.VarName)) {

Check warning

Code scanning / InspectCode

Dereference of a possibly null reference. Warning

Dereference of a possibly null reference
variable = varObject.GetVariable(varOverride.VarName);
} else if (varObject.HasGlobalVariable(varOverride.VarName)) {
variable = varObject.GetGlobalVariable(varOverride.VarName);
DMCompiler.Emit(WarningCode.StaticOverride, varOverride.Location, $"var \"{varOverride.VarName}\" cannot be overridden - it is a global var");
} else {
throw new UnknownIdentifierException(varOverride.Location, varOverride.VarName);
}

OverrideVariableValue(varObject, ref variable, varOverride.Value);

Check warning

Code scanning / InspectCode

Possible null reference assignment. Warning

Possible null reference assignment
varObject.VariableOverrides[variable.Name] = variable;
}

private static void ProcessProcDefinition(DMASTProcDefinition procDefinition, DMObject? currentObject) {
string procName = procDefinition.Name;
try {
DMObject dmObject = DMObjectTree.GetDMObject(currentObject.Path.Combine(procDefinition.ObjectPath));
bool hasProc = dmObject.HasProc(procName); // Trying to avoid calling this several times since it's recursive and maybe slow
if (!procDefinition.IsOverride && hasProc) { // If this is a define and we already had a proc somehow
if(!dmObject.HasProcNoInheritance(procName)) { // If we're inheriting this proc (so making a new define for it at our level is stupid)
DMCompiler.Emit(WarningCode.DuplicateProcDefinition, procDefinition.Location, $"Type {dmObject.Path} already inherits a proc named \"{procName}\" and cannot redefine it");
return; // TODO: Maybe fallthrough since this error is a little pedantic?
}
//Otherwise, it's ok
DMObject dmObject = DMObjectTree.GetDMObject(currentObject.Path.Combine(procDefinition.ObjectPath));

Check warning

Code scanning / InspectCode

Converting null literal or possible null value to non-nullable type. Warning

Converting null literal or possible null value into non-nullable type

Check warning

Code scanning / InspectCode

Dereference of a possibly null reference. Warning

Dereference of a possibly null reference
bool hasProc = dmObject.HasProc(procName); // Trying to avoid calling this several times since it's recursive and maybe slow

Check warning

Code scanning / InspectCode

Dereference of a possibly null reference. Warning

Dereference of a possibly null reference
if (!procDefinition.IsOverride && hasProc) { // If this is a define and we already had a proc somehow
if(!dmObject.HasProcNoInheritance(procName)) { // If we're inheriting this proc (so making a new define for it at our level is stupid)
DMCompiler.Emit(WarningCode.DuplicateProcDefinition, procDefinition.Location, $"Type {dmObject.Path} already inherits a proc named \"{procName}\" and cannot redefine it");
return; // TODO: Maybe fallthrough since this error is a little pedantic?
}
//Otherwise, it's ok
}

DMProc proc = DMObjectTree.CreateDMProc(dmObject, procDefinition);
proc.IsVerb = procDefinition.IsVerb;
DMProc proc = DMObjectTree.CreateDMProc(dmObject, procDefinition);
proc.IsVerb = procDefinition.IsVerb;

if (procDefinition.ObjectPath == DreamPath.Root) {
if(procDefinition.IsOverride) {
DMCompiler.Emit(WarningCode.InvalidOverride, procDefinition.Location, $"Global procs cannot be overridden - '{procDefinition.Name}' override will be ignored");
//Continue processing the proc anyhoo, just don't add it.
if (procDefinition.ObjectPath == DreamPath.Root) {
if(procDefinition.IsOverride) {
DMCompiler.Emit(WarningCode.InvalidOverride, procDefinition.Location, $"Global procs cannot be overridden - '{procDefinition.Name}' override will be ignored");
//Continue processing the proc anyhoo, just don't add it.
} else {
if (!DMObjectTree.SeenGlobalProcDefinition.Add(procName)) { // Add() is equivalent to Dictionary's TryAdd() for some reason
DMCompiler.Emit(WarningCode.DuplicateProcDefinition, procDefinition.Location, $"Global proc {procDefinition.Name} is already defined");
//Again, even though this is likely an error, process the statements anyways.
} else {
if (!DMObjectTree.SeenGlobalProcDefinition.Add(procName)) { // Add() is equivalent to Dictionary's TryAdd() for some reason
DMCompiler.Emit(WarningCode.DuplicateProcDefinition, procDefinition.Location, $"Global proc {procDefinition.Name} is already defined");
//Again, even though this is likely an error, process the statements anyways.
} else {
DMObjectTree.AddGlobalProc(proc);
}
DMObjectTree.AddGlobalProc(proc);
}
} else {
dmObject.AddProc(procName, proc);
}
} else {
dmObject.AddProc(procName, proc);
}

if (procDefinition.Body != null) {
foreach (var stmt in GetStatements(procDefinition.Body)) {
// TODO multiple var definitions.
if (stmt is DMASTProcStatementVarDeclaration varDeclaration && varDeclaration.IsGlobal) {
DMVariable variable = proc.CreateGlobalVariable(varDeclaration.Type, varDeclaration.Name, varDeclaration.IsConst, out var globalId);
variable.Value = new Expressions.Null(varDeclaration.Location);
if (procDefinition.Body != null) {
foreach (var stmt in GetStatements(procDefinition.Body)) {
// TODO multiple var definitions.
if (stmt is DMASTProcStatementVarDeclaration varDeclaration && varDeclaration.IsGlobal) {

Check notice

Code scanning / InspectCode

Merge null/pattern checks into complex pattern Note

Merge into pattern
DMVariable variable = proc.CreateGlobalVariable(varDeclaration.Type, varDeclaration.Name, varDeclaration.IsConst, out var globalId);
variable.Value = new Expressions.Null(varDeclaration.Location);

Check warning

Code scanning / InspectCode

Redundant name qualifier Warning

Qualifier is redundant

StaticProcVars.Add((dmObject, proc, globalId, varDeclaration));
}
StaticProcVars.Add((dmObject, proc, globalId, varDeclaration));
}
}
}

if (procDefinition.IsVerb && (dmObject.IsSubtypeOf(DreamPath.Atom) || dmObject.IsSubtypeOf(DreamPath.Client)) && !DMCompiler.Settings.NoStandard) {
dmObject.AddVerb(proc);
}
} catch (CompileErrorException e) {
DMCompiler.Emit(e.Error);
if (procDefinition.IsVerb && (dmObject.IsSubtypeOf(DreamPath.Atom) || dmObject.IsSubtypeOf(DreamPath.Client)) && !DMCompiler.Settings.NoStandard) {
dmObject.AddVerb(proc);
}
}

Expand Down Expand Up @@ -499,7 +480,11 @@
private static void EmitInitializationAssign(DMObject currentObject, DMVariable variable, DMExpression expression) {
if (variable.IsGlobal) {
int? globalId = currentObject.GetGlobalVariableId(variable.Name);
if (globalId == null) throw new CompileAbortException(expression?.Location ?? Location.Unknown, $"Invalid global {currentObject.Path}.{variable.Name}");
if (globalId == null) {
DMCompiler.Emit(WarningCode.BadExpression, expression?.Location ?? Location.Unknown,

Check warning

Code scanning / InspectCode

Conditional access qualifier expression is never null according to nullable reference types' annotations Warning

Conditional access qualifier expression is never null according to nullable reference types' annotations
$"Invalid global {currentObject.Path}.{variable.Name}");
return;
}

DMObjectTree.AddGlobalInitAssign(globalId.Value, expression);
} else {
Expand Down Expand Up @@ -544,7 +529,7 @@

// Success! Remove this one from the list
lateProcVarDefs.RemoveAt(i--);
} catch (UnknownIdentifierException e) {
} catch (UnknownIdentifierException) {
// Keep it in the list, try again after the rest have been processed
} finally {
DMExpressionBuilder.CurrentScopeMode = DMExpressionBuilder.ScopeMode.Normal;
Expand All @@ -558,7 +543,7 @@

// Success! Remove this one from the list
lateOverrides.RemoveAt(i--);
} catch (UnknownIdentifierException e) {
} catch (UnknownIdentifierException) {
// Keep it in the list, try again after the rest have been processed
}
}
Expand Down
Loading
Loading