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); 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; ModuleRepository moduleRepository;
try try
@@ -55,6 +67,8 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1; return 1;
} }
diagnostics.Clear();
Directory.CreateDirectory(".build"); Directory.CreateDirectory(".build");
for (var i = 0; i < args.Length; i++) for (var i = 0; i < args.Length; i++)

View File

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

View File

@@ -126,10 +126,10 @@ public class LlvmGenerator
case BlockNode blockNode: case BlockNode blockNode:
EmitBlock(writer, blockNode); EmitBlock(writer, blockNode);
break; break;
case BreakNode breakNode: case BreakNode:
EmitBreak(writer); EmitBreak(writer);
break; break;
case ContinueNode continueNode: case ContinueNode:
EmitContinue(writer); EmitContinue(writer);
break; break;
case DeferNode deferNode: case DeferNode deferNode:
@@ -380,7 +380,8 @@ public class LlvmGenerator
private Tmp EmitDereference(IndentedTextWriter writer, DereferenceNode dereferenceNode) 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) private Tmp EmitUnaryExpression(IndentedTextWriter writer, UnaryExpressionNode unaryExpressionNode)

View File

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

View File

@@ -2,18 +2,38 @@
namespace NubLang.Syntax; namespace NubLang.Syntax;
public abstract record Token(SourceSpan Span); public abstract class Token(SourceSpan span)
public record IdentifierToken(SourceSpan Span, string Value) : Token(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() public override string ToString()
{ {
return Value; 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() private string GetNumericValue()
{ {
return Base switch 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() public override string ToString()
{ {
return $"\"{Value}\""; 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() public override string ToString()
{ {
return Value ? "true" : "false"; 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 float AsF32 => Convert.ToSingle(Value);
public double AsF64 => Convert.ToDouble(Value); public double AsF64 => Convert.ToDouble(Value);
@@ -134,8 +160,10 @@ public enum Symbol
QuestionMark, 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() public override string ToString()
{ {
return Symbol switch return Symbol switch
@@ -189,7 +217,6 @@ public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
Symbol.Pipe => "|", Symbol.Pipe => "|",
Symbol.At => "@", Symbol.At => "@",
Symbol.QuestionMark => "?", Symbol.QuestionMark => "?",
Symbol.Tilde => "~",
_ => "none", _ => "none",
}; };
} }

View File

@@ -29,32 +29,7 @@ public sealed class Tokenizer
{ {
try try
{ {
var current = _content[_index]; tokens.Add(ParseToken());
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));
} }
catch (CompileException e) catch (CompileException e)
{ {
@@ -66,14 +41,40 @@ public sealed class Tokenizer
return tokens; 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); return ParseNumber(lineStart, columnStart);
} }
if (current == '"') if (_content[_index] == '"')
{ {
return ParseString(lineStart, columnStart); 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); 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) private Token ParseNumber(int lineStart, int columnStart)
@@ -382,7 +383,26 @@ public sealed class Tokenizer
private void Next(int count = 1) private void Next(int count = 1)
{ {
_index += count; for (var i = 0; i < count; i++)
_column += count; {
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) extern "main" func main(argc: i64, argv: [?]^i8)
{ {
let x = [1, 2, 3] let x: ^i8 = "test"
// test
test(x) ^x^ = "uwu"
puts(x)
} }
func test(arr: [?]i64) func test(arr: [?]i64)