diff --git a/compiler/.gitignore b/compiler/.gitignore
index c6cc67a..66cc8b5 100644
--- a/compiler/.gitignore
+++ b/compiler/.gitignore
@@ -1,4 +1,4 @@
-# Common IntelliJ Platform excludes
+# Common IntelliJ Platform excludes
# User specific
**/.idea/**/workspace.xml
@@ -31,4 +31,6 @@ _UpgradeReport_Files/
Thumbs.db
Desktop.ini
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+out.c
\ No newline at end of file
diff --git a/compiler/.idea/.idea.Compiler/.idea/.gitignore b/compiler/.idea/.idea.Compiler/.idea/.gitignore
deleted file mode 100644
index cda1cf4..0000000
--- a/compiler/.idea/.idea.Compiler/.idea/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/modules.xml
-/projectSettingsUpdater.xml
-/contentModel.xml
-/.idea.Compiler.iml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/compiler/.idea/.idea.Compiler/.idea/.name b/compiler/.idea/.idea.Compiler/.idea/.name
deleted file mode 100644
index b92b7a3..0000000
--- a/compiler/.idea/.idea.Compiler/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-Compiler
\ No newline at end of file
diff --git a/compiler/.idea/.idea.Compiler/.idea/encodings.xml b/compiler/.idea/.idea.Compiler/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/compiler/.idea/.idea.Compiler/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/compiler/.idea/.idea.Compiler/.idea/indexLayout.xml b/compiler/.idea/.idea.Compiler/.idea/indexLayout.xml
deleted file mode 100644
index 2135b43..0000000
--- a/compiler/.idea/.idea.Compiler/.idea/indexLayout.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- Runtime
-
-
-
-
-
\ No newline at end of file
diff --git a/compiler/.idea/.idea.Compiler/.idea/vcs.xml b/compiler/.idea/.idea.Compiler/.idea/vcs.xml
deleted file mode 100644
index 6c0b863..0000000
--- a/compiler/.idea/.idea.Compiler/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/compiler/Compiler/Compiler.csproj b/compiler/Compiler.csproj
similarity index 100%
rename from compiler/Compiler/Compiler.csproj
rename to compiler/Compiler.csproj
diff --git a/compiler/Compiler/.gitignore b/compiler/Compiler/.gitignore
deleted file mode 100644
index eb306b3..0000000
--- a/compiler/Compiler/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-out.c
\ No newline at end of file
diff --git a/compiler/Compiler/Diagnostic.cs b/compiler/Diagnostic.cs
similarity index 100%
rename from compiler/Compiler/Diagnostic.cs
rename to compiler/Diagnostic.cs
diff --git a/compiler/Compiler/Generator.cs b/compiler/Generator.cs
similarity index 100%
rename from compiler/Compiler/Generator.cs
rename to compiler/Generator.cs
diff --git a/compiler/NubLang.CLI/NubLang.CLI.csproj b/compiler/NubLang.CLI/NubLang.CLI.csproj
deleted file mode 100644
index 0550d0f..0000000
--- a/compiler/NubLang.CLI/NubLang.CLI.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- nubc
- Exe
- net9.0
- enable
- enable
- true
-
-
-
-
-
-
-
diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs
deleted file mode 100644
index 4806c9d..0000000
--- a/compiler/NubLang.CLI/Program.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using NubLang.Ast;
-using NubLang.Diagnostics;
-using NubLang.Syntax;
-
-var diagnostics = new List();
-var syntaxTrees = new List();
-
-foreach (var file in args)
-{
- var tokenizer = new Tokenizer(file, File.ReadAllText(file));
- tokenizer.Tokenize();
- diagnostics.AddRange(tokenizer.Diagnostics);
-
- var parser = new Parser();
- var syntaxTree = parser.Parse(tokenizer.Tokens);
- diagnostics.AddRange(parser.Diagnostics);
-
- syntaxTrees.Add(syntaxTree);
-}
-
-var modules = Module.Collect(syntaxTrees);
-var compilationUnits = new List();
-
-for (var i = 0; i < args.Length; i++)
-{
- var typeChecker = new TypeChecker(syntaxTrees[i], modules);
- var compilationUnit = typeChecker.Check();
-
- compilationUnits.Add(compilationUnit);
- diagnostics.AddRange(typeChecker.Diagnostics);
-}
-
-foreach (var diagnostic in diagnostics)
-{
- Console.Error.WriteLine(diagnostic.FormatANSI());
-}
-
-if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error))
-{
- return 1;
-}
-
-return 0;
\ No newline at end of file
diff --git a/compiler/NubLang/Ast/CompilationUnit.cs b/compiler/NubLang/Ast/CompilationUnit.cs
deleted file mode 100644
index f2115c1..0000000
--- a/compiler/NubLang/Ast/CompilationUnit.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace NubLang.Ast;
-
-public sealed class CompilationUnit
-{
- public CompilationUnit(List functions, List importedStructTypes, List importedFunctions)
- {
- Functions = functions;
- ImportedStructTypes = importedStructTypes;
- ImportedFunctions = importedFunctions;
- }
-
- public List Functions { get; }
- public List ImportedStructTypes { get; }
- public List ImportedFunctions { get; }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Ast/Node.cs b/compiler/NubLang/Ast/Node.cs
deleted file mode 100644
index aca79fd..0000000
--- a/compiler/NubLang/Ast/Node.cs
+++ /dev/null
@@ -1,590 +0,0 @@
-using NubLang.Syntax;
-
-namespace NubLang.Ast;
-
-public abstract class Node(List tokens)
-{
- public List Tokens { get; } = tokens;
-
- public abstract IEnumerable Children();
-
- public IEnumerable Descendants()
- {
- foreach (var child in Children())
- {
- foreach (var descendant in child.DescendantsAndSelf())
- {
- yield return descendant;
- }
- }
- }
-
- public IEnumerable DescendantsAndSelf()
- {
- yield return this;
- foreach (var descendant in Descendants())
- {
- yield return descendant;
- }
- }
-}
-
-#region Definitions
-
-public abstract class DefinitionNode(List tokens, string module, string name) : Node(tokens)
-{
- public string Module { get; } = module;
- public string Name { get; } = name;
-}
-
-public class FuncParameterNode(List tokens, string name, NubType type) : Node(tokens)
-{
- public string Name { get; } = name;
- public NubType Type { get; } = type;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class FuncPrototypeNode(List tokens, string module, string name, string? externSymbol, List parameters, NubType returnType) : Node(tokens)
-{
- public string Module { get; } = module;
- public string Name { get; } = name;
- public string? ExternSymbol { get; } = externSymbol;
- public List Parameters { get; } = parameters;
- public NubType ReturnType { get; } = returnType;
-
- public override IEnumerable Children()
- {
- return Parameters;
- }
-}
-
-public class FuncNode(List tokens, FuncPrototypeNode prototype, BlockNode? body) : DefinitionNode(tokens, prototype.Module, prototype.Name)
-{
- public FuncPrototypeNode Prototype { get; } = prototype;
- public BlockNode? Body { get; } = body;
-
- public override IEnumerable Children()
- {
- yield return Prototype;
- if (Body != null)
- {
- yield return Body;
- }
- }
-}
-
-#endregion
-
-#region Statements
-
-public abstract class StatementNode(List tokens) : Node(tokens);
-
-public abstract class TerminalStatementNode(List tokens) : StatementNode(tokens);
-
-public class BlockNode(List tokens, List statements) : StatementNode(tokens)
-{
- public List Statements { get; } = statements;
-
- public override IEnumerable Children()
- {
- return Statements;
- }
-}
-
-public class StatementFuncCallNode(List tokens, FuncCallNode funcCall) : StatementNode(tokens)
-{
- public FuncCallNode FuncCall { get; } = funcCall;
-
- public override IEnumerable Children()
- {
- yield return FuncCall;
- }
-}
-
-public class ReturnNode(List tokens, ExpressionNode? value) : TerminalStatementNode(tokens)
-{
- public ExpressionNode? Value { get; } = value;
-
- public override IEnumerable Children()
- {
- if (Value != null) yield return Value;
- }
-}
-
-public class AssignmentNode(List tokens, LValueExpressionNode target, ExpressionNode value) : StatementNode(tokens)
-{
- public LValueExpressionNode Target { get; } = target;
- public ExpressionNode Value { get; } = value;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Value;
- }
-}
-
-public class IfNode(List tokens, ExpressionNode condition, BlockNode body, Variant? @else) : StatementNode(tokens)
-{
- public ExpressionNode Condition { get; } = condition;
- public BlockNode Body { get; } = body;
- public Variant? Else { get; } = @else;
-
- public override IEnumerable Children()
- {
- yield return Condition;
- yield return Body;
- if (Else.HasValue)
- {
- yield return Else.Value.Match(x => x, x => x);
- }
- }
-}
-
-public class VariableDeclarationNode(List tokens, string name, ExpressionNode? assignment, NubType type) : StatementNode(tokens)
-{
- public string Name { get; } = name;
- public ExpressionNode? Assignment { get; } = assignment;
- public NubType Type { get; } = type;
-
- public override IEnumerable Children()
- {
- if (Assignment != null) yield return Assignment;
- }
-}
-
-public class ContinueNode(List tokens) : TerminalStatementNode(tokens)
-{
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class BreakNode(List tokens) : TerminalStatementNode(tokens)
-{
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class WhileNode(List tokens, ExpressionNode condition, BlockNode body) : StatementNode(tokens)
-{
- public ExpressionNode Condition { get; } = condition;
- public BlockNode Body { get; } = body;
-
- public override IEnumerable Children()
- {
- yield return Condition;
- yield return Body;
- }
-}
-
-public class ForSliceNode(List tokens, string elementName, string? indexName, ExpressionNode target, BlockNode body) : StatementNode(tokens)
-{
- public string ElementName { get; } = elementName;
- public string? IndexName { get; } = indexName;
- public ExpressionNode Target { get; } = target;
- public BlockNode Body { get; } = body;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Body;
- }
-}
-
-public class ForConstArrayNode(List tokens, string elementName, string? indexName, ExpressionNode target, BlockNode body) : StatementNode(tokens)
-{
- public string ElementName { get; } = elementName;
- public string? IndexName { get; } = indexName;
- public ExpressionNode Target { get; } = target;
- public BlockNode Body { get; } = body;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Body;
- }
-}
-
-public class DeferNode(List tokens, StatementNode statement) : StatementNode(tokens)
-{
- public StatementNode Statement { get; } = statement;
-
- public override IEnumerable Children()
- {
- yield return Statement;
- }
-}
-
-#endregion
-
-#region Expressions
-
-public enum UnaryOperator
-{
- Negate,
- Invert
-}
-
-public enum BinaryOperator
-{
- Equal,
- NotEqual,
- GreaterThan,
- GreaterThanOrEqual,
- LessThan,
- LessThanOrEqual,
- LogicalAnd,
- LogicalOr,
- Plus,
- Minus,
- Multiply,
- Divide,
- Modulo,
- LeftShift,
- RightShift,
- BitwiseAnd,
- BitwiseXor,
- BitwiseOr
-}
-
-public abstract class ExpressionNode(List tokens, NubType type) : Node(tokens)
-{
- public NubType Type { get; } = type;
-}
-
-public abstract class LValueExpressionNode(List tokens, NubType type) : ExpressionNode(tokens, type);
-
-public abstract class RValueExpressionNode(List tokens, NubType type) : ExpressionNode(tokens, type);
-
-public abstract class IntermediateExpression(List tokens) : ExpressionNode(tokens, new NubVoidType());
-
-public class StringLiteralNode(List tokens, string value) : RValueExpressionNode(tokens, new NubStringType())
-{
- public string Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class CStringLiteralNode(List tokens, string value) : RValueExpressionNode(tokens, new NubPointerType(new NubIntType(true, 8)))
-{
- public string Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class I8LiteralNode(List tokens, sbyte value) : RValueExpressionNode(tokens, new NubIntType(true, 8))
-{
- public sbyte Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class I16LiteralNode(List tokens, short value) : RValueExpressionNode(tokens, new NubIntType(true, 16))
-{
- public short Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class I32LiteralNode(List tokens, int value) : RValueExpressionNode(tokens, new NubIntType(true, 32))
-{
- public int Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class I64LiteralNode(List tokens, long value) : RValueExpressionNode(tokens, new NubIntType(true, 64))
-{
- public long Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class U8LiteralNode(List tokens, byte value) : RValueExpressionNode(tokens, new NubIntType(false, 8))
-{
- public byte Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class U16LiteralNode(List tokens, ushort value) : RValueExpressionNode(tokens, new NubIntType(false, 16))
-{
- public ushort Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class U32LiteralNode(List tokens, uint value) : RValueExpressionNode(tokens, new NubIntType(false, 32))
-{
- public uint Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class U64LiteralNode(List tokens, ulong value) : RValueExpressionNode(tokens, new NubIntType(false, 64))
-{
- public ulong Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class Float32LiteralNode(List tokens, float value) : RValueExpressionNode(tokens, new NubFloatType(32))
-{
- public float Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class Float64LiteralNode(List tokens, double value) : RValueExpressionNode(tokens, new NubFloatType(64))
-{
- public double Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class BoolLiteralNode(List tokens, NubType type, bool value) : RValueExpressionNode(tokens, type)
-{
- public bool Value { get; } = value;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class BinaryExpressionNode(List tokens, NubType type, ExpressionNode left, BinaryOperator @operator, ExpressionNode right) : RValueExpressionNode(tokens, type)
-{
- public ExpressionNode Left { get; } = left;
- public BinaryOperator Operator { get; } = @operator;
- public ExpressionNode Right { get; } = right;
-
- public override IEnumerable Children()
- {
- yield return Left;
- yield return Right;
- }
-}
-
-public class UnaryExpressionNode(List tokens, NubType type, UnaryOperator @operator, ExpressionNode operand) : RValueExpressionNode(tokens, type)
-{
- public UnaryOperator Operator { get; } = @operator;
- public ExpressionNode Operand { get; } = operand;
-
- public override IEnumerable Children()
- {
- yield return Operand;
- }
-}
-
-public class FuncCallNode(List tokens, NubType type, ExpressionNode expression, List parameters) : RValueExpressionNode(tokens, type)
-{
- public ExpressionNode Expression { get; } = expression;
- public List Parameters { get; } = parameters;
-
- public override IEnumerable Children()
- {
- yield return Expression;
- foreach (var expressionNode in Parameters)
- {
- yield return expressionNode;
- }
- }
-}
-
-public class VariableIdentifierNode(List tokens, NubType type, string name) : LValueExpressionNode(tokens, type)
-{
- public string Name { get; } = name;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class FuncIdentifierNode(List tokens, NubType type, string module, string name, string? externSymbol) : RValueExpressionNode(tokens, type)
-{
- public string Module { get; } = module;
- public string Name { get; } = name;
- public string? ExternSymbol { get; } = externSymbol;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class ArrayInitializerNode(List tokens, NubType type, List values) : RValueExpressionNode(tokens, type)
-{
- public List Values { get; } = values;
-
- public override IEnumerable Children()
- {
- return Values;
- }
-}
-
-public class ConstArrayInitializerNode(List tokens, NubType type, List values) : RValueExpressionNode(tokens, type)
-{
- public List Values { get; } = values;
-
- public override IEnumerable Children()
- {
- return Values;
- }
-}
-
-public class ArrayIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type)
-{
- public ExpressionNode Target { get; } = target;
- public ExpressionNode Index { get; } = index;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Index;
- }
-}
-
-public class ConstArrayIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type)
-{
- public ExpressionNode Target { get; } = target;
- public ExpressionNode Index { get; } = index;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Index;
- }
-}
-
-public class SliceIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type)
-{
- public ExpressionNode Target { get; } = target;
- public ExpressionNode Index { get; } = index;
-
- public override IEnumerable Children()
- {
- yield return Target;
- yield return Index;
- }
-}
-
-public class AddressOfNode(List tokens, NubType type, LValueExpressionNode lValue) : RValueExpressionNode(tokens, type)
-{
- public LValueExpressionNode LValue { get; } = lValue;
-
- public override IEnumerable Children()
- {
- yield return LValue;
- }
-}
-
-public class StructFieldAccessNode(List tokens, NubType type, ExpressionNode target, string field) : LValueExpressionNode(tokens, type)
-{
- public ExpressionNode Target { get; } = target;
- public string Field { get; } = field;
-
- public override IEnumerable Children()
- {
- yield return Target;
- }
-}
-
-public class StructInitializerNode(List tokens, NubType type, Dictionary initializers) : RValueExpressionNode(tokens, type)
-{
- public Dictionary Initializers { get; } = initializers;
-
- public override IEnumerable Children()
- {
- foreach (var initializer in Initializers)
- {
- yield return initializer.Value;
- }
- }
-}
-
-public class DereferenceNode(List tokens, NubType type, ExpressionNode target) : LValueExpressionNode(tokens, type)
-{
- public ExpressionNode Target { get; } = target;
-
- public override IEnumerable Children()
- {
- yield return Target;
- }
-}
-
-public class SizeNode(List tokens, NubType TargetType) : RValueExpressionNode(tokens, new NubIntType(false, 64))
-{
- public NubType TargetType { get; } = TargetType;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-public class CastNode(List tokens, NubType type, ExpressionNode value) : RValueExpressionNode(tokens, type)
-{
- public ExpressionNode Value { get; } = value;
-
- public override IEnumerable Children()
- {
- yield return Value;
- }
-}
-
-public class EnumReferenceIntermediateNode(List tokens, string module, string name) : IntermediateExpression(tokens)
-{
- public string Module { get; } = module;
- public string Name { get; } = name;
-
- public override IEnumerable Children()
- {
- return [];
- }
-}
-
-#endregion
\ No newline at end of file
diff --git a/compiler/NubLang/Ast/NubType.cs b/compiler/NubLang/Ast/NubType.cs
deleted file mode 100644
index ef0981b..0000000
--- a/compiler/NubLang/Ast/NubType.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using System.Security.Cryptography;
-using System.Text;
-
-namespace NubLang.Ast;
-
-public abstract class NubType : IEquatable
-{
- public override bool Equals(object? obj) => obj is NubType other && Equals(other);
- public abstract bool Equals(NubType? other);
-
- public abstract override int GetHashCode();
- public abstract override string ToString();
-
- public static bool operator ==(NubType? left, NubType? right) => Equals(left, right);
- public static bool operator !=(NubType? left, NubType? right) => !Equals(left, right);
-}
-
-public class NubVoidType : NubType
-{
- public override string ToString() => "void";
- public override bool Equals(NubType? other) => other is NubVoidType;
- public override int GetHashCode() => HashCode.Combine(typeof(NubVoidType));
-}
-
-public sealed class NubIntType(bool signed, int width) : NubType
-{
- public bool Signed { get; } = signed;
- public int Width { get; } = width;
-
- public override string ToString() => $"{(Signed ? "i" : "u")}{Width}";
- public override bool Equals(NubType? other) => other is NubIntType @int && @int.Width == Width && @int.Signed == Signed;
- public override int GetHashCode() => HashCode.Combine(typeof(NubIntType), Signed, Width);
-}
-
-public sealed class NubFloatType(int width) : NubType
-{
- public int Width { get; } = width;
-
- public override string ToString() => $"f{Width}";
- public override bool Equals(NubType? other) => other is NubFloatType @float && @float.Width == Width;
- public override int GetHashCode() => HashCode.Combine(typeof(NubFloatType), Width);
-}
-
-public class NubBoolType : NubType
-{
- public override string ToString() => "bool";
- public override bool Equals(NubType? other) => other is NubBoolType;
- public override int GetHashCode() => HashCode.Combine(typeof(NubBoolType));
-}
-
-public sealed class NubPointerType(NubType baseType) : NubType
-{
- public NubType BaseType { get; } = baseType;
-
- public override string ToString() => "^" + BaseType;
- public override bool Equals(NubType? other) => other is NubPointerType pointer && BaseType.Equals(pointer.BaseType);
- public override int GetHashCode() => HashCode.Combine(typeof(NubPointerType), BaseType);
-}
-
-public class NubFuncType(List parameters, NubType returnType) : NubType
-{
- public List Parameters { get; } = parameters;
- public NubType ReturnType { get; } = returnType;
-
- public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
- public override bool Equals(NubType? other) => other is NubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters);
-
- public override int GetHashCode()
- {
- var hash = new HashCode();
- hash.Add(typeof(NubFuncType));
- hash.Add(ReturnType);
- foreach (var param in Parameters)
- {
- hash.Add(param);
- }
-
- return hash.ToHashCode();
- }
-}
-
-public class NubStructType(string module, string name, List fields) : NubType
-{
- public string Module { get; } = module;
- public string Name { get; } = name;
- public List Fields { get; set; } = fields;
-
- public override string ToString() => $"{Module}::{Name}";
- public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module;
- public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name);
-}
-
-public class NubStructFieldType(string name, NubType type, bool hasDefaultValue)
-{
- public string Name { get; } = name;
- public NubType Type { get; } = type;
- public bool HasDefaultValue { get; } = hasDefaultValue;
-}
-
-public class NubSliceType(NubType elementType) : NubType
-{
- public NubType ElementType { get; } = elementType;
-
- public override string ToString() => "[]" + ElementType;
- public override bool Equals(NubType? other) => other is NubSliceType slice && ElementType.Equals(slice.ElementType);
- public override int GetHashCode() => HashCode.Combine(typeof(NubSliceType), ElementType);
-}
-
-public class NubConstArrayType(NubType elementType, long size) : NubType
-{
- public NubType ElementType { get; } = elementType;
- public long Size { get; } = size;
-
- public override string ToString() => $"[{Size}]{ElementType}";
- public override bool Equals(NubType? other) => other is NubConstArrayType array && ElementType.Equals(array.ElementType) && Size == array.Size;
- public override int GetHashCode() => HashCode.Combine(typeof(NubConstArrayType), ElementType, Size);
-}
-
-public class NubArrayType(NubType elementType) : NubType
-{
- public NubType ElementType { get; } = elementType;
-
- public override string ToString() => $"[?]{ElementType}";
- public override bool Equals(NubType? other) => other is NubArrayType array && ElementType.Equals(array.ElementType);
- public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType);
-}
-
-public class NubStringType : NubType
-{
- public override string ToString() => "string";
- public override bool Equals(NubType? other) => other is NubStringType;
- public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
-}
-
-public static class NameMangler
-{
- public static string Mangle(params IEnumerable types)
- {
- var readable = string.Join(":", types.Select(EncodeType));
- return ComputeShortHash(readable);
- }
-
- private static string EncodeType(NubType node) => node switch
- {
- NubVoidType => "V",
- NubBoolType => "B",
- NubIntType i => (i.Signed ? "I" : "U") + i.Width,
- NubFloatType f => "F" + f.Width,
- NubStringType => "S",
- NubArrayType a => $"A({EncodeType(a.ElementType)})",
- NubConstArrayType ca => $"CA({EncodeType(ca.ElementType)})",
- NubSliceType a => $"SL{EncodeType(a.ElementType)}()",
- NubPointerType p => $"P({EncodeType(p.BaseType)})",
- NubFuncType fn => $"FN({string.Join(":", fn.Parameters.Select(EncodeType))}:{EncodeType(fn.ReturnType)})",
- NubStructType st => $"ST({st.Module}:{st.Name})",
- _ => throw new NotSupportedException($"Cannot encode type: {node}")
- };
-
- private static string ComputeShortHash(string input)
- {
- var bytes = Encoding.UTF8.GetBytes(input);
- var hash = SHA256.HashData(bytes);
- return Convert.ToHexString(hash[..8]).ToLower();
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Ast/TypeChecker.cs b/compiler/NubLang/Ast/TypeChecker.cs
deleted file mode 100644
index 4224115..0000000
--- a/compiler/NubLang/Ast/TypeChecker.cs
+++ /dev/null
@@ -1,1167 +0,0 @@
-using System.Diagnostics;
-using NubLang.Diagnostics;
-using NubLang.Syntax;
-
-namespace NubLang.Ast;
-
-public sealed class TypeChecker
-{
- private readonly SyntaxTree _syntaxTree;
- private readonly Dictionary _importedModules;
-
- private readonly Stack _scopes = [];
- private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new();
- private readonly HashSet<(string Module, string Name)> _resolvingTypes = [];
-
- private Scope Scope => _scopes.Peek();
-
- public List Diagnostics { get; } = [];
-
- public TypeChecker(SyntaxTree syntaxTree, Dictionary modules)
- {
- _syntaxTree = syntaxTree;
- _importedModules = modules
- .Where(x => syntaxTree.Imports.Contains(x.Key) || _syntaxTree.ModuleName == x.Key)
- .ToDictionary();
- }
-
- public CompilationUnit Check()
- {
- _scopes.Clear();
- _typeCache.Clear();
- _resolvingTypes.Clear();
-
- var functions = new List();
-
- using (BeginRootScope(_syntaxTree.ModuleName))
- {
- foreach (var funcSyntax in _syntaxTree.Definitions.OfType())
- {
- try
- {
- functions.Add(CheckFuncDefinition(funcSyntax));
- }
- catch (TypeCheckerException e)
- {
- Diagnostics.Add(e.Diagnostic);
- }
- }
- }
-
- var importedStructTypes = new List();
- var importedFunctions = new List();
-
- foreach (var (name, module) in _importedModules)
- {
- using (BeginRootScope(name))
- {
- foreach (var structSyntax in module.Structs(true))
- {
- try
- {
- var fields = structSyntax.Fields
- .Select(f => new NubStructFieldType(f.Name, ResolveType(f.Type), f.Value != null))
- .ToList();
-
- importedStructTypes.Add(new NubStructType(name, structSyntax.Name, fields));
- }
- catch (TypeCheckerException e)
- {
- Diagnostics.Add(e.Diagnostic);
- }
- }
-
- foreach (var funcSyntax in module.Functions(true))
- {
- try
- {
- importedFunctions.Add(CheckFuncPrototype(funcSyntax.Prototype));
- }
- catch (TypeCheckerException e)
- {
- Diagnostics.Add(e.Diagnostic);
- }
- }
- }
- }
-
- return new CompilationUnit(functions, importedStructTypes, importedFunctions);
- }
-
- private ScopeDisposer BeginScope()
- {
- _scopes.Push(Scope.SubScope());
- return new ScopeDisposer(this);
- }
-
- private ScopeDisposer BeginRootScope(string moduleName)
- {
- _scopes.Push(new Scope(moduleName));
- return new ScopeDisposer(this);
- }
-
- private sealed class ScopeDisposer(TypeChecker owner) : IDisposable
- {
- private bool _disposed;
-
- public void Dispose()
- {
- if (_disposed) return;
- owner._scopes.Pop();
- _disposed = true;
- }
- }
-
- private FuncNode CheckFuncDefinition(FuncSyntax node)
- {
- using (BeginScope())
- {
- var prototype = CheckFuncPrototype(node.Prototype);
-
- Scope.SetReturnType(prototype.ReturnType);
- foreach (var parameter in prototype.Parameters)
- {
- Scope.DeclareVariable(new Variable(parameter.Name, parameter.Type));
- }
-
- var body = node.Body == null ? null : CheckBlock(node.Body);
- return new FuncNode(node.Tokens, prototype, body);
- }
- }
-
- private AssignmentNode CheckAssignment(AssignmentSyntax statement)
- {
- var target = CheckExpression(statement.Target);
- if (target is not LValueExpressionNode lValue)
- {
- throw new TypeCheckerException(Diagnostic.Error("Cannot assign to an rvalue").At(statement).Build());
- }
-
- var value = CheckExpression(statement.Value, lValue.Type);
-
- if (value.Type != lValue.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot assign {value.Type} to {lValue.Type}")
- .At(statement.Value)
- .Build());
- }
-
- return new AssignmentNode(statement.Tokens, lValue, value);
- }
-
- private IfNode CheckIf(IfSyntax statement)
- {
- var condition = CheckExpression(statement.Condition);
- var body = CheckBlock(statement.Body);
- Variant? elseStatement = null;
- if (statement.Else.HasValue)
- {
- elseStatement = statement.Else.Value.Match>(elif => CheckIf(elif), el => CheckBlock(el));
- }
-
- return new IfNode(statement.Tokens, condition, body, elseStatement);
- }
-
- private ReturnNode CheckReturn(ReturnSyntax statement)
- {
- ExpressionNode? value = null;
-
- if (statement.Value != null)
- {
- var expectedReturnType = Scope.GetReturnType();
- value = CheckExpression(statement.Value, expectedReturnType);
- }
-
- return new ReturnNode(statement.Tokens, value);
- }
-
- private StatementNode CheckStatementExpression(StatementExpressionSyntax statement)
- {
- var expression = CheckExpression(statement.Expression);
-
- return expression switch
- {
- FuncCallNode funcCall => new StatementFuncCallNode(statement.Tokens, funcCall),
- _ => throw new TypeCheckerException(Diagnostic.Error("Expressions statements can only be function calls").At(statement).Build())
- };
- }
-
- private VariableDeclarationNode CheckVariableDeclaration(VariableDeclarationSyntax statement)
- {
- NubType? type = null;
- ExpressionNode? assignmentNode = null;
-
- if (statement.ExplicitType != null)
- {
- type = ResolveType(statement.ExplicitType);
- }
-
- if (statement.Assignment != null)
- {
- assignmentNode = CheckExpression(statement.Assignment, type);
-
- if (type == null)
- {
- type = assignmentNode.Type;
- }
- else if (assignmentNode.Type != type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot assign {assignmentNode.Type} to variable of type {type}")
- .At(statement.Assignment)
- .Build());
- }
- }
-
- if (type == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot infer type of variable {statement.Name}")
- .At(statement)
- .Build());
- }
-
- Scope.DeclareVariable(new Variable(statement.Name, type));
-
- return new VariableDeclarationNode(statement.Tokens, statement.Name, assignmentNode, type);
- }
-
- private WhileNode CheckWhile(WhileSyntax statement)
- {
- var condition = CheckExpression(statement.Condition);
- var body = CheckBlock(statement.Body);
- return new WhileNode(statement.Tokens, condition, body);
- }
-
- private StatementNode CheckFor(ForSyntax forSyntax)
- {
- var target = CheckExpression(forSyntax.Target);
-
-
- switch (target.Type)
- {
- case NubSliceType sliceType:
- {
- using (BeginScope())
- {
- Scope.DeclareVariable(new Variable(forSyntax.ElementName, sliceType.ElementType));
- if (forSyntax.IndexName != null)
- {
- Scope.DeclareVariable(new Variable(forSyntax.IndexName, new NubIntType(false, 64)));
- }
-
- var body = CheckBlock(forSyntax.Body);
- return new ForSliceNode(forSyntax.Tokens, forSyntax.ElementName, forSyntax.IndexName, target, body);
- }
- }
- case NubConstArrayType constArrayType:
- {
- using (BeginScope())
- {
- Scope.DeclareVariable(new Variable(forSyntax.ElementName, constArrayType.ElementType));
- if (forSyntax.IndexName != null)
- {
- Scope.DeclareVariable(new Variable(forSyntax.IndexName, new NubIntType(false, 64)));
- }
-
- var body = CheckBlock(forSyntax.Body);
- return new ForConstArrayNode(forSyntax.Tokens, forSyntax.ElementName, forSyntax.IndexName, target, body);
- }
- }
- default:
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot iterate over type {target.Type} which does not have size information")
- .At(forSyntax.Target)
- .Build());
- }
- }
- }
-
- private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement)
- {
- var parameters = new List();
- foreach (var parameter in statement.Parameters)
- {
- parameters.Add(new FuncParameterNode(parameter.Tokens, parameter.Name, ResolveType(parameter.Type)));
- }
-
- return new FuncPrototypeNode(statement.Tokens, Scope.Module, statement.Name, statement.ExternSymbol, parameters, ResolveType(statement.ReturnType));
- }
-
- private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null)
- {
- var result = node switch
- {
- AddressOfSyntax expression => CheckAddressOf(expression, expectedType),
- ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression, expectedType),
- ArrayInitializerSyntax expression => CheckArrayInitializer(expression, expectedType),
- BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
- UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
- DereferenceSyntax expression => CheckDereference(expression, expectedType),
- FuncCallSyntax expression => CheckFuncCall(expression, expectedType),
- LocalIdentifierSyntax expression => CheckLocalIdentifier(expression, expectedType),
- ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression, expectedType),
- BoolLiteralSyntax expression => CheckBoolLiteral(expression, expectedType),
- StringLiteralSyntax expression => CheckStringLiteral(expression, expectedType),
- IntLiteralSyntax expression => CheckIntLiteral(expression, expectedType),
- FloatLiteralSyntax expression => CheckFloatLiteral(expression, expectedType),
- MemberAccessSyntax expression => CheckMemberAccess(expression, expectedType),
- StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
- SizeSyntax expression => new SizeNode(node.Tokens, ResolveType(expression.Type)),
- CastSyntax expression => CheckCast(expression, expectedType),
- _ => throw new ArgumentOutOfRangeException(nameof(node))
- };
-
- if (expectedType != null)
- {
- if (result.Type == expectedType)
- {
- return result;
- }
-
- if (IsCastAllowed(result.Type, expectedType))
- {
- return new CastNode(result.Tokens, expectedType, result);
- }
- }
-
- return result;
- }
-
- private ExpressionNode CheckCast(CastSyntax expression, NubType? expectedType)
- {
- if (expectedType == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Unable to infer target type of cast")
- .At(expression)
- .WithHelp("Specify target type where value is used")
- .Build());
- }
-
- var value = CheckExpression(expression.Value, expectedType);
-
- if (value.Type == expectedType)
- {
- Diagnostics.Add(Diagnostic
- .Warning("Target type of cast is same as the value. Cast is unnecessary")
- .At(expression)
- .Build());
-
- return value;
- }
-
- if (!IsCastAllowed(value.Type, expectedType, false))
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot cast from {value.Type} to {expectedType}")
- .Build());
- }
-
- return new CastNode(expression.Tokens, expectedType, value);
- }
-
- private static bool IsCastAllowed(NubType from, NubType to, bool strict = true)
- {
- // note(nub31): Implicit casts
- switch (from)
- {
- case NubIntType fromInt when to is NubIntType toInt && fromInt.Width < toInt.Width:
- case NubPointerType when to is NubPointerType { BaseType: NubVoidType }:
- case NubConstArrayType constArrayType1 when to is NubArrayType arrayType && constArrayType1.ElementType == arrayType.ElementType:
- case NubConstArrayType constArrayType3 when to is NubSliceType sliceType2 && constArrayType3.ElementType == sliceType2.ElementType:
- {
- return true;
- }
- }
-
- if (!strict)
- {
- // note(nub31): Explicit casts
- switch (from)
- {
- case NubIntType when to is NubIntType:
- case NubIntType when to is NubFloatType:
- case NubFloatType when to is NubIntType:
- case NubFloatType when to is NubFloatType:
- case NubPointerType when to is NubPointerType:
- case NubPointerType when to is NubIntType:
- case NubIntType when to is NubPointerType:
- {
- return true;
- }
- }
- }
-
-
- return false;
- }
-
- private AddressOfNode CheckAddressOf(AddressOfSyntax expression, NubType? expectedType)
- {
- var target = CheckExpression(expression.Target, (expectedType as NubPointerType)?.BaseType);
- if (target is not LValueExpressionNode lvalue)
- {
- throw new TypeCheckerException(Diagnostic.Error("Cannot take address of an rvalue").At(expression).Build());
- }
-
- var type = new NubPointerType(target.Type);
- return new AddressOfNode(expression.Tokens, type, lvalue);
- }
-
- private ExpressionNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression, NubType? _)
- {
- var index = CheckExpression(expression.Index);
- if (index.Type is not NubIntType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Array indexer must be of type int")
- .At(expression.Index)
- .Build());
- }
-
- var target = CheckExpression(expression.Target);
-
- return target.Type switch
- {
- NubArrayType arrayType => new ArrayIndexAccessNode(expression.Tokens, arrayType.ElementType, target, index),
- NubConstArrayType constArrayType => new ConstArrayIndexAccessNode(expression.Tokens, constArrayType.ElementType, target, index),
- NubSliceType sliceType => new SliceIndexAccessNode(expression.Tokens, sliceType.ElementType, target, index),
- _ => throw new TypeCheckerException(Diagnostic.Error($"Cannot use array indexer on type {target.Type}").At(expression).Build())
- };
- }
-
- private ExpressionNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? expectedType)
- {
- var elementType = expectedType switch
- {
- NubArrayType arrayType => arrayType.ElementType,
- NubConstArrayType constArrayType => constArrayType.ElementType,
- NubSliceType sliceType => sliceType.ElementType,
- _ => null
- };
-
- if (elementType == null)
- {
- var firstValue = expression.Values.FirstOrDefault();
- if (firstValue != null)
- {
- elementType = CheckExpression(firstValue).Type;
- }
- }
-
- if (elementType == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Unable to infer type of array initializer")
- .At(expression)
- .WithHelp("Provide a type for a variable assignment")
- .Build());
- }
-
- var values = new List();
- foreach (var valueExpression in expression.Values)
- {
- var value = CheckExpression(valueExpression, elementType);
- if (value.Type != elementType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Value in array initializer is not the same as the array type")
- .At(valueExpression)
- .Build());
- }
-
- values.Add(value);
- }
-
- return expectedType switch
- {
- NubArrayType => new ArrayInitializerNode(expression.Tokens, new NubArrayType(elementType), values),
- NubConstArrayType constArrayType => new ConstArrayInitializerNode(expression.Tokens, constArrayType, values),
- _ => new ConstArrayInitializerNode(expression.Tokens, new NubConstArrayType(elementType, expression.Values.Count), values)
- };
- }
-
- private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression, NubType? expectedType)
- {
- var op = expression.Operator switch
- {
- BinaryOperatorSyntax.Equal => BinaryOperator.Equal,
- BinaryOperatorSyntax.NotEqual => BinaryOperator.NotEqual,
- BinaryOperatorSyntax.GreaterThan => BinaryOperator.GreaterThan,
- BinaryOperatorSyntax.GreaterThanOrEqual => BinaryOperator.GreaterThanOrEqual,
- BinaryOperatorSyntax.LessThan => BinaryOperator.LessThan,
- BinaryOperatorSyntax.LessThanOrEqual => BinaryOperator.LessThanOrEqual,
- BinaryOperatorSyntax.LogicalAnd => BinaryOperator.LogicalAnd,
- BinaryOperatorSyntax.LogicalOr => BinaryOperator.LogicalOr,
- BinaryOperatorSyntax.Plus => BinaryOperator.Plus,
- BinaryOperatorSyntax.Minus => BinaryOperator.Minus,
- BinaryOperatorSyntax.Multiply => BinaryOperator.Multiply,
- BinaryOperatorSyntax.Divide => BinaryOperator.Divide,
- BinaryOperatorSyntax.Modulo => BinaryOperator.Modulo,
- BinaryOperatorSyntax.LeftShift => BinaryOperator.LeftShift,
- BinaryOperatorSyntax.RightShift => BinaryOperator.RightShift,
- BinaryOperatorSyntax.BitwiseAnd => BinaryOperator.BitwiseAnd,
- BinaryOperatorSyntax.BitwiseXor => BinaryOperator.BitwiseXor,
- BinaryOperatorSyntax.BitwiseOr => BinaryOperator.BitwiseOr,
- _ => throw new ArgumentOutOfRangeException()
- };
-
- switch (expression.Operator)
- {
- case BinaryOperatorSyntax.Equal:
- case BinaryOperatorSyntax.NotEqual:
- {
- var left = CheckExpression(expression.Left);
- if (left.Type is not NubIntType and not NubFloatType and not NubBoolType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Equal and not equal operators must must be used with int, float or bool types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
- }
- case BinaryOperatorSyntax.GreaterThan:
- case BinaryOperatorSyntax.GreaterThanOrEqual:
- case BinaryOperatorSyntax.LessThan:
- case BinaryOperatorSyntax.LessThanOrEqual:
- {
- var left = CheckExpression(expression.Left);
- if (left.Type is not NubIntType and not NubFloatType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Greater than and less than operators must must be used with int or float types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
- }
- case BinaryOperatorSyntax.LogicalAnd:
- case BinaryOperatorSyntax.LogicalOr:
- {
- var left = CheckExpression(expression.Left);
- if (left.Type is not NubBoolType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Logical and/or must must be used with bool types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
- }
- case BinaryOperatorSyntax.Plus:
- {
- var left = CheckExpression(expression.Left, expectedType);
- if (left.Type is not NubIntType and not NubFloatType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("The plus operator must only be used with int and float types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
- }
- case BinaryOperatorSyntax.Minus:
- case BinaryOperatorSyntax.Multiply:
- case BinaryOperatorSyntax.Divide:
- case BinaryOperatorSyntax.Modulo:
- {
- var left = CheckExpression(expression.Left, expectedType);
- if (left.Type is not NubIntType and not NubFloatType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Math operators must be used with int or float types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
- }
- case BinaryOperatorSyntax.LeftShift:
- case BinaryOperatorSyntax.RightShift:
- case BinaryOperatorSyntax.BitwiseAnd:
- case BinaryOperatorSyntax.BitwiseXor:
- case BinaryOperatorSyntax.BitwiseOr:
- {
- var left = CheckExpression(expression.Left, expectedType);
- if (left.Type is not NubIntType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Bitwise operators must be used with int types")
- .At(expression.Left)
- .Build());
- }
-
- var right = CheckExpression(expression.Right, left.Type);
- if (right.Type != left.Type)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
- .At(expression.Right)
- .Build());
- }
-
- return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression, NubType? expectedType)
- {
- switch (expression.Operator)
- {
- case UnaryOperatorSyntax.Negate:
- {
- var operand = CheckExpression(expression.Operand, expectedType);
- if (operand.Type is not NubIntType { Signed: true } and not NubFloatType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Negation operator must be used with signed integer or float types")
- .At(expression)
- .Build());
- }
-
- return new UnaryExpressionNode(expression.Tokens, operand.Type, UnaryOperator.Negate, operand);
- }
- case UnaryOperatorSyntax.Invert:
- {
- var operand = CheckExpression(expression.Operand, expectedType);
- if (operand.Type is not NubBoolType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Invert operator must be used with booleans")
- .At(expression)
- .Build());
- }
-
- return new UnaryExpressionNode(expression.Tokens, operand.Type, UnaryOperator.Invert, operand);
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private DereferenceNode CheckDereference(DereferenceSyntax expression, NubType? _)
- {
- var target = CheckExpression(expression.Target);
- if (target.Type is not NubPointerType pointerType)
- {
- throw new TypeCheckerException(Diagnostic.Error($"Cannot dereference non-pointer type {target.Type}").At(expression).Build());
- }
-
- return new DereferenceNode(expression.Tokens, pointerType.BaseType, target);
- }
-
- private FuncCallNode CheckFuncCall(FuncCallSyntax expression, NubType? _)
- {
- var accessor = CheckExpression(expression.Expression);
- if (accessor.Type is not NubFuncType funcType)
- {
- throw new TypeCheckerException(Diagnostic.Error($"Cannot call non-function type {accessor.Type}").At(expression.Expression).Build());
- }
-
- if (expression.Parameters.Count != funcType.Parameters.Count)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Function {funcType} expects {funcType.Parameters.Count} parameters but got {expression.Parameters.Count}")
- .At(expression.Parameters.LastOrDefault(expression))
- .Build());
- }
-
- var parameters = new List();
- for (var i = 0; i < expression.Parameters.Count; i++)
- {
- var parameter = expression.Parameters[i];
- var expectedParameterType = funcType.Parameters[i];
-
- var parameterExpression = CheckExpression(parameter, expectedParameterType);
- if (parameterExpression.Type != expectedParameterType)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Parameter {i + 1} does not match the type {expectedParameterType} for function {funcType}")
- .At(parameter)
- .Build());
- }
-
- parameters.Add(parameterExpression);
- }
-
- return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters);
- }
-
- private ExpressionNode? CheckIdentifier(ExpressionSyntax expression, string moduleName, string name)
- {
- if (!_importedModules.TryGetValue(moduleName, out var module))
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Module {moduleName} not found")
- .WithHelp($"import \"{moduleName}\"")
- .At(expression)
- .Build());
- }
-
- var function = module.Functions(IsCurretModule(moduleName)).FirstOrDefault(x => x.Name == name);
- if (function != null)
- {
- using (BeginRootScope(moduleName))
- {
- var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
- var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
- return new FuncIdentifierNode(expression.Tokens, type, moduleName, name, function.Prototype.ExternSymbol);
- }
- }
-
- var enumDef = module.Enums(IsCurretModule(moduleName)).FirstOrDefault(x => x.Name == name);
- if (enumDef != null)
- {
- return new EnumReferenceIntermediateNode(expression.Tokens, moduleName, name);
- }
-
- return null;
- }
-
- private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression, NubType? _)
- {
- // note(nub31): Local identifiers can be variables or a symbol in a module
- var scopeIdent = Scope.LookupVariable(expression.Name);
- if (scopeIdent != null)
- {
- return new VariableIdentifierNode(expression.Tokens, scopeIdent.Type, expression.Name);
- }
-
- var ident = CheckIdentifier(expression, Scope.Module, expression.Name);
- if (ident == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"There is no identifier named {expression.Name}")
- .At(expression)
- .Build());
- }
-
- return ident;
- }
-
- private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression, NubType? _)
- {
- // note(nub31): Unlike local identifiers, module identifiers does not look for local variables
- var ident = CheckIdentifier(expression, expression.Module, expression.Name);
- if (ident == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Module {expression.Module} does not export a member named {expression.Name}")
- .At(expression)
- .Build());
- }
-
- return ident;
- }
-
- private ExpressionNode CheckStringLiteral(StringLiteralSyntax expression, NubType? expectedType)
- {
- if (expectedType is NubPointerType { BaseType: NubIntType { Signed: true, Width: 8 } })
- {
- return new CStringLiteralNode(expression.Tokens, expression.Value);
- }
-
- return new StringLiteralNode(expression.Tokens, expression.Value);
- }
-
- private ExpressionNode CheckIntLiteral(IntLiteralSyntax expression, NubType? expectedType)
- {
- if (expectedType is NubIntType intType)
- {
- return intType.Width switch
- {
- 8 => intType.Signed ? new I8LiteralNode(expression.Tokens, Convert.ToSByte(expression.Value, expression.Base)) : new U8LiteralNode(expression.Tokens, Convert.ToByte(expression.Value, expression.Base)),
- 16 => intType.Signed ? new I16LiteralNode(expression.Tokens, Convert.ToInt16(expression.Value, expression.Base)) : new U16LiteralNode(expression.Tokens, Convert.ToUInt16(expression.Value, expression.Base)),
- 32 => intType.Signed ? new I32LiteralNode(expression.Tokens, Convert.ToInt32(expression.Value, expression.Base)) : new U32LiteralNode(expression.Tokens, Convert.ToUInt32(expression.Value, expression.Base)),
- 64 => intType.Signed ? new I64LiteralNode(expression.Tokens, Convert.ToInt64(expression.Value, expression.Base)) : new U64LiteralNode(expression.Tokens, Convert.ToUInt64(expression.Value, expression.Base)),
- _ => throw new ArgumentOutOfRangeException()
- };
- }
-
- if (expectedType is NubFloatType floatType)
- {
- return floatType.Width switch
- {
- 32 => new Float32LiteralNode(expression.Tokens, Convert.ToSingle(expression.Value)),
- 64 => new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value)),
- _ => throw new ArgumentOutOfRangeException()
- };
- }
-
- return new I64LiteralNode(expression.Tokens, Convert.ToInt64(expression.Value, expression.Base));
- }
-
- private ExpressionNode CheckFloatLiteral(FloatLiteralSyntax expression, NubType? expectedType)
- {
- if (expectedType is NubFloatType floatType)
- {
- return floatType.Width switch
- {
- 32 => new Float32LiteralNode(expression.Tokens, Convert.ToSingle(expression.Value)),
- 64 => new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value)),
- _ => throw new ArgumentOutOfRangeException()
- };
- }
-
- return new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value));
- }
-
- private BoolLiteralNode CheckBoolLiteral(BoolLiteralSyntax expression, NubType? _)
- {
- return new BoolLiteralNode(expression.Tokens, new NubBoolType(), expression.Value);
- }
-
- private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression, NubType? _)
- {
- var target = CheckExpression(expression.Target);
-
- if (target is EnumReferenceIntermediateNode enumReferenceIntermediate)
- {
- var enumDef = _importedModules[enumReferenceIntermediate.Module]
- .Enums(IsCurretModule(enumReferenceIntermediate.Module))
- .First(x => x.Name == enumReferenceIntermediate.Name);
-
- var field = enumDef.Fields.FirstOrDefault(x => x.Name == expression.Member);
- if (field == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Enum {Scope.Module}::{enumReferenceIntermediate.Name} does not have a field named {expression.Member}")
- .At(enumDef)
- .Build());
- }
-
- var enumType = enumDef.Type != null ? ResolveType(enumDef.Type) : new NubIntType(false, 64);
- if (enumType is not NubIntType enumIntType)
- {
- throw new TypeCheckerException(Diagnostic.Error("Enum type must be an int type").At(enumDef.Type).Build());
- }
-
- return enumIntType.Width switch
- {
- 8 => enumIntType.Signed ? new I8LiteralNode(expression.Tokens, (sbyte)field.Value) : new U8LiteralNode(expression.Tokens, (byte)field.Value),
- 16 => enumIntType.Signed ? new I16LiteralNode(expression.Tokens, (short)field.Value) : new U16LiteralNode(expression.Tokens, (ushort)field.Value),
- 32 => enumIntType.Signed ? new I32LiteralNode(expression.Tokens, (int)field.Value) : new U32LiteralNode(expression.Tokens, (uint)field.Value),
- 64 => enumIntType.Signed ? new I64LiteralNode(expression.Tokens, field.Value) : new U64LiteralNode(expression.Tokens, (ulong)field.Value),
- _ => throw new ArgumentOutOfRangeException()
- };
- }
-
- if (target.Type is NubStructType structType)
- {
- var field = structType.Fields.FirstOrDefault(x => x.Name == expression.Member);
- if (field == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Struct {target.Type} does not have a field with the name {expression.Member}")
- .At(expression)
- .Build());
- }
-
- return new StructFieldAccessNode(expression.Tokens, field.Type, target, expression.Member);
- }
-
- throw new TypeCheckerException(Diagnostic
- .Error($"Cannot access struct member {expression.Member} on type {target.Type}")
- .At(expression)
- .Build());
- }
-
- private StructInitializerNode CheckStructInitializer(StructInitializerSyntax expression, NubType? expectedType)
- {
- NubStructType? structType = null;
-
- if (expression.StructType != null)
- {
- var checkedType = ResolveType(expression.StructType);
- if (checkedType is not NubStructType checkedStructType)
- {
- throw new UnreachableException("Parser fucked up");
- }
-
- structType = checkedStructType;
- }
- else if (expectedType is NubStructType expectedStructType)
- {
- structType = expectedStructType;
- }
-
- if (structType == null)
- {
- throw new TypeCheckerException(Diagnostic
- .Error("Cannot get implicit type of struct")
- .WithHelp("Specify struct type with struct {type_name} syntax")
- .At(expression)
- .Build());
- }
-
- var initializers = new Dictionary();
-
- foreach (var initializer in expression.Initializers)
- {
- var typeField = structType.Fields.FirstOrDefault(x => x.Name == initializer.Key);
- if (typeField == null)
- {
- Diagnostics.AddRange(Diagnostic
- .Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
- .At(initializer.Value)
- .Build());
-
- continue;
- }
-
- initializers.Add(initializer.Key, CheckExpression(initializer.Value, typeField.Type));
- }
-
- var missingFields = structType.Fields
- .Where(x => !x.HasDefaultValue && !initializers.ContainsKey(x.Name))
- .Select(x => x.Name)
- .ToArray();
-
- if (missingFields.Length != 0)
- {
- Diagnostics.Add(Diagnostic
- .Warning($"Fields {string.Join(", ", missingFields)} are not initialized")
- .At(expression)
- .Build());
- }
-
- return new StructInitializerNode(expression.Tokens, structType, initializers);
- }
-
- private BlockNode CheckBlock(BlockSyntax node)
- {
- using (BeginScope())
- {
- var statements = new List();
- foreach (var statement in node.Statements)
- {
- try
- {
- statements.Add(CheckStatement(statement));
- }
- catch (TypeCheckerException e)
- {
- Diagnostics.Add(e.Diagnostic);
- }
- }
-
- return new BlockNode(node.Tokens, statements);
- }
- }
-
- private StatementNode CheckStatement(StatementSyntax statement)
- {
- return statement switch
- {
- AssignmentSyntax assignmentStmt => CheckAssignment(assignmentStmt),
- BlockSyntax blockStmt => CheckBlock(blockStmt),
- BreakSyntax => new BreakNode(statement.Tokens),
- ContinueSyntax => new ContinueNode(statement.Tokens),
- IfSyntax ifStmt => CheckIf(ifStmt),
- ReturnSyntax retStmt => CheckReturn(retStmt),
- StatementExpressionSyntax stmtExpr => CheckStatementExpression(stmtExpr),
- VariableDeclarationSyntax varDeclStmt => CheckVariableDeclaration(varDeclStmt),
- WhileSyntax whileStmt => CheckWhile(whileStmt),
- DeferSyntax defer => new DeferNode(statement.Tokens, CheckStatement(defer.Statement)),
- ForSyntax forSyntax => CheckFor(forSyntax),
- _ => throw new ArgumentOutOfRangeException(nameof(statement))
- };
- }
-
- private NubType ResolveType(TypeSyntax type)
- {
- return type switch
- {
- ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType)),
- BoolTypeSyntax => new NubBoolType(),
- IntTypeSyntax i => new NubIntType(i.Signed, i.Width),
- FloatTypeSyntax f => new NubFloatType(f.Width),
- FuncTypeSyntax func => new NubFuncType(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)),
- SliceTypeSyntax slice => new NubSliceType(ResolveType(slice.BaseType)),
- ConstArrayTypeSyntax arr => new NubConstArrayType(ResolveType(arr.BaseType), arr.Size),
- PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
- StringTypeSyntax => new NubStringType(),
- CustomTypeSyntax c => ResolveCustomType(c),
- VoidTypeSyntax => new NubVoidType(),
- _ => throw new NotSupportedException($"Unknown type syntax: {type}")
- };
- }
-
- private NubType ResolveCustomType(CustomTypeSyntax customType)
- {
- if (!_importedModules.TryGetValue(customType.Module ?? Scope.Module, out var module))
- {
- throw new TypeCheckerException(Diagnostic
- .Error($"Module {customType.Module ?? Scope.Module} not found")
- .WithHelp($"import \"{customType.Module ?? Scope.Module}\"")
- .At(customType)
- .Build());
- }
-
- var enumDef = module.Enums(IsCurretModule(customType.Module)).FirstOrDefault(x => x.Name == customType.Name);
- if (enumDef != null)
- {
- return enumDef.Type != null ? ResolveType(enumDef.Type) : new NubIntType(false, 64);
- }
-
- var structDef = module.Structs(IsCurretModule(customType.Module)).FirstOrDefault(x => x.Name == customType.Name);
- if (structDef != null)
- {
- var key = (customType.Module ?? Scope.Module, customType.Name);
-
- if (_typeCache.TryGetValue(key, out var cachedType))
- {
- return cachedType;
- }
-
- if (!_resolvingTypes.Add(key))
- {
- var placeholder = new NubStructType(customType.Module ?? Scope.Module, customType.Name, []);
- _typeCache[key] = placeholder;
- return placeholder;
- }
-
- try
- {
- var result = new NubStructType(customType.Module ?? Scope.Module, structDef.Name, []);
- _typeCache[key] = result;
-
- var fields = structDef.Fields
- .Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
- .ToList();
-
- result.Fields.AddRange(fields);
- return result;
- }
- finally
- {
- _resolvingTypes.Remove(key);
- }
- }
-
- throw new TypeCheckerException(Diagnostic
- .Error($"Type {customType.Name} not found in module {customType.Module ?? Scope.Module}")
- .At(customType)
- .Build());
- }
-
- private bool IsCurretModule(string? module)
- {
- if (module == null)
- {
- return true;
- }
-
- return module == Scope.Module;
- }
-}
-
-public record Variable(string Name, NubType Type);
-
-public class Scope(string module, Scope? parent = null)
-{
- private NubType? _returnType;
- private readonly List _variables = [];
- public string Module { get; } = module;
-
- public void DeclareVariable(Variable variable)
- {
- _variables.Add(variable);
- }
-
- public void SetReturnType(NubType returnType)
- {
- _returnType = returnType;
- }
-
- public NubType? GetReturnType()
- {
- return _returnType ?? parent?.GetReturnType();
- }
-
- public Variable? LookupVariable(string name)
- {
- var variable = _variables.FirstOrDefault(x => x.Name == name);
- if (variable != null)
- {
- return variable;
- }
-
- return parent?.LookupVariable(name);
- }
-
- public Scope SubScope()
- {
- return new Scope(Module, this);
- }
-}
-
-public class TypeCheckerException : Exception
-{
- public Diagnostic Diagnostic { get; }
-
- public TypeCheckerException(Diagnostic diagnostic) : base(diagnostic.Message)
- {
- Diagnostic = diagnostic;
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Diagnostics/Diagnostic.cs b/compiler/NubLang/Diagnostics/Diagnostic.cs
deleted file mode 100644
index bf3cf54..0000000
--- a/compiler/NubLang/Diagnostics/Diagnostic.cs
+++ /dev/null
@@ -1,398 +0,0 @@
-using System.Text;
-using NubLang.Syntax;
-
-namespace NubLang.Diagnostics;
-
-public class Diagnostic
-{
- public class DiagnosticBuilder
- {
- private readonly DiagnosticSeverity _severity;
- private readonly string _message;
- private SourceSpan? _span;
- private string? _help;
-
- public DiagnosticBuilder(DiagnosticSeverity severity, string message)
- {
- _severity = severity;
- _message = message;
- }
-
- public DiagnosticBuilder At(SyntaxNode? node)
- {
- if (node != null)
- {
- _span = SourceSpan.Merge(node.Tokens.Select(x => x.Span));
- }
-
- return this;
- }
-
- public DiagnosticBuilder At(Token? token)
- {
- if (token != null)
- {
- At(token.Span);
- }
-
- return this;
- }
-
- public DiagnosticBuilder At(SourceSpan? span)
- {
- if (span != null)
- {
- _span = span;
- }
-
- return this;
- }
-
- public DiagnosticBuilder At(string filePath, int line, int column)
- {
- _span = new SourceSpan(filePath, new SourceLocation(line, column), new SourceLocation(line, column));
- return this;
- }
-
- public DiagnosticBuilder WithHelp(string help)
- {
- _help = help;
- return this;
- }
-
- public Diagnostic Build() => new(_severity, _message, _help, _span);
- }
-
- public static DiagnosticBuilder Error(string message) => new(DiagnosticSeverity.Error, message);
- public static DiagnosticBuilder Warning(string message) => new(DiagnosticSeverity.Warning, message);
- public static DiagnosticBuilder Info(string message) => new(DiagnosticSeverity.Info, message);
-
- public DiagnosticSeverity Severity { get; }
- public string Message { get; }
- public string? Help { get; }
- public SourceSpan? Span { get; }
-
- private Diagnostic(DiagnosticSeverity severity, string message, string? help, SourceSpan? span)
- {
- Severity = severity;
- Message = message;
- Help = help;
- Span = span;
- }
-
- public string FormatANSI()
- {
- var sb = new StringBuilder();
-
- sb.Append(Severity switch
- {
- DiagnosticSeverity.Error => ConsoleColors.Colorize("error", ConsoleColors.Bold + ConsoleColors.Red),
- DiagnosticSeverity.Warning => ConsoleColors.Colorize("warning", ConsoleColors.Bold + ConsoleColors.Yellow),
- DiagnosticSeverity.Info => ConsoleColors.Colorize("info", ConsoleColors.Bold + ConsoleColors.Blue),
- _ => ConsoleColors.Colorize("unknown", ConsoleColors.Bold + ConsoleColors.White)
- });
-
- if (Span.HasValue)
- {
- sb.Append(ConsoleColors.Colorize($" at {Span.Value}", ConsoleColors.Faint));
- }
-
- sb.Append(": ");
- sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
-
- if (Span.HasValue)
- {
- sb.AppendLine();
- var text = File.ReadAllText(Span.Value.FilePath);
-
- var tokenizer = new Tokenizer(Span.Value.FilePath, text);
- tokenizer.Tokenize();
-
- var lines = text.Split('\n');
-
- var startLine = Span.Value.Start.Line;
- var endLine = Span.Value.End.Line;
-
- const int CONTEXT_LINES = 3;
-
- var contextStartLine = Math.Max(1, startLine - CONTEXT_LINES);
- var contextEndLine = Math.Min(lines.Length, endLine + CONTEXT_LINES);
-
- var numberPadding = contextEndLine.ToString().Length;
-
- var codePadding = 0;
- for (var i = contextStartLine - 1; i < contextEndLine && i < lines.Length; i++)
- {
- var lineLength = lines[i].Length;
- if (lineLength > codePadding)
- {
- codePadding = lineLength;
- }
- }
-
- sb.Append('╭');
- sb.Append(new string('─', numberPadding + 2));
- sb.Append('┬');
- sb.Append(new string('─', codePadding + 2));
- sb.Append('╮');
- sb.AppendLine();
-
- for (var i = contextStartLine; i <= contextEndLine; i++)
- {
- var line = lines[i - 1];
-
- sb.Append("│ ");
- sb.Append(i.ToString().PadRight(numberPadding));
- sb.Append(" │ ");
- sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
- // sb.Append(line.PadRight(codePadding));
- sb.Append(" │");
- sb.AppendLine();
-
- if (i >= startLine && i <= endLine)
- {
- var markerStartColumn = 1;
- var markerEndColumn = line.Length;
-
- if (i == startLine)
- {
- markerStartColumn = Span.Value.Start.Column;
- }
-
- if (i == endLine)
- {
- markerEndColumn = Span.Value.End.Column;
- }
-
- var markerLength = markerEndColumn - markerStartColumn;
- var marker = new string('^', markerLength);
-
- var markerColor = Severity switch
- {
- DiagnosticSeverity.Info => ConsoleColors.Blue,
- DiagnosticSeverity.Warning => ConsoleColors.Yellow,
- DiagnosticSeverity.Error => ConsoleColors.Red,
- _ => ConsoleColors.White
- };
-
- sb.Append("│ ");
- sb.Append(new string(' ', numberPadding));
- sb.Append(" │ ");
- sb.Append(new string(' ', markerStartColumn - 1));
- sb.Append(ConsoleColors.Colorize(marker, markerColor));
- sb.Append(new string(' ', codePadding - (markerStartColumn - 1) - markerLength));
- sb.Append(" │");
- sb.AppendLine();
- }
- }
-
- sb.Append('╰');
- sb.Append(new string('─', numberPadding + 2));
- sb.Append('┴');
- sb.Append(new string('─', codePadding + 2));
- sb.Append('╯');
- }
-
- if (Help != null)
- {
- sb.AppendLine();
- sb.Append(ConsoleColors.Colorize($"help: {Help}", ConsoleColors.Cyan));
- }
-
- return sb.ToString();
- }
-
- private static string ApplySyntaxHighlighting(string line, int lineNumber, List tokens)
- {
- var sb = new StringBuilder();
- var lineTokens = tokens
- .Where(t => t.Span.Start.Line == lineNumber)
- .OrderBy(t => t.Span.Start.Column)
- .ToList();
-
- if (lineTokens.Count == 0)
- {
- return line;
- }
-
- var currentColumn = 1;
-
- foreach (var token in lineTokens)
- {
- var tokenStart = token.Span.Start.Column;
- var tokenEnd = token.Span.End.Column;
-
- if (tokenStart > currentColumn && currentColumn - 1 < line.Length)
- {
- var beforeLength = Math.Min(tokenStart - currentColumn, line.Length - (currentColumn - 1));
- if (beforeLength > 0)
- {
- var beforeToken = line.Substring(currentColumn - 1, beforeLength);
- sb.Append(beforeToken);
- }
- }
-
- var tokenLength = tokenEnd - tokenStart;
- if (tokenStart >= 1 && tokenStart - 1 < line.Length && tokenLength > 0)
- {
- var availableLength = line.Length - (tokenStart - 1);
- var actualLength = Math.Min(tokenLength, availableLength);
-
- if (actualLength > 0)
- {
- var tokenText = line.Substring(tokenStart - 1, actualLength);
- var coloredToken = ColorizeToken(token, tokenText);
- sb.Append(coloredToken);
- }
- }
-
- currentColumn = tokenEnd;
- }
-
- if (currentColumn - 1 < line.Length)
- {
- var remaining = line[(currentColumn - 1)..];
- sb.Append(remaining);
- }
-
- return sb.ToString();
- }
-
- private static string ColorizeToken(Token token, string tokenText)
- {
- switch (token)
- {
- case IdentifierToken:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.BrightWhite);
- }
- case StringLiteralToken:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.Green);
- }
- case IntLiteralToken:
- case FloatLiteralToken:
- case BoolLiteralToken:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.Magenta);
- }
- case SymbolToken symbolToken:
- {
- switch (symbolToken.Symbol)
- {
- case Symbol.Func:
- case Symbol.Return:
- case Symbol.If:
- case Symbol.Else:
- case Symbol.While:
- case Symbol.Break:
- case Symbol.Continue:
- case Symbol.Struct:
- case Symbol.Let:
- case Symbol.Extern:
- case Symbol.For:
- case Symbol.In:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.Bold + ConsoleColors.Blue);
- }
- case Symbol.Assign:
- case Symbol.Bang:
- case Symbol.Equal:
- case Symbol.NotEqual:
- case Symbol.LessThan:
- case Symbol.LessThanOrEqual:
- case Symbol.GreaterThan:
- case Symbol.GreaterThanOrEqual:
- case Symbol.Plus:
- case Symbol.Minus:
- case Symbol.Star:
- case Symbol.ForwardSlash:
- case Symbol.Caret:
- case Symbol.Ampersand:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.Yellow);
- }
- case Symbol.Colon:
- case Symbol.OpenParen:
- case Symbol.CloseParen:
- case Symbol.OpenBrace:
- case Symbol.CloseBrace:
- case Symbol.OpenBracket:
- case Symbol.CloseBracket:
- case Symbol.Comma:
- case Symbol.Period:
- case Symbol.Semi:
- {
- return ConsoleColors.Colorize(tokenText, ConsoleColors.BrightBlack);
- }
- }
-
- break;
- }
- }
-
- return tokenText;
- }
-}
-
-public enum DiagnosticSeverity
-{
- Info,
- Warning,
- Error
-}
-
-public static class ConsoleColors
-{
- public const string Reset = "\e[0m";
- public const string Bold = "\e[1m";
- public const string Faint = "\e[2m";
- public const string Italic = "\e[3m";
- public const string Underline = "\e[4m";
- public const string SlowBlink = "\e[5m";
- public const string RapidBlink = "\e[6m";
- public const string SwapBgAndFg = "\e[7m";
- public const string Conceal = "\e[8m";
- public const string CrossedOut = "\e[9m";
-
- public const string DefaultFont = "\e[10m";
- public const string AltFont1 = "\e[11m";
- public const string AltFont2 = "\e[12m";
- public const string AltFont3 = "\e[13m";
- public const string AltFont4 = "\e[14m";
- public const string AltFont5 = "\e[15m";
- public const string AltFont6 = "\e[16m";
- public const string AltFont7 = "\e[17m";
- public const string AltFont8 = "\e[18m";
- public const string AltFont9 = "\e[19m";
-
- public const string Black = "\e[30m";
- public const string Red = "\e[31m";
- public const string Green = "\e[32m";
- public const string Yellow = "\e[33m";
- public const string Blue = "\e[34m";
- public const string Magenta = "\e[35m";
- public const string Cyan = "\e[36m";
- public const string White = "\e[37m";
-
- public const string BrightBlack = "\e[90m";
- public const string BrightRed = "\e[91m";
- public const string BrightGreen = "\e[92m";
- public const string BrightYellow = "\e[93m";
- public const string BrightBlue = "\e[94m";
- public const string BrightMagenta = "\e[95m";
- public const string BrightCyan = "\e[96m";
- public const string BrightWhite = "\e[97m";
-
- private static bool IsColorSupported()
- {
- var term = Environment.GetEnvironmentVariable("TERM");
- var colorTerm = Environment.GetEnvironmentVariable("COLORTERM");
- return !string.IsNullOrEmpty(term) || !string.IsNullOrEmpty(colorTerm) || !Console.IsOutputRedirected;
- }
-
- public static string Colorize(string text, string color)
- {
- return IsColorSupported() ? $"{color}{text}{Reset}" : text;
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Diagnostics/SourceSpan.cs b/compiler/NubLang/Diagnostics/SourceSpan.cs
deleted file mode 100644
index 121fe6e..0000000
--- a/compiler/NubLang/Diagnostics/SourceSpan.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-namespace NubLang.Diagnostics;
-
-public readonly struct SourceSpan : IEquatable, IComparable
-{
- public static SourceSpan Merge(params IEnumerable spans)
- {
- var spanArray = spans as SourceSpan[] ?? spans.ToArray();
- if (spanArray.Length == 0)
- {
- return new SourceSpan(string.Empty, new SourceLocation(0, 0), new SourceLocation(0, 0));
- }
-
- var minStart = spanArray.Min(s => s.Start);
- var maxEnd = spanArray.Max(s => s.End);
-
- return new SourceSpan(spanArray[0].FilePath, minStart, maxEnd);
- }
-
- public SourceSpan(string filePath, SourceLocation start, SourceLocation end)
- {
- if (start > end)
- {
- throw new ArgumentException("Start location cannot be after end location");
- }
-
- FilePath = filePath;
- Start = start;
- End = end;
- }
-
- public string FilePath { get; }
- public SourceLocation Start { get; }
- public SourceLocation End { get; }
-
- public override string ToString()
- {
- if (Start == End)
- {
- return $"{FilePath}:{Start}";
- }
-
- if (Start.Line == End.Line)
- {
- return Start.Column == End.Column ? $"{FilePath}:{Start}" : $"{FilePath}:{Start.Line}:{Start.Column}-{End.Column}";
- }
-
- return $"{FilePath}:{Start}-{End}";
- }
-
- public bool Equals(SourceSpan other) => Start == other.Start && End == other.End;
- public override bool Equals(object? obj) => obj is SourceSpan other && Equals(other);
- public override int GetHashCode() => HashCode.Combine(typeof(SourceSpan), Start, End);
-
- public static bool operator ==(SourceSpan left, SourceSpan right) => Equals(left, right);
- public static bool operator !=(SourceSpan left, SourceSpan right) => !Equals(left, right);
-
- public static bool operator <(SourceSpan left, SourceSpan right) => left.CompareTo(right) < 0;
- public static bool operator <=(SourceSpan left, SourceSpan right) => left.CompareTo(right) <= 0;
- public static bool operator >(SourceSpan left, SourceSpan right) => left.CompareTo(right) > 0;
- public static bool operator >=(SourceSpan left, SourceSpan right) => left.CompareTo(right) >= 0;
-
- public int CompareTo(SourceSpan other)
- {
- var startComparison = Start.CompareTo(other.Start);
- return startComparison != 0 ? startComparison : End.CompareTo(other.End);
- }
-}
-
-public readonly struct SourceLocation : IEquatable, IComparable
-{
- public SourceLocation(int line, int column)
- {
- Line = line;
- Column = column;
- }
-
- public int Line { get; }
- public int Column { get; }
-
- public override string ToString()
- {
- return $"{Line}:{Column}";
- }
-
- public override bool Equals(object? obj)
- {
- return obj is SourceLocation other && Equals(other);
- }
-
- public bool Equals(SourceLocation other)
- {
- return Line == other.Line && Column == other.Column;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(typeof(SourceLocation), Line, Column);
- }
-
- public static bool operator ==(SourceLocation left, SourceLocation right) => Equals(left, right);
- public static bool operator !=(SourceLocation left, SourceLocation right) => !Equals(left, right);
- public static bool operator <(SourceLocation left, SourceLocation right) => left.Line < right.Line || (left.Line == right.Line && left.Column < right.Column);
- public static bool operator >(SourceLocation left, SourceLocation right) => left.Line > right.Line || (left.Line == right.Line && left.Column > right.Column);
- public static bool operator <=(SourceLocation left, SourceLocation right) => left.Line <= right.Line || (left.Line == right.Line && left.Column <= right.Column);
- public static bool operator >=(SourceLocation left, SourceLocation right) => left.Line >= right.Line || (left.Line == right.Line && left.Column >= right.Column);
-
- public int CompareTo(SourceLocation other)
- {
- var lineComparison = Line.CompareTo(other.Line);
- return lineComparison != 0 ? lineComparison : Column.CompareTo(other.Column);
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/NubLang.csproj b/compiler/NubLang/NubLang.csproj
deleted file mode 100644
index b682a68..0000000
--- a/compiler/NubLang/NubLang.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- true
-
-
-
diff --git a/compiler/NubLang/Sugar/DeSugar.cs b/compiler/NubLang/Sugar/DeSugar.cs
deleted file mode 100644
index 6856ab8..0000000
--- a/compiler/NubLang/Sugar/DeSugar.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace NubLang.Sugar;
-
-public class DeSugar
-{
-
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Syntax/Module.cs b/compiler/NubLang/Syntax/Module.cs
deleted file mode 100644
index b5776ae..0000000
--- a/compiler/NubLang/Syntax/Module.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace NubLang.Syntax;
-
-public sealed class Module
-{
- public static Dictionary Collect(List syntaxTrees)
- {
- var modules = new Dictionary();
- foreach (var syntaxTree in syntaxTrees)
- {
- if (!modules.TryGetValue(syntaxTree.ModuleName, out var module))
- {
- module = new Module();
- modules.Add(syntaxTree.ModuleName, module);
- }
-
- module._definitions.AddRange(syntaxTree.Definitions);
- }
-
- return modules;
- }
-
- private readonly List _definitions = [];
-
- public List Structs(bool includePrivate)
- {
- return _definitions
- .OfType()
- .Where(x => x.Exported || includePrivate)
- .ToList();
- }
-
- public List Functions(bool includePrivate)
- {
- return _definitions
- .OfType()
- .Where(x => x.Exported || includePrivate)
- .ToList();
- }
-
- public List Enums(bool includePrivate)
- {
- return _definitions
- .OfType()
- .Where(x => x.Exported || includePrivate)
- .ToList();
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Syntax/Parser.cs b/compiler/NubLang/Syntax/Parser.cs
deleted file mode 100644
index b6aacd6..0000000
--- a/compiler/NubLang/Syntax/Parser.cs
+++ /dev/null
@@ -1,951 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using NubLang.Diagnostics;
-
-namespace NubLang.Syntax;
-
-public sealed class Parser
-{
- private List _tokens = [];
- private int _tokenIndex;
-
- private Token? CurrentToken => _tokenIndex < _tokens.Count ? _tokens[_tokenIndex] : null;
- private bool HasToken => CurrentToken != null;
-
- public List Diagnostics { get; } = [];
-
- public SyntaxTree Parse(List tokens)
- {
- Diagnostics.Clear();
- _tokens = tokens;
- _tokenIndex = 0;
-
- string? moduleName = null;
- var imports = new List();
- var definitions = new List();
-
- while (HasToken)
- {
- try
- {
- var startIndex = _tokenIndex;
-
- if (TryExpectSymbol(Symbol.Import))
- {
- var name = ExpectStringLiteral();
- if (imports.Contains(name.Value))
- {
- Diagnostics.Add(Diagnostic
- .Warning($"Module {name.Value} is imported twice")
- .At(name)
- .WithHelp($"Remove duplicate import \"{name.Value}\"")
- .Build());
- }
- else
- {
- imports.Add(name.Value);
- }
-
- continue;
- }
-
- if (TryExpectSymbol(Symbol.Module))
- {
- if (moduleName != null)
- {
- throw new ParseException(Diagnostic
- .Error("Module is declared more than once")
- .At(CurrentToken)
- .WithHelp("Remove duplicate module declaration")
- .Build());
- }
-
- moduleName = ExpectStringLiteral().Value;
- continue;
- }
-
- var exported = TryExpectSymbol(Symbol.Export);
-
- if (TryExpectSymbol(Symbol.Extern))
- {
- var externSymbol = ExpectStringLiteral();
- ExpectSymbol(Symbol.Func);
- definitions.Add(ParseFunc(startIndex, exported, externSymbol.Value));
- continue;
- }
-
- var keyword = ExpectSymbol();
- DefinitionSyntax definition = keyword.Symbol switch
- {
- Symbol.Func => ParseFunc(startIndex, exported, null),
- Symbol.Struct => ParseStruct(startIndex, exported),
- Symbol.Enum => ParseEnum(startIndex, exported),
- _ => throw new ParseException(Diagnostic
- .Error($"Expected 'func', 'struct', 'enum', 'import' or 'module' but found '{keyword.Symbol}'")
- .WithHelp("Valid top level statements are 'func', 'struct', 'enum', 'import' and 'module'")
- .At(keyword)
- .Build())
- };
-
- definitions.Add(definition);
- }
- catch (ParseException e)
- {
- Diagnostics.Add(e.Diagnostic);
- while (HasToken)
- {
- if (CurrentToken is SymbolToken { Symbol: Symbol.Extern or Symbol.Func or Symbol.Struct })
- {
- break;
- }
-
- Next();
- }
- }
- }
-
- return new SyntaxTree(definitions, moduleName ?? "default", imports);
- }
-
- private FuncParameterSyntax ParseFuncParameter()
- {
- var startIndex = _tokenIndex;
- var name = ExpectIdentifier();
- ExpectSymbol(Symbol.Colon);
- var type = ParseType();
-
- return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
- }
-
- private FuncSyntax ParseFunc(int startIndex, bool exported, string? externSymbol)
- {
- var name = ExpectIdentifier();
- List parameters = [];
-
- ExpectSymbol(Symbol.OpenParen);
-
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- parameters.Add(ParseFuncParameter());
-
- if (!TryExpectSymbol(Symbol.Comma))
- {
- ExpectSymbol(Symbol.CloseParen);
- break;
- }
- }
-
- var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([]);
-
- var prototype = new FuncPrototypeSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, parameters, returnType);
-
- BlockSyntax? body = null;
- var bodyStartIndex = _tokenIndex;
- if (TryExpectSymbol(Symbol.OpenBrace))
- {
- body = ParseBlock(bodyStartIndex);
- }
-
- return new FuncSyntax(GetTokens(startIndex), prototype, body);
- }
-
- private StructSyntax ParseStruct(int startIndex, bool exported)
- {
- var name = ExpectIdentifier();
-
- ExpectSymbol(Symbol.OpenBrace);
-
- List fields = [];
-
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- var memberStartIndex = _tokenIndex;
-
- var fieldName = ExpectIdentifier().Value;
- ExpectSymbol(Symbol.Colon);
- var fieldType = ParseType();
-
- ExpressionSyntax? fieldValue = null;
-
- if (TryExpectSymbol(Symbol.Assign))
- {
- fieldValue = ParseExpression();
- }
-
- fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
- }
-
- return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields);
- }
-
- private EnumSyntax ParseEnum(int startIndex, bool exported)
- {
- var name = ExpectIdentifier();
-
- TypeSyntax? type = null;
-
- if (TryExpectSymbol(Symbol.Colon))
- {
- type = ParseType();
- }
-
- List fields = [];
-
- ExpectSymbol(Symbol.OpenBrace);
-
- long value = -1;
-
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- var memberStartIndex = _tokenIndex;
- var fieldName = ExpectIdentifier().Value;
- long fieldValue;
-
- if (TryExpectSymbol(Symbol.Assign))
- {
- if (!TryExpectIntLiteral(out var intLiteralToken))
- {
- throw new ParseException(Diagnostic
- .Error("Value of enum field must be an integer literal")
- .At(CurrentToken)
- .Build());
- }
-
- fieldValue = Convert.ToInt64(intLiteralToken.Value, intLiteralToken.Base);
- value = fieldValue;
- }
- else
- {
- fieldValue = value + 1;
- value = fieldValue;
- }
-
- fields.Add(new EnumFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldValue));
- }
-
- return new EnumSyntax(GetTokens(startIndex), name.Value, exported, type, fields);
- }
-
- private StatementSyntax ParseStatement()
- {
- var startIndex = _tokenIndex;
-
- if (TryExpectSymbol(out var symbol))
- {
- switch (symbol)
- {
- case Symbol.OpenBrace:
- return ParseBlock(startIndex);
- case Symbol.Return:
- return ParseReturn(startIndex);
- case Symbol.If:
- return ParseIf(startIndex);
- case Symbol.While:
- return ParseWhile(startIndex);
- case Symbol.For:
- return ParseFor(startIndex);
- case Symbol.Let:
- return ParseVariableDeclaration(startIndex);
- case Symbol.Defer:
- return ParseDefer(startIndex);
- case Symbol.Break:
- return new BreakSyntax(GetTokens(startIndex));
- case Symbol.Continue:
- return new ContinueSyntax(GetTokens(startIndex));
- }
- }
-
- var expr = ParseExpression();
-
- if (TryExpectSymbol(Symbol.Assign))
- {
- var value = ParseExpression();
- return new AssignmentSyntax(GetTokens(startIndex), expr, value);
- }
-
- return new StatementExpressionSyntax(GetTokens(startIndex), expr);
- }
-
- private VariableDeclarationSyntax ParseVariableDeclaration(int startIndex)
- {
- var name = ExpectIdentifier().Value;
-
- TypeSyntax? explicitType = null;
- if (TryExpectSymbol(Symbol.Colon))
- {
- explicitType = ParseType();
- }
-
- ExpressionSyntax? assignment = null;
- if (TryExpectSymbol(Symbol.Assign))
- {
- assignment = ParseExpression();
- }
-
- return new VariableDeclarationSyntax(GetTokens(startIndex), name, explicitType, assignment);
- }
-
- private DeferSyntax ParseDefer(int startIndex)
- {
- var statement = ParseStatement();
- return new DeferSyntax(GetTokens(startIndex), statement);
- }
-
- private ReturnSyntax ParseReturn(int startIndex)
- {
- ExpressionSyntax? value = null;
-
- if (!TryExpectSymbol(Symbol.Semi))
- {
- value = ParseExpression();
- }
-
- return new ReturnSyntax(GetTokens(startIndex), value);
- }
-
- private IfSyntax ParseIf(int startIndex)
- {
- var condition = ParseExpression();
- var body = ParseBlock();
-
- Variant? elseStatement = null;
-
- var elseStartIndex = _tokenIndex;
- if (TryExpectSymbol(Symbol.Else))
- {
- if (TryExpectSymbol(Symbol.If))
- {
- elseStatement = (Variant)ParseIf(elseStartIndex);
- }
- else
- {
- elseStatement = (Variant)ParseBlock();
- }
- }
-
- return new IfSyntax(GetTokens(startIndex), condition, body, elseStatement);
- }
-
- private WhileSyntax ParseWhile(int startIndex)
- {
- var condition = ParseExpression();
- var body = ParseBlock();
- return new WhileSyntax(GetTokens(startIndex), condition, body);
- }
-
- private ForSyntax ParseFor(int startIndex)
- {
- var itemName = ExpectIdentifier().Value;
- string? indexName = null;
-
- if (TryExpectSymbol(Symbol.Comma))
- {
- indexName = ExpectIdentifier().Value;
- }
-
- ExpectSymbol(Symbol.In);
- var target = ParseExpression();
- var body = ParseBlock();
-
- return new ForSyntax(GetTokens(startIndex), itemName, indexName, target, body);
- }
-
- private ExpressionSyntax ParseExpression(int precedence = 0)
- {
- var startIndex = _tokenIndex;
- var left = ParsePrimaryExpression();
-
- while (CurrentToken is SymbolToken symbolToken && TryGetBinaryOperator(symbolToken.Symbol, out var op) && GetBinaryOperatorPrecedence(op.Value) >= precedence)
- {
- Next();
- var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
- left = new BinaryExpressionSyntax(GetTokens(startIndex), left, op.Value, right);
- }
-
- return left;
- }
-
- private static int GetBinaryOperatorPrecedence(BinaryOperatorSyntax operatorSyntax)
- {
- return operatorSyntax switch
- {
- BinaryOperatorSyntax.Multiply => 10,
- BinaryOperatorSyntax.Divide => 10,
- BinaryOperatorSyntax.Modulo => 10,
-
- BinaryOperatorSyntax.Plus => 9,
- BinaryOperatorSyntax.Minus => 9,
-
- BinaryOperatorSyntax.LeftShift => 8,
- BinaryOperatorSyntax.RightShift => 8,
-
- BinaryOperatorSyntax.GreaterThan => 7,
- BinaryOperatorSyntax.GreaterThanOrEqual => 7,
- BinaryOperatorSyntax.LessThan => 7,
- BinaryOperatorSyntax.LessThanOrEqual => 7,
-
- BinaryOperatorSyntax.Equal => 7,
- BinaryOperatorSyntax.NotEqual => 7,
-
- BinaryOperatorSyntax.BitwiseAnd => 6,
- BinaryOperatorSyntax.BitwiseXor => 5,
- BinaryOperatorSyntax.BitwiseOr => 4,
-
- BinaryOperatorSyntax.LogicalAnd => 3,
- BinaryOperatorSyntax.LogicalOr => 2,
-
- _ => throw new ArgumentOutOfRangeException(nameof(operatorSyntax), operatorSyntax, null)
- };
- }
-
- private bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryOperatorSyntax? binaryExpressionOperator)
- {
- switch (symbol)
- {
- case Symbol.Equal:
- binaryExpressionOperator = BinaryOperatorSyntax.Equal;
- return true;
- case Symbol.NotEqual:
- binaryExpressionOperator = BinaryOperatorSyntax.NotEqual;
- return true;
- case Symbol.LessThan:
- binaryExpressionOperator = BinaryOperatorSyntax.LessThan;
- return true;
- case Symbol.LessThanOrEqual:
- binaryExpressionOperator = BinaryOperatorSyntax.LessThanOrEqual;
- return true;
- case Symbol.GreaterThan:
- binaryExpressionOperator = BinaryOperatorSyntax.GreaterThan;
- return true;
- case Symbol.GreaterThanOrEqual:
- binaryExpressionOperator = BinaryOperatorSyntax.GreaterThanOrEqual;
- return true;
- case Symbol.And:
- binaryExpressionOperator = BinaryOperatorSyntax.LogicalAnd;
- return true;
- case Symbol.Or:
- binaryExpressionOperator = BinaryOperatorSyntax.LogicalOr;
- return true;
- case Symbol.Plus:
- binaryExpressionOperator = BinaryOperatorSyntax.Plus;
- return true;
- case Symbol.Minus:
- binaryExpressionOperator = BinaryOperatorSyntax.Minus;
- return true;
- case Symbol.Star:
- binaryExpressionOperator = BinaryOperatorSyntax.Multiply;
- return true;
- case Symbol.ForwardSlash:
- binaryExpressionOperator = BinaryOperatorSyntax.Divide;
- return true;
- case Symbol.Percent:
- binaryExpressionOperator = BinaryOperatorSyntax.Modulo;
- return true;
- case Symbol.LeftShift:
- binaryExpressionOperator = BinaryOperatorSyntax.LeftShift;
- return true;
- case Symbol.RightShift:
- binaryExpressionOperator = BinaryOperatorSyntax.RightShift;
- return true;
- case Symbol.Ampersand:
- binaryExpressionOperator = BinaryOperatorSyntax.BitwiseAnd;
- return true;
- case Symbol.Pipe:
- binaryExpressionOperator = BinaryOperatorSyntax.BitwiseOr;
- return true;
- case Symbol.Caret:
- binaryExpressionOperator = BinaryOperatorSyntax.BitwiseXor;
- return true;
- default:
- binaryExpressionOperator = null;
- return false;
- }
- }
-
- private ExpressionSyntax ParsePrimaryExpression()
- {
- var startIndex = _tokenIndex;
- var token = ExpectToken();
- var expr = token switch
- {
- BoolLiteralToken boolLiteral => new BoolLiteralSyntax(GetTokens(startIndex), boolLiteral.Value),
- StringLiteralToken stringLiteral => new StringLiteralSyntax(GetTokens(startIndex), stringLiteral.Value),
- FloatLiteralToken floatLiteral => new FloatLiteralSyntax(GetTokens(startIndex), floatLiteral.Value),
- IntLiteralToken intLiteral => new IntLiteralSyntax(GetTokens(startIndex), intLiteral.Value, intLiteral.Base),
- IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
- SymbolToken symbolToken => symbolToken.Symbol switch
- {
- Symbol.OpenParen => ParseParenthesizedExpression(),
- Symbol.Minus => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Negate, ParsePrimaryExpression()),
- Symbol.Bang => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Invert, ParsePrimaryExpression()),
- Symbol.OpenBracket => ParseArrayInitializer(startIndex),
- Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
- Symbol.Struct => ParseStructInitializer(startIndex),
- Symbol.At => ParseBuiltinFunction(startIndex),
- _ => throw new ParseException(Diagnostic
- .Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
- .WithHelp("Expected '(', '-', '!', '[' or '{'")
- .At(symbolToken)
- .Build())
- },
- _ => throw new ParseException(Diagnostic
- .Error($"Unexpected token '{token.GetType().Name}' in expression")
- .WithHelp("Expected literal, identifier, or parenthesized expression")
- .At(token)
- .Build())
- };
-
- return ParsePostfixOperators(expr);
- }
-
- private ExpressionSyntax ParseBuiltinFunction(int startIndex)
- {
- var name = ExpectIdentifier();
- ExpectSymbol(Symbol.OpenParen);
-
- switch (name.Value)
- {
- case "size":
- {
- var type = ParseType();
- ExpectSymbol(Symbol.CloseParen);
- return new SizeSyntax(GetTokens(startIndex), type);
- }
- case "cast":
- {
- var expression = ParseExpression();
- ExpectSymbol(Symbol.CloseParen);
- return new CastSyntax(GetTokens(startIndex), expression);
- }
- default:
- {
- throw new ParseException(Diagnostic.Error($"Unknown builtin {name.Value}").At(name).Build());
- }
- }
- }
-
- private ExpressionSyntax ParseIdentifier(int startIndex, IdentifierToken identifier)
- {
- if (TryExpectSymbol(Symbol.DoubleColon))
- {
- var name = ExpectIdentifier();
- return new ModuleIdentifierSyntax(GetTokens(startIndex), identifier.Value, name.Value);
- }
-
- return new LocalIdentifierSyntax(GetTokens(startIndex), identifier.Value);
- }
-
- private ExpressionSyntax ParseParenthesizedExpression()
- {
- var expression = ParseExpression();
- ExpectSymbol(Symbol.CloseParen);
- return expression;
- }
-
- private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
- {
- var startIndex = _tokenIndex;
- while (HasToken)
- {
- if (TryExpectSymbol(Symbol.Ampersand))
- {
- expr = new AddressOfSyntax(GetTokens(startIndex), expr);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.Caret))
- {
- expr = new DereferenceSyntax(GetTokens(startIndex), expr);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.Period))
- {
- var member = ExpectIdentifier().Value;
- expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.OpenBracket))
- {
- var index = ParseExpression();
- ExpectSymbol(Symbol.CloseBracket);
- expr = new ArrayIndexAccessSyntax(GetTokens(startIndex), expr, index);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.OpenParen))
- {
- var parameters = new List();
-
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- parameters.Add(ParseExpression());
- if (!TryExpectSymbol(Symbol.Comma))
- {
- ExpectSymbol(Symbol.CloseParen);
- break;
- }
- }
-
- expr = new FuncCallSyntax(GetTokens(startIndex), expr, parameters);
- continue;
- }
-
- break;
- }
-
- return expr;
- }
-
- private ExpressionSyntax ParseArrayInitializer(int startIndex)
- {
- var values = new List();
- while (!TryExpectSymbol(Symbol.CloseBracket))
- {
- values.Add(ParseExpression());
- if (!TryExpectSymbol(Symbol.Comma))
- {
- ExpectSymbol(Symbol.CloseBracket);
- break;
- }
- }
-
- return new ArrayInitializerSyntax(GetTokens(startIndex), values);
- }
-
- private StructInitializerSyntax ParseStructInitializer(int startIndex)
- {
- TypeSyntax? type = null;
- if (!TryExpectSymbol(Symbol.OpenBrace))
- {
- type = ParseType();
- ExpectSymbol(Symbol.OpenBrace);
- }
-
- var initializers = ParseStructInitializerBody();
-
- return new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
- }
-
- private Dictionary ParseStructInitializerBody()
- {
- Dictionary initializers = [];
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- var name = ExpectIdentifier().Value;
- ExpectSymbol(Symbol.Assign);
- var value = ParseExpression();
- initializers.Add(name, value);
- }
-
- return initializers;
- }
-
- private BlockSyntax ParseBlock()
- {
- var startIndex = _tokenIndex;
- ExpectSymbol(Symbol.OpenBrace);
- return ParseBlock(startIndex);
- }
-
- private BlockSyntax ParseBlock(int startIndex)
- {
- List statements = [];
-
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- try
- {
- statements.Add(ParseStatement());
- }
- catch (ParseException ex)
- {
- Diagnostics.Add(ex.Diagnostic);
- if (HasToken)
- {
- Next();
- }
- else
- {
- break;
- }
- }
- }
-
- return new BlockSyntax(GetTokens(startIndex), statements);
- }
-
- private TypeSyntax ParseType()
- {
- var startIndex = _tokenIndex;
- if (TryExpectIdentifier(out var name))
- {
- if (name.Value[0] == 'u' && int.TryParse(name.Value[1..], out var size))
- {
- if (size is not 8 and not 16 and not 32 and not 64)
- {
- throw new ParseException(Diagnostic
- .Error("Arbitrary uint size is not supported")
- .WithHelp("Use u8, u16, u32 or u64")
- .At(name)
- .Build());
- }
-
- return new IntTypeSyntax(GetTokens(startIndex), false, size);
- }
-
- if (name.Value[0] == 'i' && int.TryParse(name.Value[1..], out size))
- {
- if (size is not 8 and not 16 and not 32 and not 64)
- {
- throw new ParseException(Diagnostic
- .Error("Arbitrary int size is not supported")
- .WithHelp("Use i8, i16, i32 or i64")
- .At(name)
- .Build());
- }
-
- return new IntTypeSyntax(GetTokens(startIndex), true, size);
- }
-
- if (name.Value[0] == 'f' && int.TryParse(name.Value[1..], out size))
- {
- if (size is not 32 and not 64)
- {
- throw new ParseException(Diagnostic
- .Error("Arbitrary float size is not supported")
- .WithHelp("Use f32 or f64")
- .At(name)
- .Build());
- }
-
- return new FloatTypeSyntax(GetTokens(startIndex), size);
- }
-
- switch (name.Value)
- {
- case "void":
- return new VoidTypeSyntax(GetTokens(startIndex));
- case "string":
- return new StringTypeSyntax(GetTokens(startIndex));
- case "bool":
- return new BoolTypeSyntax(GetTokens(startIndex));
- default:
- {
- string? module = null;
-
- if (TryExpectSymbol(Symbol.DoubleColon))
- {
- var customTypeName = ExpectIdentifier();
- module = name.Value;
- name = customTypeName;
- }
-
- return new CustomTypeSyntax(GetTokens(startIndex), module, name.Value);
- }
- }
- }
-
- if (TryExpectSymbol(Symbol.Caret))
- {
- var baseType = ParseType();
- return new PointerTypeSyntax(GetTokens(startIndex), baseType);
- }
-
- if (TryExpectSymbol(Symbol.Func))
- {
- ExpectSymbol(Symbol.OpenParen);
-
- List parameters = [];
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- parameters.Add(ParseType());
- if (!TryExpectSymbol(Symbol.Comma))
- {
- ExpectSymbol(Symbol.CloseParen);
- break;
- }
- }
-
- var returnType = TryExpectSymbol(Symbol.Colon)
- ? ParseType()
- : new VoidTypeSyntax([]);
-
- return new FuncTypeSyntax(GetTokens(startIndex), parameters, returnType);
- }
-
- if (TryExpectSymbol(Symbol.OpenBracket))
- {
- if (TryExpectIntLiteral(out var intLiteral))
- {
- ExpectSymbol(Symbol.CloseBracket);
- var baseType = ParseType();
- return new ConstArrayTypeSyntax(GetTokens(startIndex), baseType, Convert.ToInt64(intLiteral.Value, intLiteral.Base));
- }
- else if (TryExpectSymbol(Symbol.QuestionMark))
- {
- ExpectSymbol(Symbol.CloseBracket);
- var baseType = ParseType();
- return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
- }
- else
- {
- ExpectSymbol(Symbol.CloseBracket);
- var baseType = ParseType();
- return new SliceTypeSyntax(GetTokens(startIndex), baseType);
- }
- }
-
- throw new ParseException(Diagnostic
- .Error("Invalid type syntax")
- .WithHelp("Expected type name, '^' for pointer, or '[]' for array")
- .At(CurrentToken)
- .Build());
- }
-
- private Token ExpectToken()
- {
- if (!HasToken)
- {
- throw new ParseException(Diagnostic
- .Error("Unexpected end of file")
- .WithHelp("Expected more tokens to complete the syntax")
- .At(_tokens[^1])
- .Build());
- }
-
- var token = CurrentToken!;
- Next();
- return token;
- }
-
- private SymbolToken ExpectSymbol()
- {
- var token = ExpectToken();
- if (token is not SymbolToken symbol)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected symbol, but found {token.GetType().Name}")
- .WithHelp("This position requires a symbol like '(', ')', '{', '}', etc.")
- .At(token)
- .Build());
- }
-
- return symbol;
- }
-
- private void ExpectSymbol(Symbol expectedSymbol)
- {
- var token = ExpectSymbol();
- if (token.Symbol != expectedSymbol)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected '{expectedSymbol}', but found '{token.Symbol}'")
- .WithHelp($"Insert '{expectedSymbol}' here")
- .At(token)
- .Build());
- }
- }
-
- private bool TryExpectSymbol(out Symbol symbol)
- {
- if (CurrentToken is SymbolToken symbolToken)
- {
- Next();
- symbol = symbolToken.Symbol;
- return true;
- }
-
- symbol = default;
- return false;
- }
-
- private bool TryExpectSymbol(Symbol symbol)
- {
- if (CurrentToken is SymbolToken symbolToken && symbolToken.Symbol == symbol)
- {
- Next();
- return true;
- }
-
- return false;
- }
-
- private bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier)
- {
- if (CurrentToken is IdentifierToken identifierToken)
- {
- identifier = identifierToken;
- Next();
- return true;
- }
-
- identifier = null;
- return false;
- }
-
- private IdentifierToken ExpectIdentifier()
- {
- var token = ExpectToken();
- if (token is not IdentifierToken identifier)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected identifier, but found {token.GetType().Name}")
- .WithHelp("Provide a valid identifier name here")
- .At(token)
- .Build());
- }
-
- return identifier;
- }
-
- private bool TryExpectIntLiteral([NotNullWhen(true)] out IntLiteralToken? stringLiteral)
- {
- if (CurrentToken is IntLiteralToken token)
- {
- stringLiteral = token;
- Next();
- return true;
- }
-
- stringLiteral = null;
- return false;
- }
-
- private StringLiteralToken ExpectStringLiteral()
- {
- var token = ExpectToken();
- if (token is not StringLiteralToken identifier)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected string literal, but found {token.GetType().Name}")
- .WithHelp("Provide a valid string literal")
- .At(token)
- .Build());
- }
-
- return identifier;
- }
-
- private void Next()
- {
- _tokenIndex++;
- }
-
- private List GetTokens(int tokenStartIndex)
- {
- return _tokens.Skip(tokenStartIndex).Take(_tokenIndex - tokenStartIndex).ToList();
- }
-}
-
-public record SyntaxTree(List Definitions, string ModuleName, List Imports);
-
-public class ParseException : Exception
-{
- public Diagnostic Diagnostic { get; }
-
- public ParseException(Diagnostic diagnostic) : base(diagnostic.Message)
- {
- Diagnostic = diagnostic;
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Syntax/Syntax.cs b/compiler/NubLang/Syntax/Syntax.cs
deleted file mode 100644
index 8d4472c..0000000
--- a/compiler/NubLang/Syntax/Syntax.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-namespace NubLang.Syntax;
-
-public abstract record SyntaxNode(List Tokens);
-
-#region Definitions
-
-public abstract record DefinitionSyntax(List Tokens, string Name, bool Exported) : SyntaxNode(Tokens);
-
-public record FuncParameterSyntax(List Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens);
-
-public record FuncPrototypeSyntax(List Tokens, string Name, bool Exported, string? ExternSymbol, List Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens);
-
-public record FuncSyntax(List Tokens, FuncPrototypeSyntax Prototype, BlockSyntax? Body) : DefinitionSyntax(Tokens, Prototype.Name, Prototype.Exported);
-
-public record StructFieldSyntax(List Tokens, string Name, TypeSyntax Type, ExpressionSyntax? Value) : SyntaxNode(Tokens);
-
-public record StructSyntax(List Tokens, string Name, bool Exported, List Fields) : DefinitionSyntax(Tokens, Name, Exported);
-
-public record EnumFieldSyntax(List Tokens, string Name, long Value) : SyntaxNode(Tokens);
-
-public record EnumSyntax(List Tokens, string Name, bool Exported, TypeSyntax? Type, List Fields) : DefinitionSyntax(Tokens, Name, Exported);
-
-public enum UnaryOperatorSyntax
-{
- Negate,
- Invert
-}
-
-public enum BinaryOperatorSyntax
-{
- Equal,
- NotEqual,
- GreaterThan,
- GreaterThanOrEqual,
- LessThan,
- LessThanOrEqual,
- LogicalAnd,
- LogicalOr,
- Plus,
- Minus,
- Multiply,
- Divide,
- Modulo,
- LeftShift,
- RightShift,
- BitwiseAnd,
- BitwiseXor,
- BitwiseOr,
-}
-
-#endregion
-
-#region Statements
-
-public abstract record StatementSyntax(List Tokens) : SyntaxNode(Tokens);
-
-public record BlockSyntax(List Tokens, List Statements) : StatementSyntax(Tokens);
-
-public record StatementExpressionSyntax(List Tokens, ExpressionSyntax Expression) : StatementSyntax(Tokens);
-
-public record ReturnSyntax(List Tokens, ExpressionSyntax? Value) : StatementSyntax(Tokens);
-
-public record AssignmentSyntax(List Tokens, ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax(Tokens);
-
-public record IfSyntax(List Tokens, ExpressionSyntax Condition, BlockSyntax Body, Variant? Else) : StatementSyntax(Tokens);
-
-public record VariableDeclarationSyntax(List Tokens, string Name, TypeSyntax? ExplicitType, ExpressionSyntax? Assignment) : StatementSyntax(Tokens);
-
-public record ContinueSyntax(List Tokens) : StatementSyntax(Tokens);
-
-public record BreakSyntax(List Tokens) : StatementSyntax(Tokens);
-
-public record DeferSyntax(List Tokens, StatementSyntax Statement) : StatementSyntax(Tokens);
-
-public record WhileSyntax(List Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens);
-
-public record ForSyntax(List Tokens, string ElementName, string? IndexName, ExpressionSyntax Target, BlockSyntax Body) : StatementSyntax(Tokens);
-
-#endregion
-
-#region Expressions
-
-public abstract record ExpressionSyntax(List Tokens) : SyntaxNode(Tokens);
-
-public record BinaryExpressionSyntax(List Tokens, ExpressionSyntax Left, BinaryOperatorSyntax Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens);
-
-public record UnaryExpressionSyntax(List Tokens, UnaryOperatorSyntax Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens);
-
-public record FuncCallSyntax(List Tokens, ExpressionSyntax Expression, List Parameters) : ExpressionSyntax(Tokens);
-
-public record LocalIdentifierSyntax(List Tokens, string Name) : ExpressionSyntax(Tokens);
-
-public record ModuleIdentifierSyntax(List Tokens, string Module, string Name) : ExpressionSyntax(Tokens);
-
-public record ArrayInitializerSyntax(List Tokens, List Values) : ExpressionSyntax(Tokens);
-
-public record ArrayIndexAccessSyntax(List Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens);
-
-public record AddressOfSyntax(List Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
-
-public record IntLiteralSyntax(List Tokens, string Value, int Base) : ExpressionSyntax(Tokens);
-
-public record StringLiteralSyntax(List Tokens, string Value) : ExpressionSyntax(Tokens);
-
-public record BoolLiteralSyntax(List Tokens, bool Value) : ExpressionSyntax(Tokens);
-
-public record FloatLiteralSyntax(List Tokens, string Value) : ExpressionSyntax(Tokens);
-
-public record MemberAccessSyntax(List Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens);
-
-public record StructInitializerSyntax(List Tokens, TypeSyntax? StructType, Dictionary Initializers) : ExpressionSyntax(Tokens);
-
-public record DereferenceSyntax(List Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
-
-public record SizeSyntax(List Tokens, TypeSyntax Type) : ExpressionSyntax(Tokens);
-
-public record CastSyntax(List Tokens, ExpressionSyntax Value) : ExpressionSyntax(Tokens);
-
-#endregion
-
-#region Types
-
-public abstract record TypeSyntax(List Tokens) : SyntaxNode(Tokens);
-
-public record FuncTypeSyntax(List Tokens, List Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens);
-
-public record PointerTypeSyntax(List Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens);
-
-public record VoidTypeSyntax(List Tokens) : TypeSyntax(Tokens);
-
-public record IntTypeSyntax(List Tokens, bool Signed, int Width) : TypeSyntax(Tokens);
-
-public record FloatTypeSyntax(List Tokens, int Width) : TypeSyntax(Tokens);
-
-public record BoolTypeSyntax(List Tokens) : TypeSyntax(Tokens);
-
-public record StringTypeSyntax(List Tokens) : TypeSyntax(Tokens);
-
-public record SliceTypeSyntax(List Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens);
-
-public record ArrayTypeSyntax(List Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens);
-
-public record ConstArrayTypeSyntax(List Tokens, TypeSyntax BaseType, long Size) : TypeSyntax(Tokens);
-
-public record CustomTypeSyntax(List Tokens, string? Module, string Name) : TypeSyntax(Tokens);
-
-#endregion
\ No newline at end of file
diff --git a/compiler/NubLang/Syntax/Token.cs b/compiler/NubLang/Syntax/Token.cs
deleted file mode 100644
index 66f0980..0000000
--- a/compiler/NubLang/Syntax/Token.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using NubLang.Diagnostics;
-
-namespace NubLang.Syntax;
-
-public enum Symbol
-{
- // Control
- If,
- Else,
- While,
- For,
- In,
- Break,
- Continue,
- Return,
- Let,
- Defer,
-
- // Declaration
- Func,
- Struct,
- Enum,
- Import,
- Module,
-
- // Modifier
- Extern,
- Export,
-
- Colon,
- DoubleColon,
- OpenParen,
- CloseParen,
- OpenBrace,
- CloseBrace,
- OpenBracket,
- CloseBracket,
- Comma,
- Period,
- Assign,
- Bang,
- Equal,
- NotEqual,
- LessThan,
- LessThanOrEqual,
- GreaterThan,
- GreaterThanOrEqual,
- Plus,
- Minus,
- Star,
- ForwardSlash,
- Caret,
- Ampersand,
- Semi,
- Percent,
- LeftShift,
- RightShift,
- Pipe,
- And,
- Or,
- At,
- QuestionMark,
-}
-
-public abstract record Token(SourceSpan Span);
-
-public record IdentifierToken(SourceSpan Span, string Value) : Token(Span);
-
-public record IntLiteralToken(SourceSpan Span, string Value, int Base) : Token(Span);
-
-public record StringLiteralToken(SourceSpan Span, string Value) : Token(Span);
-
-public record BoolLiteralToken(SourceSpan Span, bool Value) : Token(Span);
-
-public record FloatLiteralToken(SourceSpan Span, string Value) : Token(Span);
-
-public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span);
\ No newline at end of file
diff --git a/compiler/NubLang/Syntax/Tokenizer.cs b/compiler/NubLang/Syntax/Tokenizer.cs
deleted file mode 100644
index 565ab43..0000000
--- a/compiler/NubLang/Syntax/Tokenizer.cs
+++ /dev/null
@@ -1,331 +0,0 @@
-using NubLang.Diagnostics;
-
-namespace NubLang.Syntax;
-
-public sealed class Tokenizer
-{
- private static readonly Dictionary Keywords = new()
- {
- ["func"] = Symbol.Func,
- ["if"] = Symbol.If,
- ["else"] = Symbol.Else,
- ["while"] = Symbol.While,
- ["for"] = Symbol.For,
- ["in"] = Symbol.In,
- ["break"] = Symbol.Break,
- ["continue"] = Symbol.Continue,
- ["return"] = Symbol.Return,
- ["struct"] = Symbol.Struct,
- ["let"] = Symbol.Let,
- ["extern"] = Symbol.Extern,
- ["module"] = Symbol.Module,
- ["export"] = Symbol.Export,
- ["import"] = Symbol.Import,
- ["defer"] = Symbol.Defer,
- ["enum"] = Symbol.Enum,
- };
-
- private static readonly Dictionary Symbols = new()
- {
- [['=', '=']] = Symbol.Equal,
- [['!', '=']] = Symbol.NotEqual,
- [['<', '=']] = Symbol.LessThanOrEqual,
- [['>', '=']] = Symbol.GreaterThanOrEqual,
- [['<', '<']] = Symbol.LeftShift,
- [['>', '>']] = Symbol.RightShift,
- [['&', '&']] = Symbol.And,
- [['|', '|']] = Symbol.Or,
- [[':', ':']] = Symbol.DoubleColon,
- [[':']] = Symbol.Colon,
- [['(']] = Symbol.OpenParen,
- [[')']] = Symbol.CloseParen,
- [['{']] = Symbol.OpenBrace,
- [['}']] = Symbol.CloseBrace,
- [['[']] = Symbol.OpenBracket,
- [[']']] = Symbol.CloseBracket,
- [[',']] = Symbol.Comma,
- [['.']] = Symbol.Period,
- [['=']] = Symbol.Assign,
- [['<']] = Symbol.LessThan,
- [['>']] = Symbol.GreaterThan,
- [['+']] = Symbol.Plus,
- [['-']] = Symbol.Minus,
- [['*']] = Symbol.Star,
- [['/']] = Symbol.ForwardSlash,
- [['!']] = Symbol.Bang,
- [['^']] = Symbol.Caret,
- [['&']] = Symbol.Ampersand,
- [[';']] = Symbol.Semi,
- [['%']] = Symbol.Percent,
- [['|']] = Symbol.Pipe,
- [['@']] = Symbol.At,
- [['?']] = Symbol.QuestionMark,
- };
-
- private static readonly (char[] Pattern, Symbol Symbol)[] OrderedSymbols = Symbols
- .OrderByDescending(kvp => kvp.Key.Length)
- .Select(kvp => (kvp.Key, kvp.Value))
- .ToArray();
-
- private readonly string _fileName;
- private readonly string _content;
- private int _index = 0;
- private int _line = 1;
- private int _column = 1;
-
- public Tokenizer(string fileName, string content)
- {
- _fileName = fileName;
- _content = content;
- }
-
- public List Diagnostics { get; } = [];
- public List Tokens { get; } = [];
-
- public void Tokenize()
- {
- Diagnostics.Clear();
- Tokens.Clear();
- _index = 0;
- _line = 1;
- _column = 1;
-
- while (Peek().HasValue)
- {
- try
- {
- var current = Peek()!.Value;
- if (char.IsWhiteSpace(current))
- {
- if (current is '\n')
- {
- _line += 1;
- // note(nub31): Next increments the column, so 0 is correct here
- _column = 0;
- }
-
- Next();
- continue;
- }
-
- if (current == '/' && Peek(1) == '/')
- {
- // note(nub31): Keep newline so next iteration increments the line counter
- while (Peek() is not '\n')
- {
- Next();
- }
-
- continue;
- }
-
- Tokens.Add(ParseToken(current, _line, _column));
- }
- catch (TokenizerException e)
- {
- Diagnostics.Add(e.Diagnostic);
- Next();
- }
- }
- }
-
- private Token ParseToken(char current, int lineStart, int columnStart)
- {
- if (char.IsLetter(current) || current == '_')
- {
- var buffer = string.Empty;
-
- while (Peek() != null && (char.IsLetterOrDigit(Peek()!.Value) || Peek() == '_'))
- {
- buffer += Peek();
- Next();
- }
-
- if (Keywords.TryGetValue(buffer, out var keywordSymbol))
- {
- return new SymbolToken(CreateSpan(lineStart, columnStart), keywordSymbol);
- }
-
- if (buffer is "true" or "false")
- {
- return new BoolLiteralToken(CreateSpan(lineStart, columnStart), Convert.ToBoolean(buffer));
- }
-
- return new IdentifierToken(CreateSpan(lineStart, columnStart), buffer);
- }
-
- if (char.IsDigit(current))
- {
- var buffer = string.Empty;
-
- if (current == '0' && Peek(1) is 'x')
- {
- buffer += "0x";
- Next();
- Next();
- while (Peek() != null && Uri.IsHexDigit(Peek()!.Value))
- {
- buffer += Peek()!.Value;
- Next();
- }
-
- if (buffer.Length <= 2)
- {
- throw new TokenizerException(Diagnostic
- .Error("Invalid hex literal, no digits found")
- .At(_fileName, _line, _column)
- .Build());
- }
-
- return new IntLiteralToken(CreateSpan(lineStart, columnStart), buffer, 16);
- }
-
- if (current == '0' && Peek(1) is 'b')
- {
- buffer += "0b";
- Next();
- Next();
- while (Peek() != null && (Peek() == '0' || Peek() == '1'))
- {
- buffer += Peek()!.Value;
- Next();
- }
-
- if (buffer.Length <= 2)
- {
- throw new TokenizerException(Diagnostic
- .Error("Invalid binary literal, no digits found")
- .At(_fileName, _line, _column)
- .Build());
- }
-
- return new IntLiteralToken(CreateSpan(lineStart, columnStart), buffer, 2);
- }
-
- var isFloat = false;
- while (Peek() != null)
- {
- var next = Peek()!.Value;
- if (next == '.')
- {
- if (isFloat)
- {
- throw new TokenizerException(Diagnostic
- .Error("More than one period found in float literal")
- .At(_fileName, _line, _column)
- .Build());
- }
-
- isFloat = true;
- buffer += next;
- Next();
- }
- else if (char.IsDigit(next))
- {
- buffer += next;
- Next();
- }
- else
- {
- break;
- }
- }
-
- if (isFloat)
- {
- return new FloatLiteralToken(CreateSpan(lineStart, columnStart), buffer);
- }
- else
- {
- return new IntLiteralToken(CreateSpan(lineStart, columnStart), buffer, 10);
- }
- }
-
- if (current == '"')
- {
- Next();
- var buffer = string.Empty;
-
- while (true)
- {
- var next = Peek();
- if (!next.HasValue)
- {
- throw new TokenizerException(Diagnostic
- .Error("Unclosed string literal")
- .At(_fileName, _line, _column)
- .Build());
- }
-
- if (next is '\n')
- {
- _line += 1;
- break;
- }
-
- if (next is '"')
- {
- Next();
- break;
- }
-
- buffer += next;
- Next();
- }
-
- return new StringLiteralToken(CreateSpan(lineStart, columnStart), buffer);
- }
-
- foreach (var (pattern, symbol) in OrderedSymbols)
- {
- for (var i = 0; i < pattern.Length; i++)
- {
- var c = Peek(i);
- if (!c.HasValue || c.Value != pattern[i]) break;
-
- if (i == pattern.Length - 1)
- {
- for (var j = 0; j <= i; j++)
- {
- Next();
- }
-
- return new SymbolToken(CreateSpan(lineStart, columnStart), symbol);
- }
- }
- }
-
- throw new TokenizerException(Diagnostic.Error($"Unknown token '{current}'").Build());
- }
-
- private SourceSpan CreateSpan(int lineStart, int columnStart)
- {
- return new SourceSpan(_fileName, new SourceLocation(lineStart, columnStart), new SourceLocation(_line, _column));
- }
-
- private char? Peek(int offset = 0)
- {
- if (_index + offset < _content.Length)
- {
- return _content[_index + offset];
- }
-
- return null;
- }
-
- private void Next()
- {
- _index += 1;
- _column += 1;
- }
-}
-
-public class TokenizerException : Exception
-{
- public Diagnostic Diagnostic { get; }
-
- public TokenizerException(Diagnostic diagnostic) : base(diagnostic.Message)
- {
- Diagnostic = diagnostic;
- }
-}
\ No newline at end of file
diff --git a/compiler/NubLang/Variant.cs b/compiler/NubLang/Variant.cs
deleted file mode 100644
index c9898b8..0000000
--- a/compiler/NubLang/Variant.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace NubLang;
-
-public readonly struct Variant where T1 : notnull where T2 : notnull
-{
- public Variant()
- {
- throw new InvalidOperationException("Variant must be initialized with a value");
- }
-
- public Variant(T1 value)
- {
- _value = value;
- }
-
- public Variant(T2 value)
- {
- _value = value;
- }
-
- private readonly object _value;
-
- public void Match(Action on1, Action on2)
- {
- switch (_value)
- {
- case T1 v1:
- on1(v1);
- break;
- case T2 v2:
- on2(v2);
- break;
- default:
- throw new InvalidCastException();
- }
- }
-
- public T Match(Func on1, Func on2)
- {
- return _value switch
- {
- T1 v1 => on1(v1),
- T2 v2 => on2(v2),
- _ => throw new InvalidCastException()
- };
- }
-
- public bool IsCase1([NotNullWhen(true)] out T1? value)
- {
- if (_value is T1 converted)
- {
- value = converted;
- return true;
- }
-
- value = default;
- return false;
- }
-
- public bool IsCase2([NotNullWhen(true)] out T2? value)
- {
- if (_value is T2 converted)
- {
- value = converted;
- return true;
- }
-
- value = default;
- return false;
- }
-
- public static implicit operator Variant