Allow for implicit int conversion to larger type
This commit is contained in:
@@ -1,37 +1,13 @@
|
|||||||
// c
|
// c
|
||||||
extern func puts(text: cstring)
|
extern func puts(text: cstring)
|
||||||
|
|
||||||
interface Printable
|
|
||||||
{
|
|
||||||
func print()
|
|
||||||
func test()
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Human : Printable
|
|
||||||
{
|
|
||||||
name: cstring
|
|
||||||
age: u32
|
|
||||||
|
|
||||||
func print()
|
|
||||||
{
|
|
||||||
puts(this.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func test()
|
|
||||||
{
|
|
||||||
puts("test")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main(args: []cstring): i64
|
func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
let x = struct Human {
|
let x: i32 = 23
|
||||||
name = "Oliver"
|
test(x)
|
||||||
age = 23
|
|
||||||
}
|
|
||||||
|
|
||||||
x.print()
|
|
||||||
x.test()
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func test(test: u8)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -600,6 +600,8 @@ public class QBEGenerator
|
|||||||
FuncCallNode funcCall => EmitFuncCall(funcCall),
|
FuncCallNode funcCall => EmitFuncCall(funcCall),
|
||||||
InterfaceFuncCallNode interfaceFuncCall => EmitInterfaceFuncCall(interfaceFuncCall),
|
InterfaceFuncCallNode interfaceFuncCall => EmitInterfaceFuncCall(interfaceFuncCall),
|
||||||
InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer),
|
InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer),
|
||||||
|
ConvertIntNode convertInt => EmitConvertInt(convertInt),
|
||||||
|
ConvertFloatNode convertFloat => EmitConvertFloat(convertFloat),
|
||||||
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
|
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
|
||||||
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
|
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
|
||||||
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
|
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
|
||||||
@@ -1118,6 +1120,59 @@ public class QBEGenerator
|
|||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string EmitConvertInt(ConvertIntNode convertInt)
|
||||||
|
{
|
||||||
|
var value = EmitExpression(convertInt.Value);
|
||||||
|
|
||||||
|
if (convertInt.ValueType == convertInt.TargetType || convertInt.ValueType.Width > convertInt.TargetType.Width)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var method = convertInt.ValueType.Signed switch
|
||||||
|
{
|
||||||
|
true => convertInt.ValueType.Width switch
|
||||||
|
{
|
||||||
|
8 => "extsb",
|
||||||
|
16 => "extsh",
|
||||||
|
32 => "extsw",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
},
|
||||||
|
false => convertInt.ValueType.Width switch
|
||||||
|
{
|
||||||
|
8 => "extub",
|
||||||
|
16 => "extuh",
|
||||||
|
32 => "extuw",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = TmpName();
|
||||||
|
_writer.Indented($"{result} {QBEAssign(convertInt.TargetType)} {method} {value}");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EmitConvertFloat(ConvertFloatNode convertFloat)
|
||||||
|
{
|
||||||
|
var value = EmitExpression(convertFloat.Value);
|
||||||
|
|
||||||
|
if (convertFloat.ValueType == convertFloat.TargetType)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var method = convertFloat.ValueType.Width switch
|
||||||
|
{
|
||||||
|
32 => "exts",
|
||||||
|
64 => "truncd",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = TmpName();
|
||||||
|
_writer.Indented($"{result} {QBEAssign(convertFloat.TargetType)} {method} {value}");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private string EmitFuncCall(FuncCallNode funcCall)
|
private string EmitFuncCall(FuncCallNode funcCall)
|
||||||
{
|
{
|
||||||
var funcPointer = EmitExpression(funcCall.Expression);
|
var funcPointer = EmitExpression(funcCall.Expression);
|
||||||
|
|||||||
@@ -59,4 +59,8 @@ public record StructInitializerNode(StructTypeNode StructType, Dictionary<string
|
|||||||
|
|
||||||
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type);
|
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type);
|
||||||
|
|
||||||
public record InterfaceInitializerNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : LValueExpressionNode(Type);
|
public record InterfaceInitializerNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : LValueExpressionNode(Type);
|
||||||
|
|
||||||
|
public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode TargetType, IntTypeNode ValueType) : RValueExpressionNode(Type);
|
||||||
|
|
||||||
|
public record ConvertFloatNode(TypeNode Type, ExpressionNode Value, FloatTypeNode TargetType, FloatTypeNode ValueType) : RValueExpressionNode(Type);
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public sealed class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckerException(Diagnostic.Error("Cannot assign to rvalue").Build());
|
throw new TypeCheckerException(Diagnostic.Error("Cannot assign to rvalue").Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = CheckExpression(statement.Value, target.Type);
|
var value = CheckExpression(statement.Value, target.Type);
|
||||||
return new AssignmentNode(targetLValue, value);
|
return new AssignmentNode(targetLValue, value);
|
||||||
}
|
}
|
||||||
@@ -296,13 +296,25 @@ public sealed class TypeChecker
|
|||||||
|
|
||||||
private ExpressionNode CheckConversion(TypeNode targetType, ExpressionNode expression)
|
private ExpressionNode CheckConversion(TypeNode targetType, ExpressionNode expression)
|
||||||
{
|
{
|
||||||
// todo(nub): Add conversions for primitive types such as i32 -> i64 etc.
|
if (expression.Type is StructTypeNode structType && targetType is InterfaceTypeNode interfaceType)
|
||||||
switch (expression.Type)
|
|
||||||
{
|
{
|
||||||
case StructTypeNode structType when targetType is InterfaceTypeNode interfaceType:
|
return new InterfaceInitializerNode(interfaceType, interfaceType, structType, expression);
|
||||||
{
|
}
|
||||||
return new InterfaceInitializerNode(interfaceType, interfaceType, structType, expression);
|
|
||||||
}
|
if (expression.Type is IntTypeNode sourceIntType && targetType is IntTypeNode targetIntType)
|
||||||
|
{
|
||||||
|
// if ((sourceIntType.Width < targetIntType.Width) || (sourceIntType.Width == targetIntType.Width && sourceIntType.Signed != targetIntType.Signed))
|
||||||
|
// {
|
||||||
|
return new ConvertIntNode(targetIntType, expression, targetIntType, sourceIntType);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression.Type is FloatTypeNode sourceFloatType && targetType is FloatTypeNode targetFloatType)
|
||||||
|
{
|
||||||
|
// if (sourceFloatType.Width < targetFloatType.Width)
|
||||||
|
// {
|
||||||
|
return new ConvertFloatNode(targetFloatType, expression, targetFloatType, sourceFloatType);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {expression.Type} to {targetType}").Build());
|
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {expression.Type} to {targetType}").Build());
|
||||||
@@ -316,7 +328,7 @@ public sealed class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckerException(Diagnostic.Error("Cannot take address of rvalue").Build());
|
throw new TypeCheckerException(Diagnostic.Error("Cannot take address of rvalue").Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AddressOfNode(new PointerTypeNode(inner.Type), lValueInner);
|
return new AddressOfNode(new PointerTypeNode(inner.Type), lValueInner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user