...
This commit is contained in:
@@ -9,7 +9,7 @@ struct Human {
|
|||||||
export func main(args: []^string) {
|
export func main(args: []^string) {
|
||||||
let i: i64
|
let i: i64
|
||||||
|
|
||||||
c:printf("%d\n", args.count)
|
c::printf("%d\n", args.count)
|
||||||
|
|
||||||
while i < args.count {
|
while i < args.count {
|
||||||
c::printf("%s\n", args[i])
|
c::printf("%s\n", args[i])
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ foreach (var file in Directory.EnumerateFiles(srcDir, "*.nub", SearchOption.AllD
|
|||||||
{
|
{
|
||||||
var content = File.ReadAllText(file);
|
var content = File.ReadAllText(file);
|
||||||
|
|
||||||
var tokenizeResult = lexer.Tokenize(new SourceText(content));
|
var tokenizeResult = lexer.Tokenize(new SourceText(file, content));
|
||||||
tokenizeResult.PrintAllDiagnostics();
|
tokenizeResult.PrintAllDiagnostics();
|
||||||
error = error || tokenizeResult.HasErrors;
|
error = error || tokenizeResult.HasErrors;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,54 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Nub.Lang.Frontend.Lexing;
|
||||||
|
using Nub.Lang.Frontend.Typing;
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Diagnostics;
|
namespace Nub.Lang.Frontend.Diagnostics;
|
||||||
|
|
||||||
public static class ConsoleColors
|
public static class ConsoleColors
|
||||||
{
|
{
|
||||||
public const string Reset = "\e[0m";
|
public const string Reset = "\e[0m";
|
||||||
public const string Bold = "\e[1m";
|
public const string Bold = "\e[1m";
|
||||||
|
public const string Faint = "\e[2m";
|
||||||
|
public const string Italic = "\e[3m";
|
||||||
|
public const string Underline = "\e[4m";
|
||||||
|
public const string SlowBlink = "\e[5m";
|
||||||
|
public const string RapidBlink = "\e[6m";
|
||||||
|
public const string SwapBgAndFg = "\e[7m";
|
||||||
|
public const string Conceal = "\e[8m";
|
||||||
|
public const string CrossedOut = "\e[9m";
|
||||||
|
|
||||||
|
public const string DefaultFont = "\e[10m";
|
||||||
|
public const string AltFont1 = "\e[11m";
|
||||||
|
public const string AltFont2 = "\e[12m";
|
||||||
|
public const string AltFont3 = "\e[13m";
|
||||||
|
public const string AltFont4 = "\e[14m";
|
||||||
|
public const string AltFont5 = "\e[15m";
|
||||||
|
public const string AltFont6 = "\e[16m";
|
||||||
|
public const string AltFont7 = "\e[17m";
|
||||||
|
public const string AltFont8 = "\e[18m";
|
||||||
|
public const string AltFont9 = "\e[19m";
|
||||||
|
|
||||||
|
public const string Black = "\e[30m";
|
||||||
public const string Red = "\e[31m";
|
public const string Red = "\e[31m";
|
||||||
|
public const string Green = "\e[32m";
|
||||||
public const string Yellow = "\e[33m";
|
public const string Yellow = "\e[33m";
|
||||||
public const string Blue = "\e[34m";
|
public const string Blue = "\e[34m";
|
||||||
|
public const string Magenta = "\e[35m";
|
||||||
public const string Cyan = "\e[36m";
|
public const string Cyan = "\e[36m";
|
||||||
public const string White = "\e[37m";
|
public const string White = "\e[37m";
|
||||||
|
|
||||||
|
public const string LightBlue = "\e[94m";
|
||||||
|
|
||||||
|
public const string BrightBlack = "\e[90m";
|
||||||
|
public const string BrightRed = "\e[91m";
|
||||||
|
public const string BrightGreen = "\e[92m";
|
||||||
|
public const string BrightYellow = "\e[93m";
|
||||||
|
public const string BrightBlue = "\e[94m";
|
||||||
|
public const string BrightMagenta = "\e[95m";
|
||||||
|
public const string BrightCyan = "\e[96m";
|
||||||
public const string BrightWhite = "\e[97m";
|
public const string BrightWhite = "\e[97m";
|
||||||
public const string Gray = "\e[90m";
|
|
||||||
|
private static readonly Lexer Lexer = new();
|
||||||
|
|
||||||
private static bool IsColorSupported()
|
private static bool IsColorSupported()
|
||||||
{
|
{
|
||||||
@@ -24,4 +61,130 @@ public static class ConsoleColors
|
|||||||
{
|
{
|
||||||
return IsColorSupported() ? $"{color}{text}{Reset}" : text;
|
return IsColorSupported() ? $"{color}{text}{Reset}" : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetTokenColor(Token token)
|
||||||
|
{
|
||||||
|
switch (token)
|
||||||
|
{
|
||||||
|
case DocumentationToken:
|
||||||
|
return Faint;
|
||||||
|
case IdentifierToken:
|
||||||
|
return White;
|
||||||
|
case LiteralToken literal:
|
||||||
|
if (literal.Type.Equals(NubPrimitiveType.String))
|
||||||
|
{
|
||||||
|
return Green;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.Equals(NubPrimitiveType.I64) || literal.Type.Equals(NubPrimitiveType.F64))
|
||||||
|
{
|
||||||
|
return LightBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.Equals(NubPrimitiveType.Bool))
|
||||||
|
{
|
||||||
|
return Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return White;
|
||||||
|
case ModifierToken:
|
||||||
|
return 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.Semicolon:
|
||||||
|
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 BrightYellow;
|
||||||
|
default:
|
||||||
|
return White;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return White;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ColorizeSource(SourceText sourceText)
|
||||||
|
{
|
||||||
|
var tokens = Lexer.Tokenize(sourceText).Value;
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ public class Diagnostic
|
|||||||
|
|
||||||
if (Span.HasValue)
|
if (Span.HasValue)
|
||||||
{
|
{
|
||||||
// var locationText = $" at {Span.Value.Path}:{Span}";
|
var locationText = $" at {Span.Value.Text.Name}:{Span}";
|
||||||
// sb.Append(ConsoleColors.Colorize(locationText, ConsoleColors.Gray));
|
sb.Append(ConsoleColors.Colorize(locationText, ConsoleColors.Faint));
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Append(": ");
|
sb.Append(": ");
|
||||||
@@ -107,7 +107,7 @@ public class Diagnostic
|
|||||||
|
|
||||||
private static void AppendSourceContext(StringBuilder sb, SourceSpan span)
|
private static void AppendSourceContext(StringBuilder sb, SourceSpan span)
|
||||||
{
|
{
|
||||||
var lines = span.Content.Text.Split('\n');
|
var lines = span.Text.Content.Split('\n');
|
||||||
var startLine = span.Start.Line;
|
var startLine = span.Start.Line;
|
||||||
var endLine = span.End.Line;
|
var endLine = span.End.Line;
|
||||||
|
|
||||||
@@ -125,13 +125,13 @@ public class Diagnostic
|
|||||||
|
|
||||||
for (var lineNum = contextStart; lineNum < startLine; lineNum++)
|
for (var lineNum = contextStart; lineNum < startLine; lineNum++)
|
||||||
{
|
{
|
||||||
var line = lines[lineNum - 1];
|
var line = ConsoleColors.ColorizeSource(new SourceText(span.Text.Name, lines[lineNum - 1]));
|
||||||
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var lineNum = startLine; lineNum <= endLine; lineNum++)
|
for (var lineNum = startLine; lineNum <= endLine; lineNum++)
|
||||||
{
|
{
|
||||||
var line = lines[lineNum - 1];
|
var line = ConsoleColors.ColorizeSource(new SourceText(span.Text.Name, lines[lineNum - 1]));
|
||||||
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
||||||
AppendErrorIndicators(sb, span, lineNum, line, lineNumWidth);
|
AppendErrorIndicators(sb, span, lineNum, line, lineNumWidth);
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ public class Diagnostic
|
|||||||
var contextEnd = Math.Min(lines.Length, endLine + contextLines);
|
var contextEnd = Math.Min(lines.Length, endLine + contextLines);
|
||||||
for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++)
|
for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++)
|
||||||
{
|
{
|
||||||
var line = lines[lineNum - 1];
|
var line = ConsoleColors.ColorizeSource(new SourceText(span.Text.Name, lines[lineNum - 1]));
|
||||||
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
AppendContextLine(sb, lineNum, line, lineNumWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,8 +147,8 @@ public class Diagnostic
|
|||||||
private static void AppendContextLine(StringBuilder sb, int lineNum, string line, int lineNumWidth)
|
private static void AppendContextLine(StringBuilder sb, int lineNum, string line, int lineNumWidth)
|
||||||
{
|
{
|
||||||
var lineNumStr = lineNum.ToString().PadLeft(lineNumWidth);
|
var lineNumStr = lineNum.ToString().PadLeft(lineNumWidth);
|
||||||
sb.Append(ConsoleColors.Colorize(lineNumStr, ConsoleColors.Gray));
|
sb.Append(ConsoleColors.Colorize(lineNumStr, ConsoleColors.Faint));
|
||||||
sb.Append(ConsoleColors.Colorize(" | ", ConsoleColors.Gray));
|
sb.Append(ConsoleColors.Colorize(" | ", ConsoleColors.Faint));
|
||||||
sb.AppendLine(line);
|
sb.AppendLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
public class DocumentationToken(SourceSpan span, string documentation) : Token(span)
|
public class DocumentationToken(SourceSpan span, string documentation) : Token(span)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
|
||||||
|
|
||||||
public class IdentifierToken(SourceSpan span, string value) : Token(span)
|
public class IdentifierToken(SourceSpan span, string value) : Token(span)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -245,10 +245,10 @@ public class Lexer
|
|||||||
private SourceLocation CreateLocation(int index)
|
private SourceLocation CreateLocation(int index)
|
||||||
{
|
{
|
||||||
var line = 1;
|
var line = 1;
|
||||||
var column = 0;
|
var column = 1;
|
||||||
for (var i = 0; i < index; i++)
|
for (var i = 0; i < index; i++)
|
||||||
{
|
{
|
||||||
if (_sourceText.Text[i] == '\n')
|
if (_sourceText.Content[i] == '\n')
|
||||||
{
|
{
|
||||||
column = 1;
|
column = 1;
|
||||||
line += 1;
|
line += 1;
|
||||||
@@ -269,9 +269,9 @@ public class Lexer
|
|||||||
|
|
||||||
private Optional<char> Peek(int offset = 0)
|
private Optional<char> Peek(int offset = 0)
|
||||||
{
|
{
|
||||||
if (_index + offset < _sourceText.Text.Length)
|
if (_index + offset < _sourceText.Content.Length)
|
||||||
{
|
{
|
||||||
return _sourceText.Text[_index + offset];
|
return _sourceText.Content[_index + offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional<char>.Empty();
|
return Optional<char>.Empty();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
using Nub.Lang.Frontend.Typing;
|
||||||
using Nub.Lang.Frontend.Typing;
|
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
public class ModifierToken(SourceSpan span, Modifier modifier) : Token(span)
|
public class ModifierToken(SourceSpan span, Modifier modifier) : Token(span)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
|
||||||
|
|
||||||
public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
|
public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Nub.Lang.Frontend.Diagnostics;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Lexing;
|
|
||||||
|
|
||||||
public abstract class Token(SourceSpan span)
|
public abstract class Token(SourceSpan span)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
|
|
||||||
namespace Nub.Lang;
|
namespace Nub.Lang;
|
||||||
|
|
||||||
public readonly struct SourceSpan(SourceText content, SourceLocation start, SourceLocation end) : IEquatable<SourceSpan>
|
public readonly struct SourceSpan(SourceText text, SourceLocation start, SourceLocation end) : IEquatable<SourceSpan>
|
||||||
{
|
{
|
||||||
public SourceText Content { get; } = content;
|
public SourceText Text { get; } = text;
|
||||||
public SourceLocation Start { get; } = start;
|
public SourceLocation Start { get; } = start;
|
||||||
public SourceLocation End { get; } = end;
|
public SourceLocation End { get; } = end;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ public readonly struct SourceSpan(SourceText content, SourceLocation start, Sour
|
|||||||
throw new ArgumentException("Cannot merge empty spans", nameof(spanEnumerable));
|
throw new ArgumentException("Cannot merge empty spans", nameof(spanEnumerable));
|
||||||
}
|
}
|
||||||
|
|
||||||
var files = spans.Select(s => s.Content).Distinct().ToArray();
|
var files = spans.Select(s => s.Text).Distinct().ToArray();
|
||||||
if (files.Length > 1)
|
if (files.Length > 1)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Cannot merge spans from multiple files", nameof(spanEnumerable));
|
throw new ArgumentException("Cannot merge spans from multiple files", nameof(spanEnumerable));
|
||||||
@@ -55,12 +55,12 @@ public readonly struct SourceSpan(SourceText content, SourceLocation start, Sour
|
|||||||
|
|
||||||
public bool Equals(SourceSpan other)
|
public bool Equals(SourceSpan other)
|
||||||
{
|
{
|
||||||
return Content.Equals(other.Content) && Start.Equals(other.Start) && End.Equals(other.End);
|
return Text.Equals(other.Text) && Start.Equals(other.Start) && End.Equals(other.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine(Content, Start, End);
|
return HashCode.Combine(Text, Start, End);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(SourceSpan left, SourceSpan right)
|
public static bool operator ==(SourceSpan left, SourceSpan right)
|
||||||
@@ -74,13 +74,14 @@ public readonly struct SourceSpan(SourceText content, SourceLocation start, Sour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct SourceText(string text) : IEquatable<SourceText>
|
public readonly struct SourceText(string name, string content) : IEquatable<SourceText>
|
||||||
{
|
{
|
||||||
public string Text { get; } = text;
|
public string Name { get; } = name;
|
||||||
|
public string Content { get; } = content;
|
||||||
|
|
||||||
public bool Equals(SourceText other)
|
public bool Equals(SourceText other)
|
||||||
{
|
{
|
||||||
return Text == other.Text;
|
return Content == other.Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
@@ -90,7 +91,7 @@ public readonly struct SourceText(string text) : IEquatable<SourceText>
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return Text.GetHashCode();
|
return Content.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(SourceText left, SourceText right)
|
public static bool operator ==(SourceText left, SourceText right)
|
||||||
|
|||||||
Reference in New Issue
Block a user