From 3dab4c7e60e0425e638875a374f3d36fce4e6324 Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 21 Oct 2025 18:03:27 +0200 Subject: [PATCH] init llvm --- compiler/NubLang.CLI/Program.cs | 220 +++--- compiler/NubLang/Generation/{ => C}/CType.cs | 2 +- compiler/NubLang/Generation/C/Generator.cs | 581 ++++++++++++++++ compiler/NubLang/Generation/Generator.cs | 683 +++++++------------ compiler/NubLang/NubLang.csproj | 4 + 5 files changed, 955 insertions(+), 535 deletions(-) rename compiler/NubLang/Generation/{ => C}/CType.cs (98%) create mode 100644 compiler/NubLang/Generation/C/Generator.cs diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs index 18c4bd7..d037cd0 100644 --- a/compiler/NubLang.CLI/Program.cs +++ b/compiler/NubLang.CLI/Program.cs @@ -45,116 +45,126 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro return 1; } -var cPaths = new List(); - -Directory.CreateDirectory(".build"); - for (var i = 0; i < nubFiles.Length; i++) { - var file = nubFiles[i]; var compilationUnit = compilationUnits[i]; var generator = new Generator(compilationUnit); - var directory = Path.GetDirectoryName(file); - if (!string.IsNullOrWhiteSpace(directory)) - { - Directory.CreateDirectory(Path.Combine(".build", directory)); - } - - var path = Path.Combine(".build", Path.ChangeExtension(file, "c")); - File.WriteAllText(path, generator.Emit()); - cPaths.Add(path); + Console.WriteLine(generator.Generate()); } -var objectPaths = new List(); +return 0; -foreach (var cPath in cPaths) -{ - var objectPath = Path.ChangeExtension(cPath, "o"); - using var compileProcess = Process.Start("gcc", [ - "-ffreestanding", "-nostartfiles", "-std=c23", - "-g", "-lm", - "-c", "-o", objectPath, - cPath, - ]); - - compileProcess.WaitForExit(); - - if (compileProcess.ExitCode != 0) - { - Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}"); - return 1; - } - - objectPaths.Add(objectPath); -} - -if (modules.TryGetValue("main", out var mainModule)) -{ - var mainFunction = mainModule - .Functions(true) - .FirstOrDefault(x => x.Prototype.ExternSymbol == "main"); - - if (mainFunction is { Prototype.ExternSymbol: not null }) - { - var runtime = $""" - .intel_syntax noprefix - - .text - .globl _start - _start: - mov rdi, [rsp] # argc - mov rsi, [rsp + 8] # argv - call {mainFunction.Prototype.ExternSymbol} - mov rdi, rax # Move return value into rdi - mov rax, 60 # syscall: exit - syscall - - """; - - var runtimePath = Path.Combine(".build", "runtime.s"); - File.WriteAllText(runtimePath, runtime); - - using var assembleProcess = Process.Start(new ProcessStartInfo("as", ["-g", "-c", runtimePath, "-o", Path.Combine(".build", "runtime.o")])); - if (assembleProcess == null) return 1; - assembleProcess.WaitForExit(); - - if (assembleProcess.ExitCode != 0) - { - Console.Error.WriteLine($"gcc failed with exit code {assembleProcess.ExitCode}"); - return 1; - } - - if (assembleProcess.ExitCode != 0) return 1; - - using var linkProcess = Process.Start(new ProcessStartInfo("gcc", [ - "-ffreestanding", "-nostartfiles", "-std=c23", - "-g", "-lm", - "-o", Path.Combine(".build", "out"), - ..objectPaths, - Path.Combine(".build", "runtime.o"), - ..objectFileArgs - ])); - - if (linkProcess == null) return 1; - linkProcess.WaitForExit(); - - if (linkProcess.ExitCode != 0) - { - Console.Error.WriteLine($"gcc failed with exit code {linkProcess.ExitCode}"); - return 1; - } - - Console.WriteLine("Build successful: .build/out"); - } - else - { - Console.WriteLine("No main function found in module main, skipping link step"); - } -} -else -{ - Console.WriteLine("No main function found in module main, skipping link step"); -} - -return 0; \ No newline at end of file +// var cPaths = new List(); +// +// Directory.CreateDirectory(".build"); +// +// for (var i = 0; i < nubFiles.Length; i++) +// { +// var file = nubFiles[i]; +// var compilationUnit = compilationUnits[i]; +// +// var generator = new Generator(compilationUnit); +// var directory = Path.GetDirectoryName(file); +// if (!string.IsNullOrWhiteSpace(directory)) +// { +// Directory.CreateDirectory(Path.Combine(".build", directory)); +// } +// +// var path = Path.Combine(".build", Path.ChangeExtension(file, "c")); +// File.WriteAllText(path, generator.Emit()); +// cPaths.Add(path); +// } +// +// var objectPaths = new List(); +// +// foreach (var cPath in cPaths) +// { +// var objectPath = Path.ChangeExtension(cPath, "o"); +// using var compileProcess = Process.Start("gcc", [ +// "-ffreestanding", "-nostartfiles", "-std=c23", +// "-g", "-lm", +// "-c", "-o", objectPath, +// cPath, +// ]); +// +// compileProcess.WaitForExit(); +// +// if (compileProcess.ExitCode != 0) +// { +// Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}"); +// return 1; +// } +// +// objectPaths.Add(objectPath); +// } +// +// if (modules.TryGetValue("main", out var mainModule)) +// { +// var mainFunction = mainModule +// .Functions(true) +// .FirstOrDefault(x => x.Prototype.ExternSymbol == "main"); +// +// if (mainFunction is { Prototype.ExternSymbol: not null }) +// { +// var runtime = $""" +// .intel_syntax noprefix +// +// .text +// .globl _start +// _start: +// mov rdi, [rsp] # argc +// mov rsi, [rsp + 8] # argv +// call {mainFunction.Prototype.ExternSymbol} +// mov rdi, rax # Move return value into rdi +// mov rax, 60 # syscall: exit +// syscall +// +// """; +// +// var runtimePath = Path.Combine(".build", "runtime.s"); +// File.WriteAllText(runtimePath, runtime); +// +// using var assembleProcess = Process.Start(new ProcessStartInfo("as", ["-g", "-c", runtimePath, "-o", Path.Combine(".build", "runtime.o")])); +// if (assembleProcess == null) return 1; +// assembleProcess.WaitForExit(); +// +// if (assembleProcess.ExitCode != 0) +// { +// Console.Error.WriteLine($"gcc failed with exit code {assembleProcess.ExitCode}"); +// return 1; +// } +// +// if (assembleProcess.ExitCode != 0) return 1; +// +// using var linkProcess = Process.Start(new ProcessStartInfo("gcc", [ +// "-ffreestanding", "-nostartfiles", "-std=c23", +// "-g", "-lm", +// "-o", Path.Combine(".build", "out"), +// ..objectPaths, +// Path.Combine(".build", "runtime.o"), +// ..objectFileArgs +// ])); +// +// if (linkProcess == null) return 1; +// linkProcess.WaitForExit(); +// +// if (linkProcess.ExitCode != 0) +// { +// Console.Error.WriteLine($"gcc failed with exit code {linkProcess.ExitCode}"); +// return 1; +// } +// +// Console.WriteLine("Build successful: .build/out"); +// } +// else +// { +// Console.WriteLine("No main function found in module main, skipping link step"); +// } +// } +// else +// { +// Console.WriteLine("No main function found in module main, skipping link step"); +// } +// +// return 0; \ No newline at end of file diff --git a/compiler/NubLang/Generation/CType.cs b/compiler/NubLang/Generation/C/CType.cs similarity index 98% rename from compiler/NubLang/Generation/CType.cs rename to compiler/NubLang/Generation/C/CType.cs index d2c45c4..1357a5f 100644 --- a/compiler/NubLang/Generation/CType.cs +++ b/compiler/NubLang/Generation/C/CType.cs @@ -1,6 +1,6 @@ using NubLang.Ast; -namespace NubLang.Generation; +namespace NubLang.Generation.C; public static class CType { diff --git a/compiler/NubLang/Generation/C/Generator.cs b/compiler/NubLang/Generation/C/Generator.cs new file mode 100644 index 0000000..f709df9 --- /dev/null +++ b/compiler/NubLang/Generation/C/Generator.cs @@ -0,0 +1,581 @@ +using NubLang.Ast; +using NubLang.Syntax; + +namespace NubLang.Generation.C; + +public class Generator +{ + private readonly CompilationUnit _compilationUnit; + private readonly IndentedTextWriter _writer; + private readonly Stack> _deferStack = []; + private int _tmpIndex; + + public Generator(CompilationUnit compilationUnit) + { + _compilationUnit = compilationUnit; + _writer = new IndentedTextWriter(); + } + + // todo(nub31): Handle name collisions + private string NewTmp() + { + return $"_t{++_tmpIndex}"; + } + + private static string FuncName(string module, string name, string? externSymbol) + { + return externSymbol ?? $"{module}_{name}"; + } + + private static string StructName(string module, string name) + { + return $"{module}_{name}"; + } + + public string Emit() + { + _writer.WriteLine("#include "); + _writer.WriteLine("#include "); + _writer.WriteLine("#include "); + _writer.WriteLine(); + + foreach (var structType in _compilationUnit.ImportedStructTypes) + { + _writer.WriteLine("typedef struct"); + _writer.WriteLine("{"); + using (_writer.Indent()) + { + foreach (var field in structType.Fields) + { + _writer.WriteLine($"{CType.Create(field.Type, field.Name)};"); + } + } + + _writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};"); + _writer.WriteLine(); + } + + // note(nub31): Forward declarations + foreach (var prototype in _compilationUnit.ImportedFunctions) + { + EmitLine(prototype.Tokens.FirstOrDefault()); + var parameters = prototype.Parameters.Count != 0 + ? string.Join(", ", prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) + : "void"; + + var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol); + _writer.WriteLine($"{CType.Create(prototype.ReturnType, name)}({parameters});"); + _writer.WriteLine(); + } + + // note(nub31): declare extern functions + foreach (var funcNode in _compilationUnit.Functions) + { + if (funcNode.Body != null) continue; + + EmitLine(funcNode.Tokens.FirstOrDefault()); + var parameters = funcNode.Prototype.Parameters.Count != 0 + ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) + : "void"; + + var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); + _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters});"); + } + + _writer.WriteLine(); + + // note(nub31): Normal functions + foreach (var funcNode in _compilationUnit.Functions) + { + if (funcNode.Body == null) continue; + + EmitLine(funcNode.Tokens.FirstOrDefault()); + var parameters = funcNode.Prototype.Parameters.Count != 0 + ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) + : "void"; + + if (funcNode.Prototype.ExternSymbol == null) + { + _writer.Write("static "); + } + + var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); + _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters})"); + EmitBlock(funcNode.Body); + _writer.WriteLine(); + } + + return _writer.ToString(); + } + + private void EmitStatement(StatementNode statementNode) + { + EmitLine(statementNode.Tokens.FirstOrDefault()); + switch (statementNode) + { + case AssignmentNode assignmentNode: + EmitAssignment(assignmentNode); + break; + case BlockNode blockNode: + EmitBlock(blockNode); + break; + case BreakNode breakNode: + EmitBreak(breakNode); + break; + case ContinueNode continueNode: + EmitContinue(continueNode); + break; + case DeferNode deferNode: + EmitDefer(deferNode); + break; + case IfNode ifNode: + EmitIf(ifNode); + break; + case ReturnNode returnNode: + EmitReturn(returnNode); + break; + case StatementFuncCallNode statementFuncCallNode: + EmitStatementFuncCall(statementFuncCallNode); + break; + case VariableDeclarationNode variableDeclarationNode: + EmitVariableDeclaration(variableDeclarationNode); + break; + case WhileNode whileNode: + EmitWhile(whileNode); + break; + default: + throw new ArgumentOutOfRangeException(nameof(statementNode)); + } + } + + private void EmitLine(Token? token) + { + if (token == null) return; + var file = token.Span.FilePath; + var line = token.Span.Start.Line; + _writer.WriteLine($"#line {line} \"{file}\""); + } + + private void EmitAssignment(AssignmentNode assignmentNode) + { + var target = EmitExpression(assignmentNode.Target); + var value = EmitExpression(assignmentNode.Value); + _writer.WriteLine($"{target} = {value};"); + } + + private void EmitBreak(BreakNode _) + { + _writer.WriteLine("break;"); + } + + private void EmitContinue(ContinueNode _) + { + _writer.WriteLine("continue;"); + } + + private void EmitDefer(DeferNode deferNode) + { + _deferStack.Peek().Add(deferNode); + } + + private void EmitIf(IfNode ifNode, bool elseIf = false) + { + var condition = EmitExpression(ifNode.Condition); + _writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})"); + EmitBlock(ifNode.Body); + ifNode.Else?.Match + ( + elseIfNode => EmitIf(elseIfNode, true), + elseNode => + { + _writer.WriteLine("else"); + EmitBlock(elseNode); + } + ); + } + + private void EmitReturn(ReturnNode returnNode) + { + if (returnNode.Value == null) + { + var blockDefers = _deferStack.Peek(); + for (var i = blockDefers.Count - 1; i >= 0; i--) + { + EmitStatement(blockDefers[i].Statement); + } + + _writer.WriteLine("return;"); + } + else + { + var returnValue = EmitExpression(returnNode.Value); + + if (_deferStack.Peek().Count != 0) + { + var tmp = NewTmp(); + _writer.WriteLine($"{CType.Create(returnNode.Value.Type, tmp)} = {returnValue};"); + + var blockDefers = _deferStack.Peek(); + for (var i = blockDefers.Count - 1; i >= 0; i--) + { + EmitStatement(blockDefers[i].Statement); + } + + EmitLine(returnNode.Tokens.FirstOrDefault()); + _writer.WriteLine($"return {tmp};"); + } + else + { + EmitLine(returnNode.Tokens.FirstOrDefault()); + _writer.WriteLine($"return {returnValue};"); + } + } + } + + private void EmitStatementFuncCall(StatementFuncCallNode statementFuncCallNode) + { + var funcCall = EmitFuncCall(statementFuncCallNode.FuncCall); + _writer.WriteLine($"{funcCall};"); + } + + private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) + { + if (variableDeclarationNode.Assignment != null) + { + var value = EmitExpression(variableDeclarationNode.Assignment); + _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};"); + } + else + { + _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)};"); + } + } + + private void EmitWhile(WhileNode whileNode) + { + var condition = EmitExpression(whileNode.Condition); + _writer.WriteLine($"while ({condition})"); + EmitBlock(whileNode.Body); + } + + private string EmitExpression(ExpressionNode expressionNode) + { + var expr = expressionNode switch + { + ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(arrayIndexAccessNode), + ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode), + BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode), + BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode), + ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode), + ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode), + // ConvertConstArrayToArrayNode convertConstArrayToArrayNode => EmitConvertConstArrayToArray(convertConstArrayToArrayNode), + ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode), + ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode), + CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(cStringLiteralNode), + DereferenceNode dereferenceNode => EmitDereference(dereferenceNode), + Float32LiteralNode float32LiteralNode => EmitFloat32Literal(float32LiteralNode), + Float64LiteralNode float64LiteralNode => EmitFloat64Literal(float64LiteralNode), + FloatToIntBuiltinNode floatToIntBuiltinNode => EmitFloatToIntBuiltin(floatToIntBuiltinNode), + FuncCallNode funcCallNode => EmitFuncCall(funcCallNode), + FuncIdentifierNode funcIdentifierNode => EmitFuncIdentifier(funcIdentifierNode), + IntLiteralNode intLiteralNode => EmitIntLiteral(intLiteralNode), + AddressOfNode addressOfNode => EmitAddressOf(addressOfNode), + LValueIdentifierNode lValueIdentifierNode => EmitLValueIdentifier(lValueIdentifierNode), + RValueIdentifierNode rValueIdentifierNode => EmitRValueIdentifier(rValueIdentifierNode), + SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode), + SliceIndexAccessNode sliceIndexAccessNode => EmitSliceArrayIndexAccess(sliceIndexAccessNode), + StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode), + StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode), + StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode), + UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode), + UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode), + _ => throw new ArgumentOutOfRangeException(nameof(expressionNode)) + }; + + if (expressionNode is ConstArrayInitializerNode) + { + return expr; + } + + return $"({expr})"; + } + + private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode) + { + var array = EmitExpression(arrayIndexAccessNode.Target); + var index = EmitExpression(arrayIndexAccessNode.Index); + return $"{array}[{index}]"; + } + + private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) + { + var type = (NubArrayType)arrayInitializerNode.Type; + var capacity = EmitExpression(arrayInitializerNode.Capacity); + var tmp = NewTmp(); + _writer.WriteLine($"{CType.Create(type.ElementType)} {tmp}[{capacity}];"); + return tmp; + } + + private string EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode) + { + var left = EmitExpression(binaryExpressionNode.Left); + var right = EmitExpression(binaryExpressionNode.Right); + + var op = binaryExpressionNode.Operator switch + { + BinaryOperator.Plus => "+", + BinaryOperator.Minus => "-", + BinaryOperator.Multiply => "*", + BinaryOperator.Divide => "/", + BinaryOperator.Modulo => "%", + BinaryOperator.Equal => "==", + BinaryOperator.NotEqual => "!=", + BinaryOperator.LessThan => "<", + BinaryOperator.LessThanOrEqual => "<=", + BinaryOperator.GreaterThan => ">", + BinaryOperator.GreaterThanOrEqual => ">=", + BinaryOperator.LogicalAnd => "&&", + BinaryOperator.LogicalOr => "||", + BinaryOperator.BitwiseAnd => "&", + BinaryOperator.BitwiseOr => "|", + BinaryOperator.BitwiseXor => "^", + BinaryOperator.LeftShift => "<<", + BinaryOperator.RightShift => ">>", + _ => throw new ArgumentOutOfRangeException() + }; + + return $"{left} {op} {right}"; + } + + private string EmitBoolLiteral(BoolLiteralNode boolLiteralNode) + { + return boolLiteralNode.Value ? "true" : "false"; + } + + private string EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode) + { + var array = EmitExpression(constArrayIndexAccessNode.Target); + var index = EmitExpression(constArrayIndexAccessNode.Index); + // todo(nub31): We can emit bounds checking here + return $"{array}[{index}]"; + } + + private string EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode) + { + return "{0}"; + } + + // private string EmitConvertConstArrayToArray(ConvertConstArrayToArrayNode convertConstArrayToArrayNode) + // { + // var value = EmitExpression(convertConstArrayToArrayNode.Value); + // return $"({CType.Create(convertConstArrayToArrayNode.Type)}){value}"; + // } + + private string EmitConvertFloat(ConvertFloatNode convertFloatNode) + { + var value = EmitExpression(convertFloatNode.Value); + var targetCast = convertFloatNode.TargetType.Width switch + { + 32 => "f32", + 64 => "f64", + _ => throw new ArgumentOutOfRangeException() + }; + + return $"({targetCast}){value}"; + } + + private string EmitConvertInt(ConvertIntNode convertIntNode) + { + var value = EmitExpression(convertIntNode.Value); + var targetType = (convertIntNode.TargetType.Signed, convertIntNode.TargetType.Width) switch + { + (false, 8) => "u8", + (false, 16) => "u16", + (false, 32) => "u32", + (false, 64) => "u64", + (true, 8) => "i8", + (true, 16) => "i16", + (true, 32) => "i32", + (true, 64) => "i64", + _ => throw new ArgumentOutOfRangeException() + }; + return $"({targetType}){value}"; + } + + private string EmitCStringLiteral(CStringLiteralNode cStringLiteralNode) + { + return $"\"{cStringLiteralNode.Value}\""; + } + + private string EmitDereference(DereferenceNode dereferenceNode) + { + var pointer = EmitExpression(dereferenceNode.Target); + return $"*{pointer}"; + } + + private string EmitFloat32Literal(Float32LiteralNode float32LiteralNode) + { + var str = float32LiteralNode.Value.ToString("G9", System.Globalization.CultureInfo.InvariantCulture); + if (!str.Contains('.') && !str.Contains('e') && !str.Contains('E')) + { + str += ".0"; + } + + return str + "f"; + } + + private string EmitFloat64Literal(Float64LiteralNode float64LiteralNode) + { + var str = float64LiteralNode.Value.ToString("G17", System.Globalization.CultureInfo.InvariantCulture); + if (!str.Contains('.') && !str.Contains('e') && !str.Contains('E')) + { + str += ".0"; + } + + return str; + } + + private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode) + { + var value = EmitExpression(floatToIntBuiltinNode.Value); + var targetType = (floatToIntBuiltinNode.TargetType.Signed, floatToIntBuiltinNode.TargetType.Width) switch + { + (false, 8) => "u8", + (false, 16) => "u16", + (false, 32) => "u32", + (false, 64) => "u64", + (true, 8) => "i8", + (true, 16) => "i16", + (true, 32) => "i32", + (true, 64) => "i64", + _ => throw new ArgumentOutOfRangeException() + }; + return $"({targetType}){value}"; + } + + private string EmitFuncCall(FuncCallNode funcCallNode) + { + var name = EmitExpression(funcCallNode.Expression); + var parameterNames = funcCallNode.Parameters.Select(x => EmitExpression(x)).ToList(); + return $"{name}({string.Join(", ", parameterNames)})"; + } + + private string EmitFuncIdentifier(FuncIdentifierNode funcIdentifierNode) + { + return FuncName(funcIdentifierNode.Module, funcIdentifierNode.Name, funcIdentifierNode.ExternSymbol); + } + + private string EmitIntLiteral(IntLiteralNode intLiteralNode) + { + var type = (NubIntType)intLiteralNode.Type; + return type.Width switch + { + 8 or 16 or 32 => intLiteralNode.Value.ToString(), + 64 => intLiteralNode.Value + "LL", + _ => throw new ArgumentOutOfRangeException() + }; + } + + private string EmitAddressOf(AddressOfNode addressOfNode) + { + var value = EmitExpression(addressOfNode.LValue); + return $"&{value}"; + } + + private string EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode) + { + return lValueIdentifierNode.Name; + } + + private string EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode) + { + return rValueIdentifierNode.Name; + } + + private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) + { + return $"sizeof({CType.Create(sizeBuiltinNode.TargetType)})"; + } + + private string EmitSliceArrayIndexAccess(SliceIndexAccessNode sliceIndexAccessNode) + { + var value = EmitExpression(sliceIndexAccessNode.Target); + var index = EmitExpression(sliceIndexAccessNode.Index); + // todo(nub31): We can emit bounds checking here + return $"{value}.data[{index}]"; + } + + private string EmitStringLiteral(StringLiteralNode stringLiteralNode) + { + throw new NotImplementedException(); + } + + private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode) + { + var structExpr = EmitExpression(structFieldAccessNode.Target); + return $"{structExpr}.{structFieldAccessNode.Field}"; + } + + private string EmitStructInitializer(StructInitializerNode structInitializerNode) + { + var initValues = new List(); + foreach (var initializer in structInitializerNode.Initializers) + { + var value = EmitExpression(initializer.Value); + initValues.Add($".{initializer.Key} = {value}"); + } + + var initString = initValues.Count == 0 + ? "0" + : string.Join(", ", initValues); + + return $"({CType.Create(structInitializerNode.Type)}){{{initString}}}"; + } + + private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) + { + var type = (NubIntType)uIntLiteralNode.Type; + return type.Width switch + { + 8 or 16 or 32 => uIntLiteralNode.Value + "U", + 64 => uIntLiteralNode.Value + "ULL", + _ => throw new ArgumentOutOfRangeException() + }; + } + + private string EmitUnaryExpression(UnaryExpressionNode unaryExpressionNode) + { + var value = EmitExpression(unaryExpressionNode.Operand); + + return unaryExpressionNode.Operator switch + { + UnaryOperator.Negate => $"-{value}", + UnaryOperator.Invert => $"!{value}", + _ => throw new ArgumentOutOfRangeException() + }; + } + + private void EmitBlock(BlockNode blockNode) + { + EmitLine(blockNode.Tokens.FirstOrDefault()); + _writer.WriteLine("{"); + using (_writer.Indent()) + { + _deferStack.Push([]); + + foreach (var statementNode in blockNode.Statements) + { + EmitStatement(statementNode); + } + + var blockDefers = _deferStack.Pop(); + for (var i = blockDefers.Count - 1; i >= 0; i--) + { + EmitStatement(blockDefers[i].Statement); + } + } + + EmitLine(blockNode.Tokens.LastOrDefault()); + _writer.WriteLine("}"); + } +} \ No newline at end of file diff --git a/compiler/NubLang/Generation/Generator.cs b/compiler/NubLang/Generation/Generator.cs index 7c91d07..ca8b687 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -1,117 +1,164 @@ +using LLVMSharp.Interop; using NubLang.Ast; -using NubLang.Syntax; namespace NubLang.Generation; public class Generator { private readonly CompilationUnit _compilationUnit; - private readonly IndentedTextWriter _writer; - private readonly Stack> _deferStack = []; - private int _tmpIndex; public Generator(CompilationUnit compilationUnit) { _compilationUnit = compilationUnit; - _writer = new IndentedTextWriter(); + + LLVM.LinkInMCJIT(); + LLVM.InitializeX86TargetInfo(); + LLVM.InitializeX86Target(); + LLVM.InitializeX86TargetMC(); + LLVM.InitializeX86AsmPrinter(); + + _module = LLVMModuleRef.CreateWithName("test"); } - // todo(nub31): Handle name collisions - private string NewTmp() - { - return $"_t{++_tmpIndex}"; - } + private bool _done; + private readonly Dictionary _namedTypes = new(); + private readonly LLVMModuleRef _module; - private static string FuncName(string module, string name, string? externSymbol) - { - return externSymbol ?? $"{module}_{name}"; - } + private LLVMBuilderRef _builder; + private LLVMValueRef _currentFunction; + private Dictionary _namedValues = []; - private static string StructName(string module, string name) + private LLVMTypeRef MapType(NubType nubType) { - return $"{module}_{name}"; - } - - public string Emit() - { - _writer.WriteLine("#include "); - _writer.WriteLine("#include "); - _writer.WriteLine("#include "); - _writer.WriteLine(); - - foreach (var structType in _compilationUnit.ImportedStructTypes) + return nubType switch { - _writer.WriteLine("typedef struct"); - _writer.WriteLine("{"); - using (_writer.Indent()) + NubArrayType nubArrayType => LLVMTypeRef.CreatePointer(MapType(nubArrayType.ElementType), 0), + NubBoolType => LLVMTypeRef.Int1, + NubConstArrayType nubConstArrayType => LLVMTypeRef.CreateArray(MapType(nubConstArrayType.ElementType), (uint)nubConstArrayType.Size), + NubCStringType => LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), + NubFloatType nubFloatType => nubFloatType.Width switch { - foreach (var field in structType.Fields) - { - _writer.WriteLine($"{CType.Create(field.Type, field.Name)};"); - } - } + 32 => LLVMTypeRef.Float, + 64 => LLVMTypeRef.Double, + _ => throw new ArgumentOutOfRangeException(nameof(nubFloatType.Width)) + }, + NubFuncType nubFuncType => LLVMTypeRef.CreateFunction(MapType(nubFuncType.ReturnType), nubFuncType.Parameters.Select(MapType).ToArray()), + NubIntType nubIntType => LLVMTypeRef.CreateInt((uint)nubIntType.Width), + NubPointerType nubPointerType => LLVMTypeRef.CreatePointer(MapType(nubPointerType.BaseType), 0), + NubSliceType nubSliceType => GetOrCreateSliceType(nubSliceType), + NubStringType => GetOrCreateStringType(), + NubStructType nubStructType => GetOrCreateStructType(nubStructType), + NubVoidType => LLVMTypeRef.Void, + _ => throw new ArgumentOutOfRangeException(nameof(nubType)) + }; + } - _writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};"); - _writer.WriteLine(); - } - - // note(nub31): Forward declarations - foreach (var prototype in _compilationUnit.ImportedFunctions) + private LLVMTypeRef GetOrCreateStructType(NubStructType structType) + { + var key = $"struct.{structType.Module}.{structType.Name}"; + if (!_namedTypes.TryGetValue(key, out var llvmType)) { - EmitLine(prototype.Tokens.FirstOrDefault()); - var parameters = prototype.Parameters.Count != 0 - ? string.Join(", ", prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) - : "void"; - - var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol); - _writer.WriteLine($"{CType.Create(prototype.ReturnType, name)}({parameters});"); - _writer.WriteLine(); + llvmType = _module.Context.CreateNamedStruct(structType.Name); + _namedTypes[key] = llvmType; + var fields = structType.Fields.Select(f => MapType(f.Type)).ToArray(); + llvmType.StructSetBody(fields, false); } - // note(nub31): declare extern functions + return llvmType; + } + + private LLVMTypeRef GetOrCreateSliceType(NubSliceType sliceType) + { + var key = $"slice.{sliceType.ElementType}"; + if (!_namedTypes.TryGetValue(key, out var llvmType)) + { + llvmType = LLVMTypeRef.CreateStruct([LLVMTypeRef.CreatePointer(MapType(sliceType.ElementType), 0), LLVMTypeRef.Int64], false); + _namedTypes[key] = llvmType; + } + + return llvmType; + } + + private LLVMTypeRef GetOrCreateStringType() + { + const string key = "string"; + if (!_namedTypes.TryGetValue(key, out var llvmType)) + { + llvmType = _module.Context.CreateNamedStruct("string"); + llvmType.StructSetBody([LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), LLVMTypeRef.Int64], false); + _namedTypes[key] = llvmType; + } + + return llvmType; + } + + public string Generate() + { + if (_done) + { + return _module.PrintToString(); + } + + _done = true; + _builder = _module.Context.CreateBuilder(); + foreach (var funcNode in _compilationUnit.Functions) { - if (funcNode.Body != null) continue; - - EmitLine(funcNode.Tokens.FirstOrDefault()); - var parameters = funcNode.Prototype.Parameters.Count != 0 - ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) - : "void"; - - var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); - _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters});"); + EmitFunction(funcNode); } - _writer.WriteLine(); - - // note(nub31): Normal functions - foreach (var funcNode in _compilationUnit.Functions) + if (_module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out string error)) { - if (funcNode.Body == null) continue; - - EmitLine(funcNode.Tokens.FirstOrDefault()); - var parameters = funcNode.Prototype.Parameters.Count != 0 - ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) - : "void"; - - if (funcNode.Prototype.ExternSymbol == null) - { - _writer.Write("static "); - } - - var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); - _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters})"); - EmitBlock(funcNode.Body); - _writer.WriteLine(); + return _module.PrintToString(); + } + else + { + throw new InvalidOperationException($"Invalid LLVM module: {error}"); } - - return _writer.ToString(); } - private void EmitStatement(StatementNode statementNode) + private void EmitFunction(FuncNode funcNode) { - EmitLine(statementNode.Tokens.FirstOrDefault()); - switch (statementNode) + var parameters = funcNode.Prototype.Parameters.Select(x => MapType(x.Type)).ToArray(); + var functionType = LLVMTypeRef.CreateFunction(MapType(funcNode.Prototype.ReturnType), parameters); + + _currentFunction = _module.AddFunction(funcNode.Name, functionType); + + if (funcNode.Body == null) + { + return; + } + + _namedValues.Clear(); + + var entryBlock = _currentFunction.AppendBasicBlock("entry"); + _builder.PositionAtEnd(entryBlock); + + for (var i = 0; i < funcNode.Prototype.Parameters.Count; i++) + { + var param = funcNode.Prototype.Parameters[i]; + var llvmParam = _currentFunction.GetParam((uint)i); + llvmParam.Name = param.Name; + + var alloca = _builder.BuildAlloca(MapType(param.Type), param.Name); + _builder.BuildStore(llvmParam, alloca); + _namedValues[param.Name] = alloca; + } + + EmitBlock(funcNode.Body); + } + + private void EmitBlock(BlockNode blockNode) + { + foreach (var statement in blockNode.Statements) + { + EmitStatement(statement); + } + } + + private void EmitStatement(StatementNode statement) + { + switch (statement) { case AssignmentNode assignmentNode: EmitAssignment(assignmentNode); @@ -144,123 +191,58 @@ public class Generator EmitWhile(whileNode); break; default: - throw new ArgumentOutOfRangeException(nameof(statementNode)); + throw new ArgumentOutOfRangeException(nameof(statement)); } } - private void EmitLine(Token? token) - { - if (token == null) return; - var file = token.Span.FilePath; - var line = token.Span.Start.Line; - _writer.WriteLine($"#line {line} \"{file}\""); - } - private void EmitAssignment(AssignmentNode assignmentNode) { - var target = EmitExpression(assignmentNode.Target); - var value = EmitExpression(assignmentNode.Value); - _writer.WriteLine($"{target} = {value};"); + throw new NotImplementedException(); } - private void EmitBreak(BreakNode _) + private void EmitBreak(BreakNode breakNode) { - _writer.WriteLine("break;"); + throw new NotImplementedException(); } - private void EmitContinue(ContinueNode _) + private void EmitContinue(ContinueNode continueNode) { - _writer.WriteLine("continue;"); + throw new NotImplementedException(); } private void EmitDefer(DeferNode deferNode) { - _deferStack.Peek().Add(deferNode); + throw new NotImplementedException(); } - private void EmitIf(IfNode ifNode, bool elseIf = false) + private void EmitIf(IfNode ifNode) { - var condition = EmitExpression(ifNode.Condition); - _writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})"); - EmitBlock(ifNode.Body); - ifNode.Else?.Match - ( - elseIfNode => EmitIf(elseIfNode, true), - elseNode => - { - _writer.WriteLine("else"); - EmitBlock(elseNode); - } - ); + throw new NotImplementedException(); } private void EmitReturn(ReturnNode returnNode) { - if (returnNode.Value == null) - { - var blockDefers = _deferStack.Peek(); - for (var i = blockDefers.Count - 1; i >= 0; i--) - { - EmitStatement(blockDefers[i].Statement); - } - - _writer.WriteLine("return;"); - } - else - { - var returnValue = EmitExpression(returnNode.Value); - - if (_deferStack.Peek().Count != 0) - { - var tmp = NewTmp(); - _writer.WriteLine($"{CType.Create(returnNode.Value.Type, tmp)} = {returnValue};"); - - var blockDefers = _deferStack.Peek(); - for (var i = blockDefers.Count - 1; i >= 0; i--) - { - EmitStatement(blockDefers[i].Statement); - } - - EmitLine(returnNode.Tokens.FirstOrDefault()); - _writer.WriteLine($"return {tmp};"); - } - else - { - EmitLine(returnNode.Tokens.FirstOrDefault()); - _writer.WriteLine($"return {returnValue};"); - } - } + throw new NotImplementedException(); } private void EmitStatementFuncCall(StatementFuncCallNode statementFuncCallNode) { - var funcCall = EmitFuncCall(statementFuncCallNode.FuncCall); - _writer.WriteLine($"{funcCall};"); + throw new NotImplementedException(); } private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) { - if (variableDeclarationNode.Assignment != null) - { - var value = EmitExpression(variableDeclarationNode.Assignment); - _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};"); - } - else - { - _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)};"); - } + throw new NotImplementedException(); } private void EmitWhile(WhileNode whileNode) { - var condition = EmitExpression(whileNode.Condition); - _writer.WriteLine($"while ({condition})"); - EmitBlock(whileNode.Body); + throw new NotImplementedException(); } - private string EmitExpression(ExpressionNode expressionNode) + private LLVMValueRef EmitExpression(ExpressionNode expressionNode) { - var expr = expressionNode switch + return expressionNode switch { ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(arrayIndexAccessNode), ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode), @@ -268,7 +250,6 @@ public class Generator BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode), ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode), ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode), - // ConvertConstArrayToArrayNode convertConstArrayToArrayNode => EmitConvertConstArrayToArray(convertConstArrayToArrayNode), ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode), ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode), CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(cStringLiteralNode), @@ -283,7 +264,7 @@ public class Generator LValueIdentifierNode lValueIdentifierNode => EmitLValueIdentifier(lValueIdentifierNode), RValueIdentifierNode rValueIdentifierNode => EmitRValueIdentifier(rValueIdentifierNode), SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode), - SliceIndexAccessNode sliceIndexAccessNode => EmitSliceArrayIndexAccess(sliceIndexAccessNode), + SliceIndexAccessNode sliceIndexAccessNode => EmitSliceIndexAccess(sliceIndexAccessNode), StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode), StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode), StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode), @@ -291,291 +272,135 @@ public class Generator UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode), _ => throw new ArgumentOutOfRangeException(nameof(expressionNode)) }; - - if (expressionNode is ConstArrayInitializerNode) - { - return expr; - } - - return $"({expr})"; } - private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode) - { - var array = EmitExpression(arrayIndexAccessNode.Target); - var index = EmitExpression(arrayIndexAccessNode.Index); - return $"{array}[{index}]"; - } - - private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) - { - var type = (NubArrayType)arrayInitializerNode.Type; - var capacity = EmitExpression(arrayInitializerNode.Capacity); - var tmp = NewTmp(); - _writer.WriteLine($"{CType.Create(type.ElementType)} {tmp}[{capacity}];"); - return tmp; - } - - private string EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode) - { - var left = EmitExpression(binaryExpressionNode.Left); - var right = EmitExpression(binaryExpressionNode.Right); - - var op = binaryExpressionNode.Operator switch - { - BinaryOperator.Plus => "+", - BinaryOperator.Minus => "-", - BinaryOperator.Multiply => "*", - BinaryOperator.Divide => "/", - BinaryOperator.Modulo => "%", - BinaryOperator.Equal => "==", - BinaryOperator.NotEqual => "!=", - BinaryOperator.LessThan => "<", - BinaryOperator.LessThanOrEqual => "<=", - BinaryOperator.GreaterThan => ">", - BinaryOperator.GreaterThanOrEqual => ">=", - BinaryOperator.LogicalAnd => "&&", - BinaryOperator.LogicalOr => "||", - BinaryOperator.BitwiseAnd => "&", - BinaryOperator.BitwiseOr => "|", - BinaryOperator.BitwiseXor => "^", - BinaryOperator.LeftShift => "<<", - BinaryOperator.RightShift => ">>", - _ => throw new ArgumentOutOfRangeException() - }; - - return $"{left} {op} {right}"; - } - - private string EmitBoolLiteral(BoolLiteralNode boolLiteralNode) - { - return boolLiteralNode.Value ? "true" : "false"; - } - - private string EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode) - { - var array = EmitExpression(constArrayIndexAccessNode.Target); - var index = EmitExpression(constArrayIndexAccessNode.Index); - // todo(nub31): We can emit bounds checking here - return $"{array}[{index}]"; - } - - private string EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode) - { - return "{0}"; - } - - // private string EmitConvertConstArrayToArray(ConvertConstArrayToArrayNode convertConstArrayToArrayNode) - // { - // var value = EmitExpression(convertConstArrayToArrayNode.Value); - // return $"({CType.Create(convertConstArrayToArrayNode.Type)}){value}"; - // } - - private string EmitConvertFloat(ConvertFloatNode convertFloatNode) - { - var value = EmitExpression(convertFloatNode.Value); - var targetCast = convertFloatNode.TargetType.Width switch - { - 32 => "f32", - 64 => "f64", - _ => throw new ArgumentOutOfRangeException() - }; - - return $"({targetCast}){value}"; - } - - private string EmitConvertInt(ConvertIntNode convertIntNode) - { - var value = EmitExpression(convertIntNode.Value); - var targetType = (convertIntNode.TargetType.Signed, convertIntNode.TargetType.Width) switch - { - (false, 8) => "u8", - (false, 16) => "u16", - (false, 32) => "u32", - (false, 64) => "u64", - (true, 8) => "i8", - (true, 16) => "i16", - (true, 32) => "i32", - (true, 64) => "i64", - _ => throw new ArgumentOutOfRangeException() - }; - return $"({targetType}){value}"; - } - - private string EmitCStringLiteral(CStringLiteralNode cStringLiteralNode) - { - return $"\"{cStringLiteralNode.Value}\""; - } - - private string EmitDereference(DereferenceNode dereferenceNode) - { - var pointer = EmitExpression(dereferenceNode.Target); - return $"*{pointer}"; - } - - private string EmitFloat32Literal(Float32LiteralNode float32LiteralNode) - { - var str = float32LiteralNode.Value.ToString("G9", System.Globalization.CultureInfo.InvariantCulture); - if (!str.Contains('.') && !str.Contains('e') && !str.Contains('E')) - { - str += ".0"; - } - - return str + "f"; - } - - private string EmitFloat64Literal(Float64LiteralNode float64LiteralNode) - { - var str = float64LiteralNode.Value.ToString("G17", System.Globalization.CultureInfo.InvariantCulture); - if (!str.Contains('.') && !str.Contains('e') && !str.Contains('E')) - { - str += ".0"; - } - - return str; - } - - private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode) - { - var value = EmitExpression(floatToIntBuiltinNode.Value); - var targetType = (floatToIntBuiltinNode.TargetType.Signed, floatToIntBuiltinNode.TargetType.Width) switch - { - (false, 8) => "u8", - (false, 16) => "u16", - (false, 32) => "u32", - (false, 64) => "u64", - (true, 8) => "i8", - (true, 16) => "i16", - (true, 32) => "i32", - (true, 64) => "i64", - _ => throw new ArgumentOutOfRangeException() - }; - return $"({targetType}){value}"; - } - - private string EmitFuncCall(FuncCallNode funcCallNode) - { - var name = EmitExpression(funcCallNode.Expression); - var parameterNames = funcCallNode.Parameters.Select(x => EmitExpression(x)).ToList(); - return $"{name}({string.Join(", ", parameterNames)})"; - } - - private string EmitFuncIdentifier(FuncIdentifierNode funcIdentifierNode) - { - return FuncName(funcIdentifierNode.Module, funcIdentifierNode.Name, funcIdentifierNode.ExternSymbol); - } - - private string EmitIntLiteral(IntLiteralNode intLiteralNode) - { - var type = (NubIntType)intLiteralNode.Type; - return type.Width switch - { - 8 or 16 or 32 => intLiteralNode.Value.ToString(), - 64 => intLiteralNode.Value + "LL", - _ => throw new ArgumentOutOfRangeException() - }; - } - - private string EmitAddressOf(AddressOfNode addressOfNode) - { - var value = EmitExpression(addressOfNode.LValue); - return $"&{value}"; - } - - private string EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode) - { - return lValueIdentifierNode.Name; - } - - private string EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode) - { - return rValueIdentifierNode.Name; - } - - private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) - { - return $"sizeof({CType.Create(sizeBuiltinNode.TargetType)})"; - } - - private string EmitSliceArrayIndexAccess(SliceIndexAccessNode sliceIndexAccessNode) - { - var value = EmitExpression(sliceIndexAccessNode.Target); - var index = EmitExpression(sliceIndexAccessNode.Index); - // todo(nub31): We can emit bounds checking here - return $"{value}.data[{index}]"; - } - - private string EmitStringLiteral(StringLiteralNode stringLiteralNode) + private LLVMValueRef EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode) { throw new NotImplementedException(); } - private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode) + private LLVMValueRef EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) { - var structExpr = EmitExpression(structFieldAccessNode.Target); - return $"{structExpr}.{structFieldAccessNode.Field}"; + throw new NotImplementedException(); } - private string EmitStructInitializer(StructInitializerNode structInitializerNode) + private LLVMValueRef EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode) { - var initValues = new List(); - foreach (var initializer in structInitializerNode.Initializers) - { - var value = EmitExpression(initializer.Value); - initValues.Add($".{initializer.Key} = {value}"); - } - - var initString = initValues.Count == 0 - ? "0" - : string.Join(", ", initValues); - - return $"({CType.Create(structInitializerNode.Type)}){{{initString}}}"; + throw new NotImplementedException(); } - private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) + private LLVMValueRef EmitBoolLiteral(BoolLiteralNode boolLiteralNode) { - var type = (NubIntType)uIntLiteralNode.Type; - return type.Width switch - { - 8 or 16 or 32 => uIntLiteralNode.Value + "U", - 64 => uIntLiteralNode.Value + "ULL", - _ => throw new ArgumentOutOfRangeException() - }; + throw new NotImplementedException(); } - private string EmitUnaryExpression(UnaryExpressionNode unaryExpressionNode) + private LLVMValueRef EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode) { - var value = EmitExpression(unaryExpressionNode.Operand); - - return unaryExpressionNode.Operator switch - { - UnaryOperator.Negate => $"-{value}", - UnaryOperator.Invert => $"!{value}", - _ => throw new ArgumentOutOfRangeException() - }; + throw new NotImplementedException(); } - private void EmitBlock(BlockNode blockNode) + private LLVMValueRef EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode) { - EmitLine(blockNode.Tokens.FirstOrDefault()); - _writer.WriteLine("{"); - using (_writer.Indent()) - { - _deferStack.Push([]); + throw new NotImplementedException(); + } - foreach (var statementNode in blockNode.Statements) - { - EmitStatement(statementNode); - } + private LLVMValueRef EmitConvertFloat(ConvertFloatNode convertFloatNode) + { + throw new NotImplementedException(); + } - var blockDefers = _deferStack.Pop(); - for (var i = blockDefers.Count - 1; i >= 0; i--) - { - EmitStatement(blockDefers[i].Statement); - } - } + private LLVMValueRef EmitConvertInt(ConvertIntNode convertIntNode) + { + throw new NotImplementedException(); + } - EmitLine(blockNode.Tokens.LastOrDefault()); - _writer.WriteLine("}"); + private LLVMValueRef EmitCStringLiteral(CStringLiteralNode cStringLiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitDereference(DereferenceNode dereferenceNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitFloat32Literal(Float32LiteralNode float32LiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitFloat64Literal(Float64LiteralNode float64LiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitFuncCall(FuncCallNode funcCallNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitFuncIdentifier(FuncIdentifierNode funcIdentifierNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitIntLiteral(IntLiteralNode intLiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitAddressOf(AddressOfNode addressOfNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitSliceIndexAccess(SliceIndexAccessNode sliceIndexAccessNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitStringLiteral(StringLiteralNode stringLiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitStructInitializer(StructInitializerNode structInitializerNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) + { + throw new NotImplementedException(); + } + + private LLVMValueRef EmitUnaryExpression(UnaryExpressionNode unaryExpressionNode) + { + throw new NotImplementedException(); } } \ No newline at end of file diff --git a/compiler/NubLang/NubLang.csproj b/compiler/NubLang/NubLang.csproj index b682a68..c648dd5 100644 --- a/compiler/NubLang/NubLang.csproj +++ b/compiler/NubLang/NubLang.csproj @@ -7,4 +7,8 @@ true + + + +