internal override SObject GetMember(ScriptProcessor processor, SObject accessor, bool isIndexer) { if (isIndexer && accessor.TypeOf() == LITERAL_TYPE_NUMBER) { if (IndexerGetFunction != null) { return IndexerGetFunction.Call(processor, this, this, new SObject[] { accessor }); } else { return processor.Undefined; } } string memberName; if (accessor is SString) memberName = ((SString)accessor).Value; else memberName = accessor.ToString(processor).Value; if (Members.ContainsKey(memberName)) { return Members[memberName]; } else if (Prototype != null && Prototype.HasMember(processor, memberName)) { return Prototype.GetMember(processor, accessor, isIndexer); } else if (SuperClass != null) { return SuperClass.GetMember(processor, accessor, isIndexer); } return processor.Undefined; }
internal static string AddOperator(ScriptProcessor processor, SObject left, SObject right) { if (left is SString || right is SString) { string strLeft, strRight; if (left is SString) strLeft = ((SString)left).Value; else strLeft = left.ToString(processor).Value; if (right is SString) strRight = ((SString)right).Value; else strRight = right.ToString(processor).Value; return strLeft + strRight; } else { var numbers = GetNumericOperatorParameters(processor, left, right); return SNumber.ConvertToScriptString(numbers.Item1 + numbers.Item2); } }
internal override void SetMember(ScriptProcessor processor, SObject accessor, bool isIndexer, SObject value) { if (processor.Context.HasCallback(CallbackType.SetMember)) { var callback = (DSetMember)processor.Context.GetCallback(CallbackType.SetMember); Task task = Task.Factory.StartNew(() => callback(processor, accessor, isIndexer, value)); task.Wait(); } else { processor.ErrorHandler.ThrowError(ErrorType.APIError, ErrorHandler.MESSAGE_API_NOT_SUPPORTED); } }
internal override SObject ExecuteMethod(ScriptProcessor processor, string methodName, SObject caller, SObject This, SObject[] parameters) { if (processor.Context.HasCallback(CallbackType.ExecuteMethod)) { var callback = (DExecuteMethod)processor.Context.GetCallback(CallbackType.ExecuteMethod); Task<SObject> task = Task<SObject>.Factory.StartNew(() => callback(processor, methodName, parameters)); task.Wait(); return task.Result; } else { processor.ErrorHandler.ThrowError(ErrorType.APIError, ErrorHandler.MESSAGE_API_NOT_SUPPORTED); return processor.Undefined; } }
private static Tuple<double, double> GetNumericOperatorParameters(ScriptProcessor processor, SObject left, SObject right) { double numLeft, numRight; if (left is SNumber) numLeft = ((SNumber)left).Value; else numLeft = left.ToNumber(processor).Value; if (right is SNumber) numRight = ((SNumber)right).Value; else numRight = right.ToNumber(processor).Value; return new Tuple<double, double>(numLeft, numRight); }
internal override SObject GetMember(ScriptProcessor processor, SObject accessor, bool isIndexer) { if (processor.Context.HasCallback(CallbackType.GetMember)) { var callback = (DGetMember)processor.Context.GetCallback(CallbackType.GetMember); Task<SObject> task = Task<SObject>.Factory.StartNew(() => callback(processor, accessor, isIndexer)); task.Wait(); return task.Result; } else { processor.ErrorHandler.ThrowError(ErrorType.APIError, ErrorHandler.MESSAGE_API_NOT_SUPPORTED); return processor.Undefined; } }
private static Tuple<bool, bool> GetBooleanicOperatorParameters(ScriptProcessor processor, SObject left, SObject right) { bool boolLeft, boolRight; if (left is SBool) boolLeft = ((SBool)left).Value; else boolLeft = left.ToBool(processor).Value; if (right is SBool) boolRight = ((SBool)right).Value; else boolRight = right.ToBool(processor).Value; return new Tuple<bool, bool>(boolLeft, boolRight); }
internal override void SetMember(ScriptProcessor processor, SObject accessor, bool isIndexer, SObject value) { string memberName; if (accessor is SString) memberName = ((SString)accessor).Value; else memberName = accessor.ToString(processor).Value; if (_context.IsVariable(memberName)) { _context.GetVariable(memberName).Data = value; } else { processor.ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MESSAGE_REFERENCE_NOT_DEFINED, new object[] { memberName }); } }
/// <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: else if (left.TypeOf() == SObject.LITERAL_UNDEFINED || left.TypeOf() == SObject.LITERAL_NULL) { return true; } // Both are numbers: else if (left.TypeOf() == SObject.LITERAL_TYPE_NUMBER) { double numLeft = ((SNumber)left).Value; double numRight = ((SNumber)right).Value; return numLeft == numRight; } // Both are string: else if (left.TypeOf() == SObject.LITERAL_TYPE_STRING) { string strLeft = ((SString)left).Value; string strRight = ((SString)right).Value; return strLeft == strRight; } // Both are bool: else if (left.TypeOf() == SObject.LITERAL_TYPE_BOOL) { bool boolLeft = ((SBool)left).Value; bool boolRight = ((SBool)right).Value; return boolLeft == boolRight; } else { return ReferenceEquals(left, right); } }
internal override SObject ExecuteMethod(ScriptProcessor processor, string methodName, SObject caller, SObject This, SObject[] parameters) { // The statement that entered this method looks like this: this.varName(), where varName is a variable containing an SFunction object. if (_context.IsVariable(methodName)) { SVariable methodVariable = _context.GetVariable(methodName); SObject method = methodVariable.Data; if (method is SFunction) { return ((SFunction)method).Call(processor, caller, This, parameters); } else { return processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_NOT_A_FUNCTION, new object[] { methodName }); } } return processor.ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MESSAGE_REFERENCE_NOT_DEFINED, new object[] { methodName }); }
internal static string AndOperator(ScriptProcessor processor, SObject left, SObject right) { var bools = GetBooleanicOperatorParameters(processor, left, right); return SBool.ConvertToScriptString(bools.Item1 && bools.Item2); }
internal static string LargerOperator(ScriptProcessor processor, SObject left, SObject right) { var numbers = GetNumericOperatorParameters(processor, left, right); return SBool.ConvertToScriptString(numbers.Item1 > numbers.Item2); }
internal static string TypeNotEqualsOperator(ScriptProcessor processor, SObject left, SObject right) { return SBool.ConvertToScriptString(!ObjectComparer.StrictEquals(processor, left, right)); }
internal static string DecrementOperator(ScriptProcessor processor, SObject obj) { // Only variables can be decremented: if (obj is SVariable) { var svar = (SVariable)obj; svar.Data = processor.CreateNumber(svar.Data.ToNumber(processor).Value - 1D); return svar.Identifier; } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_INVALID_DECREMENT); return ""; } }
/// <summary> /// Creates an instance of the given prototype. /// </summary> internal SObject CreateInstance(Prototype prototype, SObject[] parameters) { if (!prototype.IsAbstract) return prototype.CreateInstance(_processor, parameters, true); else return _processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_ABSTRACT_NO_INSTANCE); }
internal static string NotOperator(ScriptProcessor processor, SObject obj) { return SBool.ConvertToScriptString(!obj.ToBool(processor).Value); }
internal override SObject ExecuteMethod(ScriptProcessor processor, string methodName, SObject caller, SObject This, SObject[] parameters) { if (Members.ContainsKey(methodName)) { if (Members[methodName].Data.TypeOf() == LITERAL_TYPE_FUNCTION) { return ((SFunction)Members[methodName].Data).Call(processor, caller, this, parameters); } else { return processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_NOT_A_FUNCTION, new object[] { methodName }); } } else if (Prototype != null && Prototype.HasMember(processor, methodName)) { return Prototype.ExecuteMethod(processor, methodName, caller, This, parameters); } else if (SuperClass != null) { return SuperClass.ExecuteMethod(processor, methodName, caller, This, parameters); } else { return processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_NOT_A_FUNCTION, new object[] { methodName }); } }
internal static string ModulusOperator(ScriptProcessor processor, SObject left, SObject right) { var numbers = GetNumericOperatorParameters(processor, left, right); if (numbers.Item2 == 0D) // Because, when we divide by 0, we get Infinity, but when we do (x % 0), we get NaN. Great. return SObject.LITERAL_NAN; return SNumber.ConvertToScriptString(numbers.Item1 % numbers.Item2); }
/// <summary> /// Throws an error with the given error object. /// </summary> public SObject ThrowError(SObject errorObject) { ErrorObject = errorObject; throw new ScriptException(ErrorObject); }
internal static string MultiplyOperator(ScriptProcessor processor, SObject left, SObject right) { var numbers = GetNumericOperatorParameters(processor, left, right); return SNumber.ConvertToScriptString(numbers.Item1 * numbers.Item2); }
public ScriptException(SObject errorObject) { ErrorObject = errorObject; }
internal void AddMember(string idenfifier, SObject data) { Members.Add(idenfifier, new SVariable(idenfifier, data)); }
/// <summary> /// Creates an instance with the given prototype name. /// </summary> internal SObject CreateInstance(string prototypeName, SObject[] parameters) { return CreateInstance(GetPrototype(prototypeName), parameters); }
internal static string ExponentOperator(ScriptProcessor processor, SObject left, SObject right) { var numbers = GetNumericOperatorParameters(processor, left, right); return SNumber.ConvertToScriptString(Math.Pow(numbers.Item1, numbers.Item2)); }
internal override SObject ExecuteMethod(ScriptProcessor processor, string methodName, SObject caller, SObject This, SObject[] parameters) { return Call(processor, caller, This, parameters); }
internal override void SetMember(ScriptProcessor processor, SObject accessor, bool isIndexer, SObject value) { if (isIndexer && accessor.TypeOf() == LITERAL_TYPE_NUMBER) { if (IndexerSetFunction != null) { IndexerSetFunction.Call(processor, this, this, new SObject[] { accessor, value }); } } string memberName; if (accessor is SString) memberName = ((SString)accessor).Value; else memberName = accessor.ToString(processor).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 if (SuperClass != null) { SuperClass.SetMember(processor, accessor, isIndexer, value); } }
/// <summary> /// Multiplies an object with -1. /// </summary> internal static SObject NegateNumber(ScriptProcessor processor, SObject obj) { double number; if (obj is SNumber) number = ((SNumber)obj).Value; else number = obj.ToNumber(processor).Value; return processor.CreateNumber(number * -1); }
/// <summary> /// Executes the function. /// </summary> /// <param name="processor">The processor with context that called this functions.</param> /// <param name="caller">The calling object.</param> /// <param name="This">The "This" reference used in the call context.</param> /// <param name="parameters">The parameters used in this function call.</param> public SObject Call(ScriptProcessor processor, SObject caller, SObject This, SObject[] parameters) { ScriptProcessor functionProcessor = new ScriptProcessor(processor.Context); SObject functionReturnObject; if (_method != null) { functionReturnObject = _method(functionProcessor, caller, This, parameters); } else { for (int i = 0; i < _parameters.Length; i++) { if (parameters.Length > i) { functionProcessor.Context.AddVariable(_parameters[i], parameters[i]); } else { functionProcessor.Context.AddVariable(_parameters[i], functionProcessor.Undefined); } } functionProcessor.Context.This = This; functionReturnObject = functionProcessor.Run(Body); } if (functionProcessor.ErrorHandler.ThrownError) processor.ErrorHandler.ThrowError(functionProcessor.ErrorHandler.ErrorObject); return functionReturnObject; }
/// <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.LITERAL_UNDEFINED || left.TypeOf() == SObject.LITERAL_NULL) { return true; } // Both are numbers: else if (left.TypeOf() == SObject.LITERAL_TYPE_NUMBER) { double numLeft = ((SNumber)left).Value; double numRight = ((SNumber)right).Value; return numLeft == numRight; } // Both are string: else if (left.TypeOf() == SObject.LITERAL_TYPE_STRING) { string strLeft = ((SString)left).Value; string strRight = ((SString)right).Value; return strLeft == strRight; } // Both are bool: else if (left.TypeOf() == SObject.LITERAL_TYPE_BOOL) { bool boolLeft = ((SBool)left).Value; bool boolRight = ((SBool)right).Value; return boolLeft == boolRight; } else { return ReferenceEquals(left, right); } } // null & undefined else if (left.TypeOf() == SObject.LITERAL_NULL && right.TypeOf() == SObject.LITERAL_UNDEFINED || left.TypeOf() == SObject.LITERAL_UNDEFINED && right.TypeOf() == SObject.LITERAL_NULL) { return true; } // When one is a number and another is a string, convert the string to a number and compare: else if (left.TypeOf() == SObject.LITERAL_TYPE_STRING && right.TypeOf() == SObject.LITERAL_TYPE_NUMBER) { double numLeft = left.ToNumber(processor).Value; double numRight = ((SNumber)right).Value; return numLeft == numRight; } else if (left.TypeOf() == SObject.LITERAL_TYPE_NUMBER && right.TypeOf() == SObject.LITERAL_TYPE_STRING) { double numRight = right.ToNumber(processor).Value; double numLeft = ((SNumber)left).Value; return numLeft == numRight; } else if (left.TypeOf() == SObject.LITERAL_TYPE_BOOL) { return LooseEquals(processor, left.ToNumber(processor), right); } else if (right.TypeOf() == SObject.LITERAL_TYPE_BOOL) { return LooseEquals(processor, left, right.ToNumber(processor)); } else { return false; } }
internal static string DivideOperator(ScriptProcessor processor, SObject left, SObject right) { var numbers = GetNumericOperatorParameters(processor, left, right); if (numbers.Item2 == 0D) // Catch division by 0 by returning infinity (wtf -> what a terrible feature). return SObject.LITERAL_INFINITY; return SNumber.ConvertToScriptString(numbers.Item1 / numbers.Item2); }