diff --git a/compiler/NubLang/Ast/Node.cs b/compiler/NubLang/Ast/Node.cs index 0e9cb19..c904912 100644 --- a/compiler/NubLang/Ast/Node.cs +++ b/compiler/NubLang/Ast/Node.cs @@ -128,6 +128,8 @@ public record ConvertIntNode(List Tokens, NubType Type, ExpressionNode Va public record ConvertFloatNode(List Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Tokens, Type); +// public record ConvertConstArrayToArrayNode(List Tokens, NubType Type, ExpressionNode Value) : RValueExpressionNode(Tokens, Type); + public record SizeBuiltinNode(List Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type); public record FloatToIntBuiltinNode(List Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type); diff --git a/compiler/NubLang/Ast/TypeChecker.cs b/compiler/NubLang/Ast/TypeChecker.cs index 9813b79..90802d3 100644 --- a/compiler/NubLang/Ast/TypeChecker.cs +++ b/compiler/NubLang/Ast/TypeChecker.cs @@ -265,10 +265,10 @@ public sealed class TypeChecker return result; } - if (result.Type is NubConstArrayType && expectedType is NubArrayType) - { - 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) { diff --git a/compiler/NubLang/Generation/CType.cs b/compiler/NubLang/Generation/CType.cs new file mode 100644 index 0000000..d2c45c4 --- /dev/null +++ b/compiler/NubLang/Generation/CType.cs @@ -0,0 +1,89 @@ +using NubLang.Ast; + +namespace NubLang.Generation; + +public static class CType +{ + public static string Create(NubType type, string? variableName = null) + { + return type switch + { + NubVoidType => "void" + (variableName != null ? $" {variableName}" : ""), + NubBoolType => "bool" + (variableName != null ? $" {variableName}" : ""), + NubIntType intType => CreateIntType(intType, variableName), + NubFloatType floatType => CreateFloatType(floatType, variableName), + NubCStringType => "char*" + (variableName != null ? $" {variableName}" : ""), + NubPointerType ptr => CreatePointerType(ptr, variableName), + NubConstArrayType arr => CreateConstArrayType(arr, variableName), + NubArrayType arr => CreateArrayType(arr, variableName), + NubFuncType fn => CreateFuncType(fn, variableName), + NubStructType st => $"{st.Name}" + (variableName != null ? $" {variableName}" : ""), + _ => throw new NotSupportedException($"C type generation not supported for: {type}") + }; + } + + private static string CreateIntType(NubIntType intType, string? varName) + { + var cType = intType.Width switch + { + 8 => intType.Signed ? "int8_t" : "uint8_t", + 16 => intType.Signed ? "int16_t" : "uint16_t", + 32 => intType.Signed ? "int32_t" : "uint32_t", + 64 => intType.Signed ? "int64_t" : "uint64_t", + _ => throw new NotSupportedException($"Unsupported integer width: {intType.Width}") + }; + return cType + (varName != null ? $" {varName}" : ""); + } + + private static string CreateFloatType(NubFloatType floatType, string? varName) + { + var cType = floatType.Width switch + { + 32 => "float", + 64 => "double", + _ => throw new NotSupportedException($"Unsupported float width: {floatType.Width}") + }; + return cType + (varName != null ? $" {varName}" : ""); + } + + private static string CreatePointerType(NubPointerType ptr, string? varName) + { + var baseType = Create(ptr.BaseType); + return baseType + "*" + (varName != null ? $" {varName}" : ""); + } + + private static string CreateConstArrayType(NubConstArrayType arr, string? varName) + { + var elementType = Create(arr.ElementType); + if (varName != null) + { + return $"{elementType} {varName}[{arr.Size}]"; + } + + return $"{elementType}[{arr.Size}]"; + } + + private static string CreateArrayType(NubArrayType arr, string? varName) + { + var elementType = Create(arr.ElementType); + return elementType + "*" + (varName != null ? $" {varName}" : ""); + } + + private static string CreateFuncType(NubFuncType fn, string? varName) + { + var returnType = Create(fn.ReturnType); + var parameters = string.Join(", ", fn.Parameters.Select(p => Create(p))); + + if (string.IsNullOrEmpty(parameters)) + { + parameters = "void"; + } + + if (varName != null) + { + return $"{returnType} (*{varName})({parameters})"; + } + + return $"{returnType} (*)({parameters})"; + } +} \ No newline at end of file diff --git a/compiler/NubLang/Generation/Generator.cs b/compiler/NubLang/Generation/Generator.cs index ae15c21..7c91d07 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -22,63 +22,6 @@ public class Generator return $"_t{++_tmpIndex}"; } - private static string MapNameWithType(NubType nubType, string name) - { - var prefix = ""; - var postfix = ""; - - switch (nubType) - { - case NubCStringType or NubPointerType or NubFuncType: - prefix = "*"; - break; - case NubArrayType: - postfix = "[]"; - break; - case NubConstArrayType constArrayType: - postfix = $"[{constArrayType.Size}]"; - break; - } - - return $"{MapBaseType(nubType)} {prefix}{name}{postfix}"; - - string MapBaseType(NubType type) - { - return type switch - { - NubSliceType sliceType => throw new NotImplementedException(), - NubConstArrayType constArrayType => MapBaseType(constArrayType.ElementType), - NubArrayType arrayType => MapBaseType(arrayType.ElementType), - NubBoolType => "bool", - NubCStringType => "char", - NubFloatType floatType => floatType.Width switch - { - 32 => "f32", - 64 => "f64", - _ => throw new ArgumentOutOfRangeException() - }, - NubFuncType funcType => "void", - NubIntType intType => (intType.Signed, intType.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() - }, - NubPointerType pointerType => MapBaseType(pointerType.BaseType), - NubStringType => throw new NotImplementedException(), - NubStructType structType => StructName(structType.Module, structType.Name), - NubVoidType => "void", - _ => throw new ArgumentOutOfRangeException(nameof(type)) - }; - } - } - private static string FuncName(string module, string name, string? externSymbol) { return externSymbol ?? $"{module}_{name}"; @@ -91,7 +34,11 @@ public class Generator public string Emit() { - // note(nub31): Struct definitions + _writer.WriteLine("#include "); + _writer.WriteLine("#include "); + _writer.WriteLine("#include "); + _writer.WriteLine(); + foreach (var structType in _compilationUnit.ImportedStructTypes) { _writer.WriteLine("typedef struct"); @@ -100,7 +47,7 @@ public class Generator { foreach (var field in structType.Fields) { - _writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};"); + _writer.WriteLine($"{CType.Create(field.Type, field.Name)};"); } } @@ -113,15 +60,14 @@ public class Generator { EmitLine(prototype.Tokens.FirstOrDefault()); var parameters = prototype.Parameters.Count != 0 - ? string.Join(", ", prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name))) + ? string.Join(", ", prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) : "void"; var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol); - _writer.WriteLine($"{MapNameWithType(prototype.ReturnType, name)}({parameters});"); + _writer.WriteLine($"{CType.Create(prototype.ReturnType, name)}({parameters});"); + _writer.WriteLine(); } - _writer.WriteLine(); - // note(nub31): declare extern functions foreach (var funcNode in _compilationUnit.Functions) { @@ -129,11 +75,11 @@ public class Generator EmitLine(funcNode.Tokens.FirstOrDefault()); var parameters = funcNode.Prototype.Parameters.Count != 0 - ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name))) + ? 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($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters});"); + _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters});"); } _writer.WriteLine(); @@ -145,7 +91,7 @@ public class Generator EmitLine(funcNode.Tokens.FirstOrDefault()); var parameters = funcNode.Prototype.Parameters.Count != 0 - ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name))) + ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => CType.Create(x.Type, x.Name))) : "void"; if (funcNode.Prototype.ExternSymbol == null) @@ -154,52 +100,12 @@ public class Generator } var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); - _writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters})"); + _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters})"); EmitBlock(funcNode.Body); _writer.WriteLine(); } - return $""" - 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} - """; + return _writer.ToString(); } private void EmitStatement(StatementNode statementNode) @@ -307,7 +213,7 @@ public class Generator if (_deferStack.Peek().Count != 0) { var tmp = NewTmp(); - _writer.WriteLine($"{MapNameWithType(returnNode.Value.Type, tmp)} = {returnValue};"); + _writer.WriteLine($"{CType.Create(returnNode.Value.Type, tmp)} = {returnValue};"); var blockDefers = _deferStack.Peek(); for (var i = blockDefers.Count - 1; i >= 0; i--) @@ -334,14 +240,14 @@ public class Generator private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) { - if (variableDeclarationNode.Assignment is { Type: not NubArrayType and not NubConstArrayType }) + if (variableDeclarationNode.Assignment != null) { var value = EmitExpression(variableDeclarationNode.Assignment); - _writer.WriteLine($"{MapNameWithType(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};"); + _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};"); } else { - _writer.WriteLine($"{MapNameWithType(variableDeclarationNode.Type, variableDeclarationNode.Name)};"); + _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.Name)};"); } } @@ -362,6 +268,7 @@ public class Generator 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), @@ -385,6 +292,11 @@ public class Generator _ => throw new ArgumentOutOfRangeException(nameof(expressionNode)) }; + if (expressionNode is ConstArrayInitializerNode) + { + return expr; + } + return $"({expr})"; } @@ -397,7 +309,11 @@ public class Generator private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) { - throw new NotImplementedException(); + 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) @@ -446,9 +362,15 @@ public class Generator private string EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode) { - return string.Empty; + 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); @@ -534,7 +456,7 @@ public class Generator private string EmitFuncCall(FuncCallNode funcCallNode) { var name = EmitExpression(funcCallNode.Expression); - var parameterNames = funcCallNode.Parameters.Select(EmitExpression).ToList(); + var parameterNames = funcCallNode.Parameters.Select(x => EmitExpression(x)).ToList(); return $"{name}({string.Join(", ", parameterNames)})"; } @@ -548,10 +470,8 @@ public class Generator 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})", + 8 or 16 or 32 => intLiteralNode.Value.ToString(), + 64 => intLiteralNode.Value + "LL", _ => throw new ArgumentOutOfRangeException() }; } @@ -574,7 +494,7 @@ public class Generator private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) { - throw new NotImplementedException(); + return $"sizeof({CType.Create(sizeBuiltinNode.TargetType)})"; } private string EmitSliceArrayIndexAccess(SliceIndexAccessNode sliceIndexAccessNode) @@ -609,7 +529,7 @@ public class Generator ? "0" : string.Join(", ", initValues); - return $"({StructName(structInitializerNode.StructType.Module, structInitializerNode.StructType.Name)}){{{initString}}}"; + return $"({CType.Create(structInitializerNode.Type)}){{{initString}}}"; } private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) @@ -617,10 +537,8 @@ public class Generator 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})", + 8 or 16 or 32 => uIntLiteralNode.Value + "U", + 64 => uIntLiteralNode.Value + "ULL", _ => throw new ArgumentOutOfRangeException() }; } diff --git a/examples/array/main.nub b/examples/array/main.nub index 75c1bc0..513b656 100644 --- a/examples/array/main.nub +++ b/examples/array/main.nub @@ -4,7 +4,7 @@ extern "puts" func puts(text: cstring) extern "main" func main(argc: i64, argv: [?]cstring): i64 { - let x: [?]i32 = [10]i32 + let x = [10]i32 x[0] = 23 return 0 } \ No newline at end of file