internal override SObject GetMember(ScriptProcessor processor, SObject accessor, bool isIndexer) { if (isIndexer && accessor.TypeOf() == LiteralTypeNumber) { if (Prototype.GetIndexerGetFunction() != IndexerGetFunction) { IndexerGetFunction = Prototype.GetIndexerGetFunction(); } return(IndexerGetFunction != null?IndexerGetFunction.Call(processor, this, this, new[] { accessor }) : processor.Undefined); } var accessorAsString = accessor as SString; var memberName = accessorAsString != null ? accessorAsString.Value : accessor.ToString(processor).Value; if (Members.ContainsKey(PropertyGetPrefix + memberName)) // getter property { return(((SFunction)Members[PropertyGetPrefix + memberName].Data).Call(processor, this, this, new SObject[] { })); } if (Members.ContainsKey(memberName)) { return(Members[memberName]); } if (Prototype != null && Prototype.HasMember(processor, memberName)) { return(Prototype.GetMember(processor, accessor, isIndexer)); } if (SuperClass != null) { return(SuperClass.GetMember(processor, accessor, isIndexer)); } return(processor.Undefined); }
/// <summary> /// Compares two objects for equality, respecting their typings. /// </summary> /// <remarks>Used by the === and !== equality operators.</remarks> public static bool StrictEquals(ScriptProcessor processor, SObject left, SObject right) { left = SObject.Unbox(left); right = SObject.Unbox(right); if (left.TypeOf() != right.TypeOf()) { return(false); } // If they are undefined or null, return true: if (left.TypeOf() == SObject.LiteralUndefined || left.TypeOf() == SObject.LiteralNull) { return(true); } // Both are numbers: if (left.TypeOf() == SObject.LiteralTypeNumber) { var numLeft = ((SNumber)left).Value; var numRight = ((SNumber)right).Value; return(Math.Abs(numLeft - numRight) < double.Epsilon); } // Both are string: if (left.TypeOf() == SObject.LiteralTypeString) { var strLeft = ((SString)left).Value; var strRight = ((SString)right).Value; return(strLeft == strRight); } // Both are bool: if (left.TypeOf() == SObject.LiteralTypeBool) { var boolLeft = ((SBool)left).Value; var boolRight = ((SBool)right).Value; return(boolLeft == boolRight); } return(ReferenceEquals(left, right)); }
internal override void SetMember(ScriptProcessor processor, SObject accessor, bool isIndexer, SObject value) { if (isIndexer) { if (Prototype.GetIndexerSetFunction() != IndexerSetFunction) { IndexerSetFunction = Prototype.GetIndexerSetFunction(); } } if (isIndexer && accessor.TypeOf() == LiteralTypeNumber && IndexerSetFunction != null) { IndexerSetFunction.Call(processor, this, this, new[] { accessor, value }); } else { var accessorAsString = accessor as SString; var memberName = accessorAsString != null ? accessorAsString.Value : accessor.ToString(processor).Value; if (Members.ContainsKey(PropertySetPrefix + memberName)) // setter property { ((SFunction)Members[PropertySetPrefix + memberName].Data).Call(processor, this, this, new[] { value }); } if (Members.ContainsKey(memberName)) { Members[memberName].Data = value; } else if (Prototype != null && Prototype.HasMember(processor, memberName) && !Prototype.IsStaticMember(memberName)) { // This is the case when new members got added to the prototype, and we haven't copied them over to the instance yet. // So we do that now, and then set the value of that member: AddMember(memberName, value); } else { SuperClass?.SetMember(processor, accessor, isIndexer, value); } } }
/// <summary> /// Compares two objects for equality, converting types if needed. /// </summary> /// <remarks>Used by the == and != equality operators.</remarks> public static bool LooseEquals(ScriptProcessor processor, SObject left, SObject right) { left = SObject.Unbox(left); right = SObject.Unbox(right); // both types are the same: if (left.TypeOf() == right.TypeOf()) { // If they are undefined or null, return true: if (left.TypeOf() == SObject.LiteralUndefined || left.TypeOf() == SObject.LiteralNull) { return(true); } // Both are numbers: if (left.TypeOf() == SObject.LiteralTypeNumber) { var numLeft = ((SNumber)left).Value; var numRight = ((SNumber)right).Value; return(Math.Abs(numLeft - numRight) < double.Epsilon); } // Both are string: if (left.TypeOf() == SObject.LiteralTypeString) { var strLeft = ((SString)left).Value; var strRight = ((SString)right).Value; return(strLeft == strRight); } // Both are bool: if (left.TypeOf() == SObject.LiteralTypeBool) { var boolLeft = ((SBool)left).Value; var boolRight = ((SBool)right).Value; return(boolLeft == boolRight); } return(ReferenceEquals(left, right)); } // null & undefined if (left.TypeOf() == SObject.LiteralNull && right.TypeOf() == SObject.LiteralUndefined || left.TypeOf() == SObject.LiteralUndefined && right.TypeOf() == SObject.LiteralNull) { return(true); } // When one is a number and another is a string, convert the string to a number and compare: if (left.TypeOf() == SObject.LiteralTypeString && right.TypeOf() == SObject.LiteralTypeNumber) { var numLeft = left.ToNumber(processor).Value; var numRight = ((SNumber)right).Value; return(Math.Abs(numLeft - numRight) < double.Epsilon); } if (left.TypeOf() == SObject.LiteralTypeNumber && right.TypeOf() == SObject.LiteralTypeString) { var numRight = right.ToNumber(processor).Value; var numLeft = ((SNumber)left).Value; return(Math.Abs(numLeft - numRight) < double.Epsilon); } if (left.TypeOf() == SObject.LiteralTypeBool) { return(LooseEquals(processor, left.ToNumber(processor), right)); } if (right.TypeOf() == SObject.LiteralTypeBool) { return(LooseEquals(processor, left, right.ToNumber(processor))); } return(false); }