...
This commit is contained in:
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user