diff --git a/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 7d1cc0a..99e9319 100644 --- a/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -1,7 +1,5 @@ using System.Diagnostics; -using System.Globalization; using System.Text; -using NubLang.Tokenization; using NubLang.TypeChecking.Node; namespace NubLang.Generation.QBE; @@ -666,6 +664,13 @@ public class QBEGenerator { return rValue switch { + StringLiteralNode expr => EmitStringLiteral(expr), + CStringLiteralNode expr => EmitCStringLiteral(expr), + IntLiteralNode expr => expr.Value.ToString(), + UIntLiteralNode expr => expr.Value.ToString(), + Float32LiteralNode expr => BitConverter.SingleToInt32Bits(expr.Value).ToString(), + Float64LiteralNode expr => BitConverter.DoubleToInt64Bits(expr.Value).ToString(), + BoolLiteralNode expr => expr.Value ? "1" : "0", AddressOfNode expr => EmitAddressOf(expr.LValue), ArrayInitializerNode expr => EmitArrayInitializer(expr), BinaryExpressionNode expr => EmitBinaryExpression(expr), @@ -675,7 +680,6 @@ public class QBEGenerator FuncCallNode expr => EmitFuncCall(expr), FuncIdentifierNode expr => FuncName(expr.Module, expr.Name, expr.ExternSymbol), FuncParameterIdentifierNode expr => $"%{expr.Name}", - LiteralNode expr => EmitLiteral(expr), StructFuncCallNode expr => EmitStructFuncCall(expr), StructInitializerNode expr => EmitStructInitializer(expr), UnaryExpressionNode expr => EmitUnaryExpression(expr), @@ -695,6 +699,20 @@ public class QBEGenerator return EmitLoad(lValue.Type, address); } + private string EmitStringLiteral(StringLiteralNode expr) + { + var stringLiteral = new StringLiteral(expr.Value, StringName()); + _stringLiterals.Add(stringLiteral); + return stringLiteral.Name; + } + + private string EmitCStringLiteral(CStringLiteralNode expr) + { + var cStringLiteral = new CStringLiteral(expr.Value, CStringName()); + _cStringLiterals.Add(cStringLiteral); + return cStringLiteral.Name; + } + private string EmitArrayInitializer(ArrayInitializerNode arrayInitializer) { var capacity = EmitExpression(arrayInitializer.Capacity); @@ -922,88 +940,6 @@ public class QBEGenerator }; } - private string EmitLiteral(LiteralNode literal) - { - switch (literal.Kind) - { - case LiteralKind.Integer: - { - if (literal.Type is FloatTypeNode { Width: 32 }) - { - var value = float.Parse(literal.Value, CultureInfo.InvariantCulture); - var bits = BitConverter.SingleToInt32Bits(value); - return bits.ToString(); - } - - if (literal.Type is FloatTypeNode { Width: 64 }) - { - var value = double.Parse(literal.Value, CultureInfo.InvariantCulture); - var bits = BitConverter.DoubleToInt64Bits(value); - return bits.ToString(); - } - - if (literal.Type is IntTypeNode) - { - return literal.Value; - } - - break; - } - case LiteralKind.Float: - { - if (literal.Type is IntTypeNode) - { - return literal.Value.Split(".").First(); - } - - if (literal.Type is FloatTypeNode { Width: 32 }) - { - var value = float.Parse(literal.Value, CultureInfo.InvariantCulture); - var bits = BitConverter.SingleToInt32Bits(value); - return bits.ToString(); - } - - if (literal.Type is FloatTypeNode { Width: 64 }) - { - var value = double.Parse(literal.Value, CultureInfo.InvariantCulture); - var bits = BitConverter.DoubleToInt64Bits(value); - return bits.ToString(); - } - - break; - } - case LiteralKind.String: - { - if (literal.Type is StringTypeNode) - { - var stringLiteral = new StringLiteral(literal.Value, StringName()); - _stringLiterals.Add(stringLiteral); - return stringLiteral.Name; - } - - if (literal.Type is CStringTypeNode) - { - var cStringLiteral = new CStringLiteral(literal.Value, CStringName()); - _cStringLiterals.Add(cStringLiteral); - return cStringLiteral.Name; - } - - break; - } - case LiteralKind.Bool: - { - if (literal.Type is BoolTypeNode) - { - return bool.Parse(literal.Value) ? "1" : "0"; - } - - break; - } - } - - throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}"); - } - private string EmitStructInitializer(StructInitializerNode structInitializer) { var destination = TmpName(); diff --git a/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs b/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs index 8e28030..1aef4ed 100644 --- a/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs +++ b/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs @@ -1,6 +1,4 @@ -using NubLang.Tokenization; - -namespace NubLang.TypeChecking.Node; +namespace NubLang.TypeChecking.Node; public enum UnaryOperator { @@ -36,6 +34,20 @@ public abstract record LValueExpressionNode(TypeNode Type) : ExpressionNode(Type public abstract record RValueExpressionNode(TypeNode Type) : ExpressionNode(Type); +public record StringLiteralNode(TypeNode Type, string Value) : RValueExpressionNode(Type); + +public record CStringLiteralNode(TypeNode Type, string Value) : RValueExpressionNode(Type); + +public record IntLiteralNode(TypeNode Type, long Value) : RValueExpressionNode(Type); + +public record UIntLiteralNode(TypeNode Type, ulong Value) : RValueExpressionNode(Type); + +public record Float32LiteralNode(TypeNode Type, float Value) : RValueExpressionNode(Type); + +public record Float64LiteralNode(TypeNode Type, double Value) : RValueExpressionNode(Type); + +public record BoolLiteralNode(TypeNode Type, bool Value) : RValueExpressionNode(Type); + public record BinaryExpressionNode(TypeNode Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right) : RValueExpressionNode(Type); public record UnaryExpressionNode(TypeNode Type, UnaryOperator Operator, ExpressionNode Operand) : RValueExpressionNode(Type); @@ -56,8 +68,6 @@ public record ArrayIndexAccessNode(TypeNode Type, ExpressionNode Target, Express public record AddressOfNode(TypeNode Type, LValueExpressionNode LValue) : RValueExpressionNode(Type); -public record LiteralNode(TypeNode Type, string Value, LiteralKind Kind) : RValueExpressionNode(Type); - public record StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, ExpressionNode Target, string Field) : LValueExpressionNode(Type); public record StructInitializerNode(StructTypeNode StructType, Dictionary Initializers) : RValueExpressionNode(StructType); diff --git a/compiler/NubLang/TypeChecking/TypeChecker.cs b/compiler/NubLang/TypeChecking/TypeChecker.cs index e606ad2..5c04497 100644 --- a/compiler/NubLang/TypeChecking/TypeChecker.cs +++ b/compiler/NubLang/TypeChecking/TypeChecker.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Globalization; using NubLang.Diagnostics; using NubLang.Modules; using NubLang.Parsing.Syntax; @@ -618,19 +619,42 @@ public sealed class TypeChecker throw new TypeCheckerException(Diagnostic.Error($"No exported symbol {expression.Name} not found in module {expression.Module}").At(expression).Build()); } - private LiteralNode CheckLiteral(LiteralSyntax expression, TypeNode? expectedType) + private ExpressionNode CheckLiteral(LiteralSyntax expression, TypeNode? expectedType) { - // todo(nub31): Check if the types can actually be represented as another one. For example, an int should be passed when a string is expected - var type = expectedType ?? expression.Kind switch + switch (expression.Kind) { - LiteralKind.Integer => new IntTypeNode(true, 64), - LiteralKind.Float => new FloatTypeNode(64), - LiteralKind.String => new StringTypeNode(), - LiteralKind.Bool => new BoolTypeNode(), - _ => throw new ArgumentOutOfRangeException() - }; - - return new LiteralNode(type, expression.Value, expression.Kind); + case LiteralKind.Integer: + { + var type = expectedType as IntTypeNode ?? new IntTypeNode(true, 64); + return type.Signed + ? new IntLiteralNode(type, long.Parse(expression.Value)) + : new UIntLiteralNode(type, ulong.Parse(expression.Value)); + } + case LiteralKind.Float: + { + var type = expectedType as FloatTypeNode ?? new FloatTypeNode(64); + return type.Width == 32 + ? new Float32LiteralNode(type, float.Parse(expression.Value, CultureInfo.InvariantCulture)) + : new Float64LiteralNode(type, double.Parse(expression.Value, CultureInfo.InvariantCulture)); + } + case LiteralKind.String: + { + return expectedType switch + { + CStringTypeNode => new CStringLiteralNode(expectedType, expression.Value), + StringTypeNode => new StringLiteralNode(expectedType, expression.Value), + _ => new CStringLiteralNode(new CStringTypeNode(), expression.Value) + }; + } + case LiteralKind.Bool: + { + return new BoolLiteralNode(new BoolTypeNode(), bool.Parse(expression.Value)); + } + default: + { + throw new ArgumentOutOfRangeException(nameof(expression.Kind), $"Unknown literal kind: {expression.Kind}"); + } + } } private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression) diff --git a/example/src/main.nub b/example/src/main.nub index 2ee728d..89fbe8a 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -25,10 +25,12 @@ extern "main" func main(args: []cstring): i64 puts(me.name) + test(32) + return 0 } -func test() +func test(x: u8) { } \ No newline at end of file