From 4a01fbc3060ee594b1b4b089a6bd8c96f76fd49d Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 21 Oct 2025 20:22:18 +0200 Subject: [PATCH] ... --- compiler/NubLang.CLI/NubLang.CLI.csproj | 1 + compiler/NubLang.CLI/Program.cs | 131 +--- compiler/NubLang/Ast/Node.cs | 8 +- compiler/NubLang/Ast/TypeChecker.cs | 18 +- compiler/NubLang/Diagnostics/Diagnostic.cs | 1 - compiler/NubLang/Generation/C/CType.cs | 89 --- compiler/NubLang/Generation/C/Generator.cs | 581 ------------------ compiler/NubLang/Generation/Generator.cs | 259 ++++++-- .../NubLang/Generation/IndentedTextWriter.cs | 70 --- examples/hello-world/main.nub | 14 +- 10 files changed, 237 insertions(+), 935 deletions(-) delete mode 100644 compiler/NubLang/Generation/C/CType.cs delete mode 100644 compiler/NubLang/Generation/C/Generator.cs delete mode 100644 compiler/NubLang/Generation/IndentedTextWriter.cs diff --git a/compiler/NubLang.CLI/NubLang.CLI.csproj b/compiler/NubLang.CLI/NubLang.CLI.csproj index 0550d0f..313d496 100644 --- a/compiler/NubLang.CLI/NubLang.CLI.csproj +++ b/compiler/NubLang.CLI/NubLang.CLI.csproj @@ -7,6 +7,7 @@ enable enable true + true diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs index d037cd0..5a2d919 100644 --- a/compiler/NubLang.CLI/Program.cs +++ b/compiler/NubLang.CLI/Program.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Text; +using LLVMSharp.Interop; using NubLang.Ast; using NubLang.Diagnostics; using NubLang.Generation; @@ -47,124 +49,17 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro for (var i = 0; i < nubFiles.Length; i++) { - var compilationUnit = compilationUnits[i]; + var generator = new Generator(compilationUnits[i], nubFiles[i]); + var module = generator.Generate(); - var generator = new Generator(compilationUnit); - Console.WriteLine(generator.Generate()); + var outPath = Path.ChangeExtension(Path.Combine(".build", nubFiles[i]), "ll"); + var outDir = Path.GetDirectoryName(outPath); + if (outDir != null) + { + Directory.CreateDirectory(outDir); + } + + File.WriteAllText(outPath, module.PrintToString()); } -return 0; - -// 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 +return 0; \ No newline at end of file diff --git a/compiler/NubLang/Ast/Node.cs b/compiler/NubLang/Ast/Node.cs index c904912..f6fc2f9 100644 --- a/compiler/NubLang/Ast/Node.cs +++ b/compiler/NubLang/Ast/Node.cs @@ -108,8 +108,6 @@ public record FuncIdentifierNode(List Tokens, NubType Type, string Module public record ArrayInitializerNode(List Tokens, NubType Type, ExpressionNode Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type); -public record ConstArrayInitializerNode(List Tokens, NubType Type, long Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type); - public record ArrayIndexAccessNode(List Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type); public record ConstArrayIndexAccessNode(List Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type); @@ -118,9 +116,9 @@ public record SliceIndexAccessNode(List Tokens, NubType Type, ExpressionN public record AddressOfNode(List Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type); -public record StructFieldAccessNode(List Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type); +public record StructFieldAccessNode(List Tokens, NubType Type, LValueExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type); -public record StructInitializerNode(List Tokens, NubStructType StructType, Dictionary Initializers) : RValueExpressionNode(Tokens, StructType); +public record StructInitializerNode(List Tokens, NubStructType StructType, Dictionary Initializers) : LValueExpressionNode(Tokens, StructType); public record DereferenceNode(List Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type); @@ -128,8 +126,6 @@ public record ConvertIntNode(List Tokens, NubType Type, ExpressionNode Va public record ConvertFloatNode(List Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Tokens, Type); -// public record ConvertConstArrayToArrayNode(List Tokens, NubType Type, ExpressionNode Value) : RValueExpressionNode(Tokens, Type); - public record SizeBuiltinNode(List Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type); public record FloatToIntBuiltinNode(List Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type); diff --git a/compiler/NubLang/Ast/TypeChecker.cs b/compiler/NubLang/Ast/TypeChecker.cs index 90802d3..f11903d 100644 --- a/compiler/NubLang/Ast/TypeChecker.cs +++ b/compiler/NubLang/Ast/TypeChecker.cs @@ -265,11 +265,6 @@ public sealed class TypeChecker return result; } - // if (result.Type is NubConstArrayType && expectedType is NubArrayType) - // { - // return new ConvertConstArrayToArrayNode(node.Tokens, expectedType, result); - // } - if (result.Type is NubIntType sourceIntType && expectedType is NubIntType targetIntType) { if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width) @@ -289,11 +284,11 @@ public sealed class TypeChecker throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {result.Type} to {expectedType}").At(node).Build()); } - private ConstArrayInitializerNode CheckConstArrayInitializer(ConstArrayInitializerSyntax expression) + private ArrayInitializerNode CheckConstArrayInitializer(ConstArrayInitializerSyntax expression) { var elementType = ResolveType(expression.ElementType); - var type = new NubConstArrayType(elementType, expression.Capacity); - return new ConstArrayInitializerNode(expression.Tokens, type, expression.Capacity, elementType); + var type = new NubArrayType(elementType); + return new ArrayInitializerNode(expression.Tokens, type, new IntLiteralNode([], new NubIntType(false, 64), expression.Capacity), elementType); } private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression) @@ -691,7 +686,12 @@ public sealed class TypeChecker .Build()); } - return new StructFieldAccessNode(expression.Tokens, field.Type, target, expression.Member); + if (target is not LValueExpressionNode lValueTarget) + { + throw new TypeCheckerException(Diagnostic.Error("Struct field access is not an lvalue (this should never happen)").At(expression.Target).Build()); + } + + return new StructFieldAccessNode(expression.Tokens, field.Type, lValueTarget, expression.Member); } default: { diff --git a/compiler/NubLang/Diagnostics/Diagnostic.cs b/compiler/NubLang/Diagnostics/Diagnostic.cs index fd940b4..b226949 100644 --- a/compiler/NubLang/Diagnostics/Diagnostic.cs +++ b/compiler/NubLang/Diagnostics/Diagnostic.cs @@ -145,7 +145,6 @@ public class Diagnostic sb.Append(i.ToString().PadRight(numberPadding)); sb.Append(" │ "); sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens)); - // sb.Append(line.PadRight(codePadding)); sb.Append(" │"); sb.AppendLine(); diff --git a/compiler/NubLang/Generation/C/CType.cs b/compiler/NubLang/Generation/C/CType.cs deleted file mode 100644 index 1357a5f..0000000 --- a/compiler/NubLang/Generation/C/CType.cs +++ /dev/null @@ -1,89 +0,0 @@ -using NubLang.Ast; - -namespace NubLang.Generation.C; - -public static class CType -{ - public static string Create(NubType type, string? variableName = null) - { - return type switch - { - NubVoidType => "void" + (variableName != null ? $" {variableName}" : ""), - NubBoolType => "bool" + (variableName != null ? $" {variableName}" : ""), - NubIntType intType => CreateIntType(intType, variableName), - NubFloatType floatType => CreateFloatType(floatType, variableName), - NubCStringType => "char*" + (variableName != null ? $" {variableName}" : ""), - NubPointerType ptr => CreatePointerType(ptr, variableName), - NubConstArrayType arr => CreateConstArrayType(arr, variableName), - NubArrayType arr => CreateArrayType(arr, variableName), - NubFuncType fn => CreateFuncType(fn, variableName), - NubStructType st => $"{st.Name}" + (variableName != null ? $" {variableName}" : ""), - _ => throw new NotSupportedException($"C type generation not supported for: {type}") - }; - } - - private static string CreateIntType(NubIntType intType, string? varName) - { - var cType = intType.Width switch - { - 8 => intType.Signed ? "int8_t" : "uint8_t", - 16 => intType.Signed ? "int16_t" : "uint16_t", - 32 => intType.Signed ? "int32_t" : "uint32_t", - 64 => intType.Signed ? "int64_t" : "uint64_t", - _ => throw new NotSupportedException($"Unsupported integer width: {intType.Width}") - }; - return cType + (varName != null ? $" {varName}" : ""); - } - - private static string CreateFloatType(NubFloatType floatType, string? varName) - { - var cType = floatType.Width switch - { - 32 => "float", - 64 => "double", - _ => throw new NotSupportedException($"Unsupported float width: {floatType.Width}") - }; - return cType + (varName != null ? $" {varName}" : ""); - } - - private static string CreatePointerType(NubPointerType ptr, string? varName) - { - var baseType = Create(ptr.BaseType); - return baseType + "*" + (varName != null ? $" {varName}" : ""); - } - - private static string CreateConstArrayType(NubConstArrayType arr, string? varName) - { - var elementType = Create(arr.ElementType); - if (varName != null) - { - return $"{elementType} {varName}[{arr.Size}]"; - } - - return $"{elementType}[{arr.Size}]"; - } - - private static string CreateArrayType(NubArrayType arr, string? varName) - { - var elementType = Create(arr.ElementType); - return elementType + "*" + (varName != null ? $" {varName}" : ""); - } - - private static string CreateFuncType(NubFuncType fn, string? varName) - { - var returnType = Create(fn.ReturnType); - var parameters = string.Join(", ", fn.Parameters.Select(p => Create(p))); - - if (string.IsNullOrEmpty(parameters)) - { - parameters = "void"; - } - - if (varName != null) - { - return $"{returnType} (*{varName})({parameters})"; - } - - return $"{returnType} (*)({parameters})"; - } -} \ No newline at end of file diff --git a/compiler/NubLang/Generation/C/Generator.cs b/compiler/NubLang/Generation/C/Generator.cs deleted file mode 100644 index f709df9..0000000 --- a/compiler/NubLang/Generation/C/Generator.cs +++ /dev/null @@ -1,581 +0,0 @@ -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 ca8b687..65fcaaf 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -7,26 +7,19 @@ public class Generator { private readonly CompilationUnit _compilationUnit; - public Generator(CompilationUnit compilationUnit) - { - _compilationUnit = compilationUnit; - - LLVM.LinkInMCJIT(); - LLVM.InitializeX86TargetInfo(); - LLVM.InitializeX86Target(); - LLVM.InitializeX86TargetMC(); - LLVM.InitializeX86AsmPrinter(); - - _module = LLVMModuleRef.CreateWithName("test"); - } - private bool _done; private readonly Dictionary _namedTypes = new(); + private readonly Dictionary _namedValues = []; private readonly LLVMModuleRef _module; private LLVMBuilderRef _builder; private LLVMValueRef _currentFunction; - private Dictionary _namedValues = []; + + public Generator(CompilationUnit compilationUnit, string fileName) + { + _compilationUnit = compilationUnit; + _module = LLVMModuleRef.CreateWithName(fileName); + } private LLVMTypeRef MapType(NubType nubType) { @@ -34,7 +27,7 @@ public class Generator { NubArrayType nubArrayType => LLVMTypeRef.CreatePointer(MapType(nubArrayType.ElementType), 0), NubBoolType => LLVMTypeRef.Int1, - NubConstArrayType nubConstArrayType => LLVMTypeRef.CreateArray(MapType(nubConstArrayType.ElementType), (uint)nubConstArrayType.Size), + NubConstArrayType nubConstArrayType => LLVMTypeRef.CreatePointer(MapType(nubConstArrayType.ElementType), 0), NubCStringType => LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), NubFloatType nubFloatType => nubFloatType.Width switch { @@ -92,11 +85,11 @@ public class Generator return llvmType; } - public string Generate() + public LLVMModuleRef Generate() { if (_done) { - return _module.PrintToString(); + return _module; } _done = true; @@ -107,14 +100,13 @@ public class Generator EmitFunction(funcNode); } - if (_module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out string error)) + if (!_module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out var error)) { - return _module.PrintToString(); - } - else - { - throw new InvalidOperationException($"Invalid LLVM module: {error}"); + Console.WriteLine($"Invalid LLVM module: {error}"); + // throw new InvalidOperationException($"Invalid LLVM module: {error}"); } + + return _module; } private void EmitFunction(FuncNode funcNode) @@ -140,7 +132,7 @@ public class Generator var llvmParam = _currentFunction.GetParam((uint)i); llvmParam.Name = param.Name; - var alloca = _builder.BuildAlloca(MapType(param.Type), param.Name); + var alloca = _builder.BuildAlloca(MapType(param.Type)); _builder.BuildStore(llvmParam, alloca); _namedValues[param.Name] = alloca; } @@ -197,7 +189,9 @@ public class Generator private void EmitAssignment(AssignmentNode assignmentNode) { - throw new NotImplementedException(); + var target = EmitLValue(assignmentNode.Target); + var value = EmitExpression(assignmentNode.Value); + _builder.BuildStore(value, target); } private void EmitBreak(BreakNode breakNode) @@ -222,17 +216,41 @@ public class Generator private void EmitReturn(ReturnNode returnNode) { - throw new NotImplementedException(); + if (returnNode.Value == null) + { + _builder.BuildRetVoid(); + } + else + { + var returnValue = EmitExpression(returnNode.Value); + _builder.BuildRet(returnValue); + } } private void EmitStatementFuncCall(StatementFuncCallNode statementFuncCallNode) { - throw new NotImplementedException(); + EmitFuncCall(statementFuncCallNode.FuncCall); } private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) { - throw new NotImplementedException(); + if (variableDeclarationNode.Assignment is LValueExpressionNode lValueExpressionNode) + { + var value = EmitLValue(lValueExpressionNode); + _namedValues[variableDeclarationNode.Name] = value; + return; + } + + var allocaType = MapType(variableDeclarationNode.Type); + var alloca = _builder.BuildAlloca(allocaType); + + if (variableDeclarationNode.Assignment != null) + { + var initValue = EmitExpression(variableDeclarationNode.Assignment); + _builder.BuildStore(initValue, alloca); + } + + _namedValues[variableDeclarationNode.Name] = alloca; } private void EmitWhile(WhileNode whileNode) @@ -242,66 +260,165 @@ public class Generator private LLVMValueRef EmitExpression(ExpressionNode expressionNode) { - return expressionNode switch + switch (expressionNode) + { + case LValueExpressionNode lvalue: + { + var value = EmitLValue(lvalue); + return _builder.BuildLoad2(MapType(lvalue.Type), value); + } + case RValueExpressionNode rvalue: + { + return EmitRValue(rvalue); + } + default: + { + throw new ArgumentOutOfRangeException(nameof(expressionNode)); + } + } + } + + private LLVMValueRef EmitLValue(LValueExpressionNode lValueNode) + { + return lValueNode switch { ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(arrayIndexAccessNode), + ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode), + DereferenceNode dereferenceNode => EmitDereference(dereferenceNode), + LValueIdentifierNode lValueIdentifierNode => EmitLValueIdentifier(lValueIdentifierNode), + SliceIndexAccessNode sliceIndexAccessNode => EmitSliceIndexAccess(sliceIndexAccessNode), + StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode), + StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode), + _ => throw new ArgumentOutOfRangeException(nameof(lValueNode)) + }; + } + + private LLVMValueRef EmitRValue(RValueExpressionNode rValueNode) + { + return rValueNode switch + { + AddressOfNode addressOfNode => EmitAddressOf(addressOfNode), ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode), BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode), BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode), - ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode), - ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode), 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 => EmitSliceIndexAccess(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)) + _ => throw new ArgumentOutOfRangeException(nameof(rValueNode)) }; } private LLVMValueRef EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode) { - throw new NotImplementedException(); + var arrayType = (NubArrayType)arrayIndexAccessNode.Target.Type; + var elementType = MapType(arrayType.ElementType); + + var target = EmitExpression(arrayIndexAccessNode.Target); + var index = EmitExpression(arrayIndexAccessNode.Index); + + return _builder.BuildGEP2(elementType, target, [index]); } private LLVMValueRef EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) { - throw new NotImplementedException(); + var capacity = EmitExpression(arrayInitializerNode.Capacity); + return _builder.BuildArrayAlloca(MapType(arrayInitializerNode.ElementType), capacity); } private LLVMValueRef EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode) { - throw new NotImplementedException(); + var left = EmitExpression(binaryExpressionNode.Left); + var right = EmitExpression(binaryExpressionNode.Right); + + var leftType = binaryExpressionNode.Left.Type; + + if (leftType is NubIntType) + { + return binaryExpressionNode.Operator switch + { + BinaryOperator.Plus => _builder.BuildAdd(left, right), + BinaryOperator.Minus => _builder.BuildSub(left, right), + BinaryOperator.Multiply => _builder.BuildMul(left, right), + BinaryOperator.Divide => _builder.BuildSDiv(left, right), + BinaryOperator.Modulo => _builder.BuildSRem(left, right), + + BinaryOperator.Equal => _builder.BuildICmp(LLVMIntPredicate.LLVMIntEQ, left, right), + BinaryOperator.NotEqual => _builder.BuildICmp(LLVMIntPredicate.LLVMIntNE, left, right), + BinaryOperator.LessThan => _builder.BuildICmp(LLVMIntPredicate.LLVMIntSLT, left, right), + BinaryOperator.LessThanOrEqual => _builder.BuildICmp(LLVMIntPredicate.LLVMIntSLE, left, right), + BinaryOperator.GreaterThan => _builder.BuildICmp(LLVMIntPredicate.LLVMIntSGT, left, right), + BinaryOperator.GreaterThanOrEqual => _builder.BuildICmp(LLVMIntPredicate.LLVMIntSGE, left, right), + + BinaryOperator.BitwiseAnd => _builder.BuildAnd(left, right), + BinaryOperator.BitwiseOr => _builder.BuildOr(left, right), + BinaryOperator.BitwiseXor => _builder.BuildXor(left, right), + BinaryOperator.LeftShift => _builder.BuildShl(left, right), + BinaryOperator.RightShift => _builder.BuildAShr(left, right), + + _ => throw new NotSupportedException($"Binary operator {binaryExpressionNode.Operator} not supported for int") + }; + } + + if (leftType is NubFloatType) + { + return binaryExpressionNode.Operator switch + { + BinaryOperator.Plus => _builder.BuildFAdd(left, right), + BinaryOperator.Minus => _builder.BuildFSub(left, right), + BinaryOperator.Multiply => _builder.BuildFMul(left, right), + BinaryOperator.Divide => _builder.BuildFDiv(left, right), + BinaryOperator.Modulo => _builder.BuildFRem(left, right), + + BinaryOperator.Equal => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealOEQ, left, right), + BinaryOperator.NotEqual => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealONE, left, right), + BinaryOperator.LessThan => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealOLT, left, right), + BinaryOperator.LessThanOrEqual => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealOLE, left, right), + BinaryOperator.GreaterThan => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealOGT, left, right), + BinaryOperator.GreaterThanOrEqual => _builder.BuildFCmp(LLVMRealPredicate.LLVMRealOGE, left, right), + + _ => throw new NotSupportedException($"Binary operator {binaryExpressionNode.Operator} not supported for float") + }; + } + + if (leftType is NubBoolType) + { + return binaryExpressionNode.Operator switch + { + BinaryOperator.LogicalAnd => _builder.BuildAnd(left, right), + BinaryOperator.LogicalOr => _builder.BuildOr(left, right), + BinaryOperator.Equal => _builder.BuildICmp(LLVMIntPredicate.LLVMIntEQ, left, right), + BinaryOperator.NotEqual => _builder.BuildICmp(LLVMIntPredicate.LLVMIntNE, left, right), + _ => throw new NotSupportedException($"Binary operator {binaryExpressionNode.Operator} not supported for bool") + }; + } + + throw new NotSupportedException($"Binary operations for type {leftType} not supported"); } private LLVMValueRef EmitBoolLiteral(BoolLiteralNode boolLiteralNode) { - throw new NotImplementedException(); + return LLVMValueRef.CreateConstInt(LLVMTypeRef.Int1, boolLiteralNode.Value ? 1ul : 0ul); } private LLVMValueRef EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode) { - throw new NotImplementedException(); - } + var arrayType = (NubConstArrayType)constArrayIndexAccessNode.Target.Type; - private LLVMValueRef EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode) - { - throw new NotImplementedException(); + var target = EmitExpression(constArrayIndexAccessNode.Target); + var index = EmitExpression(constArrayIndexAccessNode.Index); + + return _builder.BuildGEP2(MapType(arrayType), target, [LLVMValueRef.CreateConstInt(LLVMTypeRef.Int64, 0), index]); } private LLVMValueRef EmitConvertFloat(ConvertFloatNode convertFloatNode) @@ -316,7 +433,7 @@ public class Generator private LLVMValueRef EmitCStringLiteral(CStringLiteralNode cStringLiteralNode) { - throw new NotImplementedException(); + return _builder.BuildGlobalStringPtr(cStringLiteralNode.Value, "str"); } private LLVMValueRef EmitDereference(DereferenceNode dereferenceNode) @@ -326,12 +443,12 @@ public class Generator private LLVMValueRef EmitFloat32Literal(Float32LiteralNode float32LiteralNode) { - throw new NotImplementedException(); + return LLVMValueRef.CreateConstReal(LLVMTypeRef.Float, float32LiteralNode.Value); } private LLVMValueRef EmitFloat64Literal(Float64LiteralNode float64LiteralNode) { - throw new NotImplementedException(); + return LLVMValueRef.CreateConstReal(LLVMTypeRef.Double, float64LiteralNode.Value); } private LLVMValueRef EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode) @@ -341,17 +458,19 @@ public class Generator private LLVMValueRef EmitFuncCall(FuncCallNode funcCallNode) { - throw new NotImplementedException(); + var function = EmitExpression(funcCallNode.Expression); + var args = funcCallNode.Parameters.Select(EmitExpression).ToArray(); + return _builder.BuildCall2(MapType(funcCallNode.Expression.Type), function, args); } private LLVMValueRef EmitFuncIdentifier(FuncIdentifierNode funcIdentifierNode) { - throw new NotImplementedException(); + return _module.GetNamedFunction(funcIdentifierNode.Name); } private LLVMValueRef EmitIntLiteral(IntLiteralNode intLiteralNode) { - throw new NotImplementedException(); + return LLVMValueRef.CreateConstInt(MapType(intLiteralNode.Type), (ulong)intLiteralNode.Value, true); } private LLVMValueRef EmitAddressOf(AddressOfNode addressOfNode) @@ -361,12 +480,12 @@ public class Generator private LLVMValueRef EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode) { - throw new NotImplementedException(); + return _namedValues[lValueIdentifierNode.Name]; } private LLVMValueRef EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode) { - throw new NotImplementedException(); + return _builder.BuildLoad2(MapType(rValueIdentifierNode.Type), _namedValues[rValueIdentifierNode.Name], rValueIdentifierNode.Name); } private LLVMValueRef EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) @@ -386,21 +505,43 @@ public class Generator private LLVMValueRef EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode) { - throw new NotImplementedException(); + var type = (NubStructType)structFieldAccessNode.Target.Type; + var target = EmitLValue(structFieldAccessNode.Target); + var fieldIndex = type.Fields.FindIndex(x => x.Name == structFieldAccessNode.Field); + return _builder.BuildStructGEP2(MapType(structFieldAccessNode.Target.Type), target, (uint)fieldIndex); } private LLVMValueRef EmitStructInitializer(StructInitializerNode structInitializerNode) { - throw new NotImplementedException(); + var type = MapType(structInitializerNode.StructType); + var ptr = _builder.BuildAlloca(type); + + foreach (var initializer in structInitializerNode.Initializers) + { + var value = EmitExpression(initializer.Value); + var fieldIndex = structInitializerNode.StructType.Fields.FindIndex(x => x.Name == initializer.Key); + var fieldPtr = _builder.BuildStructGEP2(type, ptr, (uint)fieldIndex); + + _builder.BuildStore(value, fieldPtr); + } + + return ptr; } private LLVMValueRef EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) { - throw new NotImplementedException(); + return LLVMValueRef.CreateConstInt(MapType(uIntLiteralNode.Type), uIntLiteralNode.Value); } private LLVMValueRef EmitUnaryExpression(UnaryExpressionNode unaryExpressionNode) { - throw new NotImplementedException(); + var operand = EmitExpression(unaryExpressionNode.Operand); + return unaryExpressionNode.Operator switch + { + UnaryOperator.Negate when unaryExpressionNode.Operand.Type is NubIntType => _builder.BuildNeg(operand), + UnaryOperator.Negate when unaryExpressionNode.Operand.Type is NubFloatType => _builder.BuildFNeg(operand), + UnaryOperator.Invert => _builder.BuildNot(operand), + _ => throw new NotImplementedException($"Unary operator {unaryExpressionNode.Operator} not implemented") + }; } } \ No newline at end of file diff --git a/compiler/NubLang/Generation/IndentedTextWriter.cs b/compiler/NubLang/Generation/IndentedTextWriter.cs deleted file mode 100644 index 5ec5274..0000000 --- a/compiler/NubLang/Generation/IndentedTextWriter.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Text; - -namespace NubLang.Generation; - -internal class IndentedTextWriter -{ - private readonly StringBuilder _builder = new(); - private int _indentLevel; - - public IDisposable Indent() - { - _indentLevel++; - return new IndentScope(this); - } - - public void WriteLine(string text) - { - WriteIndent(); - _builder.AppendLine(text); - } - - public void Write(string text) - { - WriteIndent(); - _builder.Append(text); - } - - public void WriteLine() - { - _builder.AppendLine(); - } - - public override string ToString() - { - return _builder.ToString(); - } - - private void WriteIndent() - { - if (_builder.Length > 0) - { - var lastChar = _builder[^1]; - if (lastChar != '\n' && lastChar != '\r') - return; - } - - for (var i = 0; i < _indentLevel; i++) - { - _builder.Append(" "); - } - } - - private class IndentScope : IDisposable - { - private readonly IndentedTextWriter _writer; - private bool _disposed; - - public IndentScope(IndentedTextWriter writer) - { - _writer = writer; - } - - public void Dispose() - { - if (_disposed) return; - _writer._indentLevel--; - _disposed = true; - } - } -} \ No newline at end of file diff --git a/examples/hello-world/main.nub b/examples/hello-world/main.nub index f63a21f..2f79a66 100644 --- a/examples/hello-world/main.nub +++ b/examples/hello-world/main.nub @@ -2,9 +2,19 @@ module "main" extern "puts" func puts(text: cstring) +struct Human { + age: u32 + name: cstring +} + extern "main" func main(args: []cstring): i64 { - defer puts("Goodybye World") - puts("Hello World") + let human: Human = { + name = "test" + age = 23 + } + + puts(human.name) + return 0 } \ No newline at end of file