init llvm
This commit is contained in:
89
compiler/NubLang/Generation/C/CType.cs
Normal file
89
compiler/NubLang/Generation/C/CType.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
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})";
|
||||
}
|
||||
}
|
||||
581
compiler/NubLang/Generation/C/Generator.cs
Normal file
581
compiler/NubLang/Generation/C/Generator.cs
Normal file
@@ -0,0 +1,581 @@
|
||||
using NubLang.Ast;
|
||||
using NubLang.Syntax;
|
||||
|
||||
namespace NubLang.Generation.C;
|
||||
|
||||
public class Generator
|
||||
{
|
||||
private readonly CompilationUnit _compilationUnit;
|
||||
private readonly IndentedTextWriter _writer;
|
||||
private readonly Stack<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("}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user