c generator
This commit is contained in:
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"stdbool.h": "c",
|
||||
"stdint.h": "c"
|
||||
}
|
||||
}
|
||||
@@ -27,4 +27,28 @@ public static class GCC
|
||||
|
||||
return process.ExitCode == 0;
|
||||
}
|
||||
|
||||
public static async Task<bool> Compile(string cPath, string outPath)
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo("gcc", ["-ffreestanding", "-nostartfiles", "-c", "-o", outPath, cPath])
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
process.Start();
|
||||
|
||||
await process.WaitForExitAsync();
|
||||
|
||||
var errors = await process.StandardError.ReadToEndAsync();
|
||||
if (!string.IsNullOrWhiteSpace(errors))
|
||||
{
|
||||
await Console.Error.WriteLineAsync(errors);
|
||||
}
|
||||
|
||||
return process.ExitCode == 0;
|
||||
}
|
||||
}
|
||||
@@ -116,28 +116,38 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
||||
|
||||
Directory.CreateDirectory(".build");
|
||||
|
||||
sw.Restart();
|
||||
var generator = new CGenerator(definitions, referencedStructTypes);
|
||||
var c = generator.Emit();
|
||||
var cFilePath = Path.Combine(".build", "out.c");
|
||||
|
||||
var generator = new QBEGenerator(definitions, referencedStructTypes);
|
||||
var ssa = generator.Emit();
|
||||
var ssaFilePath = Path.Combine(".build", "out.ssa");
|
||||
File.WriteAllText(ssaFilePath, ssa);
|
||||
|
||||
Console.WriteLine($"Emit ssa: {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
|
||||
var asmFilePath = Path.Combine(".build", "out.asm");
|
||||
var qbeSuccess = await QBE.Invoke(ssaFilePath, asmFilePath);
|
||||
if (!qbeSuccess) return 1;
|
||||
|
||||
Console.WriteLine($"Emit asm: {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
File.WriteAllText(cFilePath, c);
|
||||
|
||||
var objFilePath = Path.Combine(".build", "out.o");
|
||||
var asmSuccess = await GCC.Assemble(asmFilePath, objFilePath);
|
||||
var asmSuccess = await GCC.Compile(cFilePath, objFilePath);
|
||||
if (!asmSuccess) return 1;
|
||||
|
||||
Console.WriteLine($"Assemble: {sw.ElapsedMilliseconds}ms");
|
||||
// sw.Restart();
|
||||
//
|
||||
// var generator = new QBEGenerator(definitions, referencedStructTypes);
|
||||
// var ssa = generator.Emit();
|
||||
// var ssaFilePath = Path.Combine(".build", "out.ssa");
|
||||
// File.WriteAllText(ssaFilePath, ssa);
|
||||
//
|
||||
// Console.WriteLine($"Emit ssa: {sw.ElapsedMilliseconds}ms");
|
||||
// sw.Restart();
|
||||
//
|
||||
// var asmFilePath = Path.Combine(".build", "out.asm");
|
||||
// var qbeSuccess = await QBE.Invoke(ssaFilePath, asmFilePath);
|
||||
// if (!qbeSuccess) return 1;
|
||||
//
|
||||
// Console.WriteLine($"Emit asm: {sw.ElapsedMilliseconds}ms");
|
||||
// sw.Restart();
|
||||
//
|
||||
// var objFilePath = Path.Combine(".build", "out.o");
|
||||
// var asmSuccess = await GCC.Assemble(asmFilePath, objFilePath);
|
||||
// if (!asmSuccess) return 1;
|
||||
//
|
||||
// Console.WriteLine($"Assemble: {sw.ElapsedMilliseconds}ms");
|
||||
sw.Restart();
|
||||
|
||||
return 0;
|
||||
@@ -81,6 +81,8 @@ public class Diagnostic
|
||||
}
|
||||
|
||||
public string FormatANSI()
|
||||
{
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
@@ -191,6 +193,11 @@ public class Diagnostic
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ConsoleColors.Colorize("Failed to generate error message", ConsoleColors.Red);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ApplySyntaxHighlighting(string line, int lineNumber, List<Token> tokens)
|
||||
{
|
||||
|
||||
518
compiler/NubLang/Generation/CGenerator.cs
Normal file
518
compiler/NubLang/Generation/CGenerator.cs
Normal file
@@ -0,0 +1,518 @@
|
||||
using NubLang.Ast;
|
||||
|
||||
namespace NubLang.Generation;
|
||||
|
||||
public class CGenerator
|
||||
{
|
||||
private readonly List<DefinitionNode> _definitions;
|
||||
private readonly HashSet<NubStructType> _structTypes;
|
||||
private readonly CWriter _writer;
|
||||
|
||||
public CGenerator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes)
|
||||
{
|
||||
_definitions = definitions;
|
||||
_structTypes = structTypes;
|
||||
_writer = new CWriter();
|
||||
}
|
||||
|
||||
private static string MapType(NubType nubType)
|
||||
{
|
||||
return nubType switch
|
||||
{
|
||||
NubArrayType => "uintptr_t",
|
||||
NubBoolType => "bool",
|
||||
NubCStringType => "char*",
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "f32",
|
||||
64 => "f64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubFuncType => "uintptr_t",
|
||||
NubIntType intType => intType.Signed switch
|
||||
{
|
||||
true => intType.Width switch
|
||||
{
|
||||
8 => "i8",
|
||||
16 => "i16",
|
||||
32 => "i32",
|
||||
64 => "i64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
false => intType.Width switch
|
||||
{
|
||||
8 => "u8",
|
||||
16 => "u16",
|
||||
32 => "u32",
|
||||
64 => "u64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
},
|
||||
NubPointerType => "uintptr_t",
|
||||
NubStringType => "uintptr_t",
|
||||
NubStructType structType => StructName(structType.Module, structType.Name),
|
||||
NubVoidType => "void",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(nubType))
|
||||
};
|
||||
}
|
||||
|
||||
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}";
|
||||
}
|
||||
|
||||
private static string StructFuncName(string module, string name, string function)
|
||||
{
|
||||
return $"{module}_{name}_{function}";
|
||||
}
|
||||
|
||||
public string Emit()
|
||||
{
|
||||
_writer.WriteLine("""
|
||||
typedef __builtin_va_list va_list;
|
||||
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long i64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define I8_C(x) x
|
||||
#define U8_C(x) x##U
|
||||
|
||||
#define I16_C(x) x
|
||||
#define U16_C(x) x##U
|
||||
|
||||
#define I32_C(x) x
|
||||
#define U32_C(x) x##U
|
||||
|
||||
#define I64_C(x) x##LL
|
||||
#define U64_C(x) x##ULL
|
||||
""");
|
||||
_writer.WriteLine();
|
||||
|
||||
_writer.WriteLine("// Struct definitions");
|
||||
foreach (var structType in _structTypes)
|
||||
{
|
||||
_writer.WriteLine("typedef struct");
|
||||
_writer.WriteLine("{");
|
||||
using (_writer.Indent())
|
||||
{
|
||||
foreach (var field in structType.Fields)
|
||||
{
|
||||
_writer.WriteLine($"{MapType(field.Type)} {field.Name};");
|
||||
}
|
||||
}
|
||||
|
||||
_writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};");
|
||||
_writer.WriteLine();
|
||||
}
|
||||
|
||||
_writer.WriteLine("// Function declarations");
|
||||
foreach (var funcNode in _definitions.OfType<FuncNode>())
|
||||
{
|
||||
var parameters = funcNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", funcNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}"))
|
||||
: "void";
|
||||
|
||||
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
|
||||
_writer.WriteLine($"{MapType(funcNode.Signature.ReturnType)} {name}({parameters});");
|
||||
}
|
||||
|
||||
_writer.WriteLine();
|
||||
|
||||
_writer.WriteLine("// Struct function implementations");
|
||||
foreach (var structNode in _definitions.OfType<StructNode>())
|
||||
{
|
||||
_writer.WriteLine($"// {structNode.Module}::{structNode.Name}");
|
||||
foreach (var structFuncNode in structNode.Functions)
|
||||
{
|
||||
var parameters = structFuncNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}"))
|
||||
: "void";
|
||||
|
||||
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name);
|
||||
_writer.WriteLine($"{MapType(structFuncNode.Signature.ReturnType)} {name}({parameters})");
|
||||
EmitBlock(structFuncNode.Body);
|
||||
}
|
||||
}
|
||||
|
||||
_writer.WriteLine();
|
||||
|
||||
_writer.WriteLine("// Function implementations");
|
||||
foreach (var funcNode in _definitions.OfType<FuncNode>())
|
||||
{
|
||||
if (funcNode.Body == null) continue;
|
||||
|
||||
var parameters = funcNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", funcNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}"))
|
||||
: "void";
|
||||
|
||||
if (funcNode.ExternSymbol == null)
|
||||
{
|
||||
_writer.Write("static ");
|
||||
}
|
||||
|
||||
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
|
||||
_writer.WriteLine($"{MapType(funcNode.Signature.ReturnType)} {name}({parameters})");
|
||||
EmitBlock(funcNode.Body);
|
||||
_writer.WriteLine();
|
||||
}
|
||||
|
||||
return _writer.ToString();
|
||||
}
|
||||
|
||||
private void EmitStatement(StatementNode statementNode)
|
||||
{
|
||||
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 StatementStructFuncCallNode statementStructFuncCallNode:
|
||||
EmitStatementStructFuncCall(statementStructFuncCallNode);
|
||||
break;
|
||||
case VariableDeclarationNode variableDeclarationNode:
|
||||
EmitVariableDeclaration(variableDeclarationNode);
|
||||
break;
|
||||
case WhileNode whileNode:
|
||||
EmitWhile(whileNode);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(statementNode));
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitAssignment(AssignmentNode assignmentNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void EmitBreak(BreakNode breakNode)
|
||||
{
|
||||
_writer.WriteLine("break;");
|
||||
}
|
||||
|
||||
private void EmitContinue(ContinueNode continueNode)
|
||||
{
|
||||
_writer.WriteLine("continue;");
|
||||
}
|
||||
|
||||
private void EmitDefer(DeferNode deferNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void EmitIf(IfNode ifNode)
|
||||
{
|
||||
var condition = EmitExpression(ifNode.Condition);
|
||||
_writer.WriteLine($"if ({condition})");
|
||||
EmitBlock(ifNode.Body);
|
||||
ifNode.Else?.Match
|
||||
(
|
||||
elseIfNode =>
|
||||
{
|
||||
_writer.Write("else ");
|
||||
EmitIf(elseIfNode);
|
||||
},
|
||||
elseNode =>
|
||||
{
|
||||
_writer.WriteLine("else");
|
||||
EmitBlock(elseNode);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void EmitReturn(ReturnNode returnNode)
|
||||
{
|
||||
if (returnNode.Value == null)
|
||||
{
|
||||
_writer.WriteLine("return;");
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnValue = EmitExpression(returnNode.Value);
|
||||
_writer.WriteLine($"return {returnValue};");
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitStatementFuncCall(StatementFuncCallNode statementFuncCallNode)
|
||||
{
|
||||
var funcCall = EmitFuncCall(statementFuncCallNode.FuncCall);
|
||||
_writer.WriteLine($"{funcCall};");
|
||||
}
|
||||
|
||||
private void EmitStatementStructFuncCall(StatementStructFuncCallNode statementStructFuncCallNode)
|
||||
{
|
||||
var structFuncCall = EmitStructFuncCall(statementStructFuncCallNode.StructFuncCall);
|
||||
_writer.WriteLine($"{structFuncCall};");
|
||||
}
|
||||
|
||||
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
|
||||
{
|
||||
if (variableDeclarationNode.Assignment != null)
|
||||
{
|
||||
var value = EmitExpression(variableDeclarationNode.Assignment);
|
||||
_writer.WriteLine($"{MapType(variableDeclarationNode.Type)} {variableDeclarationNode.Name} = {value};");
|
||||
}
|
||||
else
|
||||
{
|
||||
_writer.WriteLine($"{MapType(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)
|
||||
{
|
||||
return expressionNode switch
|
||||
{
|
||||
ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(arrayIndexAccessNode),
|
||||
ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode),
|
||||
BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode),
|
||||
BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode),
|
||||
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),
|
||||
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
|
||||
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
|
||||
StructFuncCallNode structFuncCallNode => EmitStructFuncCall(structFuncCallNode),
|
||||
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
|
||||
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
|
||||
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(expressionNode))
|
||||
};
|
||||
}
|
||||
|
||||
private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccessNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitBoolLiteral(BoolLiteralNode boolLiteralNode)
|
||||
{
|
||||
return boolLiteralNode.Value ? "true" : "false";
|
||||
}
|
||||
|
||||
private string EmitConvertFloat(ConvertFloatNode convertFloatNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitConvertInt(ConvertIntNode convertIntNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitCStringLiteral(CStringLiteralNode cStringLiteralNode)
|
||||
{
|
||||
return $"\"{cStringLiteralNode.Value}\"";
|
||||
}
|
||||
|
||||
private string EmitDereference(DereferenceNode dereferenceNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitFloat32Literal(Float32LiteralNode float32LiteralNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitFloat64Literal(Float64LiteralNode float64LiteralNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitFuncCall(FuncCallNode funcCallNode)
|
||||
{
|
||||
var name = EmitExpression(funcCallNode.Expression);
|
||||
var parameterNames = funcCallNode.Parameters.Select(EmitExpression).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 => $"I8_C({intLiteralNode.Value})",
|
||||
16 => $"I16_C({intLiteralNode.Value})",
|
||||
32 => $"I32_C({intLiteralNode.Value})",
|
||||
64 => $"I64_C({intLiteralNode.Value})",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
private string EmitAddressOf(AddressOfNode addressOfNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitRValueIdentifier(RValueIdentifierNode rValueIdentifierNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccessNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode)
|
||||
{
|
||||
var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName);
|
||||
var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList();
|
||||
return name + "(" + string.Join(", ", parameterNames) + ")";
|
||||
}
|
||||
|
||||
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 $"({MapType(structInitializerNode.Type)}){{ {initString} }}";
|
||||
}
|
||||
|
||||
private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode)
|
||||
{
|
||||
var type = (NubIntType)uIntLiteralNode.Type;
|
||||
return type.Width switch
|
||||
{
|
||||
8 => $"U8_C({uIntLiteralNode.Value})",
|
||||
16 => $"U16_C({uIntLiteralNode.Value})",
|
||||
32 => $"U32_C({uIntLiteralNode.Value})",
|
||||
64 => $"U64_C({uIntLiteralNode.Value})",
|
||||
_ => 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)
|
||||
{
|
||||
_writer.WriteLine("{");
|
||||
using (_writer.Indent())
|
||||
{
|
||||
foreach (var statementNode in blockNode.Statements)
|
||||
{
|
||||
EmitStatement(statementNode);
|
||||
}
|
||||
}
|
||||
|
||||
_writer.WriteLine("}");
|
||||
}
|
||||
}
|
||||
70
compiler/NubLang/Generation/CWriter.cs
Normal file
70
compiler/NubLang/Generation/CWriter.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Text;
|
||||
|
||||
namespace NubLang.Generation;
|
||||
|
||||
internal class CWriter
|
||||
{
|
||||
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 CWriter _writer;
|
||||
private bool _disposed;
|
||||
|
||||
public IndentScope(CWriter writer)
|
||||
{
|
||||
_writer = writer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_writer._indentLevel--;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,7 +324,7 @@ public sealed class Parser
|
||||
}
|
||||
else
|
||||
{
|
||||
elseStatement = (Variant<IfSyntax, BlockSyntax>)ParseBlock(elseStartIndex);
|
||||
elseStatement = (Variant<IfSyntax, BlockSyntax>)ParseBlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
examples/hello-world/.gitignore
vendored
Normal file
3
examples/hello-world/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.build
|
||||
out.a
|
||||
out
|
||||
34
examples/hello-world/main.nub
Normal file
34
examples/hello-world/main.nub
Normal file
@@ -0,0 +1,34 @@
|
||||
module "main"
|
||||
|
||||
extern "puts" func puts(text: cstring)
|
||||
|
||||
struct Human
|
||||
{
|
||||
name: cstring
|
||||
|
||||
func print()
|
||||
{
|
||||
puts("human")
|
||||
}
|
||||
}
|
||||
|
||||
extern "main" func main(args: []cstring): i64
|
||||
{
|
||||
puts("test")
|
||||
let test: Human = {
|
||||
name = "uwu"
|
||||
}
|
||||
|
||||
if false
|
||||
{
|
||||
puts("uwu")
|
||||
}
|
||||
|
||||
while true
|
||||
{
|
||||
puts("count")
|
||||
}
|
||||
|
||||
test.print()
|
||||
return 0
|
||||
}
|
||||
15
examples/hello-world/makefile
Normal file
15
examples/hello-world/makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
NUBC = ../../compiler/NubLang.CLI/bin/Debug/net9.0/nubc
|
||||
|
||||
out: .build/out.o
|
||||
gcc -nostartfiles -lm -o out x86_64.s .build/out.o
|
||||
|
||||
.build/out.o: $(NUBC) main.nub
|
||||
$(NUBC) main.nub
|
||||
|
||||
.PHONY: $(NUBC)
|
||||
$(NUBC):
|
||||
dotnet build ../../compiler/NubLang.CLI/NubLang.CLI.csproj
|
||||
|
||||
clean:
|
||||
@rm -r .build 2>/dev/null || true
|
||||
@rm out 2>/dev/null || true
|
||||
10
examples/hello-world/x86_64.s
Normal file
10
examples/hello-world/x86_64.s
Normal file
@@ -0,0 +1,10 @@
|
||||
.intel_syntax noprefix
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
mov rdi, rsp
|
||||
call main
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
Reference in New Issue
Block a user