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