Add float to int builtin

This commit is contained in:
nub31
2025-09-28 22:48:32 +02:00
parent a2bdf47f5d
commit c489f23c41
6 changed files with 111 additions and 15 deletions

View File

@@ -645,7 +645,8 @@ public class QBEGenerator
StructFuncCallNode expr => EmitStructFuncCall(expr),
StructInitializerNode expr => EmitStructInitializer(expr),
UnaryExpressionNode expr => EmitUnaryExpression(expr),
SizeCompilerMacroNode expr => $"{SizeOf(expr.TargetType)}",
SizeBuiltinNode expr => $"{SizeOf(expr.TargetType)}",
FloatToIntBuiltinNode expr => EmitFloatToIntBuiltin(expr),
_ => throw new ArgumentOutOfRangeException(nameof(rValue))
};
}
@@ -1106,6 +1107,31 @@ public class QBEGenerator
return result;
}
private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToInt)
{
var value = EmitExpression(floatToInt.Value);
var method = floatToInt.TargetType.Signed switch
{
true => floatToInt.ValueType.Width switch
{
32 => "stosi",
64 => "dtosi",
_ => throw new ArgumentOutOfRangeException()
},
false => floatToInt.ValueType.Width switch
{
32 => "stoui",
64 => "dtoui",
_ => throw new ArgumentOutOfRangeException()
}
};
var result = TmpName();
_writer.Indented($"{result} {QBEAssign(floatToInt.TargetType)} {method} {value}");
return result;
}
private string EmitFuncCall(FuncCallNode funcCall)
{
var funcPointer = EmitExpression(funcCall.Expression);

View File

@@ -461,7 +461,7 @@ public sealed class Parser
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
Symbol.Struct => ParseStructInitializer(startIndex),
Symbol.At => ParseCompilerMacro(startIndex),
Symbol.At => ParseBuiltinFunction(startIndex),
_ => throw new ParseException(Diagnostic
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
.WithHelp("Expected '(', '-', '!', '[' or '{'")
@@ -478,7 +478,7 @@ public sealed class Parser
return ParsePostfixOperators(expr);
}
private ExpressionSyntax ParseCompilerMacro(int startIndex)
private ExpressionSyntax ParseBuiltinFunction(int startIndex)
{
var name = ExpectIdentifier();
ExpectSymbol(Symbol.OpenParen);
@@ -489,7 +489,7 @@ public sealed class Parser
{
var type = ParseType();
ExpectSymbol(Symbol.CloseParen);
return new SizeCompilerMacroSyntax(GetTokens(startIndex), type);
return new SizeBuiltinSyntax(GetTokens(startIndex), type);
}
case "interpret":
{
@@ -497,11 +497,19 @@ public sealed class Parser
ExpectSymbol(Symbol.Comma);
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return new InterpretCompilerMacroSyntax(GetTokens(startIndex), type, expression);
return new InterpretBuiltinSyntax(GetTokens(startIndex), type, expression);
}
case "floatToInt":
{
var type = ParseType();
ExpectSymbol(Symbol.Comma);
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return new FloatToIntBuiltinSyntax(GetTokens(startIndex), type, expression);
}
default:
{
throw new ParseException(Diagnostic.Error("Unknown compiler macro").At(name).Build());
throw new ParseException(Diagnostic.Error($"Unknown builtin {name.Value}").At(name).Build());
}
}
}

View File

@@ -58,6 +58,8 @@ public record StructInitializerSyntax(List<Token> Tokens, TypeSyntax? StructType
public record DereferenceSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record SizeCompilerMacroSyntax(List<Token> Tokens, TypeSyntax Type) : ExpressionSyntax(Tokens);
public record SizeBuiltinSyntax(List<Token> Tokens, TypeSyntax Type) : ExpressionSyntax(Tokens);
public record InterpretCompilerMacroSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record InterpretBuiltinSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record FloatToIntBuiltinSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Value) : ExpressionSyntax(Tokens);

View File

@@ -78,4 +78,6 @@ public record ConvertIntNode(NubType Type, ExpressionNode Value, NubIntType Valu
public record ConvertFloatNode(NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Type);
public record SizeCompilerMacroNode(NubType Type, NubType TargetType) : RValueExpressionNode(Type);
public record SizeBuiltinNode(NubType Type, NubType TargetType) : RValueExpressionNode(Type);
public record FloatToIntBuiltinNode(NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Type);

View File

@@ -305,8 +305,9 @@ public sealed class TypeChecker
LiteralSyntax expression => CheckLiteral(expression, expectedType),
StructFieldAccessSyntax expression => CheckStructFieldAccess(expression),
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
InterpretCompilerMacroSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
SizeCompilerMacroSyntax expression => new SizeCompilerMacroNode(new NubIntType(false, 64), ResolveType(expression.Type)),
InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
SizeBuiltinSyntax expression => new SizeBuiltinNode(new NubIntType(false, 64), ResolveType(expression.Type)),
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
@@ -334,6 +335,29 @@ public sealed class TypeChecker
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {result.Type} to {expectedType}").At(node).Build());
}
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression)
{
var value = CheckExpression(expression.Value);
if (value.Type is not NubFloatType sourceFloatType)
{
throw new TypeCheckerException(Diagnostic
.Error("Source type of float to int conversion must be an float")
.At(expression.Value)
.Build());
}
var targetType = ResolveType(expression.Type);
if (targetType is not NubIntType targetIntType)
{
throw new TypeCheckerException(Diagnostic
.Error("Target type of float to int conversion must be an integer")
.At(expression.Type)
.Build());
}
return new FloatToIntBuiltinNode(targetIntType, value, sourceFloatType, targetIntType);
}
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
{
var target = CheckExpression(expression.Target);
@@ -652,10 +676,25 @@ public sealed class TypeChecker
{
case LiteralKind.Integer:
{
var type = expectedType as NubIntType ?? new NubIntType(true, 64);
return type.Signed
? new IntLiteralNode(type, long.Parse(expression.Value))
: new UIntLiteralNode(type, ulong.Parse(expression.Value));
if (expectedType is NubIntType intType)
{
return intType.Signed
? new IntLiteralNode(intType, long.Parse(expression.Value))
: new UIntLiteralNode(intType, ulong.Parse(expression.Value));
}
if (expectedType is NubFloatType floatType)
{
return floatType.Width switch
{
32 => new Float32LiteralNode(floatType, float.Parse(expression.Value)),
64 => new Float64LiteralNode(floatType, double.Parse(expression.Value)),
_ => throw new ArgumentOutOfRangeException()
};
}
var type = new NubIntType(true, 64);
return new IntLiteralNode(type, long.Parse(expression.Value));
}
case LiteralKind.Float:
{

View File

@@ -6,11 +6,30 @@ module "main"
extern "main" func main(args: []cstring): i64
{
raylib::InitWindow(1600, 900, "Hi from nub-lang")
raylib::SetTargetFPS(240)
let x: i32 = 0
let y: i32 = 0
let width: i32 = 100
let height: i32 = 100
let direction: raylib::Vector2 = { x = 1 y = 1 }
let bgColor: raylib::Color = { r = 0 g = 0 b = 0 a = 255 }
let color: raylib::Color = { r = 255 g = 255 b = 255 a = 255 }
while !raylib::WindowShouldClose()
{
raylib::BeginDrawing()
{
raylib::ClearBackground(bgColor);
raylib::DrawRectangle(x, y, width, height, color)
}
raylib::EndDrawing()
x = x + @floatToInt(i32, direction.x)
y = y + @floatToInt(i32, direction.y)
}
return 0