Add float to int builtin
This commit is contained in:
@@ -645,7 +645,8 @@ public class QBEGenerator
|
|||||||
StructFuncCallNode expr => EmitStructFuncCall(expr),
|
StructFuncCallNode expr => EmitStructFuncCall(expr),
|
||||||
StructInitializerNode expr => EmitStructInitializer(expr),
|
StructInitializerNode expr => EmitStructInitializer(expr),
|
||||||
UnaryExpressionNode expr => EmitUnaryExpression(expr),
|
UnaryExpressionNode expr => EmitUnaryExpression(expr),
|
||||||
SizeCompilerMacroNode expr => $"{SizeOf(expr.TargetType)}",
|
SizeBuiltinNode expr => $"{SizeOf(expr.TargetType)}",
|
||||||
|
FloatToIntBuiltinNode expr => EmitFloatToIntBuiltin(expr),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(rValue))
|
_ => throw new ArgumentOutOfRangeException(nameof(rValue))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1106,6 +1107,31 @@ public class QBEGenerator
|
|||||||
return result;
|
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)
|
private string EmitFuncCall(FuncCallNode funcCall)
|
||||||
{
|
{
|
||||||
var funcPointer = EmitExpression(funcCall.Expression);
|
var funcPointer = EmitExpression(funcCall.Expression);
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ public sealed class Parser
|
|||||||
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
|
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
|
||||||
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
|
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
|
||||||
Symbol.Struct => ParseStructInitializer(startIndex),
|
Symbol.Struct => ParseStructInitializer(startIndex),
|
||||||
Symbol.At => ParseCompilerMacro(startIndex),
|
Symbol.At => ParseBuiltinFunction(startIndex),
|
||||||
_ => throw new ParseException(Diagnostic
|
_ => throw new ParseException(Diagnostic
|
||||||
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
|
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
|
||||||
.WithHelp("Expected '(', '-', '!', '[' or '{'")
|
.WithHelp("Expected '(', '-', '!', '[' or '{'")
|
||||||
@@ -478,7 +478,7 @@ public sealed class Parser
|
|||||||
return ParsePostfixOperators(expr);
|
return ParsePostfixOperators(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseCompilerMacro(int startIndex)
|
private ExpressionSyntax ParseBuiltinFunction(int startIndex)
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier();
|
var name = ExpectIdentifier();
|
||||||
ExpectSymbol(Symbol.OpenParen);
|
ExpectSymbol(Symbol.OpenParen);
|
||||||
@@ -489,7 +489,7 @@ public sealed class Parser
|
|||||||
{
|
{
|
||||||
var type = ParseType();
|
var type = ParseType();
|
||||||
ExpectSymbol(Symbol.CloseParen);
|
ExpectSymbol(Symbol.CloseParen);
|
||||||
return new SizeCompilerMacroSyntax(GetTokens(startIndex), type);
|
return new SizeBuiltinSyntax(GetTokens(startIndex), type);
|
||||||
}
|
}
|
||||||
case "interpret":
|
case "interpret":
|
||||||
{
|
{
|
||||||
@@ -497,11 +497,19 @@ public sealed class Parser
|
|||||||
ExpectSymbol(Symbol.Comma);
|
ExpectSymbol(Symbol.Comma);
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression();
|
||||||
ExpectSymbol(Symbol.CloseParen);
|
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:
|
default:
|
||||||
{
|
{
|
||||||
throw new ParseException(Diagnostic.Error("Unknown compiler macro").At(name).Build());
|
throw new ParseException(Diagnostic.Error($"Unknown builtin {name.Value}").At(name).Build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ public record StructInitializerSyntax(List<Token> Tokens, TypeSyntax? StructType
|
|||||||
|
|
||||||
public record DereferenceSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
|
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);
|
||||||
@@ -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 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);
|
||||||
@@ -305,8 +305,9 @@ public sealed class TypeChecker
|
|||||||
LiteralSyntax expression => CheckLiteral(expression, expectedType),
|
LiteralSyntax expression => CheckLiteral(expression, expectedType),
|
||||||
StructFieldAccessSyntax expression => CheckStructFieldAccess(expression),
|
StructFieldAccessSyntax expression => CheckStructFieldAccess(expression),
|
||||||
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
|
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
|
||||||
InterpretCompilerMacroSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
|
InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
|
||||||
SizeCompilerMacroSyntax expression => new SizeCompilerMacroNode(new NubIntType(false, 64), ResolveType(expression.Type)),
|
SizeBuiltinSyntax expression => new SizeBuiltinNode(new NubIntType(false, 64), ResolveType(expression.Type)),
|
||||||
|
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
_ => 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());
|
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)
|
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
|
||||||
{
|
{
|
||||||
var target = CheckExpression(expression.Target);
|
var target = CheckExpression(expression.Target);
|
||||||
@@ -652,10 +676,25 @@ public sealed class TypeChecker
|
|||||||
{
|
{
|
||||||
case LiteralKind.Integer:
|
case LiteralKind.Integer:
|
||||||
{
|
{
|
||||||
var type = expectedType as NubIntType ?? new NubIntType(true, 64);
|
if (expectedType is NubIntType intType)
|
||||||
return type.Signed
|
{
|
||||||
? new IntLiteralNode(type, long.Parse(expression.Value))
|
return intType.Signed
|
||||||
: new UIntLiteralNode(type, ulong.Parse(expression.Value));
|
? 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:
|
case LiteralKind.Float:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,30 @@ module "main"
|
|||||||
extern "main" func main(args: []cstring): i64
|
extern "main" func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
raylib::InitWindow(1600, 900, "Hi from nub-lang")
|
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()
|
while !raylib::WindowShouldClose()
|
||||||
{
|
{
|
||||||
raylib::BeginDrawing()
|
raylib::BeginDrawing()
|
||||||
|
{
|
||||||
|
raylib::ClearBackground(bgColor);
|
||||||
|
raylib::DrawRectangle(x, y, width, height, color)
|
||||||
|
}
|
||||||
raylib::EndDrawing()
|
raylib::EndDrawing()
|
||||||
|
|
||||||
|
x = x + @floatToInt(i32, direction.x)
|
||||||
|
y = y + @floatToInt(i32, direction.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user