using NubLang.Ast; namespace NubLang.Generation; public class CGenerator { private readonly List _definitions; private readonly HashSet _structTypes; private readonly CWriter _writer; public CGenerator(List definitions, HashSet 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()) { 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()) { _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()) { 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(); 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("}"); } }