Upsilon/Upsilon/Diagnostics.cs

168 lines
5.6 KiB
C#

using System.Collections.Generic;
using Upsilon.BaseTypes;
using Upsilon.Exceptions;
using Upsilon.Parser;
using Upsilon.Text;
namespace Upsilon
{
public class Diagnostics
{
public string FileName { get; }
public SourceText ScriptString { get; }
public readonly List<DiagnosticsMessage> Errors = new List<DiagnosticsMessage>();
public readonly List<DiagnosticsMessage> Warnings = new List<DiagnosticsMessage>();
public bool ThrowsOnError { get; }
public Diagnostics(SourceText scriptString, bool throwsOnError, string fileName)
{
ScriptString = scriptString;
ThrowsOnError = throwsOnError;
FileName = fileName;
}
public void Log(DiagnosticLevel level, string message, TextSpan location)
{
if (level == DiagnosticLevel.Error)
Errors.Add(new DiagnosticsMessage(this, level, message, location));
else if (level == DiagnosticLevel.Warning)
Warnings.Add(new DiagnosticsMessage(this, level, message, location));
}
public void LogError(string message, TextSpan location)
{
if (ThrowsOnError)
{
var text = ScriptString.GetSpan(location);
throw new ParseException(FileName, message, location.StartLine, location.StartPosition, text);
}
Log(DiagnosticLevel.Error, message, location);
}
public void LogWarning(string message, TextSpan location)
{
Log(DiagnosticLevel.Warning, message, location);
}
public void LogBadCharacter(TextSpan location, SyntaxKind expectedToken, SyntaxKind currentKind)
{
LogError($"Invalid character found. Expected: '{expectedToken}', Got: '{currentKind}'", location);
}
public void LogBadCharacter(TextSpan location, SyntaxKind expectedToken)
{
LogError($"Invalid character found. Expected: '{expectedToken}'", location);
}
public void LogBadCharacter(TextSpan location, char expected, char actual)
{
LogError($"Invalid character found. Expected: '{expected}', Got: '{actual}'", location);
}
public void LogBadCharacter(TextSpan location)
{
LogError($"Invalid character found.", location);
}
public void LogUnknownVariable(TextSpan span, string variable)
{
LogError($"Unknown variable '{variable}'", span);
}
public void LogNullReferenceError(TextSpan span)
{
LogError($"Null Reference Encountered", span);
}
public void LogUnknownType(TextSpan eSpan)
{
LogError($"Unknown Type found", eSpan);
}
public void LogUnknownBinaryOperator(TextSpan eSpan, SyntaxKind text, Type leftType, Type rightType)
{
LogError($"No binary operator {text} found for types '{leftType}' and '{rightType}'", eSpan);
}
public void LogUnknownUnaryOperator(TextSpan eSpan, SyntaxKind text, Type inType)
{
LogError($"No unary operator {text} found for type '{inType}'", eSpan);
}
public void LogCannotConvert(Type actualType, Type expectedType, TextSpan span)
{
LogError($"Cannot convert type '{actualType}' to '{expectedType}'", span);
}
public void LogInvalidIndexExpression(Type expressionType, Type indexType, TextSpan span)
{
LogError($"Cannot index type '{expressionType}' with type '{indexType}'", span);
}
public void LogUnknownVariableType(string variableName, TextSpan span)
{
LogWarning(
$"Variable '{variableName}' has an unknown variable type, and as such errors won't be visible before evaluation.",
span);
}
}
public class DiagnosticsMessage
{
public Diagnostics Diagnostics { get; }
public DiagnosticLevel DiagnosticLevel { get; }
public string Message { get; }
public TextSpan Span { get; }
public DiagnosticsMessage(Diagnostics diagnostics, DiagnosticLevel diagnosticLevel, string message, TextSpan span)
{
DiagnosticLevel = diagnosticLevel;
Diagnostics = diagnostics;
Message = message;
Span = span;
}
public override string ToString()
{
return $"{Message} at ({Span.StartLine}, {Span.StartPosition})\n{Diagnostics.ScriptString.GetSpan(Span)}";
}
public string GetDiagnosticPosition()
{
return $"({Span.StartLine},{Span.StartPosition})";
}
public string LineBeforeError()
{
return Diagnostics.ScriptString.GetSpan(Span.StartLine, 0, Span.StartLine, Span.StartPosition);
}
public string BeforeError(int i = 5)
{
return Diagnostics.ScriptString.GetSpan(Span.StartLine, Span.StartPosition - i, Span.StartLine, Span.StartPosition);
}
public string AtError()
{
return Diagnostics.ScriptString.GetSpan(Span);
}
public string LineAfterError()
{
return Diagnostics.ScriptString.GetSpan(Span.EndLine, Span.EndPosition, Span.EndLine, 10000);
}
public string AfterError(int i = 5)
{
return Diagnostics.ScriptString.GetSpan(Span.EndLine, Span.EndPosition, Span.EndLine, Span.EndPosition + i);
}
}
public enum DiagnosticLevel
{
Information,
Warning,
Error,
}
}