This commit is contained in:
nub31
2025-11-03 16:01:20 +01:00
parent 7ce451768d
commit 7d49bf43b7
7 changed files with 207 additions and 109 deletions

View File

@@ -22,6 +22,18 @@ foreach (var file in args)
syntaxTrees.Add(syntaxTree);
}
foreach (var diagnostic in diagnostics)
{
Console.Error.WriteLine(diagnostic.FormatANSI());
}
if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error))
{
return 1;
}
diagnostics.Clear();
ModuleRepository moduleRepository;
try
@@ -55,6 +67,8 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1;
}
diagnostics.Clear();
Directory.CreateDirectory(".build");
for (var i = 0; i < args.Length; i++)

View File

@@ -152,7 +152,7 @@ public class Diagnostic
if (i >= startLine && i <= endLine)
{
var markerStartColumn = 1;
var markerEndColumn = line.Length;
var markerEndColumn = line.Length + 1;
if (i == startLine)
{
@@ -262,6 +262,10 @@ public class Diagnostic
{
switch (token)
{
case CommentToken:
{
return ConsoleColors.Colorize(tokenText, ConsoleColors.Green);
}
case IdentifierToken:
{
return ConsoleColors.Colorize(tokenText, ConsoleColors.BrightWhite);

View File

@@ -126,10 +126,10 @@ public class LlvmGenerator
case BlockNode blockNode:
EmitBlock(writer, blockNode);
break;
case BreakNode breakNode:
case BreakNode:
EmitBreak(writer);
break;
case ContinueNode continueNode:
case ContinueNode:
EmitContinue(writer);
break;
case DeferNode deferNode:
@@ -380,7 +380,8 @@ public class LlvmGenerator
private Tmp EmitDereference(IndentedTextWriter writer, DereferenceNode dereferenceNode)
{
throw new NotImplementedException();
var target = EmitExpression(writer, dereferenceNode.Target);
return new Tmp(target.Ident, dereferenceNode.Type, true);
}
private Tmp EmitUnaryExpression(IndentedTextWriter writer, UnaryExpressionNode unaryExpressionNode)

View File

@@ -9,6 +9,19 @@ public sealed class Parser
private int _tokenIndex;
private Token? CurrentToken => _tokenIndex < _tokens.Count ? _tokens[_tokenIndex] : null;
private bool HasTrailingWhitespace(Token token)
{
var index = _tokens.IndexOf(token);
return index + 1 < _tokens.Count && _tokens[index + 1] is WhitespaceToken or CommentToken;
}
private bool HasLeadingWhitespace(Token token)
{
var index = _tokens.IndexOf(token);
return index - 1 < _tokens.Count && _tokens[index - 1] is WhitespaceToken or CommentToken;
}
private bool HasToken => CurrentToken != null;
public List<Diagnostic> Diagnostics { get; set; } = [];
@@ -194,27 +207,36 @@ public sealed class Parser
{
var startIndex = _tokenIndex;
if (TryExpectSymbol(out var symbol))
if (CurrentToken is SymbolToken symbolToken)
{
switch (symbol)
switch (symbolToken.Symbol)
{
case Symbol.OpenBrace:
Next();
return ParseBlock(startIndex);
case Symbol.Return:
Next();
return ParseReturn(startIndex);
case Symbol.If:
Next();
return ParseIf(startIndex);
case Symbol.While:
Next();
return ParseWhile(startIndex);
case Symbol.For:
Next();
return ParseFor(startIndex);
case Symbol.Let:
Next();
return ParseVariableDeclaration(startIndex);
case Symbol.Defer:
Next();
return ParseDefer(startIndex);
case Symbol.Break:
Next();
return new BreakSyntax(GetTokens(startIndex));
case Symbol.Continue:
Next();
return new ContinueSyntax(GetTokens(startIndex));
}
}
@@ -319,7 +341,7 @@ public sealed class Parser
var startIndex = _tokenIndex;
var left = ParsePrimaryExpression();
while (CurrentToken is SymbolToken symbolToken && TryGetBinaryOperator(symbolToken.Symbol, out var op) && GetBinaryOperatorPrecedence(op.Value) >= precedence)
while (CurrentToken is SymbolToken symbolToken && HasLeadingWhitespace(symbolToken) && HasTrailingWhitespace(symbolToken) && TryGetBinaryOperator(symbolToken.Symbol, out var op) && GetBinaryOperatorPrecedence(op.Value) >= precedence)
{
Next();
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
@@ -463,6 +485,68 @@ public sealed class Parser
return ParsePostfixOperators(expr);
}
private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
{
if (CurrentToken == null || HasLeadingWhitespace(CurrentToken))
{
return expr;
}
var startIndex = _tokenIndex;
while (HasToken)
{
if (TryExpectSymbol(Symbol.Caret))
{
expr = new DereferenceSyntax(GetTokens(startIndex), expr);
continue;
}
if (TryExpectSymbol(Symbol.Period))
{
var member = ExpectIdentifier();
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member);
continue;
}
if (TryExpectSymbol(Symbol.OpenBracket))
{
var index = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
expr = new ArrayIndexAccessSyntax(GetTokens(startIndex), expr, index);
continue;
}
if (TryExpectSymbol(Symbol.OpenParen))
{
var parameters = new List<ExpressionSyntax>();
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseExpression());
if (!TryExpectSymbol(Symbol.Comma))
{
ExpectSymbol(Symbol.CloseParen);
break;
}
}
expr = new FuncCallSyntax(GetTokens(startIndex), expr, parameters);
continue;
}
break;
}
return expr;
}
private ExpressionSyntax ParseParenthesizedExpression()
{
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;
}
private AddressOfSyntax ParseAddressOf(int startIndex)
{
var expression = ParsePrimaryExpression();
@@ -518,63 +602,6 @@ public sealed class Parser
return new LocalIdentifierSyntax(GetTokens(startIndex), identifier);
}
private ExpressionSyntax ParseParenthesizedExpression()
{
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;
}
private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
{
var startIndex = _tokenIndex;
while (HasToken)
{
if (TryExpectSymbol(Symbol.Caret))
{
expr = new DereferenceSyntax(GetTokens(startIndex), expr);
continue;
}
if (TryExpectSymbol(Symbol.Period))
{
var member = ExpectIdentifier();
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member);
continue;
}
if (TryExpectSymbol(Symbol.OpenBracket))
{
var index = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
expr = new ArrayIndexAccessSyntax(GetTokens(startIndex), expr, index);
continue;
}
if (TryExpectSymbol(Symbol.OpenParen))
{
var parameters = new List<ExpressionSyntax>();
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseExpression());
if (!TryExpectSymbol(Symbol.Comma))
{
ExpectSymbol(Symbol.CloseParen);
break;
}
}
expr = new FuncCallSyntax(GetTokens(startIndex), expr, parameters);
continue;
}
break;
}
return expr;
}
private ExpressionSyntax ParseArrayInitializer(int startIndex)
{
var values = new List<ExpressionSyntax>();
@@ -914,6 +941,10 @@ public sealed class Parser
private void Next()
{
_tokenIndex++;
while (_tokenIndex < _tokens.Count && _tokens[_tokenIndex] is WhitespaceToken or CommentToken)
{
_tokenIndex++;
}
}
private List<Token> GetTokens(int tokenStartIndex)

View File

@@ -2,18 +2,38 @@
namespace NubLang.Syntax;
public abstract record Token(SourceSpan Span);
public record IdentifierToken(SourceSpan Span, string Value) : Token(Span)
public abstract class Token(SourceSpan span)
{
public SourceSpan Span { get; } = span;
}
public class WhitespaceToken(SourceSpan span) : Token(span);
public class CommentToken(SourceSpan span, string comment) : Token(span)
{
public string Comment { get; } = comment;
public override string ToString()
{
return "// " + Comment;
}
}
public class IdentifierToken(SourceSpan span, string value) : Token(span)
{
public string Value { get; } = value;
public override string ToString()
{
return Value;
}
}
public record IntLiteralToken(SourceSpan Span, string Value, int Base) : Token(Span)
public class IntLiteralToken(SourceSpan span, string value, int @base) : Token(span)
{
public string Value { get; } = value;
public int Base { get; } = @base;
private string GetNumericValue()
{
return Base switch
@@ -43,24 +63,30 @@ public record IntLiteralToken(SourceSpan Span, string Value, int Base) : Token(S
}
}
public record StringLiteralToken(SourceSpan Span, string Value) : Token(Span)
public class StringLiteralToken(SourceSpan span, string value) : Token(span)
{
public string Value { get; } = value;
public override string ToString()
{
return $"\"{Value}\"";
}
}
public record BoolLiteralToken(SourceSpan Span, bool Value) : Token(Span)
public class BoolLiteralToken(SourceSpan span, bool value) : Token(span)
{
public bool Value { get; } = value;
public override string ToString()
{
return Value ? "true" : "false";
}
}
public record FloatLiteralToken(SourceSpan Span, string Value) : Token(Span)
public class FloatLiteralToken(SourceSpan span, string value) : Token(span)
{
public string Value { get; } = value;
public float AsF32 => Convert.ToSingle(Value);
public double AsF64 => Convert.ToDouble(Value);
@@ -134,8 +160,10 @@ public enum Symbol
QuestionMark,
}
public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
{
public Symbol Symbol { get; } = symbol;
public override string ToString()
{
return Symbol switch
@@ -189,7 +217,6 @@ public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
Symbol.Pipe => "|",
Symbol.At => "@",
Symbol.QuestionMark => "?",
Symbol.Tilde => "~",
_ => "none",
};
}

View File

@@ -29,32 +29,7 @@ public sealed class Tokenizer
{
try
{
var current = _content[_index];
if (char.IsWhiteSpace(current))
{
if (current == '\n')
{
_line += 1;
_column = 0;
}
Next();
continue;
}
if (current == '/' && _index + 1 < _content.Length && _content[_index + 1] == '/')
{
Next(2);
while (_index < _content.Length && _content[_index] != '\n')
{
Next();
}
continue;
}
tokens.Add(ParseToken(current, _line, _column));
tokens.Add(ParseToken());
}
catch (CompileException e)
{
@@ -66,14 +41,40 @@ public sealed class Tokenizer
return tokens;
}
private Token ParseToken(char current, int lineStart, int columnStart)
private Token ParseToken()
{
if (char.IsDigit(current))
var lineStart = _line;
var columnStart = _column;
if (char.IsWhiteSpace(_content[_index]))
{
while (_index < _content.Length && char.IsWhiteSpace(_content[_index]))
{
Next();
}
return new WhitespaceToken(CreateSpan(lineStart, columnStart));
}
if (_content[_index] == '/' && _index + 1 < _content.Length && _content[_index + 1] == '/')
{
var startIndex = _index;
Next(2);
while (_index < _content.Length && _content[_index] != '\n')
{
Next();
}
return new CommentToken(CreateSpan(lineStart, columnStart), _content.AsSpan(startIndex, _index - startIndex).ToString());
}
if (char.IsDigit(_content[_index]))
{
return ParseNumber(lineStart, columnStart);
}
if (current == '"')
if (_content[_index] == '"')
{
return ParseString(lineStart, columnStart);
}
@@ -87,12 +88,12 @@ public sealed class Tokenizer
}
}
if (char.IsLetter(current) || current == '_')
if (char.IsLetter(_content[_index]) || _content[_index] == '_')
{
return ParseIdentifier(lineStart, columnStart);
}
throw new CompileException(Diagnostic.Error($"Unknown token '{current}'").Build());
throw new CompileException(Diagnostic.Error($"Unknown token '{_content[_index]}'").Build());
}
private Token ParseNumber(int lineStart, int columnStart)
@@ -382,7 +383,26 @@ public sealed class Tokenizer
private void Next(int count = 1)
{
_index += count;
_column += count;
for (var i = 0; i < count; i++)
{
if (_index < _content.Length)
{
if (_content[_index] == '\n')
{
_line += 1;
_column = 1;
}
else
{
_column++;
}
}
else
{
_column++;
}
_index++;
}
}
}

View File

@@ -9,9 +9,10 @@ struct Test
extern "main" func main(argc: i64, argv: [?]^i8)
{
let x = [1, 2, 3]
test(x)
let x: ^i8 = "test"
// test
^x^ = "uwu"
puts(x)
}
func test(arr: [?]i64)