...
This commit is contained in:
@@ -106,7 +106,7 @@ public class Diagnostic
|
||||
var text = File.ReadAllText(Span.Value.FilePath);
|
||||
|
||||
var tokenizer = new Tokenizer();
|
||||
tokenizer.Tokenize(Span.Value.FilePath, text);
|
||||
var tokens = tokenizer.Tokenize(Span.Value.FilePath, text);
|
||||
|
||||
var lines = text.Split('\n');
|
||||
|
||||
@@ -144,7 +144,7 @@ public class Diagnostic
|
||||
sb.Append("│ ");
|
||||
sb.Append(i.ToString().PadRight(numberPadding));
|
||||
sb.Append(" │ ");
|
||||
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
|
||||
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokens));
|
||||
// sb.Append(line.PadRight(codePadding));
|
||||
sb.Append(" │");
|
||||
sb.AppendLine();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text;
|
||||
using NubLang.Ast;
|
||||
using NubLang.Modules;
|
||||
using NubLang.Types;
|
||||
|
||||
namespace NubLang.Generation;
|
||||
@@ -12,7 +13,7 @@ public class LlvmGenerator
|
||||
private List<(string Name, int Size, string Text)> _stringLiterals = [];
|
||||
private Stack<(string breakLabel, string continueLabel)> _loopStack = [];
|
||||
|
||||
public string Emit(List<TopLevelNode> topLevelNodes)
|
||||
public string Emit(List<TopLevelNode> topLevelNodes, ModuleRepository repository)
|
||||
{
|
||||
_stringLiterals = [];
|
||||
_loopStack = [];
|
||||
@@ -26,6 +27,30 @@ public class LlvmGenerator
|
||||
writer.WriteLine("declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)");
|
||||
writer.WriteLine();
|
||||
|
||||
var declaredExternFunctions = new HashSet<string>();
|
||||
|
||||
foreach (var module in repository.GetAll())
|
||||
{
|
||||
foreach (var prototype in module.FunctionPrototypes)
|
||||
{
|
||||
// note(nub31): If we are in the current module and the function has a body, we skip it to prevent duplicate definition
|
||||
if (module.Name == _module && topLevelNodes.OfType<FuncNode>().First(x => x.NameToken.Value == prototype.NameToken.Value).Body != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prototype.ExternSymbolToken != null && !declaredExternFunctions.Add(prototype.ExternSymbolToken.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameters = prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}");
|
||||
var funcName = FuncName(module.Name, prototype.NameToken.Value, prototype.ExternSymbolToken?.Value);
|
||||
writer.WriteLine($"declare {MapType(prototype.ReturnType)} @{funcName}({string.Join(", ", parameters)})");
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var structNode in topLevelNodes.OfType<StructNode>())
|
||||
{
|
||||
var types = structNode.Fields.Select(x => MapType(x.Type));
|
||||
@@ -57,15 +82,6 @@ public class LlvmGenerator
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var funcNode in topLevelNodes.OfType<FuncNode>())
|
||||
{
|
||||
if (funcNode.Body != null) continue;
|
||||
var parameters = funcNode.Prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}");
|
||||
|
||||
writer.WriteLine($"declare {MapType(funcNode.Prototype.ReturnType)} @{FuncName(funcNode.Prototype)}({string.Join(", ", parameters)})");
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var funcNode in topLevelNodes.OfType<FuncNode>())
|
||||
{
|
||||
if (funcNode.Body == null) continue;
|
||||
@@ -335,7 +351,8 @@ public class LlvmGenerator
|
||||
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(writer, float32LiteralNode),
|
||||
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(writer, float64LiteralNode),
|
||||
FuncCallNode funcCallNode => EmitFuncCall(writer, funcCallNode),
|
||||
ModuleFuncIdentifierNode funcIdentifierNode => EmitFuncIdentifier(writer, funcIdentifierNode),
|
||||
ModuleFuncIdentifierNode moduleFuncIdentifierNode => EmitModuleFuncIdentifier(writer, moduleFuncIdentifierNode),
|
||||
LocalFuncIdentifierNode localFuncIdentifierNode => EmitLocalFuncIdentifier(writer, localFuncIdentifierNode),
|
||||
I16LiteralNode i16LiteralNode => EmitI16Literal(writer, i16LiteralNode),
|
||||
I32LiteralNode i32LiteralNode => EmitI32Literal(writer, i32LiteralNode),
|
||||
I64LiteralNode i64LiteralNode => EmitI64Literal(writer, i64LiteralNode),
|
||||
@@ -769,12 +786,18 @@ public class LlvmGenerator
|
||||
return new Tmp(result, funcCallNode.Type, false);
|
||||
}
|
||||
|
||||
private Tmp EmitFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode)
|
||||
private Tmp EmitModuleFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode)
|
||||
{
|
||||
var name = FuncName(moduleFuncIdentifierNode.ModuleToken.Value, moduleFuncIdentifierNode.NameToken.Value, moduleFuncIdentifierNode.ExternSymbolToken?.Value);
|
||||
return new Tmp($"@{name}", moduleFuncIdentifierNode.Type, false);
|
||||
}
|
||||
|
||||
private Tmp EmitLocalFuncIdentifier(IndentedTextWriter writer, LocalFuncIdentifierNode localFuncIdentifierNode)
|
||||
{
|
||||
var name = FuncName(_module, localFuncIdentifierNode.NameToken.Value, localFuncIdentifierNode.ExternSymbolToken?.Value);
|
||||
return new Tmp($"@{name}", localFuncIdentifierNode.Type, false);
|
||||
}
|
||||
|
||||
private Tmp EmitI16Literal(IndentedTextWriter writer, I16LiteralNode i16LiteralNode)
|
||||
{
|
||||
return new Tmp(i16LiteralNode.Value.ToString(), i16LiteralNode.Type, false);
|
||||
|
||||
@@ -143,7 +143,7 @@ public sealed class ModuleRepository
|
||||
}
|
||||
}
|
||||
|
||||
private ModuleRepository(Dictionary<string, Module> modules)
|
||||
public ModuleRepository(Dictionary<string, Module> modules)
|
||||
{
|
||||
_modules = modules;
|
||||
}
|
||||
@@ -167,6 +167,17 @@ public sealed class ModuleRepository
|
||||
return module != null;
|
||||
}
|
||||
|
||||
public bool TryGet(string name, [NotNullWhen(true)] out Module? module)
|
||||
{
|
||||
module = _modules.GetValueOrDefault(name);
|
||||
return module != null;
|
||||
}
|
||||
|
||||
public List<Module> GetAll()
|
||||
{
|
||||
return _modules.Values.ToList();
|
||||
}
|
||||
|
||||
public sealed class Module
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
@@ -174,6 +185,21 @@ public sealed class ModuleRepository
|
||||
public required List<NubStructType> StructTypes { get; init; } = [];
|
||||
public required Dictionary<string, NubIntType> EnumTypes { get; init; } = [];
|
||||
|
||||
public bool TryResolveFunc(string name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Func {name} not found in module {Name}").Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryResolveFunc(IdentifierToken name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name.Value);
|
||||
@@ -199,6 +225,21 @@ public sealed class ModuleRepository
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool TryResolveStruct(string name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = StructTypes.FirstOrDefault(x => x.Name == name);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Struct {name} not found in module {Name}").Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryResolveStruct(IdentifierToken name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = StructTypes.FirstOrDefault(x => x.Name == name.Value);
|
||||
@@ -224,6 +265,21 @@ public sealed class ModuleRepository
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool TryResolveEnum(string name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = EnumTypes.GetValueOrDefault(name);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Enum {name} not found in module {Name}").Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryResolveEnum(IdentifierToken name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = EnumTypes.GetValueOrDefault(name.Value);
|
||||
|
||||
@@ -417,7 +417,7 @@ public sealed class Parser
|
||||
case Symbol.Pipe:
|
||||
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseOr;
|
||||
return true;
|
||||
case Symbol.XOr:
|
||||
case Symbol.Tilde:
|
||||
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseXor;
|
||||
return true;
|
||||
default:
|
||||
@@ -439,12 +439,12 @@ public sealed class Parser
|
||||
IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
|
||||
SymbolToken symbolToken => symbolToken.Symbol switch
|
||||
{
|
||||
Symbol.Ampersand => new AddressOfSyntax(GetTokens(startIndex), ParsePrimaryExpression()),
|
||||
Symbol.Ampersand => ParseAddressOf(startIndex),
|
||||
Symbol.OpenParen => ParseParenthesizedExpression(),
|
||||
Symbol.Minus => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Negate, ParsePrimaryExpression()),
|
||||
Symbol.Bang => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Invert, ParsePrimaryExpression()),
|
||||
Symbol.Minus => ParseUnaryNegate(startIndex),
|
||||
Symbol.Bang => ParseUnaryInvert(startIndex),
|
||||
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
|
||||
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
|
||||
Symbol.OpenBrace => ParseUnnamedStructInitializer(startIndex),
|
||||
Symbol.Struct => ParseStructInitializer(startIndex),
|
||||
Symbol.At => ParseBuiltinFunction(startIndex),
|
||||
_ => throw new CompileException(Diagnostic
|
||||
@@ -463,6 +463,24 @@ public sealed class Parser
|
||||
return ParsePostfixOperators(expr);
|
||||
}
|
||||
|
||||
private AddressOfSyntax ParseAddressOf(int startIndex)
|
||||
{
|
||||
var expression = ParsePrimaryExpression();
|
||||
return new AddressOfSyntax(GetTokens(startIndex), expression);
|
||||
}
|
||||
|
||||
private UnaryExpressionSyntax ParseUnaryInvert(int startIndex)
|
||||
{
|
||||
var expression = ParsePrimaryExpression();
|
||||
return new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Invert, expression);
|
||||
}
|
||||
|
||||
private UnaryExpressionSyntax ParseUnaryNegate(int startIndex)
|
||||
{
|
||||
var expression = ParsePrimaryExpression();
|
||||
return new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Negate, expression);
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParseBuiltinFunction(int startIndex)
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
@@ -587,6 +605,12 @@ public sealed class Parser
|
||||
return new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
|
||||
}
|
||||
|
||||
private StructInitializerSyntax ParseUnnamedStructInitializer(int startIndex)
|
||||
{
|
||||
var body = ParseStructInitializerBody();
|
||||
return new StructInitializerSyntax(GetTokens(startIndex), null, body);
|
||||
}
|
||||
|
||||
private Dictionary<IdentifierToken, ExpressionSyntax> ParseStructInitializerBody()
|
||||
{
|
||||
Dictionary<IdentifierToken, ExpressionSyntax> initializers = [];
|
||||
|
||||
@@ -121,6 +121,7 @@ public enum Symbol
|
||||
Star,
|
||||
ForwardSlash,
|
||||
Caret,
|
||||
Tilde,
|
||||
Ampersand,
|
||||
Semi,
|
||||
Percent,
|
||||
@@ -129,7 +130,6 @@ public enum Symbol
|
||||
Pipe,
|
||||
And,
|
||||
Or,
|
||||
XOr,
|
||||
At,
|
||||
QuestionMark,
|
||||
}
|
||||
@@ -189,6 +189,7 @@ public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
|
||||
Symbol.Pipe => "|",
|
||||
Symbol.At => "@",
|
||||
Symbol.QuestionMark => "?",
|
||||
Symbol.Tilde => "~",
|
||||
_ => "none",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,20 +11,20 @@ public sealed class Tokenizer
|
||||
private int _column = 1;
|
||||
|
||||
public List<Diagnostic> Diagnostics { get; set; } = new(16);
|
||||
public List<Token> Tokens { get; set; } = new(256);
|
||||
|
||||
public void Tokenize(string fileName, string content)
|
||||
public List<Token> Tokenize(string fileName, string content)
|
||||
{
|
||||
_fileName = fileName;
|
||||
_content = content;
|
||||
|
||||
Diagnostics = [];
|
||||
Tokens = [];
|
||||
|
||||
_index = 0;
|
||||
_line = 1;
|
||||
_column = 1;
|
||||
|
||||
var tokens = new List<Token>();
|
||||
|
||||
while (_index < _content.Length)
|
||||
{
|
||||
try
|
||||
@@ -54,7 +54,7 @@ public sealed class Tokenizer
|
||||
continue;
|
||||
}
|
||||
|
||||
Tokens.Add(ParseToken(current, _line, _column));
|
||||
tokens.Add(ParseToken(current, _line, _column));
|
||||
}
|
||||
catch (CompileException e)
|
||||
{
|
||||
@@ -62,6 +62,8 @@ public sealed class Tokenizer
|
||||
Next();
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private Token ParseToken(char current, int lineStart, int columnStart)
|
||||
@@ -295,7 +297,6 @@ public sealed class Tokenizer
|
||||
"&&" => Symbol.And,
|
||||
"||" => Symbol.Or,
|
||||
"::" => Symbol.DoubleColon,
|
||||
"x|" => Symbol.XOr,
|
||||
_ => Symbol.None
|
||||
},
|
||||
1 => span[0] switch
|
||||
@@ -324,6 +325,7 @@ public sealed class Tokenizer
|
||||
'|' => Symbol.Pipe,
|
||||
'@' => Symbol.At,
|
||||
'?' => Symbol.QuestionMark,
|
||||
'~' => Symbol.Tilde,
|
||||
_ => Symbol.None
|
||||
},
|
||||
_ => Symbol.None
|
||||
|
||||
Reference in New Issue
Block a user