diff --git a/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm b/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm index 069fc4aaae..27c5a815ef 100644 --- a/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm +++ b/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm @@ -1,18 +1,20 @@  /proc/RunTest() + // null violates the holy trichotomy here, with how it compares to an empty string. + ASSERT( (null > "") == 0 ) ASSERT( (null >= "") == 1 ) + ASSERT( (null == "") == 0 ) ASSERT( (null <= "") == 1 ) + ASSERT( (null < "") == 0 ) ASSERT( (null > 5) == 0 ) ASSERT( (null > -5) == 1 ) ASSERT( (null > "abc") == 0 ) - ASSERT( (null > "") == 0 ) ASSERT( (null > null) == 0 ) ASSERT( (null < 5) == 1 ) ASSERT( (null < -5) == 0 ) ASSERT( (null < "abc") == 1 ) - ASSERT( (null < "") == 0 ) ASSERT( (null < null) == 0 ) ASSERT( (0.15 <= null) == 0) diff --git a/DMCompiler/DM/Expressions/Binary.cs b/DMCompiler/DM/Expressions/Binary.cs index 8679fa8c53..c05a7d3d4c 100644 --- a/DMCompiler/DM/Expressions/Binary.cs +++ b/DMCompiler/DM/Expressions/Binary.cs @@ -35,6 +35,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Add(); @@ -60,6 +65,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Subtract(); @@ -85,6 +95,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Multiply(); @@ -110,6 +125,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Divide(); @@ -125,7 +145,7 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } if (lhs is Number lhsNum && rhs is Number rhsNum) { - constant = new Number(Location, lhsNum.Value % rhsNum.Value); + constant = new Number(Location, (int)lhsNum.Value % (int)rhsNum.Value); } else { constant = null; return false; @@ -135,6 +155,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Modulus(); @@ -163,6 +188,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.ModulusModulus(); @@ -188,6 +218,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Power(); @@ -213,6 +248,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BitShiftLeft(); @@ -238,6 +278,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BitShiftRight(); @@ -265,6 +310,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryAnd(); @@ -290,6 +340,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryXor(); @@ -315,6 +370,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryOr(); @@ -378,6 +438,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.GreaterThan(); @@ -387,6 +452,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x >= y internal sealed class GreaterThanOrEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.GreaterThanOrEqual(); @@ -414,6 +484,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out // x < y internal sealed class LessThan(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.LessThan(); @@ -441,6 +516,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out // x <= y internal sealed class LessThanOrEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.LessThanOrEqual(); @@ -485,6 +565,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + string endLabel = ctx.Proc.NewLabelName(); LHS.EmitPushValue(ctx); @@ -512,6 +597,21 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (LHS.TryAsConstant(ctx.Compiler, out var lhs)) { + if (lhs.IsTruthy()) { + if (RHS.TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + + RHS.EmitPushValue(ctx); + return; + } + + lhs.EmitPushValue(ctx); + return; + } + string endLabel = ctx.Proc.NewLabelName(); LHS.EmitPushValue(ctx); diff --git a/DMCompiler/DM/Expressions/Builtins.cs b/DMCompiler/DM/Expressions/Builtins.cs index 6988c48c54..02f9a0accb 100644 --- a/DMCompiler/DM/Expressions/Builtins.cs +++ b/DMCompiler/DM/Expressions/Builtins.cs @@ -709,6 +709,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Sin(); } @@ -734,6 +739,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Cos(); } @@ -759,6 +769,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Tan(); } @@ -789,6 +804,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcSin(); } @@ -819,6 +839,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcCos(); } @@ -844,6 +869,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcTan(); } @@ -873,6 +903,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + xExpr.EmitPushValue(ctx); yExpr.EmitPushValue(ctx); ctx.Proc.ArcTan2(); @@ -904,6 +939,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Sqrt(); } @@ -946,6 +986,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); if (baseExpr == null) { ctx.Proc.LogE(); @@ -976,6 +1021,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Abs(); } diff --git a/DMCompiler/DM/Expressions/Ternary.cs b/DMCompiler/DM/Expressions/Ternary.cs index c5b874a89b..8c5ba9afba 100644 --- a/DMCompiler/DM/Expressions/Ternary.cs +++ b/DMCompiler/DM/Expressions/Ternary.cs @@ -22,6 +22,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + string cLabel = ctx.Proc.NewLabelName(); string endLabel = ctx.Proc.NewLabelName(); diff --git a/DMCompiler/DM/Expressions/Unary.cs b/DMCompiler/DM/Expressions/Unary.cs index f6b07c94fb..4de2a46821 100644 --- a/DMCompiler/DM/Expressions/Unary.cs +++ b/DMCompiler/DM/Expressions/Unary.cs @@ -18,6 +18,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.Negate(); } @@ -33,6 +38,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.Not(); } @@ -44,11 +54,16 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out if (!Expr.TryAsConstant(compiler, out constant) || constant is not Number constantNum) return false; - constant = new Number(Location, ~(int)constantNum.Value); + constant = new Number(Location, (~(int)constantNum.Value) & 0xFFFFFF); return true; } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.BinaryNot(); }