Compare commits

..

2 Commits

Author SHA1 Message Date
nub31
d771396bd4 Remove unused BasicError 2026-02-25 20:04:21 +01:00
nub31
7b1e202424 ... 2026-02-25 19:39:31 +01:00
2 changed files with 50 additions and 40 deletions

View File

@@ -81,7 +81,7 @@ public class Parser
foreach (var modifier in modifiers)
// todo(nub31): Add to diagnostics instead of throwing
throw new CompileException(Diagnostic.Error("Invalid modifier for function").At(fileName, modifier.Value).Build());
throw BasicError("Invalid modifier for function", modifier.Value);
var name = ExpectIdent();
var parameters = new List<NodeDefinitionFunc.Param>();
@@ -111,7 +111,7 @@ public class Parser
foreach (var modifier in modifiers)
// todo(nub31): Add to diagnostics instead of throwing
throw new CompileException(Diagnostic.Error("Invalid modifier for struct").At(fileName, modifier.Value).Build());
throw BasicError("Invalid modifier for struct", modifier.Value);
var name = ExpectIdent();
var fields = new List<NodeDefinitionStruct.Field>();
@@ -135,7 +135,7 @@ public class Parser
foreach (var modifier in modifiers)
// todo(nub31): Add to diagnostics instead of throwing
throw new CompileException(Diagnostic.Error("Invalid modifier for struct").At(fileName, modifier.Value).Build());
throw BasicError("Invalid modifier for struct", modifier.Value);
var name = ExpectIdent();
var variants = new List<NodeDefinitionEnum.Variant>();
@@ -174,7 +174,7 @@ public class Parser
foreach (var modifier in modifiers)
// todo(nub31): Add to diagnostics instead of throwing
throw new CompileException(Diagnostic.Error("Invalid modifier for global variable").At(fileName, modifier.Value).Build());
throw BasicError("Invalid modifier for global variable", modifier.Value);
var name = ExpectIdent();
ExpectSymbol(Symbol.Colon);
@@ -183,7 +183,7 @@ public class Parser
return new NodeDefinitionGlobalVariable(TokensFrom(startIndex), exported, name, type);
}
throw new CompileException(Diagnostic.Error("Not a valid definition").At(fileName, Peek()).Build());
throw BasicError("Not a valid definition", Peek());
}
private NodeStatement ParseStatement()
@@ -403,7 +403,7 @@ public class Parser
}
else
{
throw new CompileException(Diagnostic.Error("Expected start of expression").At(fileName, Peek()).Build());
throw BasicError("Expected start of expression", Peek());
}
while (true)
@@ -495,7 +495,7 @@ public class Parser
}
}
throw new CompileException(Diagnostic.Error("Expected type").At(fileName, Peek()).Build());
throw BasicError("Expected type", Peek());
}
private List<Token> TokensFrom(int startIndex)
@@ -511,7 +511,7 @@ public class Parser
return;
}
throw new CompileException(Diagnostic.Error($"Expected '{keyword.AsString()}'").At(fileName, Peek()).Build());
throw BasicError($"Expected '{keyword.AsString()}'", Peek());
}
private bool TryExpectKeyword(Keyword keyword)
@@ -533,7 +533,7 @@ public class Parser
return;
}
throw new CompileException(Diagnostic.Error($"Expected '{symbol.AsString()}'").At(fileName, Peek()).Build());
throw BasicError($"Expected '{symbol.AsString()}'", Peek());
}
private bool TryExpectSymbol(Symbol symbol)
@@ -555,7 +555,7 @@ public class Parser
return token;
}
throw new CompileException(Diagnostic.Error("Expected identifier").At(fileName, Peek()).Build());
throw BasicError("Expected identifier", Peek());
}
private bool TryExpectIdent([NotNullWhen(true)] out TokenIdent? ident)
@@ -613,7 +613,7 @@ public class Parser
private void Next()
{
if (index >= tokens.Count)
throw new CompileException(Diagnostic.Error("Unexpected end of tokens").At(fileName, Peek()).Build());
throw BasicError("Unexpected end of tokens", Peek());
index += 1;
}
@@ -686,6 +686,11 @@ public class Parser
return false;
}
}
private CompileException BasicError(string message, Token? ident)
{
return new CompileException(Diagnostic.Error(message).At(fileName, ident).Build());
}
}
public class Ast(string fileName, TokenIdent moduleName, List<NodeDefinition> definitions)

View File

@@ -112,7 +112,7 @@ public class TypeChecker
private TypedNodeStatementFuncCall CheckStatementExpression(NodeStatementExpression statement)
{
if (statement.Expression is not NodeExpressionFuncCall funcCall)
throw new CompileException(Diagnostic.Error("Expected statement or function call").At(fileName, statement).Build());
throw BasicError("Expected statement or function call", statement);
return new TypedNodeStatementFuncCall(statement.Tokens, CheckExpression(funcCall.Target), funcCall.Parameters.Select(CheckExpression).ToList());
}
@@ -133,7 +133,7 @@ public class TypeChecker
var value = CheckExpression(statement.Value);
if (!value.Type.IsAssignableTo(type))
throw new CompileException(Diagnostic.Error("Type of variable does match type of assigned value").At(fileName, value).Build());
throw BasicError("Type of variable does match type of assigned value", value);
scope.DeclareIdentifier(statement.Name.Ident, type);
@@ -198,10 +198,10 @@ public class TypeChecker
case NodeExpressionBinary.Op.Modulo:
{
if (left.Type is not NubTypeSInt and not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for left hand side arithmetic operation: {left.Type}").At(fileName, left).Build());
throw BasicError($"Unsupported type for left hand side arithmetic operation: {left.Type}", left);
if (right.Type is not NubTypeSInt and not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for right hand side arithmetic operation: {right.Type}").At(fileName, right).Build());
throw BasicError($"Unsupported type for right hand side arithmetic operation: {right.Type}", right);
type = left.Type;
break;
@@ -210,10 +210,10 @@ public class TypeChecker
case NodeExpressionBinary.Op.RightShift:
{
if (left.Type is not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for left hand side of left/right shift operation: {left.Type}").At(fileName, left).Build());
throw BasicError($"Unsupported type for left hand side of left/right shift operation: {left.Type}", left);
if (right.Type is not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for right hand side of left/right shift operation: {right.Type}").At(fileName, right).Build());
throw BasicError($"Unsupported type for right hand side of left/right shift operation: {right.Type}", right);
type = left.Type;
break;
@@ -226,10 +226,10 @@ public class TypeChecker
case NodeExpressionBinary.Op.GreaterThanOrEqual:
{
if (left.Type is not NubTypeSInt and not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for left hand side of comparison: {left.Type}").At(fileName, left).Build());
throw BasicError($"Unsupported type for left hand side of comparison: {left.Type}", left);
if (right.Type is not NubTypeSInt and not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for right hand side of comparison: {right.Type}").At(fileName, right).Build());
throw BasicError($"Unsupported type for right hand side of comparison: {right.Type}", right);
type = NubTypeBool.Instance;
break;
@@ -238,10 +238,10 @@ public class TypeChecker
case NodeExpressionBinary.Op.LogicalOr:
{
if (left.Type is not NubTypeBool)
throw new CompileException(Diagnostic.Error($"Unsupported type for left hand side of logical operation: {left.Type}").At(fileName, left).Build());
throw BasicError($"Unsupported type for left hand side of logical operation: {left.Type}", left);
if (right.Type is not NubTypeBool)
throw new CompileException(Diagnostic.Error($"Unsupported type for right hand side of logical operation: {right.Type}").At(fileName, right).Build());
throw BasicError($"Unsupported type for right hand side of logical operation: {right.Type}", right);
type = NubTypeBool.Instance;
break;
@@ -286,7 +286,7 @@ public class TypeChecker
case NodeExpressionUnary.Op.Negate:
{
if (target.Type is not NubTypeSInt and not NubTypeUInt)
throw new CompileException(Diagnostic.Error($"Unsupported type for negation: {target.Type}").At(fileName, target).Build());
throw BasicError($"Unsupported type for negation: {target.Type}", target);
type = target.Type;
break;
@@ -294,7 +294,7 @@ public class TypeChecker
case NodeExpressionUnary.Op.Invert:
{
if (target.Type is not NubTypeBool)
throw new CompileException(Diagnostic.Error($"Unsupported type for inversion: {target.Type}").At(fileName, target).Build());
throw BasicError($"Unsupported type for inversion: {target.Type}", target);
type = NubTypeBool.Instance;
break;
@@ -325,7 +325,7 @@ public class TypeChecker
{
var type = scope.GetIdentifierType(expression.Value.Ident);
if (type is null)
throw new CompileException(Diagnostic.Error($"Identifier '{expression.Value.Ident}' is not declared").At(fileName, expression.Value).Build());
throw BasicError($"Identifier '{expression.Value.Ident}' is not declared", expression.Value);
return new TypedNodeExpressionLocalIdent(expression.Tokens, type, expression.Value);
}
@@ -351,43 +351,43 @@ public class TypeChecker
case NubTypeStruct structType:
{
if (!moduleGraph.TryResolveModule(structType.Module, out var module))
throw new CompileException(Diagnostic.Error($"Module '{structType.Module}' not found").At(fileName, expression.Target).Build());
throw BasicError($"Module '{structType.Module}' not found", expression.Target);
if (!module.TryResolveType(structType.Name, currentModule == structType.Module, out var typeDef))
throw new CompileException(Diagnostic.Error($"Type '{structType.Name}' not found in module '{structType.Module}'").At(fileName, expression.Target).Build());
throw BasicError($"Type '{structType.Name}' not found in module '{structType.Module}'", expression.Target);
if (typeDef is not Module.TypeInfoStruct structDef)
throw new CompileException(Diagnostic.Error($"Type '{target.Type}' is not a struct").At(fileName, expression.Target).Build());
throw BasicError($"Type '{target.Type}' is not a struct", expression.Target);
var field = structDef.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident);
if (field == null)
throw new CompileException(Diagnostic.Error($"Struct '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'").At(fileName, target).Build());
throw BasicError($"Struct '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'", target);
return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name);
}
case NubTypeEnumVariant enumVariantType:
{
if (!moduleGraph.TryResolveModule(enumVariantType.EnumType.Module, out var module))
throw new CompileException(Diagnostic.Error($"Module '{enumVariantType.EnumType.Module}' not found").At(fileName, expression.Target).Build());
throw BasicError($"Module '{enumVariantType.EnumType.Module}' not found", expression.Target);
if (!module.TryResolveType(enumVariantType.EnumType.Name, currentModule == enumVariantType.EnumType.Module, out var typeDef))
throw new CompileException(Diagnostic.Error($"Type '{enumVariantType.EnumType.Name}' not found in module '{enumVariantType.EnumType.Module}'").At(fileName, expression.Target).Build());
throw BasicError($"Type '{enumVariantType.EnumType.Name}' not found in module '{enumVariantType.EnumType.Module}'", expression.Target);
if (typeDef is not Module.TypeInfoEnum enumDef)
throw new CompileException(Diagnostic.Error($"Type '{enumVariantType.EnumType.Module}::{enumVariantType.EnumType.Name}' is not an enum").At(fileName, expression.Target).Build());
throw BasicError($"Type '{enumVariantType.EnumType.Module}::{enumVariantType.EnumType.Name}' is not an enum", expression.Target);
var variant = enumDef.Variants.FirstOrDefault(x => x.Name == enumVariantType.Variant);
if (variant == null)
throw new CompileException(Diagnostic.Error($"Type '{target.Type}' does not have a variant named '{enumVariantType.Variant}'").At(fileName, expression.Target).Build());
throw BasicError($"Type '{target.Type}' does not have a variant named '{enumVariantType.Variant}'", expression.Target);
var field = variant.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident);
if (field == null)
throw new CompileException(Diagnostic.Error($"Enum variant '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'").At(fileName, target).Build());
throw BasicError($"Enum variant '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'", target);
return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name);
}
default:
throw new CompileException(Diagnostic.Error($"{target.Type} has no member '{expression.Name.Ident}'").At(fileName, target).Build());
throw BasicError($"{target.Type} has no member '{expression.Name.Ident}'", target);
}
}
@@ -395,7 +395,7 @@ public class TypeChecker
{
var target = CheckExpression(expression.Target);
if (target.Type is not NubTypeFunc funcType)
throw new CompileException(Diagnostic.Error($"Cannot invoke function call on type '{target.Type}'").At(fileName, target).Build());
throw BasicError($"Cannot invoke function call on type '{target.Type}'", target);
var parameters = expression.Parameters.Select(CheckExpression).ToList();
@@ -416,11 +416,11 @@ public class TypeChecker
{
var field = info.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
if (field == null)
throw new CompileException(Diagnostic.Error($"Field '{initializer.Name.Ident}' does not exist on struct '{expression.Module.Ident}::{expression.Name.Ident}'").At(fileName, initializer.Name).Build());
throw BasicError($"Field '{initializer.Name.Ident}' does not exist on struct '{expression.Module.Ident}::{expression.Name.Ident}'", initializer.Name);
var value = CheckExpression(initializer.Value);
if (!value.Type.IsAssignableTo(field.Type))
throw new CompileException(Diagnostic.Error($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})").At(fileName, initializer.Name).Build());
throw BasicError($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})", initializer.Name);
initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value));
}
@@ -434,18 +434,18 @@ public class TypeChecker
var variant = info.Variants.FirstOrDefault(x => x.Name == expression.VariantName.Ident);
if (variant == null)
throw new CompileException(Diagnostic.Error($"Enum '{expression.Module.Ident}::{expression.EnumName.Ident}' does not have a variant '{expression.VariantName.Ident}'").At(fileName, expression.VariantName).Build());
throw BasicError($"Enum '{expression.Module.Ident}::{expression.EnumName.Ident}' does not have a variant '{expression.VariantName.Ident}'", expression.VariantName);
var initializers = new List<TypedNodeExpressionEnumLiteral.Initializer>();
foreach (var initializer in expression.Initializers)
{
var field = variant.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
if (field == null)
throw new CompileException(Diagnostic.Error($"Field '{initializer.Name.Ident}' does not exist on enum variant '{expression.Module.Ident}::{expression.EnumName.Ident}.{expression.VariantName.Ident}'").At(fileName, initializer.Name).Build());
throw BasicError($"Field '{initializer.Name.Ident}' does not exist on enum variant '{expression.Module.Ident}::{expression.EnumName.Ident}.{expression.VariantName.Ident}'", initializer.Name);
var value = CheckExpression(initializer.Value);
if (!value.Type.IsAssignableTo(field.Type))
throw new CompileException(Diagnostic.Error($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})").At(fileName, initializer.Name).Build());
throw BasicError($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})", initializer.Name);
initializers.Add(new TypedNodeExpressionEnumLiteral.Initializer(initializer.Tokens, initializer.Name, value));
}
@@ -590,6 +590,11 @@ public class TypeChecker
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
}
private CompileException BasicError(string message, TypedNode node)
{
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
}
private sealed class Scope
{
private readonly Stack<Dictionary<string, NubType>> scopes = new();