From 242738b9b43d3dc24ffc5d2f846040a4f660bc69 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Thu, 29 Aug 2013 18:31:12 +0200 Subject: [PATCH] Initial version of strict operators --- .../PlayScript.Runtime/BinaryOperator.cs | 7 +- .../PlayScript.Runtime/Operations.cs | 48 ++++++++++++++ mcs/mcs/expression.cs | 30 ++++++--- mcs/mcs/playscript.cs | 15 +++-- mcs/mcs/ps-parser.jay | 4 +- mcs/tests/test-ps-014.play | 64 ++++++++++++++++++- 6 files changed, 149 insertions(+), 19 deletions(-) diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs index 637fe288a2c48..4c2209d419535 100644 --- a/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs @@ -52,6 +52,11 @@ public enum BinaryOperator BitwiseOr = 32, LogicalAnd = 40, - LogicalOr = 41 + LogicalOr = 41, + + StrictEquality = 50 | StrictMask, + StrictInequality = 51 | StrictMask, + + StrictMask = 1 >> 16 } } \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs index 0718b88303042..450e0d96e7aa9 100644 --- a/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs @@ -37,6 +37,11 @@ public static bool Comparison (BinaryOperator binaryOperator, object left, objec if (right is int) return Comparison (binaryOperator, left, (int) right); + if (right is string) + return Comparison (binaryOperator, left, (string) right); + + // TODO: uint, string, double, etc + return false; } @@ -46,6 +51,7 @@ public static bool Comparison (BinaryOperator binaryOperator, object left, int r var l = (int) left; switch (binaryOperator) { case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: return l == right; case BinaryOperator.Inequality: return l != right; @@ -62,6 +68,9 @@ public static bool Comparison (BinaryOperator binaryOperator, object left, int r } } + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + // TODO: uint, string, double, etc return false; @@ -73,8 +82,10 @@ public static bool Comparison (BinaryOperator binaryOperator, int left, object r var r = (int) right; switch (binaryOperator) { case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: return left == r; case BinaryOperator.Inequality: + case BinaryOperator.StrictInequality: return left != r; case BinaryOperator.GreaterThan: return left > r; @@ -89,6 +100,43 @@ public static bool Comparison (BinaryOperator binaryOperator, int left, object r } } + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + + // TODO: uint, string, double, etc + + return false; + } + + public static bool Comparison (BinaryOperator binaryOperator, object left, string right) + { + if (right is string) { + var l = (string) left; + switch (binaryOperator) { + case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: + return l == right; + case BinaryOperator.Inequality: + case BinaryOperator.StrictInequality: + return l != right; +/* TODO: rules base on char comparison but how does it work with unicode + case BinaryOperator.GreaterThan: + return l > right; + case BinaryOperator.GreaterThanOrEqual: + return l >= right; + case BinaryOperator.LessThan: + return l < right; + case BinaryOperator.LessThanOrEqual: + return l <= right; + default: + throw new NotImplementedException (binaryOperator.ToString ()); +*/ + } + } + + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + // TODO: uint, string, double, etc return false; diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 61ec4634bce22..898f801acf3d4 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -2289,8 +2289,8 @@ public enum Operator { GreaterThanOrEqual = 11 | ComparisonMask | RelationalMask, Equality = 12 | ComparisonMask | EqualityMask, Inequality = 13 | ComparisonMask | EqualityMask, - ReferenceEquality = 14 | ComparisonMask | EqualityMask, // PlayScript Reference Equality - ReferenceInequality = 15 | ComparisonMask | EqualityMask, // PlayScript Reference Inequality + StrictEquality = 14 | ComparisonMask | EqualityMask | NoUserVersion, // PlayScript Strict Equality + StrictInequality = 15 | ComparisonMask | EqualityMask | NoUserVersion, // PlayScript Strict Inequality BitwiseAnd = 16 | BitwiseMask, @@ -2316,6 +2316,7 @@ public enum Operator { DecomposedMask = 1 << 19, NullableMask = 1 << 20, + NoUserVersion = 1 << 21 } [Flags] @@ -2425,13 +2426,13 @@ string OperName (Operator oper) case Operator.Equality: s = "=="; break; - case Operator.ReferenceEquality: + case Operator.StrictEquality: s = "==="; break; case Operator.Inequality: s = "!="; break; - case Operator.ReferenceInequality: + case Operator.StrictInequality: s = "!=="; break; case Operator.BitwiseAnd: @@ -2655,10 +2656,12 @@ public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l break; case Operator.Equality: + case Operator.StrictEquality: opcode = OpCodes.Ceq; break; case Operator.Inequality: + case Operator.StrictInequality: ec.Emit (OpCodes.Ceq); ec.EmitInt (0); @@ -2769,9 +2772,11 @@ public Expression ResolveOperator (ResolveContext rc) return ResolveOperatorPointer (rc, l, r); // User operators - expr = ResolveUserOperator (rc, left, right); - if (expr != null) - return expr; + if ((oper & Operator.NoUserVersion) == 0) { + expr = ResolveUserOperator (rc, left, right); + if (expr != null) + return expr; + } bool lenum = l.IsEnum; @@ -2833,7 +2838,14 @@ public Expression ResolveOperator (ResolveContext rc) // Equality operators are more complicated // if ((oper & Operator.EqualityMask) != 0) { - return ResolveEquality (rc, l, r, primitives_only); + expr = ResolveEquality (rc, l, r, primitives_only); + if (primitives_only) + return expr; + + if (oper == Operator.StrictEquality || oper == Operator.StrictInequality) + return PlayScript.BinaryOperators.ResolveOperator (rc, this, left, right); + + return expr; } expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only); @@ -4452,6 +4464,7 @@ public override void EmitBranchable (EmitContext ec, Label target, bool on_true) switch (oper){ case Operator.Equality: + case Operator.StrictEquality: if (on_true) ec.Emit (OpCodes.Beq, target); else @@ -4459,6 +4472,7 @@ public override void EmitBranchable (EmitContext ec, Label target, bool on_true) break; case Operator.Inequality: + case Operator.StrictInequality: if (on_true) ec.Emit (OpCodes.Bne_Un, target); else diff --git a/mcs/mcs/playscript.cs b/mcs/mcs/playscript.cs index 7d5b52f300d4b..a0f5fe5def6cd 100644 --- a/mcs/mcs/playscript.cs +++ b/mcs/mcs/playscript.cs @@ -193,31 +193,32 @@ class BinaryOperators { public static Expression ResolveOperator (ResolveContext rc, Binary op, Expression left, Expression right) { - string method, oper; + string method = "Comparison"; + string oper; switch (op.Oper) { case Binary.Operator.Equality: oper = "Equality"; - method = "Comparison"; break; case Binary.Operator.Inequality: oper = "Inequality"; - method = "Comparison"; break; case Binary.Operator.GreaterThan: oper = "GreaterThan"; - method = "Comparison"; break; case Binary.Operator.GreaterThanOrEqual: oper = "GreaterThanOrEqual"; - method = "Comparison"; break; case Binary.Operator.LessThan: oper = "LessThan"; - method = "Comparison"; break; case Binary.Operator.LessThanOrEqual: oper = "LessThanOrEqual"; - method = "Comparison"; + break; + case Binary.Operator.StrictEquality: + oper = "StrictEquality"; + break; + case Binary.Operator.StrictInequality: + oper = "StrictInequality"; break; default: throw new NotImplementedException (); diff --git a/mcs/mcs/ps-parser.jay b/mcs/mcs/ps-parser.jay index c33cd03fb4b88..721c0ca7f7010 100644 --- a/mcs/mcs/ps-parser.jay +++ b/mcs/mcs/ps-parser.jay @@ -3690,12 +3690,12 @@ equality_expression } | equality_expression OP_REF_EQ relational_expression { - $$ = new Binary (Binary.Operator.ReferenceEquality, (Expression) $1, (Expression) $3); + $$ = new Binary (Binary.Operator.StrictEquality, (Expression) $1, (Expression) $3); lbag.AddLocation ($$, GetLocation ($2)); } | equality_expression OP_REF_NE relational_expression { - $$ = new Binary (Binary.Operator.ReferenceInequality, (Expression) $1, (Expression) $3); + $$ = new Binary (Binary.Operator.StrictInequality, (Expression) $1, (Expression) $3); lbag.AddLocation ($$, GetLocation ($2)); } ; diff --git a/mcs/tests/test-ps-014.play b/mcs/tests/test-ps-014.play index ea15f41236413..ab02a95815138 100644 --- a/mcs/tests/test-ps-014.play +++ b/mcs/tests/test-ps-014.play @@ -2,7 +2,7 @@ package { public class BinaryOperations { - public static function Main ():int + static function MixedTypes ():int { var a:Object = 400; if (a != 400) @@ -10,6 +10,68 @@ package if (400 != a) return 2; + + return 0; + } + + static function StrictEquality ():int + { + var i:int = 4; + var i2:int = 4; + + if (!(i == i2)) + return 1; + if (!(i === i2)) + return 2; + + var s:String = "x"; + var s2:String = "x"; + + if (!(s == s2)) + return 3; + if (!(s === s2)) + return 4; + + var d:Number = 2.0; + var di2:int = 2; + + if (!(d == di2)) + return 5; + + var o:Object = new Object (); + var o2:Object = new Object (); + if (o == o2) + return 6; + if (o === o2) + return 7; + + var o3:Object = 6; + var o4:Object = 6; + if (!(o3 == o4)) + return 8; + if (!(o3 === o4)) + return 9; + + var os:Object = "oo"; + var os2:Object = "oo"; + if (!(os == os2)) + return 10; + if (!(os === os2)) + return 11; + + return 0; + } + + public static function Main ():int + { + var r:int; + r = MixedTypes (); + if (r != 0) + return r + 100; + + r = StrictEquality (); + if (r != 0) + return r + 200; trace ("ok"); return 0;