...
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using NubLang.Code;
|
||||
|
||||
namespace NubLang.CLI;
|
||||
|
||||
public class Options
|
||||
@@ -5,5 +7,5 @@ public class Options
|
||||
public string? CustomRuntime { get; set; }
|
||||
public string? OutputPath { get; set; }
|
||||
public bool Link { get; set; } = true;
|
||||
public List<string> Files { get; } = [];
|
||||
public List<SourceFile> Files { get; } = [];
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
using NubLang.CLI;
|
||||
using NubLang;
|
||||
using NubLang.Code;
|
||||
using NubLang.Common;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Generation;
|
||||
@@ -62,16 +62,16 @@ for (var i = 0; i < args.Length; i++)
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Files.Add(arg);
|
||||
options.Files.Add(new SourceFile(arg));
|
||||
}
|
||||
}
|
||||
|
||||
var diagnostics = new List<Diagnostic>();
|
||||
var syntaxTrees = new Dictionary<string, SyntaxTree>();
|
||||
var syntaxTrees = new List<SyntaxTree>();
|
||||
|
||||
foreach (var file in options.Files)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
if (!File.Exists(file.Path))
|
||||
{
|
||||
Console.Error.WriteLine($"File '{file}' does not exist");
|
||||
return 1;
|
||||
@@ -80,30 +80,27 @@ foreach (var file in options.Files)
|
||||
|
||||
foreach (var file in options.Files)
|
||||
{
|
||||
var content = File.ReadAllText(file);
|
||||
var sourceText = new SourceText(file, content);
|
||||
|
||||
var tokenizer = new Tokenizer(sourceText);
|
||||
var tokenizer = new Tokenizer(file.GetText());
|
||||
var tokenizeResult = tokenizer.Tokenize(out var tokenizerDiagnostics);
|
||||
diagnostics.AddRange(tokenizerDiagnostics);
|
||||
|
||||
var parser = new Parser(tokenizeResult);
|
||||
var syntaxTree = parser.Parse();
|
||||
diagnostics.AddRange(syntaxTree.Diagnostics);
|
||||
var syntaxTree = parser.Parse(out var parserDiagnostics);
|
||||
diagnostics.AddRange(parserDiagnostics);
|
||||
|
||||
syntaxTrees[file] = syntaxTree;
|
||||
syntaxTrees.Add(syntaxTree);
|
||||
}
|
||||
|
||||
var definitionTable = new DefinitionTable(syntaxTrees.Values);
|
||||
var definitionTable = new DefinitionTable(syntaxTrees);
|
||||
|
||||
var boundSyntaxTrees = new Dictionary<string, BoundSyntaxTree>();
|
||||
var boundSyntaxTrees = new List<BoundSyntaxTree>();
|
||||
|
||||
foreach (var (file, syntaxTree) in syntaxTrees)
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
var binder = new Binder(syntaxTree, definitionTable);
|
||||
var boundSyntaxTree = binder.Bind();
|
||||
diagnostics.AddRange(boundSyntaxTree.Diagnostics);
|
||||
boundSyntaxTrees[file] = boundSyntaxTree;
|
||||
boundSyntaxTrees.Add(boundSyntaxTree);
|
||||
}
|
||||
|
||||
foreach (var diagnostic in diagnostics)
|
||||
@@ -116,15 +113,15 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
||||
return 1;
|
||||
}
|
||||
|
||||
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
|
||||
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees);
|
||||
|
||||
var objectFiles = new List<string>();
|
||||
|
||||
foreach (var file in options.Files)
|
||||
foreach (var syntaxTree in boundSyntaxTrees)
|
||||
{
|
||||
var outFileName = $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}";
|
||||
var outFileName = HexString.CreateUnique(8);
|
||||
|
||||
var generator = new QBEGenerator(boundSyntaxTrees[file], boundDefinitionTable, file);
|
||||
var generator = new QBEGenerator(syntaxTree, boundDefinitionTable);
|
||||
var ssa = generator.Emit();
|
||||
File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa);
|
||||
|
||||
|
||||
29
src/compiler/NubLang/Code/SourceFile.cs
Normal file
29
src/compiler/NubLang/Code/SourceFile.cs
Normal 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);
|
||||
}
|
||||
53
src/compiler/NubLang/Code/SourceLocation.cs
Normal file
53
src/compiler/NubLang/Code/SourceLocation.cs
Normal 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);
|
||||
}
|
||||
57
src/compiler/NubLang/Code/SourceSpan.cs
Normal file
57
src/compiler/NubLang/Code/SourceSpan.cs
Normal 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);
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
using System.Text;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Diagnostics;
|
||||
|
||||
public static class ConsoleColors
|
||||
@@ -56,118 +53,4 @@ public static class ConsoleColors
|
||||
{
|
||||
return IsColorSupported() ? $"{color}{text}{Reset}" : text;
|
||||
}
|
||||
|
||||
private static string GetTokenColor(Token token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case IdentifierToken:
|
||||
return White;
|
||||
case LiteralToken literal:
|
||||
return literal.Kind switch
|
||||
{
|
||||
LiteralKind.String => Green,
|
||||
LiteralKind.Integer or LiteralKind.Float => BrightBlue,
|
||||
LiteralKind.Bool => Blue,
|
||||
_ => White
|
||||
};
|
||||
case SymbolToken symbol:
|
||||
switch (symbol.Symbol)
|
||||
{
|
||||
case Symbol.If:
|
||||
case Symbol.Else:
|
||||
case Symbol.While:
|
||||
case Symbol.Break:
|
||||
case Symbol.Continue:
|
||||
case Symbol.Return:
|
||||
return Magenta;
|
||||
case Symbol.Func:
|
||||
case Symbol.Struct:
|
||||
case Symbol.Namespace:
|
||||
case Symbol.Let:
|
||||
case Symbol.Alloc:
|
||||
return Blue;
|
||||
case Symbol.Assign:
|
||||
case Symbol.Bang:
|
||||
case Symbol.Equal:
|
||||
case Symbol.NotEqual:
|
||||
case Symbol.LessThan:
|
||||
case Symbol.LessThanOrEqual:
|
||||
case Symbol.GreaterThan:
|
||||
case Symbol.GreaterThanOrEqual:
|
||||
case Symbol.Plus:
|
||||
case Symbol.Minus:
|
||||
case Symbol.Star:
|
||||
case Symbol.ForwardSlash:
|
||||
case Symbol.Caret:
|
||||
case Symbol.Ampersand:
|
||||
return White;
|
||||
case Symbol.Colon:
|
||||
case Symbol.Comma:
|
||||
case Symbol.Period:
|
||||
case Symbol.DoubleColon:
|
||||
return Faint;
|
||||
case Symbol.OpenParen:
|
||||
case Symbol.CloseParen:
|
||||
case Symbol.OpenBrace:
|
||||
case Symbol.CloseBrace:
|
||||
case Symbol.OpenBracket:
|
||||
case Symbol.CloseBracket:
|
||||
return Yellow;
|
||||
default:
|
||||
return White;
|
||||
}
|
||||
default:
|
||||
return White;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ColorizeSource(string source)
|
||||
{
|
||||
var sourceText = new SourceText(string.Empty, source);
|
||||
var tokenizer = new Tokenizer(sourceText);
|
||||
var tokens = tokenizer.Tokenize(out _);
|
||||
var result = new StringBuilder();
|
||||
var lastCharIndex = 0;
|
||||
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
var tokenStartIndex = GetCharacterIndex(sourceText, token.Span.Start);
|
||||
var tokenEndIndex = GetCharacterIndex(sourceText, token.Span.End);
|
||||
|
||||
if (tokenStartIndex > lastCharIndex)
|
||||
{
|
||||
var between = sourceText.Content.Substring(lastCharIndex, tokenStartIndex - lastCharIndex);
|
||||
result.Append(between);
|
||||
}
|
||||
|
||||
var tokenText = sourceText.Content.Substring(tokenStartIndex, tokenEndIndex - tokenStartIndex);
|
||||
|
||||
result.Append(Colorize(tokenText, GetTokenColor(token)));
|
||||
lastCharIndex = tokenEndIndex;
|
||||
}
|
||||
|
||||
if (lastCharIndex < sourceText.Content.Length)
|
||||
{
|
||||
var remaining = sourceText.Content[lastCharIndex..];
|
||||
result.Append(Colorize(remaining, Faint));
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private static int GetCharacterIndex(SourceText sourceText, SourceLocation location)
|
||||
{
|
||||
var lines = sourceText.Content.Split('\n');
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < location.Line - 1 && i < lines.Length; i++)
|
||||
{
|
||||
index += lines[i].Length + 1;
|
||||
}
|
||||
|
||||
index += location.Column - 1;
|
||||
|
||||
return Math.Min(index, sourceText.Content.Length);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Text;
|
||||
using NubLang.Syntax.Parsing.Node;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Diagnostics;
|
||||
|
||||
@@ -11,7 +9,6 @@ public class Diagnostic
|
||||
private readonly DiagnosticSeverity _severity;
|
||||
private readonly string _message;
|
||||
private string? _help;
|
||||
private SourceSpan? _sourceSpan;
|
||||
|
||||
public DiagnosticBuilder(DiagnosticSeverity severity, string message)
|
||||
{
|
||||
@@ -19,31 +16,13 @@ public class Diagnostic
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public DiagnosticBuilder At(Token token)
|
||||
{
|
||||
_sourceSpan = token.Span;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiagnosticBuilder At(SyntaxNode node)
|
||||
{
|
||||
_sourceSpan = SourceSpan.Merge(node.Tokens.Select(t => t.Span));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiagnosticBuilder At(SourceSpan span)
|
||||
{
|
||||
_sourceSpan = span;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiagnosticBuilder WithHelp(string help)
|
||||
{
|
||||
_help = help;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Diagnostic Build() => new(_severity, _message, _sourceSpan, _help);
|
||||
public Diagnostic Build() => new(_severity, _message, _help);
|
||||
}
|
||||
|
||||
public static DiagnosticBuilder Error(string message) => new(DiagnosticSeverity.Error, message);
|
||||
@@ -52,14 +31,12 @@ public class Diagnostic
|
||||
|
||||
public DiagnosticSeverity Severity { get; }
|
||||
public string Message { get; }
|
||||
public SourceSpan? Span { get; }
|
||||
public string? Help { get; }
|
||||
|
||||
private Diagnostic(DiagnosticSeverity severity, string message, SourceSpan? span, string? help)
|
||||
private Diagnostic(DiagnosticSeverity severity, string message, string? help)
|
||||
{
|
||||
Severity = severity;
|
||||
Message = message;
|
||||
Span = span;
|
||||
Help = help;
|
||||
}
|
||||
|
||||
@@ -70,21 +47,9 @@ public class Diagnostic
|
||||
var severityText = GetSeverityText(Severity);
|
||||
sb.Append(severityText);
|
||||
|
||||
if (Span.HasValue)
|
||||
{
|
||||
var locationText = $" at {Span.Value.Text.Path}:{Span}";
|
||||
sb.Append(ConsoleColors.Colorize(locationText, ConsoleColors.Faint));
|
||||
}
|
||||
|
||||
sb.Append(": ");
|
||||
sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
|
||||
|
||||
if (Span.HasValue)
|
||||
{
|
||||
sb.AppendLine();
|
||||
AppendSourceContext(sb, Span.Value, Severity);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Help))
|
||||
{
|
||||
sb.AppendLine();
|
||||
@@ -104,107 +69,6 @@ public class Diagnostic
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, "Unknown diagnostic severity")
|
||||
};
|
||||
}
|
||||
|
||||
private static void AppendSourceContext(StringBuilder sb, SourceSpan span, DiagnosticSeverity severity)
|
||||
{
|
||||
var lines = span.Text.Content.Split('\n');
|
||||
var startLine = span.Start.Line;
|
||||
var endLine = span.End.Line;
|
||||
|
||||
const int contextLines = 3;
|
||||
|
||||
var lineNumWidth = Math.Min(endLine + contextLines, lines.Length).ToString().Length;
|
||||
|
||||
var contextStart = Math.Max(1, startLine - contextLines);
|
||||
var contextEnd = Math.Min(lines.Length, endLine + contextLines);
|
||||
|
||||
var contextWidth = 0;
|
||||
for (var i = contextStart; i <= contextEnd; i++)
|
||||
{
|
||||
if (lines[i - 1].Length > contextWidth)
|
||||
{
|
||||
contextWidth = lines[i - 1].Length;
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine(ConsoleColors.Colorize('╭' + new string('─', lineNumWidth + 2) + '┬' + new string('─', contextWidth + 2) + '╮', ConsoleColors.Faint));
|
||||
|
||||
for (var lineNum = contextStart; lineNum < startLine; lineNum++)
|
||||
{
|
||||
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
|
||||
}
|
||||
|
||||
for (var lineNum = startLine; lineNum <= endLine; lineNum++)
|
||||
{
|
||||
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
|
||||
AppendErrorIndicators(sb, span, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth, severity);
|
||||
}
|
||||
|
||||
for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++)
|
||||
{
|
||||
AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
|
||||
}
|
||||
|
||||
sb.Append(ConsoleColors.Colorize('╰' + new string('─', lineNumWidth + 2) + '┴' + new string('─', contextWidth + 2) + '╯', ConsoleColors.Faint));
|
||||
}
|
||||
|
||||
private static void AppendContextLine(StringBuilder sb, int lineNum, string line, int lineNumWidth, int contextWidth)
|
||||
{
|
||||
sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
|
||||
var lineNumStr = lineNum.ToString().PadLeft(lineNumWidth);
|
||||
sb.Append(ConsoleColors.Colorize(lineNumStr, ConsoleColors.Faint));
|
||||
sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
|
||||
sb.Append(ConsoleColors.ColorizeSource(line.PadRight(contextWidth)));
|
||||
sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
private static void AppendErrorIndicators(StringBuilder sb, SourceSpan span, int lineNum, string line, int lineNumWidth, int contextWidth, DiagnosticSeverity severity)
|
||||
{
|
||||
var color = severity switch
|
||||
{
|
||||
DiagnosticSeverity.Info => ConsoleColors.Blue,
|
||||
DiagnosticSeverity.Warning => ConsoleColors.Yellow,
|
||||
DiagnosticSeverity.Error => ConsoleColors.Red,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, null)
|
||||
};
|
||||
|
||||
sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
|
||||
sb.Append(new string(' ', lineNumWidth));
|
||||
sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
|
||||
var indicators = GetIndicatorsForLine(span, lineNum, line);
|
||||
sb.Append(ConsoleColors.Colorize(indicators.PadRight(contextWidth), color));
|
||||
sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
private static string GetIndicatorsForLine(SourceSpan span, int lineNum, string line)
|
||||
{
|
||||
const char indicator = '^';
|
||||
|
||||
if (lineNum == span.Start.Line && lineNum == span.End.Line)
|
||||
{
|
||||
var startCol = Math.Max(0, span.Start.Column - 1);
|
||||
var endCol = Math.Min(line.Length, span.End.Column - 1);
|
||||
var length = Math.Max(1, endCol - startCol);
|
||||
|
||||
return new string(' ', startCol) + new string(indicator, length);
|
||||
}
|
||||
|
||||
if (lineNum == span.Start.Line)
|
||||
{
|
||||
var startCol = Math.Max(0, span.Start.Column - 1);
|
||||
return new string(' ', startCol) + new string(indicator, Math.Max(0, line.Length - startCol));
|
||||
}
|
||||
|
||||
if (lineNum == span.End.Line)
|
||||
{
|
||||
var endCol = Math.Min(line.Length, span.End.Column - 1);
|
||||
return new string(indicator, Math.Max(0, endCol));
|
||||
}
|
||||
|
||||
return new string(indicator, line.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DiagnosticSeverity
|
||||
|
||||
@@ -10,8 +10,6 @@ public partial class QBEGenerator
|
||||
{
|
||||
private Val EmitExpression(BoundExpression expression)
|
||||
{
|
||||
_writer.WriteDebugLocation(expression);
|
||||
|
||||
return expression switch
|
||||
{
|
||||
BoundArrayInitializer arrayInitializer => EmitArrayInitializer(arrayInitializer),
|
||||
@@ -27,8 +25,7 @@ public partial class QBEGenerator
|
||||
BoundLiteral literal => EmitLiteral(literal),
|
||||
BoundUnaryExpression unaryExpression => EmitUnaryExpression(unaryExpression),
|
||||
BoundStructFieldAccess structFieldAccess => EmitStructFieldAccess(structFieldAccess),
|
||||
BoundTraitFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess),
|
||||
BoundTraitImplFuncAccess traitImplFuncAccess => EmitTraitImplFuncAccess(traitImplFuncAccess),
|
||||
BoundInterfaceFuncAccess traitFuncAccess => EmitTraitFuncAccess(traitFuncAccess),
|
||||
BoundArrayIndexAccess arrayIndex => EmitArrayIndexAccess(arrayIndex),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(expression))
|
||||
};
|
||||
@@ -418,22 +415,11 @@ public partial class QBEGenerator
|
||||
return new Val(output, structFieldAccess.Type, ValKind.Pointer);
|
||||
}
|
||||
|
||||
private Val EmitTraitFuncAccess(BoundTraitFuncAccess traitFuncAccess)
|
||||
private Val EmitTraitFuncAccess(BoundInterfaceFuncAccess interfaceFuncAccess)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Val EmitTraitImplFuncAccess(BoundTraitImplFuncAccess traitImplFuncAccess)
|
||||
{
|
||||
var target = EmitExpression(traitImplFuncAccess.Target);
|
||||
|
||||
var funcImpl = _definitionTable.LookupTraitFuncImpl(traitImplFuncAccess.Target.Type, traitImplFuncAccess.FuncName);
|
||||
|
||||
var name = ImplFuncName();
|
||||
_implFunctions.TryAdd(funcImpl, name);
|
||||
return new Val(name, traitImplFuncAccess.Type, ValKind.Direct, new MethodCallContext(target));
|
||||
}
|
||||
|
||||
private Val EmitFuncCall(BoundFuncCall funcCall)
|
||||
{
|
||||
var expression = EmitExpression(funcCall.Expression);
|
||||
@@ -441,12 +427,6 @@ public partial class QBEGenerator
|
||||
|
||||
var parameterStrings = new List<string>();
|
||||
|
||||
if (expression.FuncCallContext != null)
|
||||
{
|
||||
var thisArg = EmitUnwrap(expression.FuncCallContext.ThisArg);
|
||||
parameterStrings.Add($"{FuncQBETypeName(expression.FuncCallContext.ThisArg.Type)} {thisArg}");
|
||||
}
|
||||
|
||||
foreach (var parameter in funcCall.Parameters)
|
||||
{
|
||||
var copy = EmitCreateCopyOrInitialize(parameter);
|
||||
|
||||
@@ -7,8 +7,6 @@ public partial class QBEGenerator
|
||||
{
|
||||
private void EmitStatement(BoundStatement statement)
|
||||
{
|
||||
_writer.WriteDebugLocation(statement);
|
||||
|
||||
switch (statement)
|
||||
{
|
||||
case BoundAssignment assignment:
|
||||
|
||||
@@ -18,23 +18,21 @@ public partial class QBEGenerator
|
||||
private readonly Stack<string> _breakLabels = [];
|
||||
private readonly Stack<string> _continueLabels = [];
|
||||
private readonly Queue<(BoundArrowFunc Func, string Name)> _arrowFunctions = [];
|
||||
private readonly Dictionary<BoundTraitFuncImpl, string> _implFunctions = [];
|
||||
private readonly Stack<Scope> _scopes = [];
|
||||
private int _tmpIndex;
|
||||
private int _labelIndex;
|
||||
private int _arrowFuncIndex;
|
||||
private int _cStringLiteralIndex;
|
||||
private int _stringLiteralIndex;
|
||||
private int _implFuncNameIndex;
|
||||
private bool _codeIsReachable = true;
|
||||
|
||||
private Scope Scope => _scopes.Peek();
|
||||
|
||||
public QBEGenerator(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable, string file)
|
||||
public QBEGenerator(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
|
||||
{
|
||||
_syntaxTree = syntaxTree;
|
||||
_definitionTable = definitionTable;
|
||||
_writer = new QBEWriter(file);
|
||||
_writer = new QBEWriter();
|
||||
}
|
||||
|
||||
public string Emit()
|
||||
@@ -44,14 +42,12 @@ public partial class QBEGenerator
|
||||
_breakLabels.Clear();
|
||||
_continueLabels.Clear();
|
||||
_arrowFunctions.Clear();
|
||||
_implFunctions.Clear();
|
||||
_scopes.Clear();
|
||||
_tmpIndex = 0;
|
||||
_labelIndex = 0;
|
||||
_arrowFuncIndex = 0;
|
||||
_cStringLiteralIndex = 0;
|
||||
_stringLiteralIndex = 0;
|
||||
_implFuncNameIndex = 0;
|
||||
_codeIsReachable = true;
|
||||
|
||||
foreach (var structDef in _definitionTable.GetStructs())
|
||||
@@ -78,12 +74,6 @@ public partial class QBEGenerator
|
||||
_writer.NewLine();
|
||||
}
|
||||
|
||||
foreach (var (impl, name) in _implFunctions)
|
||||
{
|
||||
EmitFuncDefinition(name, impl.Signature.Parameters, impl.Signature.ReturnType, impl.Body);
|
||||
_writer.NewLine();
|
||||
}
|
||||
|
||||
foreach (var cStringLiteral in _cStringLiterals)
|
||||
{
|
||||
_writer.WriteLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}");
|
||||
@@ -207,19 +197,16 @@ public partial class QBEGenerator
|
||||
{
|
||||
case BoundArrayInitializer arrayInitializer:
|
||||
{
|
||||
_writer.WriteDebugLocation(arrayInitializer);
|
||||
EmitStore(source.Type, EmitUnwrap(EmitArrayInitializer(arrayInitializer)), destinationPointer);
|
||||
return true;
|
||||
}
|
||||
case BoundStructInitializer structInitializer:
|
||||
{
|
||||
_writer.WriteDebugLocation(structInitializer);
|
||||
EmitStructInitializer(structInitializer, destinationPointer);
|
||||
return true;
|
||||
}
|
||||
case BoundLiteral { Kind: LiteralKind.String } literal:
|
||||
{
|
||||
_writer.WriteDebugLocation(literal);
|
||||
EmitStore(source.Type, EmitUnwrap(EmitLiteral(literal)), destinationPointer);
|
||||
return true;
|
||||
}
|
||||
@@ -521,11 +508,6 @@ public partial class QBEGenerator
|
||||
return $"${funcDef.CallName}";
|
||||
}
|
||||
|
||||
private string ImplFuncName()
|
||||
{
|
||||
return $"$impl{++_implFuncNameIndex}";
|
||||
}
|
||||
|
||||
private string CustomTypeName(NubCustomType customType)
|
||||
{
|
||||
return CustomTypeName(customType.Namespace, customType.Name);
|
||||
@@ -551,7 +533,7 @@ public class CStringLiteral(string value, string name)
|
||||
public string Name { get; } = name;
|
||||
}
|
||||
|
||||
public record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
|
||||
public record Val(string Name, NubType Type, ValKind Kind);
|
||||
|
||||
public class Scope(Scope? parent = null)
|
||||
{
|
||||
@@ -579,8 +561,6 @@ public class Scope(Scope? parent = null)
|
||||
}
|
||||
}
|
||||
|
||||
public record MethodCallContext(Val ThisArg);
|
||||
|
||||
public enum ValKind
|
||||
{
|
||||
Pointer,
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
using System.Text;
|
||||
using NubLang.Syntax.Binding.Node;
|
||||
|
||||
namespace NubLang.Generation.QBE;
|
||||
|
||||
internal class QBEWriter
|
||||
{
|
||||
private readonly StringBuilder _builder = new();
|
||||
private int _currentLine = -1;
|
||||
|
||||
public QBEWriter(string debugFile)
|
||||
{
|
||||
_builder.AppendLine($"dbgfile \"{debugFile}\"");
|
||||
_builder.AppendLine();
|
||||
}
|
||||
|
||||
public void StartFunction(string signature)
|
||||
{
|
||||
_currentLine = -1;
|
||||
_builder.Append(signature);
|
||||
_builder.AppendLine(" {");
|
||||
_builder.AppendLine("@start");
|
||||
@@ -27,26 +18,6 @@ internal class QBEWriter
|
||||
_builder.AppendLine("}");
|
||||
}
|
||||
|
||||
private void WriteDebugLocation(SourceSpan span)
|
||||
{
|
||||
var line = span.Start.Line;
|
||||
|
||||
if (_currentLine != line)
|
||||
{
|
||||
_builder.AppendLine($" dbgloc {line}");
|
||||
_currentLine = line;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteDebugLocation(BoundNode node)
|
||||
{
|
||||
var firstToken = node.Tokens.FirstOrDefault();
|
||||
if (firstToken != null)
|
||||
{
|
||||
// WriteDebugLocation(firstToken.Span);
|
||||
}
|
||||
}
|
||||
|
||||
public void Indented(string value)
|
||||
{
|
||||
_builder.Append('\t');
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -63,10 +63,10 @@ public sealed class Binder
|
||||
|
||||
foreach (var function in node.Functions)
|
||||
{
|
||||
functions.Add(new BoundTraitFunc(node.Tokens, function.Name, BindFuncSignature(function.Signature)));
|
||||
functions.Add(new BoundTraitFunc(function.Name, BindFuncSignature(function.Signature)));
|
||||
}
|
||||
|
||||
return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions);
|
||||
return new BoundTrait(node.Namespace, node.Name, functions);
|
||||
}
|
||||
|
||||
private BoundStruct BindStruct(StructSyntax node)
|
||||
@@ -82,15 +82,15 @@ public sealed class Binder
|
||||
value = BindExpression(field.Value.Value, BindType(field.Type));
|
||||
}
|
||||
|
||||
structFields.Add(new BoundStructField(field.Tokens, field.Index, field.Name, BindType(field.Type), value));
|
||||
structFields.Add(new BoundStructField(field.Index, field.Name, BindType(field.Type), value));
|
||||
}
|
||||
|
||||
return new BoundStruct(node.Tokens, node.Namespace, node.Name, structFields);
|
||||
return new BoundStruct(node.Namespace, node.Name, structFields);
|
||||
}
|
||||
|
||||
private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node)
|
||||
{
|
||||
return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
|
||||
return new BoundExternFunc(node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
|
||||
}
|
||||
|
||||
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
|
||||
@@ -98,7 +98,7 @@ public sealed class Binder
|
||||
var signature = BindFuncSignature(node.Signature);
|
||||
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters);
|
||||
|
||||
return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body);
|
||||
return new BoundLocalFunc(node.Namespace, node.Name, signature, body);
|
||||
}
|
||||
|
||||
private BoundStatement BindStatement(StatementSyntax node)
|
||||
@@ -106,8 +106,8 @@ public sealed class Binder
|
||||
return node switch
|
||||
{
|
||||
AssignmentSyntax statement => BindAssignment(statement),
|
||||
BreakSyntax statement => BindBreak(statement),
|
||||
ContinueSyntax statement => BindContinue(statement),
|
||||
BreakSyntax => new BoundBreak(),
|
||||
ContinueSyntax => new BoundContinue(),
|
||||
IfSyntax statement => BindIf(statement),
|
||||
ReturnSyntax statement => BindReturn(statement),
|
||||
StatementExpressionSyntax statement => BindStatementExpression(statement),
|
||||
@@ -121,17 +121,7 @@ public sealed class Binder
|
||||
{
|
||||
var expression = BindExpression(statement.Target);
|
||||
var value = BindExpression(statement.Value, expression.Type);
|
||||
return new BoundAssignment(statement.Tokens, expression, value);
|
||||
}
|
||||
|
||||
private BoundBreak BindBreak(BreakSyntax statement)
|
||||
{
|
||||
return new BoundBreak(statement.Tokens);
|
||||
}
|
||||
|
||||
private BoundContinue BindContinue(ContinueSyntax statement)
|
||||
{
|
||||
return new BoundContinue(statement.Tokens);
|
||||
return new BoundAssignment(expression, value);
|
||||
}
|
||||
|
||||
private BoundIf BindIf(IfSyntax statement)
|
||||
@@ -147,7 +137,7 @@ public sealed class Binder
|
||||
);
|
||||
}
|
||||
|
||||
return new BoundIf(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body), elseStatement);
|
||||
return new BoundIf(BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body), elseStatement);
|
||||
}
|
||||
|
||||
private BoundReturn BindReturn(ReturnSyntax statement)
|
||||
@@ -159,12 +149,12 @@ public sealed class Binder
|
||||
value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek());
|
||||
}
|
||||
|
||||
return new BoundReturn(statement.Tokens, value);
|
||||
return new BoundReturn(value);
|
||||
}
|
||||
|
||||
private BoundStatementExpression BindStatementExpression(StatementExpressionSyntax statement)
|
||||
{
|
||||
return new BoundStatementExpression(statement.Tokens, BindExpression(statement.Expression));
|
||||
return new BoundStatementExpression(BindExpression(statement.Expression));
|
||||
}
|
||||
|
||||
private BoundVariableDeclaration BindVariableDeclaration(VariableDeclarationSyntax statement)
|
||||
@@ -191,12 +181,12 @@ public sealed class Binder
|
||||
|
||||
Scope.Declare(new Variable(statement.Name, type));
|
||||
|
||||
return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type);
|
||||
return new BoundVariableDeclaration(statement.Name, assignment, type);
|
||||
}
|
||||
|
||||
private BoundWhile BindWhile(WhileSyntax statement)
|
||||
{
|
||||
return new BoundWhile(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body));
|
||||
return new BoundWhile(BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body));
|
||||
}
|
||||
|
||||
private BoundExpression BindExpression(ExpressionSyntax node, NubType? expectedType = null)
|
||||
@@ -222,19 +212,19 @@ public sealed class Binder
|
||||
private BoundAddressOf BindAddressOf(AddressOfSyntax expression)
|
||||
{
|
||||
var inner = BindExpression(expression.Expression);
|
||||
return new BoundAddressOf(expression.Tokens, new NubPointerType(inner.Type), inner);
|
||||
return new BoundAddressOf(new NubPointerType(inner.Type), inner);
|
||||
}
|
||||
|
||||
private BoundArrowFunc BindArrowFunc(ArrowFuncSyntax expression, NubType? expectedType = null)
|
||||
{
|
||||
if (expectedType == null)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error("Cannot infer argument types for arrow function").At(expression).Build());
|
||||
throw new BindException(Diagnostic.Error("Cannot infer argument types for arrow function").Build());
|
||||
}
|
||||
|
||||
if (expectedType is not NubFuncType funcType)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got arrow function").At(expression).Build());
|
||||
throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got arrow function").Build());
|
||||
}
|
||||
|
||||
var parameters = new List<BoundFuncParameter>();
|
||||
@@ -248,40 +238,40 @@ public sealed class Binder
|
||||
|
||||
var expectedParameterType = funcType.Parameters[i];
|
||||
var parameter = expression.Parameters[i];
|
||||
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType));
|
||||
parameters.Add(new BoundFuncParameter(parameter.Name, expectedParameterType));
|
||||
}
|
||||
|
||||
var body = BindFuncBody(expression.Body, funcType.ReturnType, parameters);
|
||||
|
||||
return new BoundArrowFunc(expression.Tokens, new NubFuncType(parameters.Select(x => x.Type).ToList(), funcType.ReturnType), parameters, funcType.ReturnType, body);
|
||||
return new BoundArrowFunc(new NubFuncType(parameters.Select(x => x.Type).ToList(), funcType.ReturnType), parameters, funcType.ReturnType, body);
|
||||
}
|
||||
|
||||
private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression)
|
||||
{
|
||||
var boundArray = BindExpression(expression.Target);
|
||||
var elementType = ((NubArrayType)boundArray.Type).ElementType;
|
||||
return new BoundArrayIndexAccess(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, new NubPrimitiveType(PrimitiveTypeKind.U64)));
|
||||
return new BoundArrayIndexAccess(elementType, boundArray, BindExpression(expression.Index, new NubPrimitiveType(PrimitiveTypeKind.U64)));
|
||||
}
|
||||
|
||||
private BoundArrayInitializer BindArrayInitializer(ArrayInitializerSyntax expression)
|
||||
{
|
||||
var capacity = BindExpression(expression.Capacity, new NubPrimitiveType(PrimitiveTypeKind.U64));
|
||||
var type = new NubArrayType(BindType(expression.ElementType));
|
||||
return new BoundArrayInitializer(expression.Tokens, type, capacity, BindType(expression.ElementType));
|
||||
return new BoundArrayInitializer(type, capacity, BindType(expression.ElementType));
|
||||
}
|
||||
|
||||
private BoundBinaryExpression BindBinaryExpression(BinaryExpressionSyntax expression)
|
||||
{
|
||||
var boundLeft = BindExpression(expression.Left);
|
||||
var boundRight = BindExpression(expression.Right, boundLeft.Type);
|
||||
return new BoundBinaryExpression(expression.Tokens, boundLeft.Type, boundLeft, BindBinaryOperator(expression.Operator), boundRight);
|
||||
return new BoundBinaryExpression(boundLeft.Type, boundLeft, BindBinaryOperator(expression.Operator), boundRight);
|
||||
}
|
||||
|
||||
private BoundDereference BindDereference(DereferenceSyntax expression)
|
||||
{
|
||||
var boundExpression = BindExpression(expression.Expression);
|
||||
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
|
||||
return new BoundDereference(expression.Tokens, dereferencedType, boundExpression);
|
||||
return new BoundDereference(dereferencedType, boundExpression);
|
||||
}
|
||||
|
||||
private BoundFuncCall BindFuncCall(FuncCallSyntax expression)
|
||||
@@ -304,7 +294,7 @@ public sealed class Binder
|
||||
parameters.Add(BindExpression(parameter, expectedType));
|
||||
}
|
||||
|
||||
return new BoundFuncCall(expression.Tokens, funcType.ReturnType, boundExpression, parameters);
|
||||
return new BoundFuncCall(funcType.ReturnType, boundExpression, parameters);
|
||||
}
|
||||
|
||||
private BoundExpression BindIdentifier(IdentifierSyntax expression)
|
||||
@@ -323,7 +313,7 @@ public sealed class Binder
|
||||
var returnType = BindType(localFunc.Signature.ReturnType);
|
||||
var parameterTypes = localFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
|
||||
var type = new NubFuncType(parameterTypes, returnType);
|
||||
return new BoundLocalFuncIdent(expression.Tokens, type, @namespace, expression.Name);
|
||||
return new BoundLocalFuncIdent(type, @namespace, expression.Name);
|
||||
}
|
||||
|
||||
var externFuncs = _definitionTable.LookupExternFunc(@namespace, expression.Name).ToArray();
|
||||
@@ -339,7 +329,7 @@ public sealed class Binder
|
||||
var returnType = BindType(externFunc.Signature.ReturnType);
|
||||
var parameterTypes = externFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
|
||||
var type = new NubFuncType(parameterTypes, returnType);
|
||||
return new BoundExternFuncIdent(expression.Tokens, type, @namespace, expression.Name);
|
||||
return new BoundExternFuncIdent(type, @namespace, expression.Name);
|
||||
}
|
||||
|
||||
if (!expression.Namespace.HasValue)
|
||||
@@ -347,7 +337,7 @@ public sealed class Binder
|
||||
var variable = Scope.Lookup(expression.Name);
|
||||
if (variable != null)
|
||||
{
|
||||
return new BoundVariableIdent(expression.Tokens, variable.Type, variable.Name);
|
||||
return new BoundVariableIdent(variable.Type, variable.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,7 +355,7 @@ public sealed class Binder
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
return new BoundLiteral(expression.Tokens, type, expression.Value, expression.Kind);
|
||||
return new BoundLiteral(type, expression.Value, expression.Kind);
|
||||
}
|
||||
|
||||
private BoundExpression BindMemberAccess(MemberAccessSyntax expression)
|
||||
@@ -385,7 +375,7 @@ public sealed class Binder
|
||||
// var returnType = BindType(impl.Signature.ReturnType);
|
||||
// var parameterTypes = impl.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
|
||||
// var type = new NubFuncType(parameterTypes, returnType);
|
||||
// return new BoundTraitImplFuncAccess(expression.Tokens, type, boundExpression, expression.Member);
|
||||
// return new BoundTraitImplFuncAccess(type, boundExpression, expression.Member);
|
||||
// }
|
||||
|
||||
if (boundExpression.Type is NubCustomType customType)
|
||||
@@ -413,7 +403,7 @@ public sealed class Binder
|
||||
var returnType = BindType(traitFunc.Signature.ReturnType);
|
||||
var parameterTypes = traitFunc.Signature.Parameters.Select(p => BindType(p.Type)).ToList();
|
||||
var type = new NubFuncType(parameterTypes, returnType);
|
||||
return new BoundTraitFuncAccess(expression.Tokens, type, customType, boundExpression, expression.Member);
|
||||
return new BoundInterfaceFuncAccess(type, customType, boundExpression, expression.Member);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +427,7 @@ public sealed class Binder
|
||||
|
||||
var field = fields[0];
|
||||
|
||||
return new BoundStructFieldAccess(expression.Tokens, BindType(field.Type), customType, boundExpression, expression.Member);
|
||||
return new BoundStructFieldAccess(BindType(field.Type), customType, boundExpression, expression.Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,7 +477,7 @@ public sealed class Binder
|
||||
initializers[field] = BindExpression(initializer, BindType(fields[0].Type));
|
||||
}
|
||||
|
||||
return new BoundStructInitializer(expression.Tokens, structType, initializers);
|
||||
return new BoundStructInitializer(structType, initializers);
|
||||
}
|
||||
|
||||
private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression)
|
||||
@@ -523,7 +513,7 @@ public sealed class Binder
|
||||
throw new NotImplementedException("Diagnostics not implemented");
|
||||
}
|
||||
|
||||
return new BoundUnaryExpression(expression.Tokens, type, BindBinaryOperator(expression.Operator), boundOperand);
|
||||
return new BoundUnaryExpression(type, BindBinaryOperator(expression.Operator), boundOperand);
|
||||
}
|
||||
|
||||
private BoundFuncSignature BindFuncSignature(FuncSignatureSyntax node)
|
||||
@@ -532,10 +522,10 @@ public sealed class Binder
|
||||
|
||||
foreach (var parameter in node.Parameters)
|
||||
{
|
||||
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
parameters.Add(new BoundFuncParameter(parameter.Name, BindType(parameter.Type)));
|
||||
}
|
||||
|
||||
return new BoundFuncSignature(node.Tokens, parameters, BindType(node.ReturnType));
|
||||
return new BoundFuncSignature(parameters, BindType(node.ReturnType));
|
||||
}
|
||||
|
||||
private BoundBinaryOperator BindBinaryOperator(BinaryOperator op)
|
||||
@@ -579,7 +569,7 @@ public sealed class Binder
|
||||
|
||||
_scopes.Pop();
|
||||
|
||||
return new BoundBlock(node.Tokens, statements);
|
||||
return new BoundBlock(statements);
|
||||
}
|
||||
|
||||
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IReadOnlyList<BoundFuncParameter> parameters)
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
using NubLang.Common;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Binding.Node;
|
||||
|
||||
public abstract record BoundDefinition(IReadOnlyList<Token> Tokens, string Namespace) : BoundNode(Tokens);
|
||||
public abstract record BoundDefinition(string Namespace) : BoundNode;
|
||||
|
||||
public record BoundFuncParameter(IReadOnlyList<Token> Tokens, string Name, NubType Type) : BoundNode(Tokens);
|
||||
public record BoundFuncParameter(string Name, NubType Type) : BoundNode;
|
||||
|
||||
public record BoundFuncSignature(IReadOnlyList<Token> Tokens, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType) : BoundNode(Tokens);
|
||||
public record BoundFuncSignature(IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType) : BoundNode;
|
||||
|
||||
public record BoundLocalFunc(IReadOnlyList<Token> Tokens, string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Tokens, Namespace);
|
||||
public record BoundLocalFunc(string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Namespace);
|
||||
|
||||
public record BoundExternFunc(IReadOnlyList<Token> Tokens, string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Tokens, Namespace);
|
||||
public record BoundExternFunc(string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Namespace);
|
||||
|
||||
public record BoundStructField(IReadOnlyList<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundNode(Tokens);
|
||||
public record BoundStructField(int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundNode;
|
||||
|
||||
public record BoundStruct(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<BoundStructField> Fields) : BoundDefinition(Tokens, Namespace);
|
||||
public record BoundStruct(string Namespace, string Name, IReadOnlyList<BoundStructField> Fields) : BoundDefinition(Namespace);
|
||||
|
||||
public record BoundTraitFunc(IReadOnlyList<Token> Tokens, string Name, BoundFuncSignature Signature) : BoundNode(Tokens);
|
||||
public record BoundTraitFunc(string Name, BoundFuncSignature Signature) : BoundNode;
|
||||
|
||||
public record BoundTrait(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<BoundTraitFunc> Functions) : BoundDefinition(Tokens, Namespace);
|
||||
public record BoundTrait(string Namespace, string Name, IReadOnlyList<BoundTraitFunc> Functions) : BoundDefinition(Namespace);
|
||||
|
||||
public record BoundTraitFuncImpl(IReadOnlyList<Token> Tokens, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundNode(Tokens);
|
||||
public record BoundTraitFuncImpl(string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundNode;
|
||||
|
||||
public record BoundTraitImpl(IReadOnlyList<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, IReadOnlyList<BoundTraitFuncImpl> Functions) : BoundDefinition(Tokens, Namespace);
|
||||
public record BoundTraitImpl(string Namespace, NubType TraitType, NubType ForType, IReadOnlyList<BoundTraitFuncImpl> Functions) : BoundDefinition(Namespace);
|
||||
@@ -22,36 +22,34 @@ public enum BoundBinaryOperator
|
||||
Divide
|
||||
}
|
||||
|
||||
public abstract record BoundExpression(IReadOnlyList<Token> Tokens, NubType Type) : BoundNode(Tokens);
|
||||
public abstract record BoundExpression(NubType Type) : BoundNode;
|
||||
|
||||
public record BoundBinaryExpression(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Left, BoundBinaryOperator Operator, BoundExpression Right) : BoundExpression(Tokens, Type);
|
||||
public record BoundBinaryExpression(NubType Type, BoundExpression Left, BoundBinaryOperator Operator, BoundExpression Right) : BoundExpression(Type);
|
||||
|
||||
public record BoundUnaryExpression(IReadOnlyList<Token> Tokens, NubType Type, BoundUnaryOperator Operator, BoundExpression Operand) : BoundExpression(Tokens, Type);
|
||||
public record BoundUnaryExpression(NubType Type, BoundUnaryOperator Operator, BoundExpression Operand) : BoundExpression(Type);
|
||||
|
||||
public record BoundFuncCall(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression, IReadOnlyList<BoundExpression> Parameters) : BoundExpression(Tokens, Type);
|
||||
public record BoundFuncCall(NubType Type, BoundExpression Expression, IReadOnlyList<BoundExpression> Parameters) : BoundExpression(Type);
|
||||
|
||||
public record BoundVariableIdent(IReadOnlyList<Token> Tokens, NubType Type, string Name) : BoundExpression(Tokens, Type);
|
||||
public record BoundVariableIdent(NubType Type, string Name) : BoundExpression(Type);
|
||||
|
||||
public record BoundLocalFuncIdent(IReadOnlyList<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpression(Tokens, Type);
|
||||
public record BoundLocalFuncIdent(NubType Type, string Namespace, string Name) : BoundExpression(Type);
|
||||
|
||||
public record BoundExternFuncIdent(IReadOnlyList<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpression(Tokens, Type);
|
||||
public record BoundExternFuncIdent(NubType Type, string Namespace, string Name) : BoundExpression(Type);
|
||||
|
||||
public record BoundArrayInitializer(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Capacity, NubType ElementType) : BoundExpression(Tokens, Type);
|
||||
public record BoundArrayInitializer(NubType Type, BoundExpression Capacity, NubType ElementType) : BoundExpression(Type);
|
||||
|
||||
public record BoundArrayIndexAccess(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type);
|
||||
public record BoundArrayIndexAccess(NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Type);
|
||||
|
||||
public record BoundArrowFunc(IReadOnlyList<Token> Tokens, NubType Type, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Tokens, Type);
|
||||
public record BoundArrowFunc(NubType Type, IReadOnlyList<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Type);
|
||||
|
||||
public record BoundAddressOf(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);
|
||||
public record BoundAddressOf(NubType Type, BoundExpression Expression) : BoundExpression(Type);
|
||||
|
||||
public record BoundLiteral(IReadOnlyList<Token> Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpression(Tokens, Type);
|
||||
public record BoundLiteral(NubType Type, string Literal, LiteralKind Kind) : BoundExpression(Type);
|
||||
|
||||
public record BoundStructFieldAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType StructType, BoundExpression Target, string Field) : BoundExpression(Tokens, Type);
|
||||
public record BoundStructFieldAccess(NubType Type, NubCustomType StructType, BoundExpression Target, string Field) : BoundExpression(Type);
|
||||
|
||||
public record BoundTraitImplFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type);
|
||||
public record BoundInterfaceFuncAccess(NubType Type, NubCustomType InterfaceType, BoundExpression Target, string FuncName) : BoundExpression(Type);
|
||||
|
||||
public record BoundTraitFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType TraitType, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type);
|
||||
public record BoundStructInitializer(NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(StructType);
|
||||
|
||||
public record BoundStructInitializer(IReadOnlyList<Token> Tokens, NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(Tokens, StructType);
|
||||
|
||||
public record BoundDereference(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);
|
||||
public record BoundDereference(NubType Type, BoundExpression Expression) : BoundExpression(Type);
|
||||
@@ -1,22 +1,21 @@
|
||||
using NubLang.Common;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Binding.Node;
|
||||
|
||||
public record BoundStatement(IReadOnlyList<Token> Tokens) : BoundNode(Tokens);
|
||||
public record BoundStatement : BoundNode;
|
||||
|
||||
public record BoundStatementExpression(IReadOnlyList<Token> Tokens, BoundExpression Expression) : BoundStatement(Tokens);
|
||||
public record BoundStatementExpression(BoundExpression Expression) : BoundStatement;
|
||||
|
||||
public record BoundReturn(IReadOnlyList<Token> Tokens, Optional<BoundExpression> Value) : BoundStatement(Tokens);
|
||||
public record BoundReturn(Optional<BoundExpression> Value) : BoundStatement;
|
||||
|
||||
public record BoundAssignment(IReadOnlyList<Token> Tokens, BoundExpression Target, BoundExpression Value) : BoundStatement(Tokens);
|
||||
public record BoundAssignment(BoundExpression Target, BoundExpression Value) : BoundStatement;
|
||||
|
||||
public record BoundIf(IReadOnlyList<Token> Tokens, BoundExpression Condition, BoundBlock Body, Optional<Variant<BoundIf, BoundBlock>> Else) : BoundStatement(Tokens);
|
||||
public record BoundIf(BoundExpression Condition, BoundBlock Body, Optional<Variant<BoundIf, BoundBlock>> Else) : BoundStatement;
|
||||
|
||||
public record BoundVariableDeclaration(IReadOnlyList<Token> Tokens, string Name, Optional<BoundExpression> Assignment, NubType Type) : BoundStatement(Tokens);
|
||||
public record BoundVariableDeclaration(string Name, Optional<BoundExpression> Assignment, NubType Type) : BoundStatement;
|
||||
|
||||
public record BoundContinue(IReadOnlyList<Token> Tokens) : BoundStatement(Tokens);
|
||||
public record BoundContinue : BoundStatement;
|
||||
|
||||
public record BoundBreak(IReadOnlyList<Token> Tokens) : BoundStatement(Tokens);
|
||||
public record BoundBreak : BoundStatement;
|
||||
|
||||
public record BoundWhile(IReadOnlyList<Token> Tokens, BoundExpression Condition, BoundBlock Body) : BoundStatement(Tokens);
|
||||
public record BoundWhile(BoundExpression Condition, BoundBlock Body) : BoundStatement;
|
||||
@@ -1,10 +1,9 @@
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Binding.Node;
|
||||
|
||||
public record BoundSyntaxTree(string Namespace, IReadOnlyList<BoundDefinition> Definitions, IReadOnlyList<Diagnostic> Diagnostics);
|
||||
|
||||
public abstract record BoundNode(IReadOnlyList<Token> Tokens);
|
||||
public abstract record BoundNode;
|
||||
|
||||
public record BoundBlock(IReadOnlyList<Token> Tokens, IReadOnlyList<BoundStatement> Statements) : BoundNode(Tokens);
|
||||
public record BoundBlock(IReadOnlyList<BoundStatement> Statements) : BoundNode;
|
||||
@@ -1,11 +1,10 @@
|
||||
using NubLang.Common;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Parsing.Node;
|
||||
|
||||
public abstract record DefinitionSyntax(IReadOnlyList<Token> Tokens, string Namespace) : SyntaxNode(Tokens);
|
||||
public abstract record DefinitionSyntax(string Namespace) : SyntaxNode;
|
||||
|
||||
public record FuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens)
|
||||
public record FuncParameterSyntax(string Name, TypeSyntax Type) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -13,7 +12,7 @@ public record FuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name, Type
|
||||
}
|
||||
}
|
||||
|
||||
public record FuncSignatureSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens)
|
||||
public record FuncSignatureSyntax(IReadOnlyList<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -26,7 +25,7 @@ public record FuncSignatureSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<Fun
|
||||
}
|
||||
}
|
||||
|
||||
public record LocalFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace)
|
||||
public record LocalFuncSyntax(string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Namespace)
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -35,7 +34,7 @@ public record LocalFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, str
|
||||
}
|
||||
}
|
||||
|
||||
public record ExternFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace)
|
||||
public record ExternFuncSyntax(string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Namespace)
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -43,7 +42,7 @@ public record ExternFuncSyntax(IReadOnlyList<Token> Tokens, string Namespace, st
|
||||
}
|
||||
}
|
||||
|
||||
public record StructFieldSyntax(IReadOnlyList<Token> Tokens, int Index, string Name, TypeSyntax Type, Optional<ExpressionSyntax> Value) : SyntaxNode(Tokens)
|
||||
public record StructFieldSyntax(int Index, string Name, TypeSyntax Type, Optional<ExpressionSyntax> Value) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -55,7 +54,7 @@ public record StructFieldSyntax(IReadOnlyList<Token> Tokens, int Index, string N
|
||||
}
|
||||
}
|
||||
|
||||
public record StructFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens)
|
||||
public record StructFuncSyntax(string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -64,7 +63,7 @@ public record StructFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSig
|
||||
}
|
||||
}
|
||||
|
||||
public record StructSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<StructFieldSyntax> Fields, IReadOnlyList<StructFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace)
|
||||
public record StructSyntax(string Namespace, string Name, IReadOnlyList<StructFieldSyntax> Fields, IReadOnlyList<StructFuncSyntax> Functions) : DefinitionSyntax(Namespace)
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -80,7 +79,7 @@ public record StructSyntax(IReadOnlyList<Token> Tokens, string Namespace, string
|
||||
}
|
||||
}
|
||||
|
||||
public record InterfaceFuncSyntax(IReadOnlyList<Token> Tokens, string Name, FuncSignatureSyntax Signature) : SyntaxNode(Tokens)
|
||||
public record InterfaceFuncSyntax(string Name, FuncSignatureSyntax Signature) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -88,7 +87,7 @@ public record InterfaceFuncSyntax(IReadOnlyList<Token> Tokens, string Name, Func
|
||||
}
|
||||
}
|
||||
|
||||
public record InterfaceSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name, IReadOnlyList<InterfaceFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace)
|
||||
public record InterfaceSyntax(string Namespace, string Name, IReadOnlyList<InterfaceFuncSyntax> Functions) : DefinitionSyntax(Namespace)
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@ public enum BinaryOperator
|
||||
Divide
|
||||
}
|
||||
|
||||
public abstract record ExpressionSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens);
|
||||
public abstract record ExpressionSyntax : SyntaxNode;
|
||||
|
||||
public record BinaryExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens)
|
||||
public record BinaryExpressionSyntax(ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -34,7 +34,7 @@ public record BinaryExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
|
||||
}
|
||||
}
|
||||
|
||||
public record UnaryExpressionSyntax(IReadOnlyList<Token> Tokens, UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens)
|
||||
public record UnaryExpressionSyntax(UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public record UnaryExpressionSyntax(IReadOnlyList<Token> Tokens, UnaryOperator O
|
||||
}
|
||||
}
|
||||
|
||||
public record FuncCallSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens)
|
||||
public record FuncCallSyntax(ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -54,12 +54,12 @@ public record FuncCallSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expre
|
||||
}
|
||||
}
|
||||
|
||||
public record IdentifierSyntax(IReadOnlyList<Token> Tokens, Optional<string> Namespace, string Name) : ExpressionSyntax(Tokens)
|
||||
public record IdentifierSyntax(Optional<string> Namespace, string Name) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record ArrayInitializerSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens)
|
||||
public record ArrayInitializerSyntax(ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -68,7 +68,7 @@ public record ArrayInitializerSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
|
||||
}
|
||||
}
|
||||
|
||||
public record ArrayIndexAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens)
|
||||
public record ArrayIndexAccessSyntax(ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -77,12 +77,12 @@ public record ArrayIndexAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSynt
|
||||
}
|
||||
}
|
||||
|
||||
public record ArrowFuncParameterSyntax(IReadOnlyList<Token> Tokens, string Name) : ExpressionSyntax(Tokens)
|
||||
public record ArrowFuncParameterSyntax(string Name) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record ArrowFuncSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<ArrowFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens)
|
||||
public record ArrowFuncSyntax(IReadOnlyList<ArrowFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -95,7 +95,7 @@ public record ArrowFuncSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<ArrowFu
|
||||
}
|
||||
}
|
||||
|
||||
public record AddressOfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens)
|
||||
public record AddressOfSyntax(ExpressionSyntax Expression) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -103,12 +103,12 @@ public record AddressOfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expr
|
||||
}
|
||||
}
|
||||
|
||||
public record LiteralSyntax(IReadOnlyList<Token> Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens)
|
||||
public record LiteralSyntax(string Value, LiteralKind Kind) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record MemberAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens)
|
||||
public record MemberAccessSyntax(ExpressionSyntax Target, string Member) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -116,7 +116,7 @@ public record MemberAccessSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax T
|
||||
}
|
||||
}
|
||||
|
||||
public record StructInitializerSyntax(IReadOnlyList<Token> Tokens, TypeSyntax StructType, Dictionary<string, ExpressionSyntax> Initializers) : ExpressionSyntax(Tokens)
|
||||
public record StructInitializerSyntax(TypeSyntax StructType, Dictionary<string, ExpressionSyntax> Initializers) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -128,7 +128,7 @@ public record StructInitializerSyntax(IReadOnlyList<Token> Tokens, TypeSyntax St
|
||||
}
|
||||
}
|
||||
|
||||
public record DereferenceSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens)
|
||||
public record DereferenceSyntax(ExpressionSyntax Expression) : ExpressionSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using NubLang.Common;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Parsing.Node;
|
||||
|
||||
public abstract record StatementSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens);
|
||||
public abstract record StatementSyntax : SyntaxNode;
|
||||
|
||||
public record StatementExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Expression) : StatementSyntax(Tokens)
|
||||
public record StatementExpressionSyntax(ExpressionSyntax Expression) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -13,7 +12,7 @@ public record StatementExpressionSyntax(IReadOnlyList<Token> Tokens, ExpressionS
|
||||
}
|
||||
}
|
||||
|
||||
public record ReturnSyntax(IReadOnlyList<Token> Tokens, Optional<ExpressionSyntax> Value) : StatementSyntax(Tokens)
|
||||
public record ReturnSyntax(Optional<ExpressionSyntax> Value) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -24,7 +23,7 @@ public record ReturnSyntax(IReadOnlyList<Token> Tokens, Optional<ExpressionSynta
|
||||
}
|
||||
}
|
||||
|
||||
public record AssignmentSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax(Tokens)
|
||||
public record AssignmentSyntax(ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -33,7 +32,7 @@ public record AssignmentSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Tar
|
||||
}
|
||||
}
|
||||
|
||||
public record IfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body, Optional<Variant<IfSyntax, BlockSyntax>> Else) : StatementSyntax(Tokens)
|
||||
public record IfSyntax(ExpressionSyntax Condition, BlockSyntax Body, Optional<Variant<IfSyntax, BlockSyntax>> Else) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -53,7 +52,7 @@ public record IfSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition,
|
||||
}
|
||||
}
|
||||
|
||||
public record VariableDeclarationSyntax(IReadOnlyList<Token> Tokens, string Name, Optional<TypeSyntax> ExplicitType, Optional<ExpressionSyntax> Assignment) : StatementSyntax(Tokens)
|
||||
public record VariableDeclarationSyntax(string Name, Optional<TypeSyntax> ExplicitType, Optional<ExpressionSyntax> Assignment) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -69,17 +68,17 @@ public record VariableDeclarationSyntax(IReadOnlyList<Token> Tokens, string Name
|
||||
}
|
||||
}
|
||||
|
||||
public record ContinueSyntax(IReadOnlyList<Token> Tokens) : StatementSyntax(Tokens)
|
||||
public record ContinueSyntax : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record BreakSyntax(IReadOnlyList<Token> Tokens) : StatementSyntax(Tokens)
|
||||
public record BreakSyntax : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record WhileSyntax(IReadOnlyList<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens)
|
||||
public record WhileSyntax(ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Parsing.Node;
|
||||
|
||||
public abstract record SyntaxNode(IReadOnlyList<Token> Tokens)
|
||||
public abstract record SyntaxNode
|
||||
{
|
||||
public abstract IEnumerable<SyntaxNode> GetChildren();
|
||||
|
||||
@@ -21,7 +18,7 @@ public abstract record SyntaxNode(IReadOnlyList<Token> Tokens)
|
||||
}
|
||||
}
|
||||
|
||||
public record SyntaxTree(IReadOnlyList<Token> Tokens, string Namespace, IReadOnlyList<DefinitionSyntax> Definitions, IReadOnlyList<Diagnostic> Diagnostics) : SyntaxNode(Tokens)
|
||||
public record SyntaxTree(string Namespace, IReadOnlyList<DefinitionSyntax> Definitions) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -32,7 +29,7 @@ public record SyntaxTree(IReadOnlyList<Token> Tokens, string Namespace, IReadOnl
|
||||
}
|
||||
}
|
||||
|
||||
public record BlockSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<StatementSyntax> Statements) : SyntaxNode(Tokens)
|
||||
public record BlockSyntax(IReadOnlyList<StatementSyntax> Statements) : SyntaxNode
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using NubLang.Syntax.Tokenization;
|
||||
|
||||
namespace NubLang.Syntax.Parsing.Node;
|
||||
|
||||
public enum PrimitiveTypeSyntaxKind
|
||||
@@ -17,7 +15,7 @@ public enum PrimitiveTypeSyntaxKind
|
||||
Bool
|
||||
}
|
||||
|
||||
public abstract record TypeSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Tokens)
|
||||
public abstract record TypeSyntax : SyntaxNode
|
||||
{
|
||||
public string MangledName()
|
||||
{
|
||||
@@ -36,7 +34,7 @@ public abstract record TypeSyntax(IReadOnlyList<Token> Tokens) : SyntaxNode(Toke
|
||||
}
|
||||
}
|
||||
|
||||
public record FuncTypeSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<TypeSyntax> Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens)
|
||||
public record FuncTypeSyntax(IReadOnlyList<TypeSyntax> Parameters, TypeSyntax ReturnType) : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -49,7 +47,7 @@ public record FuncTypeSyntax(IReadOnlyList<Token> Tokens, IReadOnlyList<TypeSynt
|
||||
}
|
||||
}
|
||||
|
||||
public record PointerTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens)
|
||||
public record PointerTypeSyntax(TypeSyntax BaseType) : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
@@ -57,32 +55,32 @@ public record PointerTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType
|
||||
}
|
||||
}
|
||||
|
||||
public record VoidTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
|
||||
public record VoidTypeSyntax : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record PrimitiveTypeSyntax(IReadOnlyList<Token> Tokens, PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax(Tokens)
|
||||
public record PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record CStringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
|
||||
public record CStringTypeSyntax : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record StringTypeSyntax(IReadOnlyList<Token> Tokens) : TypeSyntax(Tokens)
|
||||
public record StringTypeSyntax : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record CustomTypeSyntax(IReadOnlyList<Token> Tokens, string Namespace, string Name) : TypeSyntax(Tokens)
|
||||
public record CustomTypeSyntax(string Namespace, string Name) : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren() => [];
|
||||
}
|
||||
|
||||
public record ArrayTypeSyntax(IReadOnlyList<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens)
|
||||
public record ArrayTypeSyntax(TypeSyntax BaseType) : TypeSyntax
|
||||
{
|
||||
public override IEnumerable<SyntaxNode> GetChildren()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ public sealed class Parser
|
||||
private string _namespace;
|
||||
private readonly IReadOnlyList<Token> _tokens;
|
||||
|
||||
private readonly List<Diagnostic> _diagnostics = [];
|
||||
private List<Diagnostic> _diagnostics = [];
|
||||
private int _tokenIndex;
|
||||
|
||||
public Parser(IReadOnlyList<Token> tokens)
|
||||
@@ -20,9 +20,9 @@ public sealed class Parser
|
||||
_tokens = tokens;
|
||||
}
|
||||
|
||||
public SyntaxTree Parse()
|
||||
public SyntaxTree Parse(out IReadOnlyList<Diagnostic> diagnostics)
|
||||
{
|
||||
_diagnostics.Clear();
|
||||
_diagnostics = [];
|
||||
_tokenIndex = 0;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Namespace))
|
||||
@@ -34,22 +34,19 @@ public sealed class Parser
|
||||
|
||||
while (Peek().HasValue)
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
|
||||
try
|
||||
{
|
||||
var keyword = ExpectSymbol();
|
||||
|
||||
var definition = keyword.Symbol switch
|
||||
{
|
||||
Symbol.Extern => ParseExtern(startIndex),
|
||||
Symbol.Func => ParseFunc(startIndex),
|
||||
Symbol.Struct => ParseStruct(startIndex),
|
||||
Symbol.Interface => ParseInterface(startIndex),
|
||||
Symbol.Extern => ParseExtern(),
|
||||
Symbol.Func => ParseFunc(),
|
||||
Symbol.Struct => ParseStruct(),
|
||||
Symbol.Interface => ParseInterface(),
|
||||
_ => throw new ParseException(Diagnostic
|
||||
.Error($"Expected 'extern', 'func', 'struct', 'trait' or 'impl' but found '{keyword.Symbol}'")
|
||||
.WithHelp("Valid definition keywords are 'extern', 'func', 'struct', 'trait' and 'impl'")
|
||||
.At(keyword)
|
||||
.Error($"Expected 'extern', 'func', 'struct' or 'interface' but found '{keyword.Symbol}'")
|
||||
.WithHelp("Valid definition keywords are 'extern', 'func', 'struct' and 'interface'")
|
||||
.Build())
|
||||
};
|
||||
|
||||
@@ -71,13 +68,12 @@ public sealed class Parser
|
||||
}
|
||||
}
|
||||
|
||||
return new SyntaxTree(_tokens, _namespace, definitions, _diagnostics);
|
||||
diagnostics = _diagnostics;
|
||||
return new SyntaxTree(_namespace, definitions);
|
||||
}
|
||||
|
||||
private FuncSignatureSyntax ParseFuncSignature(FuncParameterSyntax? thisArg = null)
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
|
||||
List<FuncParameterSyntax> parameters = [];
|
||||
|
||||
if (thisArg != null)
|
||||
@@ -96,38 +92,36 @@ public sealed class Parser
|
||||
_diagnostics.Add(Diagnostic
|
||||
.Warning("Missing comma between function parameters")
|
||||
.WithHelp("Add a ',' to separate parameters")
|
||||
.At(token)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([GetTokens(startIndex).Last()]);
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax();
|
||||
|
||||
return new FuncSignatureSyntax(GetTokens(startIndex), parameters, returnType);
|
||||
return new FuncSignatureSyntax(parameters, returnType);
|
||||
}
|
||||
|
||||
private FuncParameterSyntax ParseFuncParameter()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var type = ParseType();
|
||||
|
||||
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
|
||||
return new FuncParameterSyntax(name.Value, type);
|
||||
}
|
||||
|
||||
private DefinitionSyntax ParseExtern(int startIndex)
|
||||
private DefinitionSyntax ParseExtern()
|
||||
{
|
||||
var keyword = ExpectSymbol();
|
||||
|
||||
return keyword.Symbol switch
|
||||
{
|
||||
Symbol.Func => ParseExternFunc(startIndex),
|
||||
_ => throw new ParseException(Diagnostic.Error($"Unexpected symbol {keyword.Symbol} after extern declaration").At(keyword).Build())
|
||||
Symbol.Func => ParseExternFunc(),
|
||||
_ => throw new ParseException(Diagnostic.Error($"Unexpected symbol {keyword.Symbol} after extern declaration").Build())
|
||||
};
|
||||
}
|
||||
|
||||
private ExternFuncSyntax ParseExternFunc(int startIndex)
|
||||
private ExternFuncSyntax ParseExternFunc()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
|
||||
@@ -140,19 +134,19 @@ public sealed class Parser
|
||||
|
||||
var signature = ParseFuncSignature();
|
||||
|
||||
return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, signature);
|
||||
return new ExternFuncSyntax(_namespace, name.Value, callName, signature);
|
||||
}
|
||||
|
||||
private LocalFuncSyntax ParseFunc(int startIndex)
|
||||
private LocalFuncSyntax ParseFunc()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
var signature = ParseFuncSignature();
|
||||
var body = ParseBlock();
|
||||
|
||||
return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, signature, body);
|
||||
return new LocalFuncSyntax(_namespace, name.Value, signature, body);
|
||||
}
|
||||
|
||||
private DefinitionSyntax ParseStruct(int startIndex)
|
||||
private DefinitionSyntax ParseStruct()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
|
||||
@@ -165,16 +159,14 @@ public sealed class Parser
|
||||
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
var memberStartIndex = _tokenIndex;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Func))
|
||||
{
|
||||
var funcName = ExpectIdentifier().Value;
|
||||
var thisArg = new FuncParameterSyntax([], "this", new CustomTypeSyntax([], _namespace, name.Value));
|
||||
var thisArg = new FuncParameterSyntax("this", new CustomTypeSyntax(_namespace, name.Value));
|
||||
var funcSignature = ParseFuncSignature(thisArg);
|
||||
var funcBody = ParseBlock();
|
||||
|
||||
funcs.Add(new StructFuncSyntax(GetTokens(memberStartIndex), funcName, funcSignature, funcBody));
|
||||
funcs.Add(new StructFuncSyntax(funcName, funcSignature, funcBody));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,14 +181,14 @@ public sealed class Parser
|
||||
fieldValue = ParseExpression();
|
||||
}
|
||||
|
||||
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldIndex++, fieldName, fieldType, fieldValue));
|
||||
fields.Add(new StructFieldSyntax(fieldIndex++, fieldName, fieldType, fieldValue));
|
||||
}
|
||||
}
|
||||
|
||||
return new StructSyntax(GetTokens(startIndex), _namespace, name.Value, fields, funcs);
|
||||
return new StructSyntax(_namespace, name.Value, fields, funcs);
|
||||
}
|
||||
|
||||
private InterfaceSyntax ParseInterface(int startIndex)
|
||||
private InterfaceSyntax ParseInterface()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
|
||||
@@ -206,27 +198,23 @@ public sealed class Parser
|
||||
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
var funcStartIndex = _tokenIndex;
|
||||
|
||||
ExpectSymbol(Symbol.Func);
|
||||
|
||||
var funcName = ExpectIdentifier().Value;
|
||||
var signature = ParseFuncSignature();
|
||||
|
||||
functions.Add(new InterfaceFuncSyntax(GetTokens(funcStartIndex), funcName, signature));
|
||||
functions.Add(new InterfaceFuncSyntax(funcName, signature));
|
||||
}
|
||||
|
||||
return new InterfaceSyntax(GetTokens(startIndex), _namespace, name.Value, functions);
|
||||
return new InterfaceSyntax(_namespace, name.Value, functions);
|
||||
}
|
||||
|
||||
private StatementSyntax ParseStatement()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
if (!Peek().TryGetValue(out var token))
|
||||
{
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Unexpected end of file while parsing statement")
|
||||
.At(_tokens[^1])
|
||||
.Build());
|
||||
}
|
||||
|
||||
@@ -235,37 +223,37 @@ public sealed class Parser
|
||||
switch (symbol.Symbol)
|
||||
{
|
||||
case Symbol.Return:
|
||||
return ParseReturn(startIndex);
|
||||
return ParseReturn();
|
||||
case Symbol.If:
|
||||
return ParseIf(startIndex);
|
||||
return ParseIf();
|
||||
case Symbol.While:
|
||||
return ParseWhile(startIndex);
|
||||
return ParseWhile();
|
||||
case Symbol.Let:
|
||||
return ParseVariableDeclaration(startIndex);
|
||||
return ParseVariableDeclaration();
|
||||
case Symbol.Break:
|
||||
return ParseBreak(startIndex);
|
||||
return ParseBreak();
|
||||
case Symbol.Continue:
|
||||
return ParseContinue(startIndex);
|
||||
return ParseContinue();
|
||||
}
|
||||
}
|
||||
|
||||
return ParseStatementExpression(startIndex);
|
||||
return ParseStatementExpression();
|
||||
}
|
||||
|
||||
private StatementSyntax ParseStatementExpression(int startIndex)
|
||||
private StatementSyntax ParseStatementExpression()
|
||||
{
|
||||
var expr = ParseExpression();
|
||||
|
||||
if (TryExpectSymbol(Symbol.Assign))
|
||||
{
|
||||
var value = ParseExpression();
|
||||
return new AssignmentSyntax(GetTokens(startIndex), expr, value);
|
||||
return new AssignmentSyntax(expr, value);
|
||||
}
|
||||
|
||||
return new StatementExpressionSyntax(GetTokens(startIndex), expr);
|
||||
return new StatementExpressionSyntax(expr);
|
||||
}
|
||||
|
||||
private VariableDeclarationSyntax ParseVariableDeclaration(int startIndex)
|
||||
private VariableDeclarationSyntax ParseVariableDeclaration()
|
||||
{
|
||||
ExpectSymbol(Symbol.Let);
|
||||
var name = ExpectIdentifier().Value;
|
||||
@@ -282,23 +270,23 @@ public sealed class Parser
|
||||
assignment = ParseExpression();
|
||||
}
|
||||
|
||||
return new VariableDeclarationSyntax(GetTokens(startIndex), name, explicitType, assignment);
|
||||
return new VariableDeclarationSyntax(name, explicitType, assignment);
|
||||
}
|
||||
|
||||
private StatementSyntax ParseBreak(int startIndex)
|
||||
private StatementSyntax ParseBreak()
|
||||
{
|
||||
ExpectSymbol(Symbol.Break);
|
||||
Next();
|
||||
return new BreakSyntax(GetTokens(startIndex));
|
||||
return new BreakSyntax();
|
||||
}
|
||||
|
||||
private StatementSyntax ParseContinue(int startIndex)
|
||||
private StatementSyntax ParseContinue()
|
||||
{
|
||||
ExpectSymbol(Symbol.Continue);
|
||||
return new ContinueSyntax(GetTokens(startIndex));
|
||||
return new ContinueSyntax();
|
||||
}
|
||||
|
||||
private ReturnSyntax ParseReturn(int startIndex)
|
||||
private ReturnSyntax ParseReturn()
|
||||
{
|
||||
ExpectSymbol(Symbol.Return);
|
||||
|
||||
@@ -309,10 +297,10 @@ public sealed class Parser
|
||||
value = ParseExpression();
|
||||
}
|
||||
|
||||
return new ReturnSyntax(GetTokens(startIndex), value);
|
||||
return new ReturnSyntax(value);
|
||||
}
|
||||
|
||||
private IfSyntax ParseIf(int startIndex)
|
||||
private IfSyntax ParseIf()
|
||||
{
|
||||
ExpectSymbol(Symbol.If);
|
||||
var condition = ParseExpression();
|
||||
@@ -321,26 +309,24 @@ public sealed class Parser
|
||||
var elseStatement = Optional<Variant<IfSyntax, BlockSyntax>>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Else))
|
||||
{
|
||||
var newStartIndex = _tokenIndex;
|
||||
elseStatement = TryExpectSymbol(Symbol.If)
|
||||
? (Variant<IfSyntax, BlockSyntax>)ParseIf(newStartIndex)
|
||||
? (Variant<IfSyntax, BlockSyntax>)ParseIf()
|
||||
: (Variant<IfSyntax, BlockSyntax>)ParseBlock();
|
||||
}
|
||||
|
||||
return new IfSyntax(GetTokens(startIndex), condition, body, elseStatement);
|
||||
return new IfSyntax(condition, body, elseStatement);
|
||||
}
|
||||
|
||||
private WhileSyntax ParseWhile(int startIndex)
|
||||
private WhileSyntax ParseWhile()
|
||||
{
|
||||
ExpectSymbol(Symbol.While);
|
||||
var condition = ParseExpression();
|
||||
var body = ParseBlock();
|
||||
return new WhileSyntax(GetTokens(startIndex), condition, body);
|
||||
return new WhileSyntax(condition, body);
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParseExpression(int precedence = 0)
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
var left = ParsePrimaryExpression();
|
||||
|
||||
while (true)
|
||||
@@ -355,7 +341,7 @@ public sealed class Parser
|
||||
Next();
|
||||
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
|
||||
|
||||
left = new BinaryExpressionSyntax(GetTokens(startIndex), left, op.Value, right);
|
||||
left = new BinaryExpressionSyntax(left, op.Value, right);
|
||||
}
|
||||
|
||||
return left;
|
||||
@@ -421,7 +407,6 @@ public sealed class Parser
|
||||
|
||||
private ExpressionSyntax ParsePrimaryExpression()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
ExpressionSyntax expr;
|
||||
|
||||
var token = ExpectToken();
|
||||
@@ -429,7 +414,7 @@ public sealed class Parser
|
||||
{
|
||||
case LiteralToken literal:
|
||||
{
|
||||
expr = new LiteralSyntax(GetTokens(startIndex), literal.Value, literal.Kind);
|
||||
expr = new LiteralSyntax(literal.Value, literal.Kind);
|
||||
break;
|
||||
}
|
||||
case IdentifierToken identifier:
|
||||
@@ -442,7 +427,7 @@ public sealed class Parser
|
||||
name = ExpectIdentifier().Value;
|
||||
}
|
||||
|
||||
expr = new IdentifierSyntax(GetTokens(startIndex), @namespace, name);
|
||||
expr = new IdentifierSyntax(@namespace, name);
|
||||
break;
|
||||
}
|
||||
case SymbolToken symbolToken:
|
||||
@@ -455,27 +440,24 @@ public sealed class Parser
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
var parameterStartIndex = _tokenIndex;
|
||||
var name = ExpectIdentifier();
|
||||
parameters.Add(new ArrowFuncParameterSyntax(GetTokens(parameterStartIndex), name.Value));
|
||||
parameters.Add(new ArrowFuncParameterSyntax(name.Value));
|
||||
}
|
||||
|
||||
BlockSyntax body;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Arrow))
|
||||
{
|
||||
var blockStartIndex = _tokenIndex;
|
||||
var returnValue = ParseExpression();
|
||||
var tokens = GetTokens(blockStartIndex);
|
||||
var arrowExpression = new ReturnSyntax(tokens, returnValue);
|
||||
body = new BlockSyntax(tokens, [arrowExpression]);
|
||||
var arrowExpression = new ReturnSyntax(returnValue);
|
||||
body = new BlockSyntax([arrowExpression]);
|
||||
}
|
||||
else
|
||||
{
|
||||
body = ParseBlock();
|
||||
}
|
||||
|
||||
expr = new ArrowFuncSyntax(GetTokens(startIndex), parameters, body);
|
||||
expr = new ArrowFuncSyntax(parameters, body);
|
||||
break;
|
||||
}
|
||||
case Symbol.OpenParen:
|
||||
@@ -488,13 +470,13 @@ public sealed class Parser
|
||||
case Symbol.Minus:
|
||||
{
|
||||
var expression = ParsePrimaryExpression();
|
||||
expr = new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperator.Negate, expression);
|
||||
expr = new UnaryExpressionSyntax(UnaryOperator.Negate, expression);
|
||||
break;
|
||||
}
|
||||
case Symbol.Bang:
|
||||
{
|
||||
var expression = ParsePrimaryExpression();
|
||||
expr = new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperator.Invert, expression);
|
||||
expr = new UnaryExpressionSyntax(UnaryOperator.Invert, expression);
|
||||
break;
|
||||
}
|
||||
case Symbol.OpenBracket:
|
||||
@@ -502,7 +484,7 @@ public sealed class Parser
|
||||
var capacity = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var type = ParseType();
|
||||
expr = new ArrayInitializerSyntax(GetTokens(startIndex), capacity, type);
|
||||
expr = new ArrayInitializerSyntax(capacity, type);
|
||||
break;
|
||||
}
|
||||
case Symbol.Alloc:
|
||||
@@ -518,7 +500,7 @@ public sealed class Parser
|
||||
initializers.Add(name, value);
|
||||
}
|
||||
|
||||
expr = new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
|
||||
expr = new StructInitializerSyntax(type, initializers);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -526,7 +508,6 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
|
||||
.WithHelp("Expected literal, identifier, or '(' to start expression")
|
||||
.At(symbolToken)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
@@ -538,34 +519,33 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error($"Unexpected token '{token.GetType().Name}' in expression")
|
||||
.WithHelp("Expected literal, identifier, or parenthesized expression")
|
||||
.At(token)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
return ParsePostfixOperators(startIndex, expr);
|
||||
return ParsePostfixOperators(expr);
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParsePostfixOperators(int startIndex, ExpressionSyntax expr)
|
||||
private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (TryExpectSymbol(Symbol.Ampersand))
|
||||
{
|
||||
expr = new AddressOfSyntax(GetTokens(startIndex), expr);
|
||||
expr = new AddressOfSyntax(expr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.Caret))
|
||||
{
|
||||
expr = new DereferenceSyntax(GetTokens(startIndex), expr);
|
||||
expr = new DereferenceSyntax(expr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.Period))
|
||||
{
|
||||
var structMember = ExpectIdentifier().Value;
|
||||
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, structMember);
|
||||
expr = new MemberAccessSyntax(expr, structMember);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -573,7 +553,7 @@ public sealed class Parser
|
||||
{
|
||||
var index = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
expr = new ArrayIndexAccessSyntax(GetTokens(startIndex), expr, index);
|
||||
expr = new ArrayIndexAccessSyntax(expr, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -588,12 +568,11 @@ public sealed class Parser
|
||||
_diagnostics.Add(Diagnostic
|
||||
.Warning("Missing comma between function arguments")
|
||||
.WithHelp("Add a ',' to separate arguments")
|
||||
.At(nextToken)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
expr = new FuncCallSyntax(GetTokens(startIndex), expr, parameters);
|
||||
expr = new FuncCallSyntax(expr, parameters);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -605,7 +584,6 @@ public sealed class Parser
|
||||
|
||||
private BlockSyntax ParseBlock()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
List<StatementSyntax> statements = [];
|
||||
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
|
||||
@@ -621,31 +599,29 @@ public sealed class Parser
|
||||
}
|
||||
}
|
||||
|
||||
return new BlockSyntax(GetTokens(startIndex), statements);
|
||||
return new BlockSyntax(statements);
|
||||
}
|
||||
|
||||
private TypeSyntax ParseType()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
|
||||
if (TryExpectIdentifier(out var name))
|
||||
{
|
||||
return name.Value switch
|
||||
{
|
||||
"void" => new VoidTypeSyntax(GetTokens(startIndex)),
|
||||
"string" => new StringTypeSyntax(GetTokens(startIndex)),
|
||||
"cstring" => new CStringTypeSyntax(GetTokens(startIndex)),
|
||||
"i64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I64),
|
||||
"i32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I32),
|
||||
"i16" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I16),
|
||||
"i8" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.I8),
|
||||
"u64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U64),
|
||||
"u32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U32),
|
||||
"u16" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U16),
|
||||
"u8" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.U8),
|
||||
"f64" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.F64),
|
||||
"f32" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.F32),
|
||||
"bool" => new PrimitiveTypeSyntax(GetTokens(startIndex), PrimitiveTypeSyntaxKind.Bool),
|
||||
"void" => new VoidTypeSyntax(),
|
||||
"string" => new StringTypeSyntax(),
|
||||
"cstring" => new CStringTypeSyntax(),
|
||||
"i64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I64),
|
||||
"i32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I32),
|
||||
"i16" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I16),
|
||||
"i8" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.I8),
|
||||
"u64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U64),
|
||||
"u32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U32),
|
||||
"u16" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U16),
|
||||
"u8" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.U8),
|
||||
"f64" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.F64),
|
||||
"f32" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.F32),
|
||||
"bool" => new PrimitiveTypeSyntax(PrimitiveTypeSyntaxKind.Bool),
|
||||
_ => ParseCustomType()
|
||||
};
|
||||
|
||||
@@ -657,14 +633,14 @@ public sealed class Parser
|
||||
@namespace = ExpectIdentifier().Value;
|
||||
}
|
||||
|
||||
return new CustomTypeSyntax(GetTokens(startIndex), @namespace, name.Value);
|
||||
return new CustomTypeSyntax(@namespace, name.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.Caret))
|
||||
{
|
||||
var baseType = ParseType();
|
||||
return new PointerTypeSyntax(GetTokens(startIndex), baseType);
|
||||
return new PointerTypeSyntax(baseType);
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.Func))
|
||||
@@ -680,21 +656,20 @@ public sealed class Parser
|
||||
_diagnostics.Add(Diagnostic
|
||||
.Warning("Missing comma between func type arguments")
|
||||
.WithHelp("Add a ',' to separate arguments")
|
||||
.At(nextToken)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax(GetTokens(startIndex));
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax();
|
||||
|
||||
return new FuncTypeSyntax(GetTokens(startIndex), parameters, returnType);
|
||||
return new FuncTypeSyntax(parameters, returnType);
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.OpenBracket))
|
||||
{
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var baseType = ParseType();
|
||||
return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
|
||||
return new ArrayTypeSyntax(baseType);
|
||||
}
|
||||
|
||||
if (!Peek().TryGetValue(out var peekToken))
|
||||
@@ -702,14 +677,12 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Unexpected end of file while parsing type")
|
||||
.WithHelp("Expected a type name")
|
||||
.At(_tokens[^1])
|
||||
.Build());
|
||||
}
|
||||
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Invalid type Syntax")
|
||||
.WithHelp("Expected type name, '^' for pointer, or '[]' for array")
|
||||
.At(peekToken)
|
||||
.Build());
|
||||
}
|
||||
|
||||
@@ -720,7 +693,6 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Unexpected end of file")
|
||||
.WithHelp("Expected more tokens to complete the Syntax")
|
||||
.At(_tokens.Last())
|
||||
.Build());
|
||||
}
|
||||
|
||||
@@ -736,7 +708,6 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error($"Expected symbol, but found {token.GetType().Name}")
|
||||
.WithHelp("This position requires a symbol like '(', ')', '{', '}', etc.")
|
||||
.At(token)
|
||||
.Build());
|
||||
}
|
||||
|
||||
@@ -751,7 +722,6 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error($"Expected '{expectedSymbol}', but found '{token.Symbol}'")
|
||||
.WithHelp($"Insert '{expectedSymbol}' here")
|
||||
.At(token)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
@@ -788,7 +758,6 @@ public sealed class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error($"Expected identifier, but found {token.GetType().Name}")
|
||||
.WithHelp("Provide a valid identifier name here")
|
||||
.At(token)
|
||||
.Build());
|
||||
}
|
||||
|
||||
@@ -810,11 +779,6 @@ public sealed class Parser
|
||||
{
|
||||
_tokenIndex++;
|
||||
}
|
||||
|
||||
private List<Token> GetTokens(int startIndex)
|
||||
{
|
||||
return _tokens.Skip(startIndex).Take(Math.Min(_tokenIndex, _tokens.Count - 1) - startIndex).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class ParseException : Exception
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
namespace NubLang.Syntax.Tokenization;
|
||||
|
||||
public abstract class Token(SourceSpan span)
|
||||
{
|
||||
public SourceSpan Span { get; } = span;
|
||||
}
|
||||
public abstract class Token;
|
||||
|
||||
public class IdentifierToken(SourceSpan span, string value) : Token(span)
|
||||
public class IdentifierToken(string value) : Token
|
||||
{
|
||||
public string Value { get; } = value;
|
||||
}
|
||||
|
||||
public class LiteralToken(SourceSpan span, LiteralKind kind, string value) : Token(span)
|
||||
public class LiteralToken(LiteralKind kind, string value) : Token
|
||||
{
|
||||
public LiteralKind Kind { get; } = kind;
|
||||
public string Value { get; } = value;
|
||||
@@ -24,7 +21,7 @@ public enum LiteralKind
|
||||
Bool
|
||||
}
|
||||
|
||||
public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
|
||||
public class SymbolToken(Symbol symbol) : Token
|
||||
{
|
||||
public Symbol Symbol { get; } = symbol;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class Tokenizer
|
||||
["extern"] = Symbol.Extern,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<char[], Symbol> Chians = new()
|
||||
private static readonly Dictionary<char[], Symbol> Symbols = new()
|
||||
{
|
||||
[['=', '=']] = Symbol.Equal,
|
||||
[['!', '=']] = Symbol.NotEqual,
|
||||
@@ -32,36 +32,32 @@ public sealed class Tokenizer
|
||||
[['>', '=']] = Symbol.GreaterThanOrEqual,
|
||||
[[':', ':']] = Symbol.DoubleColon,
|
||||
[['=', '>']] = Symbol.Arrow,
|
||||
[[':']] = Symbol.Colon,
|
||||
[['(']] = Symbol.OpenParen,
|
||||
[[')']] = Symbol.CloseParen,
|
||||
[['{']] = Symbol.OpenBrace,
|
||||
[['}']] = Symbol.CloseBrace,
|
||||
[['[']] = Symbol.OpenBracket,
|
||||
[[']']] = Symbol.CloseBracket,
|
||||
[[',']] = Symbol.Comma,
|
||||
[['.']] = Symbol.Period,
|
||||
[['=']] = Symbol.Assign,
|
||||
[['<']] = Symbol.LessThan,
|
||||
[['>']] = Symbol.GreaterThan,
|
||||
[['+']] = Symbol.Plus,
|
||||
[['-']] = Symbol.Minus,
|
||||
[['*']] = Symbol.Star,
|
||||
[['/']] = Symbol.ForwardSlash,
|
||||
[['!']] = Symbol.Bang,
|
||||
[['^']] = Symbol.Caret,
|
||||
[['&']] = Symbol.Ampersand,
|
||||
[[';']] = Symbol.Semi,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<char, Symbol> Chars = new()
|
||||
{
|
||||
[':'] = Symbol.Colon,
|
||||
['('] = Symbol.OpenParen,
|
||||
[')'] = Symbol.CloseParen,
|
||||
['{'] = Symbol.OpenBrace,
|
||||
['}'] = Symbol.CloseBrace,
|
||||
['['] = Symbol.OpenBracket,
|
||||
[']'] = Symbol.CloseBracket,
|
||||
[','] = Symbol.Comma,
|
||||
['.'] = Symbol.Period,
|
||||
['='] = Symbol.Assign,
|
||||
['<'] = Symbol.LessThan,
|
||||
['>'] = Symbol.GreaterThan,
|
||||
['+'] = Symbol.Plus,
|
||||
['-'] = Symbol.Minus,
|
||||
['*'] = Symbol.Star,
|
||||
['/'] = Symbol.ForwardSlash,
|
||||
['!'] = Symbol.Bang,
|
||||
['^'] = Symbol.Caret,
|
||||
['&'] = Symbol.Ampersand,
|
||||
[';'] = Symbol.Semi,
|
||||
};
|
||||
|
||||
private readonly SourceText _sourceText;
|
||||
private readonly string _sourceText;
|
||||
private int _index;
|
||||
|
||||
public Tokenizer(SourceText sourceText)
|
||||
public Tokenizer(string sourceText)
|
||||
{
|
||||
_sourceText = sourceText;
|
||||
}
|
||||
@@ -122,15 +118,15 @@ public sealed class Tokenizer
|
||||
|
||||
if (Keywords.TryGetValue(buffer, out var keywordSymbol))
|
||||
{
|
||||
return new SymbolToken(CreateSpan(startIndex), keywordSymbol);
|
||||
return new SymbolToken(keywordSymbol);
|
||||
}
|
||||
|
||||
if (buffer is "true" or "false")
|
||||
{
|
||||
return new LiteralToken(CreateSpan(startIndex), LiteralKind.Bool, buffer);
|
||||
return new LiteralToken(LiteralKind.Bool, buffer);
|
||||
}
|
||||
|
||||
return new IdentifierToken(CreateSpan(startIndex), buffer);
|
||||
return new IdentifierToken(buffer);
|
||||
}
|
||||
|
||||
if (char.IsDigit(current))
|
||||
@@ -162,15 +158,12 @@ public sealed class Tokenizer
|
||||
}
|
||||
}
|
||||
|
||||
return new LiteralToken(CreateSpan(startIndex), isFloat ? LiteralKind.Float : LiteralKind.Integer, buffer);
|
||||
return new LiteralToken(isFloat ? LiteralKind.Float : LiteralKind.Integer, buffer);
|
||||
}
|
||||
|
||||
// TODO: Revisit this
|
||||
foreach (var chain in Chians)
|
||||
foreach (var chain in Symbols)
|
||||
{
|
||||
if (current != chain.Key[0]) continue;
|
||||
|
||||
for (var i = 1; i < chain.Key.Length; i++)
|
||||
for (var i = 0; i < chain.Key.Length; i++)
|
||||
{
|
||||
var c = Peek(i);
|
||||
if (!c.HasValue || c.Value != chain.Key[i]) break;
|
||||
@@ -182,17 +175,11 @@ public sealed class Tokenizer
|
||||
Next();
|
||||
}
|
||||
|
||||
return new SymbolToken(CreateSpan(startIndex), chain.Value);
|
||||
return new SymbolToken(chain.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Chars.TryGetValue(current, out var charSymbol))
|
||||
{
|
||||
Next();
|
||||
return new SymbolToken(CreateSpan(startIndex), charSymbol);
|
||||
}
|
||||
|
||||
if (current == '"')
|
||||
{
|
||||
Next();
|
||||
@@ -215,42 +202,17 @@ public sealed class Tokenizer
|
||||
Next();
|
||||
}
|
||||
|
||||
return new LiteralToken(CreateSpan(startIndex), LiteralKind.String, buffer);
|
||||
return new LiteralToken(LiteralKind.String, buffer);
|
||||
}
|
||||
|
||||
throw new Exception($"Unknown character {current}");
|
||||
}
|
||||
|
||||
private SourceLocation CreateLocation(int index)
|
||||
{
|
||||
var line = 1;
|
||||
var column = 1;
|
||||
for (var i = 0; i < Math.Min(index, _sourceText.Content.Length - 1); i++)
|
||||
{
|
||||
if (_sourceText.Content[i] == '\n')
|
||||
{
|
||||
column = 1;
|
||||
line += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new SourceLocation(line, column);
|
||||
}
|
||||
|
||||
private SourceSpan CreateSpan(int startIndex)
|
||||
{
|
||||
return new SourceSpan(_sourceText, CreateLocation(startIndex), CreateLocation(_index));
|
||||
}
|
||||
|
||||
private Optional<char> Peek(int offset = 0)
|
||||
{
|
||||
if (_index + offset < _sourceText.Content.Length)
|
||||
if (_index + offset < _sourceText.Length)
|
||||
{
|
||||
return _sourceText.Content[_index + offset];
|
||||
return _sourceText[_index + offset];
|
||||
}
|
||||
|
||||
return Optional<char>.Empty();
|
||||
@@ -258,9 +220,9 @@ public sealed class Tokenizer
|
||||
|
||||
private Optional<char> Next()
|
||||
{
|
||||
if (_index < _sourceText.Content.Length)
|
||||
if (_index < _sourceText.Length)
|
||||
{
|
||||
return _sourceText.Content[_index++];
|
||||
return _sourceText[_index++];
|
||||
}
|
||||
|
||||
_index++;
|
||||
|
||||
Reference in New Issue
Block a user