WIP: dev #1
@@ -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,16 @@ public class Parser
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private CompileException BasicError(string message, Token? ident)
|
||||
{
|
||||
return new CompileException(Diagnostic.Error(message).At(fileName, ident).Build());
|
||||
}
|
||||
|
||||
private CompileException BasicError(string message, Node node)
|
||||
{
|
||||
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
|
||||
}
|
||||
}
|
||||
|
||||
public class Ast(string fileName, TokenIdent moduleName, List<NodeDefinition> definitions)
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user