This commit is contained in:
nub31
2025-07-22 22:10:31 +02:00
parent 2d2d346da0
commit 4055002a8c
25 changed files with 413 additions and 972 deletions

View File

@@ -1,3 +1,5 @@
using NubLang.Code;
namespace NubLang.CLI;
public class Options
@@ -5,5 +7,5 @@ public class Options
public string? CustomRuntime { get; set; }
public string? OutputPath { get; set; }
public bool Link { get; set; } = true;
public List<string> Files { get; } = [];
public List<SourceFile> Files { get; } = [];
}

View File

@@ -1,6 +1,6 @@
using System.Reflection;
using NubLang.CLI;
using NubLang;
using NubLang.Code;
using NubLang.Common;
using NubLang.Diagnostics;
using NubLang.Generation;
@@ -62,16 +62,16 @@ for (var i = 0; i < args.Length; i++)
}
else
{
options.Files.Add(arg);
options.Files.Add(new SourceFile(arg));
}
}
var diagnostics = new List<Diagnostic>();
var syntaxTrees = new Dictionary<string, SyntaxTree>();
var syntaxTrees = new List<SyntaxTree>();
foreach (var file in options.Files)
{
if (!File.Exists(file))
if (!File.Exists(file.Path))
{
Console.Error.WriteLine($"File '{file}' does not exist");
return 1;
@@ -80,30 +80,27 @@ foreach (var file in options.Files)
foreach (var file in options.Files)
{
var content = File.ReadAllText(file);
var sourceText = new SourceText(file, content);
var tokenizer = new Tokenizer(sourceText);
var tokenizer = new Tokenizer(file.GetText());
var tokenizeResult = tokenizer.Tokenize(out var tokenizerDiagnostics);
diagnostics.AddRange(tokenizerDiagnostics);
var parser = new Parser(tokenizeResult);
var syntaxTree = parser.Parse();
diagnostics.AddRange(syntaxTree.Diagnostics);
var syntaxTree = parser.Parse(out var parserDiagnostics);
diagnostics.AddRange(parserDiagnostics);
syntaxTrees[file] = syntaxTree;
syntaxTrees.Add(syntaxTree);
}
var definitionTable = new DefinitionTable(syntaxTrees.Values);
var definitionTable = new DefinitionTable(syntaxTrees);
var boundSyntaxTrees = new Dictionary<string, BoundSyntaxTree>();
var boundSyntaxTrees = new List<BoundSyntaxTree>();
foreach (var (file, syntaxTree) in syntaxTrees)
foreach (var syntaxTree in syntaxTrees)
{
var binder = new Binder(syntaxTree, definitionTable);
var boundSyntaxTree = binder.Bind();
diagnostics.AddRange(boundSyntaxTree.Diagnostics);
boundSyntaxTrees[file] = boundSyntaxTree;
boundSyntaxTrees.Add(boundSyntaxTree);
}
foreach (var diagnostic in diagnostics)
@@ -116,15 +113,15 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1;
}
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees);
var objectFiles = new List<string>();
foreach (var file in options.Files)
foreach (var syntaxTree in boundSyntaxTrees)
{
var outFileName = $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}";
var outFileName = HexString.CreateUnique(8);
var generator = new QBEGenerator(boundSyntaxTrees[file], boundDefinitionTable, file);
var generator = new QBEGenerator(syntaxTree, boundDefinitionTable);
var ssa = generator.Emit();
File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa);

View File

@@ -0,0 +1,29 @@
namespace NubLang.Code;
public class SourceFile
{
private string? _content;
public SourceFile(string path)
{
Path = path ?? throw new ArgumentNullException(nameof(path));
}
public string Path { get; }
public string GetText() => _content ??= File.ReadAllText(Path);
public override string ToString() => Path;
public override bool Equals(object? obj)
{
return obj is SourceFile other && other.Path == Path;
}
public override int GetHashCode()
{
return HashCode.Combine(typeof(SourceFile), Path);
}
public static bool operator ==(SourceFile? left, SourceFile? right) => Equals(left, right);
public static bool operator !=(SourceFile? left, SourceFile? right) => !Equals(left, right);
}

View File

@@ -0,0 +1,53 @@
namespace NubLang.Code;
public readonly struct SourceLocation : IEquatable<SourceLocation>
{
public static SourceLocation Zero => new(0, 0);
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 int CompareTo(SourceLocation other)
{
var lineComparison = Line.CompareTo(other.Line);
if (lineComparison == 0)
{
return Column.CompareTo(other.Column);
}
return lineComparison;
}
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);
}

View File

@@ -0,0 +1,57 @@
namespace NubLang.Code;
public readonly struct SourceSpan : IEquatable<SourceSpan>
{
public static SourceSpan Zero => new(SourceLocation.Zero, SourceLocation.Zero);
public static SourceSpan Merge(params IEnumerable<SourceSpan> spans)
{
var spanArray = spans as SourceSpan[] ?? spans.ToArray();
if (spanArray.Length == 0)
{
return Zero;
}
var minStart = spanArray.Min(s => s.Start);
var maxEnd = spanArray.Max(s => s.End);
return new SourceSpan(minStart, maxEnd);
}
public SourceSpan(SourceLocation start, SourceLocation end)
{
if (start > end)
{
throw new ArgumentException("Start location cannot be after end location");
}
Start = start;
End = end;
}
public SourceLocation Start { get; }
public SourceLocation End { get; }
public override string ToString()
{
if (Start == End)
{
return $"{Start}";
}
if (Start.Line == End.Line)
{
return Start.Column == End.Column ? $"{Start}" : $"{Start.Line}:{Start.Column}-{End.Column}";
}
return $"{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);
}

View File

@@ -1,6 +1,3 @@
using System.Text;
using NubLang.Syntax.Tokenization;
namespace NubLang.Diagnostics;
public static class ConsoleColors
@@ -56,118 +53,4 @@ public static class ConsoleColors
{
return IsColorSupported() ? $"{color}{text}{Reset}" : text;
}
private static string GetTokenColor(Token token)
{
switch (token)
{
case IdentifierToken:
return White;
case LiteralToken literal:
return literal.Kind switch
{
LiteralKind.String => Green,
LiteralKind.Integer or LiteralKind.Float => BrightBlue,
LiteralKind.Bool => Blue,
_ => White
};
case SymbolToken symbol:
switch (symbol.Symbol)
{
case Symbol.If:
case Symbol.Else:
case Symbol.While:
case Symbol.Break:
case Symbol.Continue:
case Symbol.Return:
return Magenta;
case Symbol.Func:
case Symbol.Struct:
case Symbol.Namespace:
case Symbol.Let:
case Symbol.Alloc:
return 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 White;
case Symbol.Colon:
case Symbol.Comma:
case Symbol.Period:
case Symbol.DoubleColon:
return Faint;
case Symbol.OpenParen:
case Symbol.CloseParen:
case Symbol.OpenBrace:
case Symbol.CloseBrace:
case Symbol.OpenBracket:
case Symbol.CloseBracket:
return Yellow;
default:
return White;
}
default:
return White;
}
}
public static string ColorizeSource(string source)
{
var sourceText = new SourceText(string.Empty, source);
var tokenizer = new Tokenizer(sourceText);
var tokens = tokenizer.Tokenize(out _);
var result = new StringBuilder();
var lastCharIndex = 0;
foreach (var token in tokens)
{
var tokenStartIndex = GetCharacterIndex(sourceText, token.Span.Start);
var tokenEndIndex = GetCharacterIndex(sourceText, token.Span.End);
if (tokenStartIndex > lastCharIndex)
{
var between = sourceText.Content.Substring(lastCharIndex, tokenStartIndex - lastCharIndex);
result.Append(between);
}
var tokenText = sourceText.Content.Substring(tokenStartIndex, tokenEndIndex - tokenStartIndex);
result.Append(Colorize(tokenText, GetTokenColor(token)));
lastCharIndex = tokenEndIndex;
}
if (lastCharIndex < sourceText.Content.Length)
{
var remaining = sourceText.Content[lastCharIndex..];
result.Append(Colorize(remaining, Faint));
}
return result.ToString();
}
private static int GetCharacterIndex(SourceText sourceText, SourceLocation location)
{
var lines = sourceText.Content.Split('\n');
var index = 0;
for (var i = 0; i < location.Line - 1 && i < lines.Length; i++)
{
index += lines[i].Length + 1;
}
index += location.Column - 1;
return Math.Min(index, sourceText.Content.Length);
}
}

View File

@@ -1,6 +1,4 @@
using System.Text;
using NubLang.Syntax.Parsing.Node;
using NubLang.Syntax.Tokenization;
namespace NubLang.Diagnostics;
@@ -11,7 +9,6 @@ public class Diagnostic
private readonly DiagnosticSeverity _severity;
private readonly string _message;
private string? _help;
private SourceSpan? _sourceSpan;
public DiagnosticBuilder(DiagnosticSeverity severity, string message)
{
@@ -19,31 +16,13 @@ public class Diagnostic
_message = message;
}
public DiagnosticBuilder At(Token token)
{
_sourceSpan = token.Span;
return this;
}
public DiagnosticBuilder At(SyntaxNode node)
{
_sourceSpan = SourceSpan.Merge(node.Tokens.Select(t => t.Span));
return this;
}
public DiagnosticBuilder At(SourceSpan span)
{
_sourceSpan = span;
return this;
}
public DiagnosticBuilder WithHelp(string help)
{
_help = help;
return this;
}
public Diagnostic Build() => new(_severity, _message, _sourceSpan, _help);
public Diagnostic Build() => new(_severity, _message, _help);
}
public static DiagnosticBuilder Error(string message) => new(DiagnosticSeverity.Error, message);
@@ -52,14 +31,12 @@ public class Diagnostic
public DiagnosticSeverity Severity { get; }
public string Message { get; }
public SourceSpan? Span { get; }
public string? Help { get; }
private Diagnostic(DiagnosticSeverity severity, string message, SourceSpan? span, string? help)
private Diagnostic(DiagnosticSeverity severity, string message, string? help)
{
Severity = severity;
Message = message;
Span = span;
Help = help;
}
@@ -70,21 +47,9 @@ public class Diagnostic
var severityText = GetSeverityText(Severity);
sb.Append(severityText);
if (Span.HasValue)
{
var locationText = $" at {Span.Value.Text.Path}:{Span}";
sb.Append(ConsoleColors.Colorize(locationText, ConsoleColors.Faint));
}
sb.Append(": ");
sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
if (Span.HasValue)
{
sb.AppendLine();
AppendSourceContext(sb, Span.Value, Severity);
}
if (!string.IsNullOrEmpty(Help))
{
sb.AppendLine();
@@ -104,107 +69,6 @@ public class Diagnostic
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, "Unknown diagnostic severity")
};
}
private static void AppendSourceContext(StringBuilder sb, SourceSpan span, DiagnosticSeverity severity)
{
var lines = span.Text.Content.Split('\n');
var startLine = span.Start.Line;
var endLine = span.End.Line;
const int contextLines = 3;
var lineNumWidth = Math.Min(endLine + contextLines, lines.Length).ToString().Length;
var contextStart = Math.Max(1, startLine - contextLines);
var contextEnd = Math.Min(lines.Length, endLine + contextLines);
var contextWidth = 0;
for (var i = contextStart; i <= contextEnd; i++)
{
if (lines[i - 1].Length > contextWidth)
{
contextWidth = lines[i - 1].Length;
}
}
sb.AppendLine(ConsoleColors.Colorize('╭' + new string('─', lineNumWidth + 2) + '┬' + new string('─', contextWidth + 2) + '╮', ConsoleColors.Faint));
for (var lineNum = contextStart; lineNum < startLine; lineNum++)
{
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
}
for (var lineNum = startLine; lineNum <= endLine; lineNum++)
{
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
AppendErrorIndicators(sb, span, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth, severity);
}
for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++)
{
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
}
sb.Append(ConsoleColors.Colorize('╰' + new string('─', lineNumWidth + 2) + '┴' + new string('─', contextWidth + 2) + '╯', ConsoleColors.Faint));
}
private static void AppendContextLine(StringBuilder sb, int lineNum, string line, int lineNumWidth, int contextWidth)
{
sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
var lineNumStr = lineNum.ToString().PadLeft(lineNumWidth);
sb.Append(ConsoleColors.Colorize(lineNumStr, ConsoleColors.Faint));
sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
sb.Append(ConsoleColors.ColorizeSource(line.PadRight(contextWidth)));
sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
sb.AppendLine();
}
private static void AppendErrorIndicators(StringBuilder sb, SourceSpan span, int lineNum, string line, int lineNumWidth, int contextWidth, DiagnosticSeverity severity)
{
var color = severity switch
{
DiagnosticSeverity.Info => ConsoleColors.Blue,
DiagnosticSeverity.Warning => ConsoleColors.Yellow,
DiagnosticSeverity.Error => ConsoleColors.Red,
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, null)
};
sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
sb.Append(new string(' ', lineNumWidth));
sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
var indicators = GetIndicatorsForLine(span, lineNum, line);
sb.Append(ConsoleColors.Colorize(indicators.PadRight(contextWidth), color));
sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
sb.AppendLine();
}
private static string GetIndicatorsForLine(SourceSpan span, int lineNum, string line)
{
const char indicator = '^';
if (lineNum == span.Start.Line && lineNum == span.End.Line)
{
var startCol = Math.Max(0, span.Start.Column - 1);
var endCol = Math.Min(line.Length, span.End.Column - 1);
var length = Math.Max(1, endCol - startCol);
return new string(' ', startCol) + new string(indicator, length);
}
if (lineNum == span.Start.Line)
{
var startCol = Math.Max(0, span.Start.Column - 1);
return new string(' ', startCol) + new string(indicator, Math.Max(0, line.Length - startCol));
}
if (lineNum == span.End.Line)
{
var endCol = Math.Min(line.Length, span.End.Column - 1);
return new string(indicator, Math.Max(0, endCol));
}
return new string(indicator, line.Length);
}
}
public enum DiagnosticSeverity

View File

@@ -10,8 +10,6 @@ public partial class QBEGenerator
{
private Val EmitExpression(BoundExpression expression)
{
_writer.WriteDebugLocation(expression);
return expression switch
{
BoundArrayInitializer arrayInitializer => EmitArrayInitializer(arrayInitializer),
@@ -27,8 +25,7 @@ public partial class QBEGenerator
BoundLiteral literal => EmitLiteral(literal),
BoundUnaryExpression unaryExpression => EmitUnaryExpression(unaryExpression),
BoundStructFieldAccess structFieldAccess => EmitStructFieldAccess(structFieldAccess),
BoundTraitFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess),
BoundTraitImplFuncAccess traitImplFuncAccess => EmitTraitImplFuncAccess(traitImplFuncAccess),
BoundInterfaceFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess),
BoundArrayIndexAccess arrayIndex => EmitArrayIndexAccess(arrayIndex),
_ => throw new ArgumentOutOfRangeException(nameof(expression))
};
@@ -418,22 +415,11 @@ public partial class QBEGenerator
return new Val(output, structFieldAccess.Type, ValKind.Pointer);
}
private Val EmitTraitFuncAccess(BoundTraitFuncAccess traitFuncAccess)
private Val EmitTraitFuncAccess(BoundInterfaceFuncAccess interfaceFuncAccess)
{
throw new NotImplementedException();
}
private Val EmitTraitImplFuncAccess(BoundTraitImplFuncAccess traitImplFuncAccess)
{
var target = EmitExpression(traitImplFuncAccess.Target);
var funcImpl = _definitionTable.LookupTraitFuncImpl(traitImplFuncAccess.Target.Type, traitImplFuncAccess.FuncName);
var name = ImplFuncName();
_implFunctions.TryAdd(funcImpl, name);
return new Val(name, traitImplFuncAccess.Type, ValKind.Direct, new MethodCallContext(target));
}
private Val EmitFuncCall(BoundFuncCall funcCall)
{
var expression = EmitExpression(funcCall.Expression);
@@ -441,12 +427,6 @@ public partial class QBEGenerator
var parameterStrings = new List<string>();
if (expression.FuncCallContext != null)
{
var thisArg = EmitUnwrap(expression.FuncCallContext.ThisArg);
parameterStrings.Add($"{FuncQBETypeName(expression.FuncCallContext.ThisArg.Type)} {thisArg}");
}
foreach (var parameter in funcCall.Parameters)
{
var copy = EmitCreateCopyOrInitialize(parameter);

View File

@@ -7,8 +7,6 @@ public partial class QBEGenerator
{
private void EmitStatement(BoundStatement statement)
{
_writer.WriteDebugLocation(statement);
switch (statement)
{
case BoundAssignment assignment:

View File

@@ -18,23 +18,21 @@ public partial class QBEGenerator
private readonly Stack<string> _breakLabels = [];
private readonly Stack<string> _continueLabels = [];
private readonly Queue<(BoundArrowFunc Func, string Name)> _arrowFunctions = [];
private readonly Dictionary<BoundTraitFuncImpl, string> _implFunctions = [];
private readonly Stack<Scope> _scopes = [];
private int _tmpIndex;
private int _labelIndex;
private int _arrowFuncIndex;
private int _cStringLiteralIndex;
private int _stringLiteralIndex;
private int _implFuncNameIndex;
private bool _codeIsReachable = true;
private Scope Scope => _scopes.Peek();
public QBEGenerator(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable, string file)
public QBEGenerator(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
{
_syntaxTree = syntaxTree;
_definitionTable = definitionTable;
_writer = new QBEWriter(file);
_writer = new QBEWriter();
}
public string Emit()
@@ -44,14 +42,12 @@ public partial class QBEGenerator
_breakLabels.Clear();
_continueLabels.Clear();
_arrowFunctions.Clear();
_implFunctions.Clear();
_scopes.Clear();
_tmpIndex = 0;
_labelIndex = 0;
_arrowFuncIndex = 0;
_cStringLiteralIndex = 0;
_stringLiteralIndex = 0;
_implFuncNameIndex = 0;
_codeIsReachable = true;
foreach (var structDef in _definitionTable.GetStructs())
@@ -78,12 +74,6 @@ public partial class QBEGenerator
_writer.NewLine();
}
foreach (var (impl, name) in _implFunctions)
{
EmitFuncDefinition(name, impl.Signature.Parameters, impl.Signature.ReturnType, impl.Body);
_writer.NewLine();
}
foreach (var cStringLiteral in _cStringLiterals)
{
_writer.WriteLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}");
@@ -207,19 +197,16 @@ public partial class QBEGenerator
{
case BoundArrayInitializer arrayInitializer:
{
_writer.WriteDebugLocation(arrayInitializer);
EmitStore(source.Type, EmitUnwrap(EmitArrayInitializer(arrayInitializer)), destinationPointer);
return true;
}
case BoundStructInitializer structInitializer:
{
_writer.WriteDebugLocation(structInitializer);
EmitStructInitializer(structInitializer, destinationPointer);
return true;
}
case BoundLiteral { Kind: LiteralKind.String } literal:
{
_writer.WriteDebugLocation(literal);
EmitStore(source.Type, EmitUnwrap(EmitLiteral(literal)), destinationPointer);
return true;
}
@@ -521,11 +508,6 @@ public partial class QBEGenerator
return $"${funcDef.CallName}";
}
private string ImplFuncName()
{
return $"$impl{++_implFuncNameIndex}";
}
private string CustomTypeName(NubCustomType customType)
{
return CustomTypeName(customType.Namespace, customType.Name);
@@ -551,7 +533,7 @@ public class CStringLiteral(string value, string name)
public string Name { get; } = name;
}
public record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
public record Val(string Name, NubType Type, ValKind Kind);
public class Scope(Scope? parent = null)
{
@@ -579,8 +561,6 @@ public class Scope(Scope? parent = null)
}
}
public record MethodCallContext(Val ThisArg);
public enum ValKind
{
Pointer,

View File

@@ -1,22 +1,13 @@
using System.Text;
using NubLang.Syntax.Binding.Node;
namespace NubLang.Generation.QBE;
internal class QBEWriter
{
private readonly StringBuilder _builder = new();
private int _currentLine = -1;
public QBEWriter(string debugFile)
{
_builder.AppendLine($"dbgfile \"{debugFile}\"");
_builder.AppendLine();
}
public void StartFunction(string signature)
{
_currentLine = -1;
_builder.Append(signature);
_builder.AppendLine(" {");
_builder.AppendLine("@start");
@@ -27,26 +18,6 @@ internal class QBEWriter
_builder.AppendLine("}");
}
private void WriteDebugLocation(SourceSpan span)
{
var line = span.Start.Line;
if (_currentLine != line)
{
_builder.AppendLine($" dbgloc {line}");
_currentLine = line;
}
}
public void WriteDebugLocation(BoundNode node)
{
var firstToken = node.Tokens.FirstOrDefault();
if (firstToken != null)
{
// WriteDebugLocation(firstToken.Span);
}
}
public void Indented(string value)
{
_builder.Append('\t');

View File

@@ -1,274 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace NubLang;
/// <summary>
/// Represents a location in source code with line and column information.
/// Lines and columns are 1-based to match typical editor conventions.
/// </summary>
public readonly struct SourceLocation : IEquatable<SourceLocation>, IComparable<SourceLocation>
{
public SourceLocation(int line, int column)
{
if (line < 1)
{
throw new ArgumentOutOfRangeException(nameof(line), "Line must be >= 1");
}
if (column < 1)
{
throw new ArgumentOutOfRangeException(nameof(column), "Column must be >= 1");
}
Line = line;
Column = column;
}
public int Line { get; }
public int Column { get; }
public int CompareTo(SourceLocation other)
{
var lineComparison = Line.CompareTo(other.Line);
if (lineComparison == 0)
{
return Column.CompareTo(other.Column);
}
return lineComparison;
}
public override string ToString()
{
return $"{Line}:{Column}";
}
public bool Equals(SourceLocation other)
{
return Line == other.Line && Column == other.Column;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is SourceLocation other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(Line, Column);
}
public static bool operator ==(SourceLocation left, SourceLocation right) => left.Equals(right);
public static bool operator !=(SourceLocation left, SourceLocation right) => !left.Equals(right);
public static bool operator <(SourceLocation left, SourceLocation right) => left.CompareTo(right) < 0;
public static bool operator >(SourceLocation left, SourceLocation right) => left.CompareTo(right) > 0;
public static bool operator <=(SourceLocation left, SourceLocation right) => left.CompareTo(right) <= 0;
public static bool operator >=(SourceLocation left, SourceLocation right) => left.CompareTo(right) >= 0;
}
/// <summary>
/// Represents source text with a name (typically filename) and content.
/// Equality is based on both name and content for better semantics.
/// </summary>
public struct SourceText : IEquatable<SourceText>
{
private int _lines = -1;
public SourceText(string path, string content)
{
Path = path ?? throw new ArgumentNullException(nameof(path));
Content = content ?? throw new ArgumentNullException(nameof(content));
}
public string Path { get; }
public string Content { get; }
public int LineCount()
{
if (_lines == -1)
{
_lines = Content.Split('\n').Length + 1;
}
return _lines;
}
/// <summary>
/// Gets a specific line from the source text (1-based).
/// </summary>
public string GetLine(int lineNumber)
{
if (lineNumber < 1)
{
throw new ArgumentOutOfRangeException(nameof(lineNumber));
}
var lines = Content.Split('\n');
return lineNumber <= lines.Length ? lines[lineNumber - 1] : string.Empty;
}
public bool Equals(SourceText other)
{
return Path == other.Path && Content == other.Content;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is SourceText other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(Path, Content);
}
public override string ToString()
{
return Path;
}
public static bool operator ==(SourceText left, SourceText right) => left.Equals(right);
public static bool operator !=(SourceText left, SourceText right) => !left.Equals(right);
}
/// <summary>
/// Represents a span of source code from a start to end location within a source text.
/// </summary>
public readonly struct SourceSpan : IEquatable<SourceSpan>
{
public SourceSpan(SourceText text, SourceLocation start, SourceLocation end)
{
if (start > end)
{
throw new ArgumentException("Start location cannot be after end location");
}
if (end.Line > text.LineCount() || end.Line == text.LineCount() && end.Column > text.GetLine(text.LineCount()).Length + 1)
{
throw new ArgumentException("End location cannot be after text end location");
}
Text = text;
Start = start;
End = end;
}
public SourceText Text { get; }
public SourceLocation Start { get; }
public SourceLocation End { get; }
/// <summary>
/// Gets whether this span represents a single point (start == end).
/// </summary>
public bool IsEmpty => Start == End;
/// <summary>
/// Gets whether this span is contained within a single line.
/// </summary>
public bool IsSingleLine => Start.Line == End.Line;
/// <summary>
/// Gets the text content covered by this span.
/// </summary>
public string GetText()
{
if (IsEmpty)
{
return string.Empty;
}
var lines = Text.Content.Split('\n');
if (IsSingleLine)
{
var line = lines[Start.Line - 1];
var startCol = Math.Min(Start.Column - 1, line.Length);
var endCol = Math.Min(End.Column - 1, line.Length);
return line.Substring(startCol, Math.Max(0, endCol - startCol));
}
var result = new List<string>();
for (var i = Start.Line - 1; i < Math.Min(End.Line, lines.Length); i++)
{
var line = lines[i];
if (i == Start.Line - 1)
{
result.Add(line[Math.Min(Start.Column - 1, line.Length)..]);
}
else if (i == End.Line - 1)
{
result.Add(line[..Math.Min(End.Column - 1, line.Length)]);
}
else
{
result.Add(line);
}
}
return string.Join("\n", result);
}
/// <summary>
/// Merges multiple source spans from the same file into a single span.
/// The result spans from the earliest start to the latest end.
/// </summary>
public static SourceSpan Merge(IEnumerable<SourceSpan> spans)
{
var spanArray = spans.ToArray();
if (spanArray.Length == 0)
{
throw new ArgumentException("Cannot merge empty collection of spans", nameof(spans));
}
var firstText = spanArray[0].Text;
if (spanArray.Any(s => !s.Text.Equals(firstText)))
{
throw new ArgumentException("All spans must be from the same source text", nameof(spans));
}
var minStart = spanArray.Min(s => s.Start);
var maxEnd = spanArray.Max(s => s.End);
return new SourceSpan(firstText, minStart, maxEnd);
}
public override string ToString()
{
if (IsEmpty)
{
return $"{Start}";
}
if (IsSingleLine)
{
return Start.Column == End.Column ? $"{Start}" : $"{Start.Line}:{Start.Column}-{End.Column}";
}
return $"{Start}-{End}";
}
public bool Equals(SourceSpan other)
{
return Text.Equals(other.Text) && Start.Equals(other.Start) && End.Equals(other.End);
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is SourceSpan other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(Text, Start, End);
}
public static bool operator ==(SourceSpan left, SourceSpan right)
{
return left.Equals(right);
}
public static bool operator !=(SourceSpan left, SourceSpan right)
{
return !left.Equals(right);
}
}

View File

@@ -63,10 +63,10 @@ public sealed class Binder
foreach (var function in node.Functions)
{
functions.Add(new BoundTraitFunc(node.Tokens, function.Name, BindFuncSignature(function.Signature)));
functions.Add(new BoundTraitFunc(function.Name, BindFuncSignature(function.Signature)));
}
return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions);
return new BoundTrait(node.Namespace, node.Name, functions);
}
private BoundStruct BindStruct(StructSyntax node)
@@ -82,15 +82,15 @@ public sealed class Binder
value = BindExpression(field.Value.Value, BindType(field.Type));
}
structFields.Add(new BoundStructField(field.Tokens, field.Index, field.Name, BindType(field.Type), value));
structFields.Add(new BoundStructField(field.Index, field.Name, BindType(field.Type), value));
}
return new BoundStruct(node.Tokens, node.Namespace, node.Name, structFields);
return new BoundStruct(node.Namespace, node.Name, structFields);
}
private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node)
{
return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
return new BoundExternFunc(node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
}
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
@@ -98,7 +98,7 @@ public sealed class Binder
var signature = BindFuncSignature(node.Signature);
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters);
return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body);
return new BoundLocalFunc(node.Namespace, node.Name, signature, body);
}
private BoundStatement BindStatement(StatementSyntax node)
@@ -106,8 +106,8 @@ public sealed class Binder
return node switch
{
AssignmentSyntax statement => BindAssignment(statement),
BreakSyntax statement => BindBreak(statement),
ContinueSyntax statement => BindContinue(statement),
BreakSyntax => new BoundBreak(),
ContinueSyntax => new BoundContinue(),
IfSyntax statement => BindIf(statement),
ReturnSyntax statement => BindReturn(statement),
StatementExpressionSyntax statement => BindStatementExpression(statement),
@@ -121,17 +121,7 @@ public sealed class Binder
{
var expression = BindExpression(statement.Target);
var value = BindExpression(statement.Value, expression.Type);
return new BoundAssignment(statement.Tokens, expression, value);
}
private BoundBreak BindBreak(BreakSyntax statement)
{
return new BoundBreak(statement.Tokens);
}
private BoundContinue BindContinue(ContinueSyntax statement)
{
return new BoundContinue(statement.Tokens);
return new BoundAssignment(expression, value);
}
private BoundIf BindIf(IfSyntax statement)
@@ -147,7 +137,7 @@ public sealed class Binder
);
}
return new BoundIf(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body), elseStatement);
return new BoundIf(BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body), elseStatement);
}
private BoundReturn BindReturn(ReturnSyntax statement)
@@ -159,12 +149,12 @@ public sealed class Binder
value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek());
}
return new BoundReturn(statement.Tokens, value);
return new BoundReturn(value);
}
private BoundStatementExpression BindStatementExpression(StatementExpressionSyntax statement)
{
return new BoundStatementExpression(statement.Tokens, BindExpression(statement.Expression));
return new BoundStatementExpression(BindExpression(statement.Expression));
}
private BoundVariableDeclaration BindVariableDeclaration(VariableDeclarationSyntax statement)
@@ -191,12 +181,12 @@ public sealed class Binder
Scope.Declare(new Variable(statement.Name, type));
return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type);
return new BoundVariableDeclaration(statement.Name, assignment, type);
}
private BoundWhile BindWhile(WhileSyntax statement)
{
return new BoundWhile(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body));
return new BoundWhile(BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body));
}
private BoundExpression BindExpression(ExpressionSyntax node, NubType? expectedType = null)
@@ -222,19 +212,19 @@ public sealed class Binder
private BoundAddressOf BindAddressOf(AddressOfSyntax expression)
{
var inner = BindExpression(expression.Expression);
return new BoundAddressOf(expression.Tokens, new NubPointerType(inner.Type), inner);
return new BoundAddressOf(new NubPointerType(inner.Type), inner);
}
private BoundArrowFunc BindArrowFunc(ArrowFuncSyntax expression, NubType? expectedType = null)
{
if (expectedType == null)
{
throw new BindException(Diagnostic.Error("Cannot infer argument types for arrow function").At(expression).Build());
throw new BindException(Diagnostic.Error("Cannot infer argument types for arrow function").Build());
}
if (expectedType is not NubFuncType funcType)
{
throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got arrow function").At(expression).Build());
throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got arrow function").Build());
}
var parameters = new List<BoundFuncParameter>();
@@ -248,40 +238,40 @@ public sealed class Binder
var expectedParameterType = funcType.Parameters[i];
var parameter = expression.Parameters[i];
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType));
parameters.Add(new BoundFuncParameter(parameter.Name, expectedParameterType));
}
var body = BindFuncBody(expression.Body, funcType.ReturnType, parameters);
return new BoundArrowFunc(expression.Tokens, new NubFuncType(parameters.Select(x => x.Type).ToList(), funcType.ReturnType), parameters, funcType.ReturnType, body);
return new BoundArrowFunc(new NubFuncType(parameters.Select(x => x.Type).ToList(), funcType.ReturnType), parameters, funcType.ReturnType, body);
}
private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression)
{
var boundArray = BindExpression(expression.Target);
var elementType = ((NubArrayType)boundArray.Type).ElementType;
return new BoundArrayIndexAccess(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, new NubPrimitiveType(PrimitiveTypeKind.U64)));
return new BoundArrayIndexAccess(elementType, boundArray, BindExpression(expression.Index, new NubPrimitiveType(PrimitiveTypeKind.U64)));
}
private BoundArrayInitializer BindArrayInitializer(ArrayInitializerSyntax expression)
{
var capacity = BindExpression(expression.Capacity, new NubPrimitiveType(PrimitiveTypeKind.U64));
var type = new NubArrayType(BindType(expression.ElementType));
return new BoundArrayInitializer(expression.Tokens, type, capacity, BindType(expression.ElementType));
return new BoundArrayInitializer(type, capacity, BindType(expression.ElementType));
}
private BoundBinaryExpression BindBinaryExpression(BinaryExpressionSyntax expression)
{
var boundLeft = BindExpression(expression.Left);
var boundRight = BindExpression(expression.Right, boundLeft.Type);
return new BoundBinaryExpression(expression.Tokens, boundLeft.Type, boundLeft, BindBinaryOperator(expression.Operator), boundRight);
return new BoundBinaryExpression(boundLeft.Type, boundLeft, BindBinaryOperator(expression.Operator), boundRight);
}
private BoundDereference BindDereference(DereferenceSyntax expression)
{
var boundExpression = BindExpression(expression.Expression);
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
return new BoundDereference(expression.Tokens, dereferencedType, boundExpression);
return new BoundDereference(dereferencedType, boundExpression);
}
private BoundFuncCall BindFuncCall(FuncCallSyntax expression)
@@ -304,7 +294,7 @@ public sealed class Binder
parameters.Add(BindExpression(parameter, expectedType));
}
return new BoundFuncCall(expression.Tokens, funcType.ReturnType, boundExpression, parameters);
return new BoundFuncCall(funcType.ReturnType, boundExpression, parameters);
}
private BoundExpression BindIdentifier(IdentifierSyntax expression)
@@ -323,7 +313,7 @@ public sealed class Binder
var returnType = BindType(localFunc.Signature.ReturnType);
var parameterTypes = localFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType);
return new BoundLocalFuncIdent(expression.Tokens, type, @namespace, expression.Name);
return new BoundLocalFuncIdent(type, @namespace, expression.Name);
}
var externFuncs = _definitionTable.LookupExternFunc(@namespace, expression.Name).ToArray();
@@ -339,7 +329,7 @@ public sealed class Binder
var returnType = BindType(externFunc.Signature.ReturnType);
var parameterTypes = externFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType);
return new BoundExternFuncIdent(expression.Tokens, type, @namespace, expression.Name);
return new BoundExternFuncIdent(type, @namespace, expression.Name);
}
if (!expression.Namespace.HasValue)
@@ -347,7 +337,7 @@ public sealed class Binder
var variable = Scope.Lookup(expression.Name);
if (variable != null)
{
return new BoundVariableIdent(expression.Tokens, variable.Type, variable.Name);
return new BoundVariableIdent(variable.Type, variable.Name);
}
}
@@ -365,7 +355,7 @@ public sealed class Binder
_ => throw new ArgumentOutOfRangeException()
};
return new BoundLiteral(expression.Tokens, type, expression.Value, expression.Kind);
return new BoundLiteral(type, expression.Value, expression.Kind);
}
private BoundExpression BindMemberAccess(MemberAccessSyntax expression)
@@ -385,7 +375,7 @@ public sealed class Binder
// var returnType = BindType(impl.Signature.ReturnType);
// var parameterTypes = impl.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
// var type = new NubFuncType(parameterTypes, returnType);
// return new BoundTraitImplFuncAccess(expression.Tokens, type, boundExpression, expression.Member);
// return new BoundTraitImplFuncAccess(type, boundExpression, expression.Member);
// }
if (boundExpression.Type is NubCustomType customType)
@@ -413,7 +403,7 @@ public sealed class Binder
var returnType = BindType(traitFunc.Signature.ReturnType);
var parameterTypes = traitFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType);
return new BoundTraitFuncAccess(expression.Tokens, type, customType, boundExpression, expression.Member);
return new BoundInterfaceFuncAccess(type, customType, boundExpression, expression.Member);
}
}
@@ -437,7 +427,7 @@ public sealed class Binder
var field = fields[0];
return new BoundStructFieldAccess(expression.Tokens, BindType(field.Type), customType, boundExpression, expression.Member);
return new BoundStructFieldAccess(BindType(field.Type), customType, boundExpression, expression.Member);
}
}
}
@@ -487,7 +477,7 @@ public sealed class Binder
initializers[field] = BindExpression(initializer, BindType(fields[0].Type));
}
return new BoundStructInitializer(expression.Tokens, structType, initializers);
return new BoundStructInitializer(structType, initializers);
}
private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression)
@@ -523,7 +513,7 @@ public sealed class Binder
throw new NotImplementedException("Diagnostics not implemented");
}
return new BoundUnaryExpression(expression.Tokens, type, BindBinaryOperator(expression.Operator), boundOperand);
return new BoundUnaryExpression(type, BindBinaryOperator(expression.Operator), boundOperand);
}
private BoundFuncSignature BindFuncSignature(FuncSignatureSyntax node)
@@ -532,10 +522,10 @@ public sealed class Binder
foreach (var parameter in node.Parameters)
{
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
parameters.Add(new BoundFuncParameter(parameter.Name, BindType(parameter.Type)));
}
return new BoundFuncSignature(node.Tokens, parameters, BindType(node.ReturnType));
return new BoundFuncSignature(parameters, BindType(node.ReturnType));
}
private BoundBinaryOperator BindBinaryOperator(BinaryOperator op)
@@ -579,7 +569,7 @@ public sealed class Binder
_scopes.Pop();
return new BoundBlock(node.Tokens, statements);
return new BoundBlock(statements);
}
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IReadOnlyList<BoundFuncParameter> parameters)

View File

@@ -1,26 +1,25 @@
using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node;
public abstract record BoundDefinition(IReadOnlyList<Token> Tokens, string Namespace) : BoundNode(Tokens);
public abstract record BoundDefinition(string Namespace) : BoundNode;
public record BoundFuncParameter(IReadOnlyList<Token> Tokens, string Name, NubType Type) : BoundNode(Tokens);
public record BoundFuncParameter(string Name, NubType Type) : BoundNode;
public record BoundFuncSignature(IReadOnlyList<Token> Tokens, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType) : BoundNode(Tokens);
public record BoundFuncSignature(IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType) : BoundNode;
public record BoundLocalFunc(IReadOnlyList<Token> Tokens, string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Tokens, Namespace);
public record BoundLocalFunc(string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Namespace);
public record BoundExternFunc(IReadOnlyList<Token> Tokens, string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Tokens, Namespace);
public record BoundExternFunc(string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Namespace);
public record BoundStructField(IReadOnlyList<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundNode(Tokens);
public record BoundStructField(int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundNode;
public record BoundStruct(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<BoundStructField> Fields) : BoundDefinition(Tokens, Namespace);
public record BoundStruct(string Namespace, string Name, IReadOnlyList<BoundStructField> Fields) : BoundDefinition(Namespace);
public record BoundTraitFunc(IReadOnlyList<Token> Tokens, string Name, BoundFuncSignature Signature) : BoundNode(Tokens);
public record BoundTraitFunc(string Name, BoundFuncSignature Signature) : BoundNode;
public record BoundTrait(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<BoundTraitFunc> Functions) : BoundDefinition(Tokens, Namespace);
public record BoundTrait(string Namespace, string Name, IReadOnlyList<BoundTraitFunc> Functions) : BoundDefinition(Namespace);
public record BoundTraitFuncImpl(IReadOnlyList<Token> Tokens, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundNode(Tokens);
public record BoundTraitFuncImpl(string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundNode;
public record BoundTraitImpl(IReadOnlyList<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, IReadOnlyList<BoundTraitFuncImpl> Functions) : BoundDefinition(Tokens, Namespace);
public record BoundTraitImpl(string Namespace, NubType TraitType, NubType ForType, IReadOnlyList<BoundTraitFuncImpl> Functions) : BoundDefinition(Namespace);

View File

@@ -22,36 +22,34 @@ public enum BoundBinaryOperator
Divide
}
public abstract record BoundExpression(IReadOnlyList<Token> Tokens, NubType Type) : BoundNode(Tokens);
public abstract record BoundExpression(NubType Type) : BoundNode;
public record BoundBinaryExpression(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Left, BoundBinaryOperator Operator, BoundExpression Right) : BoundExpression(Tokens, Type);
public record BoundBinaryExpression(NubType Type, BoundExpression Left, BoundBinaryOperator Operator, BoundExpression Right) : BoundExpression(Type);
public record BoundUnaryExpression(IReadOnlyList<Token> Tokens, NubType Type, BoundUnaryOperator Operator, BoundExpression Operand) : BoundExpression(Tokens, Type);
public record BoundUnaryExpression(NubType Type, BoundUnaryOperator Operator, BoundExpression Operand) : BoundExpression(Type);
public record BoundFuncCall(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression, IReadOnlyList<BoundExpression> Parameters) : BoundExpression(Tokens, Type);
public record BoundFuncCall(NubType Type, BoundExpression Expression, IReadOnlyList<BoundExpression> Parameters) : BoundExpression(Type);
public record BoundVariableIdent(IReadOnlyList<Token> Tokens, NubType Type, string Name) : BoundExpression(Tokens, Type);
public record BoundVariableIdent(NubType Type, string Name) : BoundExpression(Type);
public record BoundLocalFuncIdent(IReadOnlyList<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpression(Tokens, Type);
public record BoundLocalFuncIdent(NubType Type, string Namespace, string Name) : BoundExpression(Type);
public record BoundExternFuncIdent(IReadOnlyList<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpression(Tokens, Type);
public record BoundExternFuncIdent(NubType Type, string Namespace, string Name) : BoundExpression(Type);
public record BoundArrayInitializer(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Capacity, NubType ElementType) : BoundExpression(Tokens, Type);
public record BoundArrayInitializer(NubType Type, BoundExpression Capacity, NubType ElementType) : BoundExpression(Type);
public record BoundArrayIndexAccess(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type);
public record BoundArrayIndexAccess(NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Type);
public record BoundArrowFunc(IReadOnlyList<Token> Tokens, NubType Type, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Tokens, Type);
public record BoundArrowFunc(NubType Type, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Type);
public record BoundAddressOf(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);
public record BoundAddressOf(NubType Type, BoundExpression Expression) : BoundExpression(Type);
public record BoundLiteral(IReadOnlyList<Token> Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpression(Tokens, Type);
public record BoundLiteral(NubType Type, string Literal, LiteralKind Kind) : BoundExpression(Type);
public record BoundStructFieldAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType StructType, BoundExpression Target, string Field) : BoundExpression(Tokens, Type);
public record BoundStructFieldAccess(NubType Type, NubCustomType StructType, BoundExpression Target, string Field) : BoundExpression(Type);
public record BoundTraitImplFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type);
public record BoundInterfaceFuncAccess(NubType Type, NubCustomType InterfaceType, BoundExpression Target, string FuncName) : BoundExpression(Type);
public record BoundTraitFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType TraitType, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type);
public record BoundStructInitializer(NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(StructType);
public record BoundStructInitializer(IReadOnlyList<Token> Tokens, NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(Tokens, StructType);
public record BoundDereference(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);
public record BoundDereference(NubType Type, BoundExpression Expression) : BoundExpression(Type);

View File

@@ -1,22 +1,21 @@
using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node;
public record BoundStatement(IReadOnlyList<Token> Tokens) : BoundNode(Tokens);
public record BoundStatement : BoundNode;
public record BoundStatementExpression(IReadOnlyList<Token> Tokens, BoundExpression Expression) : BoundStatement(Tokens);
public record BoundStatementExpression(BoundExpression Expression) : BoundStatement;
public record BoundReturn(IReadOnlyList<Token> Tokens, Optional<BoundExpression> Value) : BoundStatement(Tokens);
public record BoundReturn(Optional<BoundExpression> Value) : BoundStatement;
public record BoundAssignment(IReadOnlyList<Token> Tokens, BoundExpression Target, BoundExpression Value) : BoundStatement(Tokens);
public record BoundAssignment(BoundExpression Target, BoundExpression Value) : BoundStatement;
public record BoundIf(IReadOnlyList<Token> Tokens, BoundExpression Condition, BoundBlock Body, Optional<Variant<BoundIf, BoundBlock>> Else) : BoundStatement(Tokens);
public record BoundIf(BoundExpression Condition, BoundBlock Body, Optional<Variant<BoundIf, BoundBlock>> Else) : BoundStatement;
public record BoundVariableDeclaration(IReadOnlyList<Token> Tokens, string Name, Optional<BoundExpression> Assignment, NubType Type) : BoundStatement(Tokens);
public record BoundVariableDeclaration(string Name, Optional<BoundExpression> Assignment, NubType Type) : BoundStatement;
public record BoundContinue(IReadOnlyList<Token> Tokens) : BoundStatement(Tokens);
public record BoundContinue : BoundStatement;
public record BoundBreak(IReadOnlyList<Token> Tokens) : BoundStatement(Tokens);
public record BoundBreak : BoundStatement;
public record BoundWhile(IReadOnlyList<Token> Tokens, BoundExpression Condition, BoundBlock Body) : BoundStatement(Tokens);
public record BoundWhile(BoundExpression Condition, BoundBlock Body) : BoundStatement;

View File

@@ -1,10 +1,9 @@
using NubLang.Diagnostics;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node;
public record BoundSyntaxTree(string Namespace, IReadOnlyList<BoundDefinition> Definitions, IReadOnlyList<Diagnostic> Diagnostics);
public abstract record BoundNode(IReadOnlyList<Token> Tokens);
public abstract record BoundNode;
public record BoundBlock(IReadOnlyList<Token> Tokens, IReadOnlyList<BoundStatement> Statements) : BoundNode(Tokens);
public record BoundBlock(IReadOnlyList<BoundStatement> Statements) : BoundNode;

View File

@@ -1,11 +1,10 @@
using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node;
public abstract record DefinitionSyntax(IReadOnlyList<Token> Tokens, string Namespace) : SyntaxNode(Tokens);
public abstract record DefinitionSyntax(string Namespace) : SyntaxNode;
public record FuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens)
public record FuncParameterSyntax(string Name, TypeSyntax Type) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -13,7 +12,7 @@ public record FuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name, Type
}
}
public record FuncSignatureSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens)
public record FuncSignatureSyntax(IReadOnlyList<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -26,7 +25,7 @@ public record FuncSignatureSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<Fun
}
}
public record LocalFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace)
public record LocalFuncSyntax(string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Namespace)
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -35,7 +34,7 @@ public record LocalFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, str
}
}
public record ExternFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace)
public record ExternFuncSyntax(string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Namespace)
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -43,7 +42,7 @@ public record ExternFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, st
}
}
public record StructFieldSyntax(IReadOnlyList<Token> Tokens, int Index, string Name, TypeSyntax Type, Optional<ExpressionSyntax> Value) : SyntaxNode(Tokens)
public record StructFieldSyntax(int Index, string Name, TypeSyntax Type, Optional<ExpressionSyntax> Value) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -55,7 +54,7 @@ public record StructFieldSyntax(IReadOnlyList<Token> Tokens, int Index, string N
}
}
public record StructFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens)
public record StructFuncSyntax(string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -64,7 +63,7 @@ public record StructFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSig
}
}
public record StructSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<StructFieldSyntax> Fields, IReadOnlyList<StructFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace)
public record StructSyntax(string Namespace, string Name, IReadOnlyList<StructFieldSyntax> Fields, IReadOnlyList<StructFuncSyntax> Functions) : DefinitionSyntax(Namespace)
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -80,7 +79,7 @@ public record StructSyntax(IReadOnlyList<Token> Tokens, string Namespace, string
}
}
public record InterfaceFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSignatureSyntax Signature) : SyntaxNode(Tokens)
public record InterfaceFuncSyntax(string Name, FuncSignatureSyntax Signature) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -88,7 +87,7 @@ public record InterfaceFuncSyntax(IReadOnlyList<Token> Tokens, string Name, Func
}
}
public record InterfaceSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<InterfaceFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace)
public record InterfaceSyntax(string Namespace, string Name, IReadOnlyList<InterfaceFuncSyntax> Functions) : DefinitionSyntax(Namespace)
{
public override IEnumerable<SyntaxNode> GetChildren()
{

View File

@@ -23,9 +23,9 @@ public enum BinaryOperator
Divide
}
public abstract record ExpressionSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens);
public abstract record ExpressionSyntax : SyntaxNode;
public record BinaryExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens)
public record BinaryExpressionSyntax(ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -34,7 +34,7 @@ public record BinaryExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
}
}
public record UnaryExpressionSyntax(IReadOnlyList<Token> Tokens, UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens)
public record UnaryExpressionSyntax(UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -42,7 +42,7 @@ public record UnaryExpressionSyntax(IReadOnlyList<Token> Tokens, UnaryOperator O
}
}
public record FuncCallSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens)
public record FuncCallSyntax(ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -54,12 +54,12 @@ public record FuncCallSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expre
}
}
public record IdentifierSyntax(IReadOnlyList<Token> Tokens, Optional<string> Namespace, string Name) : ExpressionSyntax(Tokens)
public record IdentifierSyntax(Optional<string> Namespace, string Name) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record ArrayInitializerSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens)
public record ArrayInitializerSyntax(ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -68,7 +68,7 @@ public record ArrayInitializerSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
}
}
public record ArrayIndexAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens)
public record ArrayIndexAccessSyntax(ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -77,12 +77,12 @@ public record ArrayIndexAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
}
}
public record ArrowFuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name) : ExpressionSyntax(Tokens)
public record ArrowFuncParameterSyntax(string Name) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record ArrowFuncSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<ArrowFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens)
public record ArrowFuncSyntax(IReadOnlyList<ArrowFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -95,7 +95,7 @@ public record ArrowFuncSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<ArrowFu
}
}
public record AddressOfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens)
public record AddressOfSyntax(ExpressionSyntax Expression) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -103,12 +103,12 @@ public record AddressOfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expr
}
}
public record LiteralSyntax(IReadOnlyList<Token> Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens)
public record LiteralSyntax(string Value, LiteralKind Kind) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record MemberAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens)
public record MemberAccessSyntax(ExpressionSyntax Target, string Member) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -116,7 +116,7 @@ public record MemberAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax T
}
}
public record StructInitializerSyntax(IReadOnlyList<Token> Tokens, TypeSyntax StructType, Dictionary<string, ExpressionSyntax> Initializers) : ExpressionSyntax(Tokens)
public record StructInitializerSyntax(TypeSyntax StructType, Dictionary<string, ExpressionSyntax> Initializers) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -128,7 +128,7 @@ public record StructInitializerSyntax(IReadOnlyList<Token> Tokens, TypeSyntax St
}
}
public record DereferenceSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens)
public record DereferenceSyntax(ExpressionSyntax Expression) : ExpressionSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{

View File

@@ -1,11 +1,10 @@
using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node;
public abstract record StatementSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens);
public abstract record StatementSyntax : SyntaxNode;
public record StatementExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : StatementSyntax(Tokens)
public record StatementExpressionSyntax(ExpressionSyntax Expression) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -13,7 +12,7 @@ public record StatementExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionS
}
}
public record ReturnSyntax(IReadOnlyList<Token> Tokens, Optional<ExpressionSyntax> Value) : StatementSyntax(Tokens)
public record ReturnSyntax(Optional<ExpressionSyntax> Value) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -24,7 +23,7 @@ public record ReturnSyntax(IReadOnlyList<Token> Tokens, Optional<ExpressionSynta
}
}
public record AssignmentSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax(Tokens)
public record AssignmentSyntax(ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -33,7 +32,7 @@ public record AssignmentSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Tar
}
}
public record IfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body, Optional<Variant<IfSyntax, BlockSyntax>> Else) : StatementSyntax(Tokens)
public record IfSyntax(ExpressionSyntax Condition, BlockSyntax Body, Optional<Variant<IfSyntax, BlockSyntax>> Else) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -53,7 +52,7 @@ public record IfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition,
}
}
public record VariableDeclarationSyntax(IReadOnlyList<Token> Tokens, string Name, Optional<TypeSyntax> ExplicitType, Optional<ExpressionSyntax> Assignment) : StatementSyntax(Tokens)
public record VariableDeclarationSyntax(string Name, Optional<TypeSyntax> ExplicitType, Optional<ExpressionSyntax> Assignment) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -69,17 +68,17 @@ public record VariableDeclarationSyntax(IReadOnlyList<Token> Tokens, string Name
}
}
public record ContinueSyntax(IReadOnlyList<Token> Tokens) : StatementSyntax(Tokens)
public record ContinueSyntax : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record BreakSyntax(IReadOnlyList<Token> Tokens) : StatementSyntax(Tokens)
public record BreakSyntax : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record WhileSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens)
public record WhileSyntax(ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}

View File

@@ -1,9 +1,6 @@
using NubLang.Diagnostics;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node;
public abstract record SyntaxNode(IReadOnlyList<Token> Tokens)
public abstract record SyntaxNode
{
public abstract IEnumerable<SyntaxNode> GetChildren();
@@ -21,7 +18,7 @@ public abstract record SyntaxNode(IReadOnlyList<Token> Tokens)
}
}
public record SyntaxTree(IReadOnlyList<Token> Tokens, string Namespace, IReadOnlyList<DefinitionSyntax> Definitions, IReadOnlyList<Diagnostic> Diagnostics) : SyntaxNode(Tokens)
public record SyntaxTree(string Namespace, IReadOnlyList<DefinitionSyntax> Definitions) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -32,7 +29,7 @@ public record SyntaxTree(IReadOnlyList<Token> Tokens, string Namespace, IReadOnl
}
}
public record BlockSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<StatementSyntax> Statements) : SyntaxNode(Tokens)
public record BlockSyntax(IReadOnlyList<StatementSyntax> Statements) : SyntaxNode
{
public override IEnumerable<SyntaxNode> GetChildren()
{

View File

@@ -1,5 +1,3 @@
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node;
public enum PrimitiveTypeSyntaxKind
@@ -17,7 +15,7 @@ public enum PrimitiveTypeSyntaxKind
Bool
}
public abstract record TypeSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens)
public abstract record TypeSyntax : SyntaxNode
{
public string MangledName()
{
@@ -36,7 +34,7 @@ public abstract record TypeSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Toke
}
}
public record FuncTypeSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<TypeSyntax> Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens)
public record FuncTypeSyntax(IReadOnlyList<TypeSyntax> Parameters, TypeSyntax ReturnType) : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -49,7 +47,7 @@ public record FuncTypeSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<TypeSynt
}
}
public record PointerTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens)
public record PointerTypeSyntax(TypeSyntax BaseType) : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{
@@ -57,32 +55,32 @@ public record PointerTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType
}
}
public record VoidTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
public record VoidTypeSyntax : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record PrimitiveTypeSyntax(IReadOnlyList<Token> Tokens, PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax(Tokens)
public record PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record CStringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
public record CStringTypeSyntax : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record StringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
public record StringTypeSyntax : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record CustomTypeSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name) : TypeSyntax(Tokens)
public record CustomTypeSyntax(string Namespace, string Name) : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren() => [];
}
public record ArrayTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens)
public record ArrayTypeSyntax(TypeSyntax BaseType) : TypeSyntax
{
public override IEnumerable<SyntaxNode> GetChildren()
{

View File

@@ -11,7 +11,7 @@ public sealed class Parser
private string _namespace;
private readonly IReadOnlyList<Token> _tokens;
private readonly List<Diagnostic> _diagnostics = [];
private List<Diagnostic> _diagnostics = [];
private int _tokenIndex;
public Parser(IReadOnlyList<Token> tokens)
@@ -20,9 +20,9 @@ public sealed class Parser
_tokens = tokens;
}
public SyntaxTree Parse()
public SyntaxTree Parse(out IReadOnlyList<Diagnostic> diagnostics)
{
_diagnostics.Clear();
_diagnostics = [];
_tokenIndex = 0;
if (TryExpectSymbol(Symbol.Namespace))
@@ -34,22 +34,19 @@ public sealed class Parser
while (Peek().HasValue)
{
var startIndex = _tokenIndex;
try
{
var keyword = ExpectSymbol();
var definition = keyword.Symbol switch
{
Symbol.Extern => ParseExtern(startIndex),
Symbol.Func => ParseFunc(startIndex),
Symbol.Struct => ParseStruct(startIndex),
Symbol.Interface => ParseInterface(startIndex),
Symbol.Extern => ParseExtern(),
Symbol.Func => ParseFunc(),
Symbol.Struct => ParseStruct(),
Symbol.Interface => ParseInterface(),
_ => throw new ParseException(Diagnostic
.Error($"Expected 'extern', 'func', 'struct', 'trait' or 'impl' but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'extern', 'func', 'struct', 'trait' and 'impl'")
.At(keyword)
.Error($"Expected 'extern', 'func', 'struct' or 'interface' but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'extern', 'func', 'struct' and 'interface'")
.Build())
};
@@ -71,13 +68,12 @@ public sealed class Parser
}
}
return new SyntaxTree(_tokens, _namespace, definitions, _diagnostics);
diagnostics = _diagnostics;
return new SyntaxTree(_namespace, definitions);
}
private FuncSignatureSyntax ParseFuncSignature(FuncParameterSyntax? thisArg = null)
{
var startIndex = _tokenIndex;
List<FuncParameterSyntax> parameters = [];
if (thisArg != null)
@@ -96,38 +92,36 @@ public sealed class Parser
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters")
.WithHelp("Add a ',' to separate parameters")
.At(token)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([GetTokens(startIndex).Last()]);
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax();
return new FuncSignatureSyntax(GetTokens(startIndex), parameters, returnType);
return new FuncSignatureSyntax(parameters, returnType);
}
private FuncParameterSyntax ParseFuncParameter()
{
var startIndex = _tokenIndex;
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
return new FuncParameterSyntax(name.Value, type);
}
private DefinitionSyntax ParseExtern(int startIndex)
private DefinitionSyntax ParseExtern()
{
var keyword = ExpectSymbol();
return keyword.Symbol switch
{
Symbol.Func => ParseExternFunc(startIndex),
_ => throw new ParseException(Diagnostic.Error($"Unexpected symbol {keyword.Symbol} after extern declaration").At(keyword).Build())
Symbol.Func => ParseExternFunc(),
_ => throw new ParseException(Diagnostic.Error($"Unexpected symbol {keyword.Symbol} after extern declaration").Build())
};
}
private ExternFuncSyntax ParseExternFunc(int startIndex)
private ExternFuncSyntax ParseExternFunc()
{
var name = ExpectIdentifier();
@@ -140,19 +134,19 @@ public sealed class Parser
var signature = ParseFuncSignature();
return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, signature);
return new ExternFuncSyntax(_namespace, name.Value, callName, signature);
}
private LocalFuncSyntax ParseFunc(int startIndex)
private LocalFuncSyntax ParseFunc()
{
var name = ExpectIdentifier();
var signature = ParseFuncSignature();
var body = ParseBlock();
return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, signature, body);
return new LocalFuncSyntax(_namespace, name.Value, signature, body);
}
private DefinitionSyntax ParseStruct(int startIndex)
private DefinitionSyntax ParseStruct()
{
var name = ExpectIdentifier();
@@ -165,16 +159,14 @@ public sealed class Parser
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var memberStartIndex = _tokenIndex;
if (TryExpectSymbol(Symbol.Func))
{
var funcName = ExpectIdentifier().Value;
var thisArg = new FuncParameterSyntax([], "this", new CustomTypeSyntax([], _namespace, name.Value));
var thisArg = new FuncParameterSyntax("this", new CustomTypeSyntax(_namespace, name.Value));
var funcSignature = ParseFuncSignature(thisArg);
var funcBody = ParseBlock();
funcs.Add(new StructFuncSyntax(GetTokens(memberStartIndex), funcName, funcSignature, funcBody));
funcs.Add(new StructFuncSyntax(funcName, funcSignature, funcBody));
}
else
{
@@ -189,14 +181,14 @@ public sealed class Parser
fieldValue = ParseExpression();
}
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldIndex++, fieldName, fieldType, fieldValue));
fields.Add(new StructFieldSyntax(fieldIndex++, fieldName, fieldType, fieldValue));
}
}
return new StructSyntax(GetTokens(startIndex), _namespace, name.Value, fields, funcs);
return new StructSyntax(_namespace, name.Value, fields, funcs);
}
private InterfaceSyntax ParseInterface(int startIndex)
private InterfaceSyntax ParseInterface()
{
var name = ExpectIdentifier();
@@ -206,27 +198,23 @@ public sealed class Parser
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var funcStartIndex = _tokenIndex;
ExpectSymbol(Symbol.Func);
var funcName = ExpectIdentifier().Value;
var signature = ParseFuncSignature();
functions.Add(new InterfaceFuncSyntax(GetTokens(funcStartIndex), funcName, signature));
functions.Add(new InterfaceFuncSyntax(funcName, signature));
}
return new InterfaceSyntax(GetTokens(startIndex), _namespace, name.Value, functions);
return new InterfaceSyntax(_namespace, name.Value, functions);
}
private StatementSyntax ParseStatement()
{
var startIndex = _tokenIndex;
if (!Peek().TryGetValue(out var token))
{
throw new ParseException(Diagnostic
.Error("Unexpected end of file while parsing statement")
.At(_tokens[^1])
.Build());
}
@@ -235,37 +223,37 @@ public sealed class Parser
switch (symbol.Symbol)
{
case Symbol.Return:
return ParseReturn(startIndex);
return ParseReturn();
case Symbol.If:
return ParseIf(startIndex);
return ParseIf();
case Symbol.While:
return ParseWhile(startIndex);
return ParseWhile();
case Symbol.Let:
return ParseVariableDeclaration(startIndex);
return ParseVariableDeclaration();
case Symbol.Break:
return ParseBreak(startIndex);
return ParseBreak();
case Symbol.Continue:
return ParseContinue(startIndex);
return ParseContinue();
}
}
return ParseStatementExpression(startIndex);
return ParseStatementExpression();
}
private StatementSyntax ParseStatementExpression(int startIndex)
private StatementSyntax ParseStatementExpression()
{
var expr = ParseExpression();
if (TryExpectSymbol(Symbol.Assign))
{
var value = ParseExpression();
return new AssignmentSyntax(GetTokens(startIndex), expr, value);
return new AssignmentSyntax(expr, value);
}
return new StatementExpressionSyntax(GetTokens(startIndex), expr);
return new StatementExpressionSyntax(expr);
}
private VariableDeclarationSyntax ParseVariableDeclaration(int startIndex)
private VariableDeclarationSyntax ParseVariableDeclaration()
{
ExpectSymbol(Symbol.Let);
var name = ExpectIdentifier().Value;
@@ -282,23 +270,23 @@ public sealed class Parser
assignment = ParseExpression();
}
return new VariableDeclarationSyntax(GetTokens(startIndex), name, explicitType, assignment);
return new VariableDeclarationSyntax(name, explicitType, assignment);
}
private StatementSyntax ParseBreak(int startIndex)
private StatementSyntax ParseBreak()
{
ExpectSymbol(Symbol.Break);
Next();
return new BreakSyntax(GetTokens(startIndex));
return new BreakSyntax();
}
private StatementSyntax ParseContinue(int startIndex)
private StatementSyntax ParseContinue()
{
ExpectSymbol(Symbol.Continue);
return new ContinueSyntax(GetTokens(startIndex));
return new ContinueSyntax();
}
private ReturnSyntax ParseReturn(int startIndex)
private ReturnSyntax ParseReturn()
{
ExpectSymbol(Symbol.Return);
@@ -309,10 +297,10 @@ public sealed class Parser
value = ParseExpression();
}
return new ReturnSyntax(GetTokens(startIndex), value);
return new ReturnSyntax(value);
}
private IfSyntax ParseIf(int startIndex)
private IfSyntax ParseIf()
{
ExpectSymbol(Symbol.If);
var condition = ParseExpression();
@@ -321,26 +309,24 @@ public sealed class Parser
var elseStatement = Optional<Variant<IfSyntax, BlockSyntax>>.Empty();
if (TryExpectSymbol(Symbol.Else))
{
var newStartIndex = _tokenIndex;
elseStatement = TryExpectSymbol(Symbol.If)
? (Variant<IfSyntax, BlockSyntax>)ParseIf(newStartIndex)
? (Variant<IfSyntax, BlockSyntax>)ParseIf()
: (Variant<IfSyntax, BlockSyntax>)ParseBlock();
}
return new IfSyntax(GetTokens(startIndex), condition, body, elseStatement);
return new IfSyntax(condition, body, elseStatement);
}
private WhileSyntax ParseWhile(int startIndex)
private WhileSyntax ParseWhile()
{
ExpectSymbol(Symbol.While);
var condition = ParseExpression();
var body = ParseBlock();
return new WhileSyntax(GetTokens(startIndex), condition, body);
return new WhileSyntax(condition, body);
}
private ExpressionSyntax ParseExpression(int precedence = 0)
{
var startIndex = _tokenIndex;
var left = ParsePrimaryExpression();
while (true)
@@ -355,7 +341,7 @@ public sealed class Parser
Next();
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
left = new BinaryExpressionSyntax(GetTokens(startIndex), left, op.Value, right);
left = new BinaryExpressionSyntax(left, op.Value, right);
}
return left;
@@ -421,7 +407,6 @@ public sealed class Parser
private ExpressionSyntax ParsePrimaryExpression()
{
var startIndex = _tokenIndex;
ExpressionSyntax expr;
var token = ExpectToken();
@@ -429,7 +414,7 @@ public sealed class Parser
{
case LiteralToken literal:
{
expr = new LiteralSyntax(GetTokens(startIndex), literal.Value, literal.Kind);
expr = new LiteralSyntax(literal.Value, literal.Kind);
break;
}
case IdentifierToken identifier:
@@ -442,7 +427,7 @@ public sealed class Parser
name = ExpectIdentifier().Value;
}
expr = new IdentifierSyntax(GetTokens(startIndex), @namespace, name);
expr = new IdentifierSyntax(@namespace, name);
break;
}
case SymbolToken symbolToken:
@@ -455,27 +440,24 @@ public sealed class Parser
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
var parameterStartIndex = _tokenIndex;
var name = ExpectIdentifier();
parameters.Add(new ArrowFuncParameterSyntax(GetTokens(parameterStartIndex), name.Value));
parameters.Add(new ArrowFuncParameterSyntax(name.Value));
}
BlockSyntax body;
if (TryExpectSymbol(Symbol.Arrow))
{
var blockStartIndex = _tokenIndex;
var returnValue = ParseExpression();
var tokens = GetTokens(blockStartIndex);
var arrowExpression = new ReturnSyntax(tokens, returnValue);
body = new BlockSyntax(tokens, [arrowExpression]);
var arrowExpression = new ReturnSyntax(returnValue);
body = new BlockSyntax([arrowExpression]);
}
else
{
body = ParseBlock();
}
expr = new ArrowFuncSyntax(GetTokens(startIndex), parameters, body);
expr = new ArrowFuncSyntax(parameters, body);
break;
}
case Symbol.OpenParen:
@@ -488,13 +470,13 @@ public sealed class Parser
case Symbol.Minus:
{
var expression = ParsePrimaryExpression();
expr = new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperator.Negate, expression);
expr = new UnaryExpressionSyntax(UnaryOperator.Negate, expression);
break;
}
case Symbol.Bang:
{
var expression = ParsePrimaryExpression();
expr = new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperator.Invert, expression);
expr = new UnaryExpressionSyntax(UnaryOperator.Invert, expression);
break;
}
case Symbol.OpenBracket:
@@ -502,7 +484,7 @@ public sealed class Parser
var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
expr = new ArrayInitializerSyntax(GetTokens(startIndex), capacity, type);
expr = new ArrayInitializerSyntax(capacity, type);
break;
}
case Symbol.Alloc:
@@ -518,7 +500,7 @@ public sealed class Parser
initializers.Add(name, value);
}
expr = new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
expr = new StructInitializerSyntax(type, initializers);
break;
}
default:
@@ -526,7 +508,6 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
.WithHelp("Expected literal, identifier, or '(' to start expression")
.At(symbolToken)
.Build());
}
}
@@ -538,34 +519,33 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error($"Unexpected token '{token.GetType().Name}' in expression")
.WithHelp("Expected literal, identifier, or parenthesized expression")
.At(token)
.Build());
}
}
return ParsePostfixOperators(startIndex, expr);
return ParsePostfixOperators(expr);
}
private ExpressionSyntax ParsePostfixOperators(int startIndex, ExpressionSyntax expr)
private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
{
while (true)
{
if (TryExpectSymbol(Symbol.Ampersand))
{
expr = new AddressOfSyntax(GetTokens(startIndex), expr);
expr = new AddressOfSyntax(expr);
break;
}
if (TryExpectSymbol(Symbol.Caret))
{
expr = new DereferenceSyntax(GetTokens(startIndex), expr);
expr = new DereferenceSyntax(expr);
continue;
}
if (TryExpectSymbol(Symbol.Period))
{
var structMember = ExpectIdentifier().Value;
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, structMember);
expr = new MemberAccessSyntax(expr, structMember);
continue;
}
@@ -573,7 +553,7 @@ public sealed class Parser
{
var index = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
expr = new ArrayIndexAccessSyntax(GetTokens(startIndex), expr, index);
expr = new ArrayIndexAccessSyntax(expr, index);
continue;
}
@@ -588,12 +568,11 @@ public sealed class Parser
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function arguments")
.WithHelp("Add a ',' to separate arguments")
.At(nextToken)
.Build());
}
}
expr = new FuncCallSyntax(GetTokens(startIndex), expr, parameters);
expr = new FuncCallSyntax(expr, parameters);
continue;
}
@@ -605,7 +584,6 @@ public sealed class Parser
private BlockSyntax ParseBlock()
{
var startIndex = _tokenIndex;
ExpectSymbol(Symbol.OpenBrace);
List<StatementSyntax> statements = [];
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
@@ -621,31 +599,29 @@ public sealed class Parser
}
}
return new BlockSyntax(GetTokens(startIndex), statements);
return new BlockSyntax(statements);
}
private TypeSyntax ParseType()
{
var startIndex = _tokenIndex;
if (TryExpectIdentifier(out var name))
{
return name.Value switch
{
"void" => new VoidTypeSyntax(GetTokens(startIndex)),
"string" => new StringTypeSyntax(GetTokens(startIndex)),
"cstring" => new CStringTypeSyntax(GetTokens(startIndex)),
"i64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I64),
"i32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I32),
"i16" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I16),
"i8" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I8),
"u64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U64),
"u32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U32),
"u16" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U16),
"u8" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U8),
"f64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.F64),
"f32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.F32),
"bool" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.Bool),
"void" => new VoidTypeSyntax(),
"string" => new StringTypeSyntax(),
"cstring" => new CStringTypeSyntax(),
"i64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I64),
"i32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I32),
"i16" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I16),
"i8" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I8),
"u64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U64),
"u32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U32),
"u16" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U16),
"u8" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U8),
"f64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.F64),
"f32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.F32),
"bool" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.Bool),
_ => ParseCustomType()
};
@@ -657,14 +633,14 @@ public sealed class Parser
@namespace = ExpectIdentifier().Value;
}
return new CustomTypeSyntax(GetTokens(startIndex), @namespace, name.Value);
return new CustomTypeSyntax(@namespace, name.Value);
}
}
if (TryExpectSymbol(Symbol.Caret))
{
var baseType = ParseType();
return new PointerTypeSyntax(GetTokens(startIndex), baseType);
return new PointerTypeSyntax(baseType);
}
if (TryExpectSymbol(Symbol.Func))
@@ -680,21 +656,20 @@ public sealed class Parser
_diagnostics.Add(Diagnostic
.Warning("Missing comma between func type arguments")
.WithHelp("Add a ',' to separate arguments")
.At(nextToken)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax(GetTokens(startIndex));
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax();
return new FuncTypeSyntax(GetTokens(startIndex), parameters, returnType);
return new FuncTypeSyntax(parameters, returnType);
}
if (TryExpectSymbol(Symbol.OpenBracket))
{
ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType();
return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
return new ArrayTypeSyntax(baseType);
}
if (!Peek().TryGetValue(out var peekToken))
@@ -702,14 +677,12 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error("Unexpected end of file while parsing type")
.WithHelp("Expected a type name")
.At(_tokens[^1])
.Build());
}
throw new ParseException(Diagnostic
.Error("Invalid type Syntax")
.WithHelp("Expected type name, '^' for pointer, or '[]' for array")
.At(peekToken)
.Build());
}
@@ -720,7 +693,6 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error("Unexpected end of file")
.WithHelp("Expected more tokens to complete the Syntax")
.At(_tokens.Last())
.Build());
}
@@ -736,7 +708,6 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error($"Expected symbol, but found {token.GetType().Name}")
.WithHelp("This position requires a symbol like '(', ')', '{', '}', etc.")
.At(token)
.Build());
}
@@ -751,7 +722,6 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error($"Expected '{expectedSymbol}', but found '{token.Symbol}'")
.WithHelp($"Insert '{expectedSymbol}' here")
.At(token)
.Build());
}
}
@@ -788,7 +758,6 @@ public sealed class Parser
throw new ParseException(Diagnostic
.Error($"Expected identifier, but found {token.GetType().Name}")
.WithHelp("Provide a valid identifier name here")
.At(token)
.Build());
}
@@ -810,11 +779,6 @@ public sealed class Parser
{
_tokenIndex++;
}
private List<Token> GetTokens(int startIndex)
{
return _tokens.Skip(startIndex).Take(Math.Min(_tokenIndex, _tokens.Count - 1) - startIndex).ToList();
}
}
public class ParseException : Exception

View File

@@ -1,16 +1,13 @@
namespace NubLang.Syntax.Tokenization;
public abstract class Token(SourceSpan span)
{
public SourceSpan Span { get; } = span;
}
public abstract class Token;
public class IdentifierToken(SourceSpan span, string value) : Token(span)
public class IdentifierToken(string value) : Token
{
public string Value { get; } = value;
}
public class LiteralToken(SourceSpan span, LiteralKind kind, string value) : Token(span)
public class LiteralToken(LiteralKind kind, string value) : Token
{
public LiteralKind Kind { get; } = kind;
public string Value { get; } = value;
@@ -24,7 +21,7 @@ public enum LiteralKind
Bool
}
public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
public class SymbolToken(Symbol symbol) : Token
{
public Symbol Symbol { get; } = symbol;
}

View File

@@ -24,7 +24,7 @@ public sealed class Tokenizer
["extern"] = Symbol.Extern,
};
private static readonly Dictionary<char[], Symbol> Chians = new()
private static readonly Dictionary<char[], Symbol> Symbols = new()
{
[['=', '=']] = Symbol.Equal,
[['!', '=']] = Symbol.NotEqual,
@@ -32,36 +32,32 @@ public sealed class Tokenizer
[['>', '=']] = Symbol.GreaterThanOrEqual,
[[':', ':']] = Symbol.DoubleColon,
[['=', '>']] = Symbol.Arrow,
[[':']] = 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,
};
private static readonly Dictionary<char, Symbol> Chars = new()
{
[':'] = 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,
};
private readonly SourceText _sourceText;
private readonly string _sourceText;
private int _index;
public Tokenizer(SourceText sourceText)
public Tokenizer(string sourceText)
{
_sourceText = sourceText;
}
@@ -122,15 +118,15 @@ public sealed class Tokenizer
if (Keywords.TryGetValue(buffer, out var keywordSymbol))
{
return new SymbolToken(CreateSpan(startIndex), keywordSymbol);
return new SymbolToken(keywordSymbol);
}
if (buffer is "true" or "false")
{
return new LiteralToken(CreateSpan(startIndex), LiteralKind.Bool, buffer);
return new LiteralToken(LiteralKind.Bool, buffer);
}
return new IdentifierToken(CreateSpan(startIndex), buffer);
return new IdentifierToken(buffer);
}
if (char.IsDigit(current))
@@ -162,15 +158,12 @@ public sealed class Tokenizer
}
}
return new LiteralToken(CreateSpan(startIndex), isFloat ? LiteralKind.Float : LiteralKind.Integer, buffer);
return new LiteralToken(isFloat ? LiteralKind.Float : LiteralKind.Integer, buffer);
}
// TODO: Revisit this
foreach (var chain in Chians)
foreach (var chain in Symbols)
{
if (current != chain.Key[0]) continue;
for (var i = 1; i < chain.Key.Length; i++)
for (var i = 0; i < chain.Key.Length; i++)
{
var c = Peek(i);
if (!c.HasValue || c.Value != chain.Key[i]) break;
@@ -182,17 +175,11 @@ public sealed class Tokenizer
Next();
}
return new SymbolToken(CreateSpan(startIndex), chain.Value);
return new SymbolToken(chain.Value);
}
}
}
if (Chars.TryGetValue(current, out var charSymbol))
{
Next();
return new SymbolToken(CreateSpan(startIndex), charSymbol);
}
if (current == '"')
{
Next();
@@ -215,42 +202,17 @@ public sealed class Tokenizer
Next();
}
return new LiteralToken(CreateSpan(startIndex), LiteralKind.String, buffer);
return new LiteralToken(LiteralKind.String, buffer);
}
throw new Exception($"Unknown character {current}");
}
private SourceLocation CreateLocation(int index)
{
var line = 1;
var column = 1;
for (var i = 0; i < Math.Min(index, _sourceText.Content.Length - 1); i++)
{
if (_sourceText.Content[i] == '\n')
{
column = 1;
line += 1;
}
else
{
column += 1;
}
}
return new SourceLocation(line, column);
}
private SourceSpan CreateSpan(int startIndex)
{
return new SourceSpan(_sourceText, CreateLocation(startIndex), CreateLocation(_index));
}
private Optional<char> Peek(int offset = 0)
{
if (_index + offset < _sourceText.Content.Length)
if (_index + offset < _sourceText.Length)
{
return _sourceText.Content[_index + offset];
return _sourceText[_index + offset];
}
return Optional<char>.Empty();
@@ -258,9 +220,9 @@ public sealed class Tokenizer
private Optional<char> Next()
{
if (_index < _sourceText.Content.Length)
if (_index < _sourceText.Length)
{
return _sourceText.Content[_index++];
return _sourceText[_index++];
}
_index++;