This commit is contained in:
nub31
2025-07-22 22:10:31 +02:00
parent 3faaf71e78
commit 6b733b9cdf
25 changed files with 413 additions and 972 deletions

View File

@@ -1,3 +1,5 @@
using NubLang.Code;
namespace NubLang.CLI; namespace NubLang.CLI;
public class Options public class Options
@@ -5,5 +7,5 @@ public class Options
public string? CustomRuntime { get; set; } public string? CustomRuntime { get; set; }
public string? OutputPath { get; set; } public string? OutputPath { get; set; }
public bool Link { get; set; } = true; 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 System.Reflection;
using NubLang.CLI; using NubLang.CLI;
using NubLang; using NubLang.Code;
using NubLang.Common; using NubLang.Common;
using NubLang.Diagnostics; using NubLang.Diagnostics;
using NubLang.Generation; using NubLang.Generation;
@@ -62,16 +62,16 @@ for (var i = 0; i < args.Length; i++)
} }
else else
{ {
options.Files.Add(arg); options.Files.Add(new SourceFile(arg));
} }
} }
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var syntaxTrees = new Dictionary<string, SyntaxTree>(); var syntaxTrees = new List<SyntaxTree>();
foreach (var file in options.Files) foreach (var file in options.Files)
{ {
if (!File.Exists(file)) if (!File.Exists(file.Path))
{ {
Console.Error.WriteLine($"File '{file}' does not exist"); Console.Error.WriteLine($"File '{file}' does not exist");
return 1; return 1;
@@ -80,30 +80,27 @@ foreach (var file in options.Files)
foreach (var file in options.Files) foreach (var file in options.Files)
{ {
var content = File.ReadAllText(file); var tokenizer = new Tokenizer(file.GetText());
var sourceText = new SourceText(file, content);
var tokenizer = new Tokenizer(sourceText);
var tokenizeResult = tokenizer.Tokenize(out var tokenizerDiagnostics); var tokenizeResult = tokenizer.Tokenize(out var tokenizerDiagnostics);
diagnostics.AddRange(tokenizerDiagnostics); diagnostics.AddRange(tokenizerDiagnostics);
var parser = new Parser(tokenizeResult); var parser = new Parser(tokenizeResult);
var syntaxTree = parser.Parse(); var syntaxTree = parser.Parse(out var parserDiagnostics);
diagnostics.AddRange(syntaxTree.Diagnostics); 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 binder = new Binder(syntaxTree, definitionTable);
var boundSyntaxTree = binder.Bind(); var boundSyntaxTree = binder.Bind();
diagnostics.AddRange(boundSyntaxTree.Diagnostics); diagnostics.AddRange(boundSyntaxTree.Diagnostics);
boundSyntaxTrees[file] = boundSyntaxTree; boundSyntaxTrees.Add(boundSyntaxTree);
} }
foreach (var diagnostic in diagnostics) foreach (var diagnostic in diagnostics)
@@ -116,15 +113,15 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1; return 1;
} }
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values); var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees);
var objectFiles = new List<string>(); 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(); var ssa = generator.Emit();
File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa); 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; namespace NubLang.Diagnostics;
public static class ConsoleColors public static class ConsoleColors
@@ -56,118 +53,4 @@ public static class ConsoleColors
{ {
return IsColorSupported() ? $"{color}{text}{Reset}" : text; 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 System.Text;
using NubLang.Syntax.Parsing.Node;
using NubLang.Syntax.Tokenization;
namespace NubLang.Diagnostics; namespace NubLang.Diagnostics;
@@ -11,7 +9,6 @@ public class Diagnostic
private readonly DiagnosticSeverity _severity; private readonly DiagnosticSeverity _severity;
private readonly string _message; private readonly string _message;
private string? _help; private string? _help;
private SourceSpan? _sourceSpan;
public DiagnosticBuilder(DiagnosticSeverity severity, string message) public DiagnosticBuilder(DiagnosticSeverity severity, string message)
{ {
@@ -19,31 +16,13 @@ public class Diagnostic
_message = message; _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) public DiagnosticBuilder WithHelp(string help)
{ {
_help = help; _help = help;
return this; 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); public static DiagnosticBuilder Error(string message) => new(DiagnosticSeverity.Error, message);
@@ -52,14 +31,12 @@ public class Diagnostic
public DiagnosticSeverity Severity { get; } public DiagnosticSeverity Severity { get; }
public string Message { get; } public string Message { get; }
public SourceSpan? Span { get; }
public string? Help { 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; Severity = severity;
Message = message; Message = message;
Span = span;
Help = help; Help = help;
} }
@@ -70,21 +47,9 @@ public class Diagnostic
var severityText = GetSeverityText(Severity); var severityText = GetSeverityText(Severity);
sb.Append(severityText); 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(": ");
sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite)); sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
if (Span.HasValue)
{
sb.AppendLine();
AppendSourceContext(sb, Span.Value, Severity);
}
if (!string.IsNullOrEmpty(Help)) if (!string.IsNullOrEmpty(Help))
{ {
sb.AppendLine(); sb.AppendLine();
@@ -104,107 +69,6 @@ public class Diagnostic
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, "Unknown diagnostic severity") _ => 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 public enum DiagnosticSeverity

View File

@@ -10,8 +10,6 @@ public partial class QBEGenerator
{ {
private Val EmitExpression(BoundExpression expression) private Val EmitExpression(BoundExpression expression)
{ {
_writer.WriteDebugLocation(expression);
return expression switch return expression switch
{ {
BoundArrayInitializer arrayInitializer => EmitArrayInitializer(arrayInitializer), BoundArrayInitializer arrayInitializer => EmitArrayInitializer(arrayInitializer),
@@ -27,8 +25,7 @@ public partial class QBEGenerator
BoundLiteral literal => EmitLiteral(literal), BoundLiteral literal => EmitLiteral(literal),
BoundUnaryExpression unaryExpression => EmitUnaryExpression(unaryExpression), BoundUnaryExpression unaryExpression => EmitUnaryExpression(unaryExpression),
BoundStructFieldAccess structFieldAccess => EmitStructFieldAccess(structFieldAccess), BoundStructFieldAccess structFieldAccess => EmitStructFieldAccess(structFieldAccess),
BoundTraitFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess), BoundInterfaceFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess),
BoundTraitImplFuncAccess traitImplFuncAccess => EmitTraitImplFuncAccess(traitImplFuncAccess),
BoundArrayIndexAccess arrayIndex => EmitArrayIndexAccess(arrayIndex), BoundArrayIndexAccess arrayIndex => EmitArrayIndexAccess(arrayIndex),
_ => throw new ArgumentOutOfRangeException(nameof(expression)) _ => throw new ArgumentOutOfRangeException(nameof(expression))
}; };
@@ -418,22 +415,11 @@ public partial class QBEGenerator
return new Val(output, structFieldAccess.Type, ValKind.Pointer); return new Val(output, structFieldAccess.Type, ValKind.Pointer);
} }
private Val EmitTraitFuncAccess(BoundTraitFuncAccess traitFuncAccess) private Val EmitTraitFuncAccess(BoundInterfaceFuncAccess interfaceFuncAccess)
{ {
throw new NotImplementedException(); 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) private Val EmitFuncCall(BoundFuncCall funcCall)
{ {
var expression = EmitExpression(funcCall.Expression); var expression = EmitExpression(funcCall.Expression);
@@ -441,12 +427,6 @@ public partial class QBEGenerator
var parameterStrings = new List<string>(); 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) foreach (var parameter in funcCall.Parameters)
{ {
var copy = EmitCreateCopyOrInitialize(parameter); var copy = EmitCreateCopyOrInitialize(parameter);

View File

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

View File

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

View File

@@ -1,22 +1,13 @@
using System.Text; using System.Text;
using NubLang.Syntax.Binding.Node;
namespace NubLang.Generation.QBE; namespace NubLang.Generation.QBE;
internal class QBEWriter internal class QBEWriter
{ {
private readonly StringBuilder _builder = new(); private readonly StringBuilder _builder = new();
private int _currentLine = -1;
public QBEWriter(string debugFile)
{
_builder.AppendLine($"dbgfile \"{debugFile}\"");
_builder.AppendLine();
}
public void StartFunction(string signature) public void StartFunction(string signature)
{ {
_currentLine = -1;
_builder.Append(signature); _builder.Append(signature);
_builder.AppendLine(" {"); _builder.AppendLine(" {");
_builder.AppendLine("@start"); _builder.AppendLine("@start");
@@ -27,26 +18,6 @@ internal class QBEWriter
_builder.AppendLine("}"); _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) public void Indented(string value)
{ {
_builder.Append('\t'); _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) 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) private BoundStruct BindStruct(StructSyntax node)
@@ -82,15 +82,15 @@ public sealed class Binder
value = BindExpression(field.Value.Value, BindType(field.Type)); 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) 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) private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
@@ -98,7 +98,7 @@ public sealed class Binder
var signature = BindFuncSignature(node.Signature); var signature = BindFuncSignature(node.Signature);
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters); 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) private BoundStatement BindStatement(StatementSyntax node)
@@ -106,8 +106,8 @@ public sealed class Binder
return node switch return node switch
{ {
AssignmentSyntax statement => BindAssignment(statement), AssignmentSyntax statement => BindAssignment(statement),
BreakSyntax statement => BindBreak(statement), BreakSyntax => new BoundBreak(),
ContinueSyntax statement => BindContinue(statement), ContinueSyntax => new BoundContinue(),
IfSyntax statement => BindIf(statement), IfSyntax statement => BindIf(statement),
ReturnSyntax statement => BindReturn(statement), ReturnSyntax statement => BindReturn(statement),
StatementExpressionSyntax statement => BindStatementExpression(statement), StatementExpressionSyntax statement => BindStatementExpression(statement),
@@ -121,17 +121,7 @@ public sealed class Binder
{ {
var expression = BindExpression(statement.Target); var expression = BindExpression(statement.Target);
var value = BindExpression(statement.Value, expression.Type); var value = BindExpression(statement.Value, expression.Type);
return new BoundAssignment(statement.Tokens, expression, value); return new BoundAssignment(expression, value);
}
private BoundBreak BindBreak(BreakSyntax statement)
{
return new BoundBreak(statement.Tokens);
}
private BoundContinue BindContinue(ContinueSyntax statement)
{
return new BoundContinue(statement.Tokens);
} }
private BoundIf BindIf(IfSyntax statement) 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) private BoundReturn BindReturn(ReturnSyntax statement)
@@ -159,12 +149,12 @@ public sealed class Binder
value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek()); value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek());
} }
return new BoundReturn(statement.Tokens, value); return new BoundReturn(value);
} }
private BoundStatementExpression BindStatementExpression(StatementExpressionSyntax statement) private BoundStatementExpression BindStatementExpression(StatementExpressionSyntax statement)
{ {
return new BoundStatementExpression(statement.Tokens, BindExpression(statement.Expression)); return new BoundStatementExpression(BindExpression(statement.Expression));
} }
private BoundVariableDeclaration BindVariableDeclaration(VariableDeclarationSyntax statement) private BoundVariableDeclaration BindVariableDeclaration(VariableDeclarationSyntax statement)
@@ -191,12 +181,12 @@ public sealed class Binder
Scope.Declare(new Variable(statement.Name, type)); 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) 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) private BoundExpression BindExpression(ExpressionSyntax node, NubType? expectedType = null)
@@ -222,19 +212,19 @@ public sealed class Binder
private BoundAddressOf BindAddressOf(AddressOfSyntax expression) private BoundAddressOf BindAddressOf(AddressOfSyntax expression)
{ {
var inner = BindExpression(expression.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) private BoundArrowFunc BindArrowFunc(ArrowFuncSyntax expression, NubType? expectedType = null)
{ {
if (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) 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>(); var parameters = new List<BoundFuncParameter>();
@@ -248,40 +238,40 @@ public sealed class Binder
var expectedParameterType = funcType.Parameters[i]; var expectedParameterType = funcType.Parameters[i];
var parameter = expression.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); 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) private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression)
{ {
var boundArray = BindExpression(expression.Target); var boundArray = BindExpression(expression.Target);
var elementType = ((NubArrayType)boundArray.Type).ElementType; 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) private BoundArrayInitializer BindArrayInitializer(ArrayInitializerSyntax expression)
{ {
var capacity = BindExpression(expression.Capacity, new NubPrimitiveType(PrimitiveTypeKind.U64)); var capacity = BindExpression(expression.Capacity, new NubPrimitiveType(PrimitiveTypeKind.U64));
var type = new NubArrayType(BindType(expression.ElementType)); 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) private BoundBinaryExpression BindBinaryExpression(BinaryExpressionSyntax expression)
{ {
var boundLeft = BindExpression(expression.Left); var boundLeft = BindExpression(expression.Left);
var boundRight = BindExpression(expression.Right, boundLeft.Type); 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) private BoundDereference BindDereference(DereferenceSyntax expression)
{ {
var boundExpression = BindExpression(expression.Expression); var boundExpression = BindExpression(expression.Expression);
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType; var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
return new BoundDereference(expression.Tokens, dereferencedType, boundExpression); return new BoundDereference(dereferencedType, boundExpression);
} }
private BoundFuncCall BindFuncCall(FuncCallSyntax expression) private BoundFuncCall BindFuncCall(FuncCallSyntax expression)
@@ -304,7 +294,7 @@ public sealed class Binder
parameters.Add(BindExpression(parameter, expectedType)); 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) private BoundExpression BindIdentifier(IdentifierSyntax expression)
@@ -323,7 +313,7 @@ public sealed class Binder
var returnType = BindType(localFunc.Signature.ReturnType); var returnType = BindType(localFunc.Signature.ReturnType);
var parameterTypes = localFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList(); var parameterTypes = localFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType); 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(); var externFuncs = _definitionTable.LookupExternFunc(@namespace, expression.Name).ToArray();
@@ -339,7 +329,7 @@ public sealed class Binder
var returnType = BindType(externFunc.Signature.ReturnType); var returnType = BindType(externFunc.Signature.ReturnType);
var parameterTypes = externFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList(); var parameterTypes = externFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType); 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) if (!expression.Namespace.HasValue)
@@ -347,7 +337,7 @@ public sealed class Binder
var variable = Scope.Lookup(expression.Name); var variable = Scope.Lookup(expression.Name);
if (variable != null) 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() _ => 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) private BoundExpression BindMemberAccess(MemberAccessSyntax expression)
@@ -385,7 +375,7 @@ public sealed class Binder
// var returnType = BindType(impl.Signature.ReturnType); // var returnType = BindType(impl.Signature.ReturnType);
// var parameterTypes = impl.Signature.Parameters.Select(p => BindType(p.Type)).ToList(); // var parameterTypes = impl.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
// var type = new NubFuncType(parameterTypes, returnType); // 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) if (boundExpression.Type is NubCustomType customType)
@@ -413,7 +403,7 @@ public sealed class Binder
var returnType = BindType(traitFunc.Signature.ReturnType); var returnType = BindType(traitFunc.Signature.ReturnType);
var parameterTypes = traitFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList(); var parameterTypes = traitFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
var type = new NubFuncType(parameterTypes, returnType); 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]; 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)); 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) private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression)
@@ -523,7 +513,7 @@ public sealed class Binder
throw new NotImplementedException("Diagnostics not implemented"); 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) private BoundFuncSignature BindFuncSignature(FuncSignatureSyntax node)
@@ -532,10 +522,10 @@ public sealed class Binder
foreach (var parameter in node.Parameters) 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) private BoundBinaryOperator BindBinaryOperator(BinaryOperator op)
@@ -579,7 +569,7 @@ public sealed class Binder
_scopes.Pop(); _scopes.Pop();
return new BoundBlock(node.Tokens, statements); return new BoundBlock(statements);
} }
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IReadOnlyList<BoundFuncParameter> parameters) private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IReadOnlyList<BoundFuncParameter> parameters)

View File

@@ -1,26 +1,25 @@
using NubLang.Common; using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node; 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 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(NubType Type, BoundExpression Expression) : BoundExpression(Type);
public record BoundDereference(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);

View File

@@ -1,22 +1,21 @@
using NubLang.Common; using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node; 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.Diagnostics;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding.Node; namespace NubLang.Syntax.Binding.Node;
public record BoundSyntaxTree(string Namespace, IReadOnlyList<BoundDefinition> Definitions, IReadOnlyList<Diagnostic> Diagnostics); 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.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node; 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() 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() 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() 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() 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() 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() 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() 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() 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() public override IEnumerable<SyntaxNode> GetChildren()
{ {

View File

@@ -23,9 +23,9 @@ public enum BinaryOperator
Divide 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() 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() 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() 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 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() 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() 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 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() 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() 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 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() 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() 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() public override IEnumerable<SyntaxNode> GetChildren()
{ {

View File

@@ -1,11 +1,10 @@
using NubLang.Common; using NubLang.Common;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node; 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() 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() 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() 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() 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() 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 override IEnumerable<SyntaxNode> GetChildren() => [];
} }
public record BreakSyntax(IReadOnlyList<Token> Tokens) : StatementSyntax(Tokens) public record BreakSyntax : StatementSyntax
{ {
public override IEnumerable<SyntaxNode> GetChildren() => []; 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() => []; public override IEnumerable<SyntaxNode> GetChildren() => [];
} }

View File

@@ -1,9 +1,6 @@
using NubLang.Diagnostics;
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Parsing.Node;
public abstract record SyntaxNode(IReadOnlyList<Token> Tokens) public abstract record SyntaxNode
{ {
public abstract IEnumerable<SyntaxNode> GetChildren(); 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() 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() public override IEnumerable<SyntaxNode> GetChildren()
{ {

View File

@@ -1,5 +1,3 @@
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Parsing.Node;
public enum PrimitiveTypeSyntaxKind public enum PrimitiveTypeSyntaxKind
@@ -17,7 +15,7 @@ public enum PrimitiveTypeSyntaxKind
Bool Bool
} }
public abstract record TypeSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens) public abstract record TypeSyntax : SyntaxNode
{ {
public string MangledName() 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() 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() 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 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 override IEnumerable<SyntaxNode> GetChildren() => [];
} }
public record CStringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens) public record CStringTypeSyntax : TypeSyntax
{ {
public override IEnumerable<SyntaxNode> GetChildren() => []; public override IEnumerable<SyntaxNode> GetChildren() => [];
} }
public record StringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens) public record StringTypeSyntax : TypeSyntax
{ {
public override IEnumerable<SyntaxNode> GetChildren() => []; 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 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() public override IEnumerable<SyntaxNode> GetChildren()
{ {

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ public sealed class Tokenizer
["extern"] = Symbol.Extern, ["extern"] = Symbol.Extern,
}; };
private static readonly Dictionary<char[], Symbol> Chians = new() private static readonly Dictionary<char[], Symbol> Symbols = new()
{ {
[['=', '=']] = Symbol.Equal, [['=', '=']] = Symbol.Equal,
[['!', '=']] = Symbol.NotEqual, [['!', '=']] = Symbol.NotEqual,
@@ -32,36 +32,32 @@ public sealed class Tokenizer
[['>', '=']] = Symbol.GreaterThanOrEqual, [['>', '=']] = Symbol.GreaterThanOrEqual,
[[':', ':']] = Symbol.DoubleColon, [[':', ':']] = Symbol.DoubleColon,
[['=', '>']] = Symbol.Arrow, [['=', '>']] = 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() private readonly string _sourceText;
{
[':'] = 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 int _index; private int _index;
public Tokenizer(SourceText sourceText) public Tokenizer(string sourceText)
{ {
_sourceText = sourceText; _sourceText = sourceText;
} }
@@ -122,15 +118,15 @@ public sealed class Tokenizer
if (Keywords.TryGetValue(buffer, out var keywordSymbol)) if (Keywords.TryGetValue(buffer, out var keywordSymbol))
{ {
return new SymbolToken(CreateSpan(startIndex), keywordSymbol); return new SymbolToken(keywordSymbol);
} }
if (buffer is "true" or "false") 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)) 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 Symbols)
foreach (var chain in Chians)
{ {
if (current != chain.Key[0]) continue; for (var i = 0; i < chain.Key.Length; i++)
for (var i = 1; i < chain.Key.Length; i++)
{ {
var c = Peek(i); var c = Peek(i);
if (!c.HasValue || c.Value != chain.Key[i]) break; if (!c.HasValue || c.Value != chain.Key[i]) break;
@@ -182,17 +175,11 @@ public sealed class Tokenizer
Next(); 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 == '"') if (current == '"')
{ {
Next(); Next();
@@ -215,42 +202,17 @@ public sealed class Tokenizer
Next(); Next();
} }
return new LiteralToken(CreateSpan(startIndex), LiteralKind.String, buffer); return new LiteralToken(LiteralKind.String, buffer);
} }
throw new Exception($"Unknown character {current}"); 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) 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(); return Optional<char>.Empty();
@@ -258,9 +220,9 @@ public sealed class Tokenizer
private Optional<char> Next() private Optional<char> Next()
{ {
if (_index < _sourceText.Content.Length) if (_index < _sourceText.Length)
{ {
return _sourceText.Content[_index++]; return _sourceText[_index++];
} }
_index++; _index++;