Better literal handling
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NubLang.Tokenization;
|
|
||||||
using NubLang.TypeChecking.Node;
|
using NubLang.TypeChecking.Node;
|
||||||
|
|
||||||
namespace NubLang.Generation.QBE;
|
namespace NubLang.Generation.QBE;
|
||||||
@@ -666,6 +664,13 @@ public class QBEGenerator
|
|||||||
{
|
{
|
||||||
return rValue switch
|
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),
|
AddressOfNode expr => EmitAddressOf(expr.LValue),
|
||||||
ArrayInitializerNode expr => EmitArrayInitializer(expr),
|
ArrayInitializerNode expr => EmitArrayInitializer(expr),
|
||||||
BinaryExpressionNode expr => EmitBinaryExpression(expr),
|
BinaryExpressionNode expr => EmitBinaryExpression(expr),
|
||||||
@@ -675,7 +680,6 @@ public class QBEGenerator
|
|||||||
FuncCallNode expr => EmitFuncCall(expr),
|
FuncCallNode expr => EmitFuncCall(expr),
|
||||||
FuncIdentifierNode expr => FuncName(expr.Module, expr.Name, expr.ExternSymbol),
|
FuncIdentifierNode expr => FuncName(expr.Module, expr.Name, expr.ExternSymbol),
|
||||||
FuncParameterIdentifierNode expr => $"%{expr.Name}",
|
FuncParameterIdentifierNode expr => $"%{expr.Name}",
|
||||||
LiteralNode expr => EmitLiteral(expr),
|
|
||||||
StructFuncCallNode expr => EmitStructFuncCall(expr),
|
StructFuncCallNode expr => EmitStructFuncCall(expr),
|
||||||
StructInitializerNode expr => EmitStructInitializer(expr),
|
StructInitializerNode expr => EmitStructInitializer(expr),
|
||||||
UnaryExpressionNode expr => EmitUnaryExpression(expr),
|
UnaryExpressionNode expr => EmitUnaryExpression(expr),
|
||||||
@@ -695,6 +699,20 @@ public class QBEGenerator
|
|||||||
return EmitLoad(lValue.Type, address);
|
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)
|
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||||
{
|
{
|
||||||
var capacity = EmitExpression(arrayInitializer.Capacity);
|
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)
|
private string EmitStructInitializer(StructInitializerNode structInitializer)
|
||||||
{
|
{
|
||||||
var destination = TmpName();
|
var destination = TmpName();
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using NubLang.Tokenization;
|
namespace NubLang.TypeChecking.Node;
|
||||||
|
|
||||||
namespace NubLang.TypeChecking.Node;
|
|
||||||
|
|
||||||
public enum UnaryOperator
|
public enum UnaryOperator
|
||||||
{
|
{
|
||||||
@@ -36,6 +34,20 @@ public abstract record LValueExpressionNode(TypeNode Type) : ExpressionNode(Type
|
|||||||
|
|
||||||
public abstract record RValueExpressionNode(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 BinaryExpressionNode(TypeNode Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right) : RValueExpressionNode(Type);
|
||||||
|
|
||||||
public record UnaryExpressionNode(TypeNode Type, UnaryOperator Operator, ExpressionNode Operand) : 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 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 StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, ExpressionNode Target, string Field) : LValueExpressionNode(Type);
|
||||||
|
|
||||||
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(StructType);
|
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(StructType);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using NubLang.Diagnostics;
|
using NubLang.Diagnostics;
|
||||||
using NubLang.Modules;
|
using NubLang.Modules;
|
||||||
using NubLang.Parsing.Syntax;
|
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());
|
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
|
switch (expression.Kind)
|
||||||
var type = expectedType ?? expression.Kind switch
|
|
||||||
{
|
{
|
||||||
LiteralKind.Integer => new IntTypeNode(true, 64),
|
case LiteralKind.Integer:
|
||||||
LiteralKind.Float => new FloatTypeNode(64),
|
{
|
||||||
LiteralKind.String => new StringTypeNode(),
|
var type = expectedType as IntTypeNode ?? new IntTypeNode(true, 64);
|
||||||
LiteralKind.Bool => new BoolTypeNode(),
|
return type.Signed
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
? new IntLiteralNode(type, long.Parse(expression.Value))
|
||||||
};
|
: new UIntLiteralNode(type, ulong.Parse(expression.Value));
|
||||||
|
}
|
||||||
return new LiteralNode(type, expression.Value, expression.Kind);
|
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)
|
private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression)
|
||||||
|
|||||||
@@ -25,10 +25,12 @@ extern "main" func main(args: []cstring): i64
|
|||||||
|
|
||||||
puts(me.name)
|
puts(me.name)
|
||||||
|
|
||||||
|
test(32)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func test()
|
func test(x: u8)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user