...
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PublishAot>true</PublishAot>
|
<PublishAot>true</PublishAot>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using LLVMSharp.Interop;
|
||||||
using NubLang.Ast;
|
using NubLang.Ast;
|
||||||
using NubLang.Diagnostics;
|
using NubLang.Diagnostics;
|
||||||
using NubLang.Generation;
|
using NubLang.Generation;
|
||||||
@@ -47,124 +49,17 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
|||||||
|
|
||||||
for (var i = 0; i < nubFiles.Length; i++)
|
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);
|
var outPath = Path.ChangeExtension(Path.Combine(".build", nubFiles[i]), "ll");
|
||||||
Console.WriteLine(generator.Generate());
|
var outDir = Path.GetDirectoryName(outPath);
|
||||||
|
if (outDir != null)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(outDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(outPath, module.PrintToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// var cPaths = new List<string>();
|
|
||||||
//
|
|
||||||
// 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<string>();
|
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
@@ -108,8 +108,6 @@ public record FuncIdentifierNode(List<Token> Tokens, NubType Type, string Module
|
|||||||
|
|
||||||
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, ExpressionNode Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
|
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, ExpressionNode Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
public record ConstArrayInitializerNode(List<Token> Tokens, NubType Type, long Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
|
|
||||||
|
|
||||||
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
|
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
|
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
|
||||||
@@ -118,9 +116,9 @@ public record SliceIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionN
|
|||||||
|
|
||||||
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type);
|
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type);
|
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, LValueExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
public record StructInitializerNode(List<Token> Tokens, NubStructType StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(Tokens, StructType);
|
public record StructInitializerNode(List<Token> Tokens, NubStructType StructType, Dictionary<string, ExpressionNode> Initializers) : LValueExpressionNode(Tokens, StructType);
|
||||||
|
|
||||||
public record DereferenceNode(List<Token> Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type);
|
public record DereferenceNode(List<Token> Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
@@ -128,8 +126,6 @@ public record ConvertIntNode(List<Token> Tokens, NubType Type, ExpressionNode Va
|
|||||||
|
|
||||||
public record ConvertFloatNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Tokens, Type);
|
public record ConvertFloatNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
// public record ConvertConstArrayToArrayNode(List<Token> Tokens, NubType Type, ExpressionNode Value) : RValueExpressionNode(Tokens, Type);
|
|
||||||
|
|
||||||
public record SizeBuiltinNode(List<Token> Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type);
|
public record SizeBuiltinNode(List<Token> Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type);
|
||||||
|
|
||||||
public record FloatToIntBuiltinNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
|
public record FloatToIntBuiltinNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
|
||||||
|
|||||||
@@ -265,11 +265,6 @@ public sealed class TypeChecker
|
|||||||
return result;
|
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 (result.Type is NubIntType sourceIntType && expectedType is NubIntType targetIntType)
|
||||||
{
|
{
|
||||||
if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width)
|
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());
|
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 elementType = ResolveType(expression.ElementType);
|
||||||
var type = new NubConstArrayType(elementType, expression.Capacity);
|
var type = new NubArrayType(elementType);
|
||||||
return new ConstArrayInitializerNode(expression.Tokens, type, expression.Capacity, elementType);
|
return new ArrayInitializerNode(expression.Tokens, type, new IntLiteralNode([], new NubIntType(false, 64), expression.Capacity), elementType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression)
|
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression)
|
||||||
@@ -691,7 +686,12 @@ public sealed class TypeChecker
|
|||||||
.Build());
|
.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:
|
default:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ public class Diagnostic
|
|||||||
sb.Append(i.ToString().PadRight(numberPadding));
|
sb.Append(i.ToString().PadRight(numberPadding));
|
||||||
sb.Append(" │ ");
|
sb.Append(" │ ");
|
||||||
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
|
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
|
||||||
// sb.Append(line.PadRight(codePadding));
|
|
||||||
sb.Append(" │");
|
sb.Append(" │");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
|
|||||||
@@ -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})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<List<DeferNode>> _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 <stdint.h>");
|
|
||||||
_writer.WriteLine("#include <stdarg.h>");
|
|
||||||
_writer.WriteLine("#include <stddef.h>");
|
|
||||||
_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<string>();
|
|
||||||
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("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,26 +7,19 @@ public class Generator
|
|||||||
{
|
{
|
||||||
private readonly CompilationUnit _compilationUnit;
|
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 bool _done;
|
||||||
private readonly Dictionary<string, LLVMTypeRef> _namedTypes = new();
|
private readonly Dictionary<string, LLVMTypeRef> _namedTypes = new();
|
||||||
|
private readonly Dictionary<string, LLVMValueRef> _namedValues = [];
|
||||||
private readonly LLVMModuleRef _module;
|
private readonly LLVMModuleRef _module;
|
||||||
|
|
||||||
private LLVMBuilderRef _builder;
|
private LLVMBuilderRef _builder;
|
||||||
private LLVMValueRef _currentFunction;
|
private LLVMValueRef _currentFunction;
|
||||||
private Dictionary<string, LLVMValueRef> _namedValues = [];
|
|
||||||
|
public Generator(CompilationUnit compilationUnit, string fileName)
|
||||||
|
{
|
||||||
|
_compilationUnit = compilationUnit;
|
||||||
|
_module = LLVMModuleRef.CreateWithName(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
private LLVMTypeRef MapType(NubType nubType)
|
private LLVMTypeRef MapType(NubType nubType)
|
||||||
{
|
{
|
||||||
@@ -34,7 +27,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
NubArrayType nubArrayType => LLVMTypeRef.CreatePointer(MapType(nubArrayType.ElementType), 0),
|
NubArrayType nubArrayType => LLVMTypeRef.CreatePointer(MapType(nubArrayType.ElementType), 0),
|
||||||
NubBoolType => LLVMTypeRef.Int1,
|
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),
|
NubCStringType => LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0),
|
||||||
NubFloatType nubFloatType => nubFloatType.Width switch
|
NubFloatType nubFloatType => nubFloatType.Width switch
|
||||||
{
|
{
|
||||||
@@ -92,11 +85,11 @@ public class Generator
|
|||||||
return llvmType;
|
return llvmType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Generate()
|
public LLVMModuleRef Generate()
|
||||||
{
|
{
|
||||||
if (_done)
|
if (_done)
|
||||||
{
|
{
|
||||||
return _module.PrintToString();
|
return _module;
|
||||||
}
|
}
|
||||||
|
|
||||||
_done = true;
|
_done = true;
|
||||||
@@ -107,14 +100,13 @@ public class Generator
|
|||||||
EmitFunction(funcNode);
|
EmitFunction(funcNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out string error))
|
if (!_module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out var error))
|
||||||
{
|
{
|
||||||
return _module.PrintToString();
|
Console.WriteLine($"Invalid LLVM module: {error}");
|
||||||
}
|
// throw new InvalidOperationException($"Invalid LLVM module: {error}");
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Invalid LLVM module: {error}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return _module;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitFunction(FuncNode funcNode)
|
private void EmitFunction(FuncNode funcNode)
|
||||||
@@ -140,7 +132,7 @@ public class Generator
|
|||||||
var llvmParam = _currentFunction.GetParam((uint)i);
|
var llvmParam = _currentFunction.GetParam((uint)i);
|
||||||
llvmParam.Name = param.Name;
|
llvmParam.Name = param.Name;
|
||||||
|
|
||||||
var alloca = _builder.BuildAlloca(MapType(param.Type), param.Name);
|
var alloca = _builder.BuildAlloca(MapType(param.Type));
|
||||||
_builder.BuildStore(llvmParam, alloca);
|
_builder.BuildStore(llvmParam, alloca);
|
||||||
_namedValues[param.Name] = alloca;
|
_namedValues[param.Name] = alloca;
|
||||||
}
|
}
|
||||||
@@ -197,7 +189,9 @@ public class Generator
|
|||||||
|
|
||||||
private void EmitAssignment(AssignmentNode assignmentNode)
|
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)
|
private void EmitBreak(BreakNode breakNode)
|
||||||
@@ -222,17 +216,41 @@ public class Generator
|
|||||||
|
|
||||||
private void EmitReturn(ReturnNode returnNode)
|
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)
|
private void EmitStatementFuncCall(StatementFuncCallNode statementFuncCallNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
EmitFuncCall(statementFuncCallNode.FuncCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
|
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)
|
private void EmitWhile(WhileNode whileNode)
|
||||||
@@ -242,66 +260,165 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitExpression(ExpressionNode expressionNode)
|
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),
|
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),
|
ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode),
|
||||||
BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode),
|
BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode),
|
||||||
BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode),
|
BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode),
|
||||||
ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode),
|
|
||||||
ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode),
|
|
||||||
ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode),
|
ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode),
|
||||||
ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode),
|
ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode),
|
||||||
CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(cStringLiteralNode),
|
CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(cStringLiteralNode),
|
||||||
DereferenceNode dereferenceNode => EmitDereference(dereferenceNode),
|
|
||||||
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(float32LiteralNode),
|
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(float32LiteralNode),
|
||||||
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(float64LiteralNode),
|
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(float64LiteralNode),
|
||||||
FloatToIntBuiltinNode floatToIntBuiltinNode => EmitFloatToIntBuiltin(floatToIntBuiltinNode),
|
FloatToIntBuiltinNode floatToIntBuiltinNode => EmitFloatToIntBuiltin(floatToIntBuiltinNode),
|
||||||
FuncCallNode funcCallNode => EmitFuncCall(funcCallNode),
|
FuncCallNode funcCallNode => EmitFuncCall(funcCallNode),
|
||||||
FuncIdentifierNode funcIdentifierNode => EmitFuncIdentifier(funcIdentifierNode),
|
FuncIdentifierNode funcIdentifierNode => EmitFuncIdentifier(funcIdentifierNode),
|
||||||
IntLiteralNode intLiteralNode => EmitIntLiteral(intLiteralNode),
|
IntLiteralNode intLiteralNode => EmitIntLiteral(intLiteralNode),
|
||||||
AddressOfNode addressOfNode => EmitAddressOf(addressOfNode),
|
|
||||||
LValueIdentifierNode lValueIdentifierNode => EmitLValueIdentifier(lValueIdentifierNode),
|
|
||||||
RValueIdentifierNode rValueIdentifierNode => EmitRValueIdentifier(rValueIdentifierNode),
|
RValueIdentifierNode rValueIdentifierNode => EmitRValueIdentifier(rValueIdentifierNode),
|
||||||
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
|
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
|
||||||
SliceIndexAccessNode sliceIndexAccessNode => EmitSliceIndexAccess(sliceIndexAccessNode),
|
|
||||||
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
|
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
|
||||||
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
|
|
||||||
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
|
|
||||||
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
|
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
|
||||||
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
|
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(expressionNode))
|
_ => throw new ArgumentOutOfRangeException(nameof(rValueNode))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode)
|
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)
|
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)
|
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)
|
private LLVMValueRef EmitBoolLiteral(BoolLiteralNode boolLiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return LLVMValueRef.CreateConstInt(LLVMTypeRef.Int1, boolLiteralNode.Value ? 1ul : 0ul);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode)
|
private LLVMValueRef EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var arrayType = (NubConstArrayType)constArrayIndexAccessNode.Target.Type;
|
||||||
}
|
|
||||||
|
|
||||||
private LLVMValueRef EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode)
|
var target = EmitExpression(constArrayIndexAccessNode.Target);
|
||||||
{
|
var index = EmitExpression(constArrayIndexAccessNode.Index);
|
||||||
throw new NotImplementedException();
|
|
||||||
|
return _builder.BuildGEP2(MapType(arrayType), target, [LLVMValueRef.CreateConstInt(LLVMTypeRef.Int64, 0), index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitConvertFloat(ConvertFloatNode convertFloatNode)
|
private LLVMValueRef EmitConvertFloat(ConvertFloatNode convertFloatNode)
|
||||||
@@ -316,7 +433,7 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitCStringLiteral(CStringLiteralNode cStringLiteralNode)
|
private LLVMValueRef EmitCStringLiteral(CStringLiteralNode cStringLiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _builder.BuildGlobalStringPtr(cStringLiteralNode.Value, "str");
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitDereference(DereferenceNode dereferenceNode)
|
private LLVMValueRef EmitDereference(DereferenceNode dereferenceNode)
|
||||||
@@ -326,12 +443,12 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitFloat32Literal(Float32LiteralNode float32LiteralNode)
|
private LLVMValueRef EmitFloat32Literal(Float32LiteralNode float32LiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return LLVMValueRef.CreateConstReal(LLVMTypeRef.Float, float32LiteralNode.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitFloat64Literal(Float64LiteralNode float64LiteralNode)
|
private LLVMValueRef EmitFloat64Literal(Float64LiteralNode float64LiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return LLVMValueRef.CreateConstReal(LLVMTypeRef.Double, float64LiteralNode.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode)
|
private LLVMValueRef EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode)
|
||||||
@@ -341,17 +458,19 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitFuncCall(FuncCallNode funcCallNode)
|
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)
|
private LLVMValueRef EmitFuncIdentifier(FuncIdentifierNode funcIdentifierNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _module.GetNamedFunction(funcIdentifierNode.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitIntLiteral(IntLiteralNode intLiteralNode)
|
private LLVMValueRef EmitIntLiteral(IntLiteralNode intLiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return LLVMValueRef.CreateConstInt(MapType(intLiteralNode.Type), (ulong)intLiteralNode.Value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitAddressOf(AddressOfNode addressOfNode)
|
private LLVMValueRef EmitAddressOf(AddressOfNode addressOfNode)
|
||||||
@@ -361,12 +480,12 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode)
|
private LLVMValueRef EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _namedValues[lValueIdentifierNode.Name];
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode)
|
private LLVMValueRef EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _builder.BuildLoad2(MapType(rValueIdentifierNode.Type), _namedValues[rValueIdentifierNode.Name], rValueIdentifierNode.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
|
private LLVMValueRef EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
|
||||||
@@ -386,21 +505,43 @@ public class Generator
|
|||||||
|
|
||||||
private LLVMValueRef EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode)
|
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)
|
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)
|
private LLVMValueRef EmitUIntLiteral(UIntLiteralNode uIntLiteralNode)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return LLVMValueRef.CreateConstInt(MapType(uIntLiteralNode.Type), uIntLiteralNode.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LLVMValueRef EmitUnaryExpression(UnaryExpressionNode unaryExpressionNode)
|
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")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,19 @@ module "main"
|
|||||||
|
|
||||||
extern "puts" func puts(text: cstring)
|
extern "puts" func puts(text: cstring)
|
||||||
|
|
||||||
|
struct Human {
|
||||||
|
age: u32
|
||||||
|
name: cstring
|
||||||
|
}
|
||||||
|
|
||||||
extern "main" func main(args: []cstring): i64
|
extern "main" func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
defer puts("Goodybye World")
|
let human: Human = {
|
||||||
puts("Hello World")
|
name = "test"
|
||||||
|
age = 23
|
||||||
|
}
|
||||||
|
|
||||||
|
puts(human.name)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user