public Completion IteratorNext(IValue?value = null) { Completion result; if (value == null) { result = NextMethod.Call(Iterator); } else { result = NextMethod.Call(Iterator, new List <IValue>() { value }); } if (result.IsAbrupt()) { return(result); } if (!(result.value is Object)) { return(Completion.ThrowTypeError("iterator next must return an object.")); } return(result); }
public Completion IteratorClose(Completion completion) { var @return = Iterator.GetMethod("return"); if (@return.IsAbrupt()) { return(@return); } if (@return.value == UndefinedValue.Instance) { return(completion); } var innerResult = (@return.value as Callable) !.Call(Iterator); if (completion.completionType == CompletionType.Throw) { return(completion); } if (innerResult.completionType == CompletionType.Throw) { return(innerResult); } if (!(innerResult.value is Object)) { return(Completion.ThrowTypeError("iterator return did not return an object.")); } return(completion); }
public static Completion At(this IReadOnlyList <IValue> arguments, int index) { if (arguments.Count <= index) { return(Completion.ThrowTypeError($"At least {index + 1} arguments are required")); } return(Completion.NormalCompletion(arguments[index])); }
public override Completion CreateMutableBinding(string name, bool deletable) { if (DeclarativeRecord.HasBinding(name).Other == true) { return(Completion.ThrowTypeError($"binding name {name} is already bound")); } return(DeclarativeRecord.CreateMutableBinding(name, deletable)); }
private static CompletionOr <BooleanValue?> thisBooleanValue(IValue value) { if (value is BooleanValue b) { return(Completion.NormalWith(b)); } if (value is BooleanObject o) { return(Completion.NormalWith(o.Value)); } return(Completion.ThrowTypeError("Must operate on a Boolean value or object").WithEmpty <BooleanValue?>()); }
private static CompletionOr <NumberValue?> thisNumberValue(IValue value) { if (value is NumberValue n) { return(Completion.NormalWith(n)); } if (value is NumberObject o) { return(Completion.NormalWith(o.value)); } return(Completion.ThrowTypeError("Must operate on a Number value or object").WithEmpty <NumberValue?>()); }
public static Completion toString(IValue @this, IReadOnlyList <IValue> arguments) { if (@this is StringValue) { return(Completion.NormalCompletion(@this)); } if (@this is StringObject s) { return(Completion.NormalCompletion(s.value)); } return(Completion.ThrowTypeError("Must be called on a string")); }
public static Completion valueOf(IValue @this, IReadOnlyList <IValue> arguments) { if (!(@this is DateObject d)) { return(Completion.ThrowTypeError("this is not a Date object")); } if (double.IsNaN(d.PrimitiveValue)) { return(Completion.NormalCompletion(new StringValue("Invalid Date"))); } return(Completion.NormalCompletion(new NumberValue(d.PrimitiveValue))); }
private static FunctionObject MakeArgGetter(string name, EnvironmentRecord env) { var getter = Utils.CreateBuiltinFunction((@this, arguments) => { if (!(@this is GetterSetter thisObj)) { return(Completion.ThrowTypeError("Not allowed to call internal function on non getter/setter")); } return(thisObj.Env.GetBindingValue(thisObj.Name, false)); }, steps => new GetterSetter(steps, name, env)); return(getter); }
public static Completion getMonth(IValue @this, IReadOnlyList <IValue> arguments) { if (!(@this is DateObject d)) { return(Completion.ThrowTypeError("this is not a Date object")); } var t = d.PrimitiveValue; if (!IsFinite(t)) { return(Completion.NormalCompletion(NumberValue.DoubleNaN)); } return(Completion.NormalCompletion(new NumberValue(MonthFromTime(LocalTime(t))))); }
public static BooleanCompletion CreateDataPropertyOrThrow(Object O, string P, IValue V) { var success = CreateDataProperty(O, P, V); if (success.IsAbrupt()) { return(success); } if (success.Other == false) { return(Completion.ThrowTypeError($"CreateDataPropertyOrThrow {P} failed").WithEmptyBool()); } return(success); }
public static Completion getTimeZoneOffset(IValue @this, IReadOnlyList <IValue> arguments) { if (!(@this is DateObject d)) { return(Completion.ThrowTypeError("this is not a Date object")); } var t = d.PrimitiveValue; if (!IsFinite(t)) { return(Completion.NormalCompletion(NumberValue.DoubleNaN)); } return(Completion.NormalCompletion(new NumberValue((int)(t - LocalTime(t)) / MsPerMinute))); }
private static Completion ObjectDefineProperties(Object O, IValue Properties) { var propsComp = Properties.ToObject(); if (propsComp.IsAbrupt()) { return(propsComp); } var props = propsComp.value as Object; var keys = props !.OwnPropertyKeys(); var descriptors = new List <(string, PropertyDescriptor)>(); foreach (var nextKey in keys) { var propDesc = props.GetOwnProperty(nextKey); if (propDesc.IsAbrupt()) { return(propDesc); } if (propDesc.Other != null && propDesc.Other.Enumerable.GetValueOrDefault() == true) { var descObj = props.Get(nextKey); if (descObj.IsAbrupt()) { return(descObj); } if (!(descObj.value is Object o)) { return(Completion.ThrowTypeError("properties of the property argument must be objects.")); } var desc = PropertyDescriptor.FromObject(o); if (desc.IsAbrupt()) { return(desc); } descriptors.Add((nextKey, desc.Other !)); } } foreach (var(P, desc) in descriptors) { var comp = O.DefinePropertyOrThrow(P, desc); if (comp.IsAbrupt()) { return(comp); } } return(Completion.NormalCompletion(O)); }
private static Completion source(IValue thisValue, IReadOnlyList <IValue> arguments) { if (!(thisValue is Object)) { return(Completion.ThrowTypeError("Not valid RegExp object")); } if (!(thisValue is RegExpObject o)) { if (thisValue == Interpreter.Instance().CurrentRealm().Intrinsics.RegExpPrototype) { return(Completion.NormalCompletion(new StringValue("(?:)"))); } return(Completion.ThrowTypeError("Not valid RegExp object")); } return(Completion.NormalCompletion(new StringValue(EscapeRegExpPattern(o.OriginalSource)))); }
private static Completion exec(IValue thisValue, IReadOnlyList <IValue> arguments) { var @string = arguments.At(0, UndefinedValue.Instance); if (!(thisValue is RegExpObject R)) { return(Completion.ThrowTypeError("this value must be a RegExp object")); } var S = @string.ToJsString(); if (S.IsAbrupt()) { return(S); } return(RegExpBuiltinExec(R, (S.value as StringValue) !.@string)); }
private Completion push(IValue @this, IReadOnlyList <IValue> arguments) { var OComp = @this.ToObject(); if (OComp.IsAbrupt()) { return(OComp); } var O = OComp.value as Object; var lenComp = O !.Get("length"); if (lenComp.IsAbrupt()) { return(lenComp); } var toLenComp = lenComp.value !.ToLength(); if (toLenComp.IsAbrupt()) { return(toLenComp); } long len = toLenComp.Other; if (len + arguments.Count > (1L << 53) - 1) { return(Completion.ThrowTypeError("Too many values in the array.")); } for (int i = 0; i < arguments.Count; i++) { O.Set((len + i).ToString(System.Globalization.CultureInfo.InvariantCulture), arguments[i], true); } var lenValue = new NumberValue(len + arguments.Count); var setComp = O.Set("length", lenValue, true); if (setComp.IsAbrupt()) { return(setComp); } return(Completion.NormalCompletion(lenValue)); }
private static Completion preventExtensions(IValue @this, IReadOnlyList <IValue> arguments) { var argCheck = Utils.CheckArguments(arguments, 1); if (argCheck.IsAbrupt()) { return(argCheck); } if (!(arguments[0] is Object O)) { return(Completion.NormalCompletion(arguments[0])); } var status = O.PreventExtensions(); if (status == false) { return(Completion.ThrowTypeError("Could not prevent extensions")); } return(Completion.NormalCompletion(O)); }
public static Completion EvaluateCall(IValue func, IValue @ref, Arguments arguments, bool tailCall) { IValue thisValue; if (@ref is ReferenceValue reference) { if (reference.IsPropertyReference()) { thisValue = reference.GetThisValue(); } else { if (!(reference.baseValue is EnvironmentRecord envRec)) { throw new InvalidOperationException("Utils.EvaluateCall: reference.baseValue is not a recognized IReferenceable"); } thisValue = envRec.WithBaseObject(); } } else { thisValue = UndefinedValue.Instance; } var argList = arguments.ArgumentListEvaluation(); if (argList.IsAbrupt()) { return(argList); } if (!(func is Callable functionObject)) { return(Completion.ThrowTypeError("Utils.EvaluateCall: func must be a function object.")); } if (tailCall) { throw new NotImplementedException("Utils.EvaluateCall: tail calls not implemented"); } return(functionObject.Call(thisValue, argList.Other)); }
private static Completion create(IValue @this, IReadOnlyList <IValue> arguments) { var argComp = Utils.CheckArguments(arguments, 1); if (argComp.IsAbrupt()) { return(argComp); } if (!(arguments[0] is Object) || arguments[0] == NullValue.Instance) { return(Completion.ThrowTypeError("An object or null is required as the first argument to Object.create")); } var obj = Utils.ObjectCreate(arguments[0]); if (arguments.Count > 1 && arguments[1] != UndefinedValue.Instance) { return(ObjectDefineProperties(obj, arguments[1])); } return(Completion.NormalCompletion(obj)); }
public static Completion toString(IValue @this, IReadOnlyList <IValue> arguments) { if (!(@this is DateObject d)) { return(Completion.ThrowTypeError("this is not a Date object")); } if (double.IsNaN(d.PrimitiveValue)) { return(Completion.NormalCompletion(new StringValue("Invalid Date"))); } var clrDate = d.ToDateTime(); if (clrDate.IsAbrupt()) { return(clrDate); } var t = ToLocalTime(clrDate.Other); return(Completion.NormalCompletion(new StringValue(t.ToString("ddd MMM dd yyyy HH:mm:ss ", CultureInfo.InvariantCulture) + TimeZoneString(t)))); }
public Completion OrdinaryHasInstance(IValue O) { if (!(O is Object obj)) { return(Completion.NormalCompletion(BooleanValue.False)); } var PComp = Get("prototype"); if (PComp.IsAbrupt()) { return(PComp); } var P = PComp.value; if (!(P is Object protoObj)) { return(Completion.ThrowTypeError("prototype is not an object")); } while (true) { var objComp = obj.GetPrototypeOf(); if (objComp.IsAbrupt()) { return(objComp); } obj = (objComp.value as Object) !; if (obj == null) { return(Completion.NormalCompletion(BooleanValue.False)); } if (obj == protoObj) { return(Completion.NormalCompletion(BooleanValue.True)); } } }
public override Completion SetMutableBinding(string name, IValue value, bool strict) { if (!bindings.ContainsKey(name)) { if (strict) { return(Completion.ThrowReferenceError($"binding {name} does not exist.")); } CreateMutableBinding(name, true); InitializeBinding(name, value); return(Completion.NormalCompletion()); } var binding = bindings[name]; if (binding.strict.GetValueOrDefault(false)) { strict = true; } if (binding.Value == null) { return(Completion.ThrowReferenceError($"{name} has not been initialized yet.")); } else if (binding.mutable) { binding.Value = value; } else { // attempt to change value of immutable binding if (strict) { return(Completion.ThrowTypeError("attempt to change value of immutable binding")); } } return(Completion.NormalCompletion()); }
public static Completion RegExpAllocAndInitialize(string P, string F) { var allowedFlags = "gimsuy"; List <char> invalidFlags; if ((invalidFlags = F.Where(c => !allowedFlags.Contains(c, StringComparison.Ordinal)).ToList()).Any()) { if (invalidFlags.Count == 1) { return(Completion.ThrowTypeError($"'{invalidFlags[0]}' is not a valid RegExp flag.")); } else { return(Completion.ThrowTypeError($"These flags not valid RegExp flags: {{ {string.Join(", ", invalidFlags.Select(f => $"'{f}'"))} }}")); } } else if (F.Distinct().Count() != F.Length) { return(Completion.ThrowTypeError($"RegExp flags should not contain duplicates.")); } var BMP = !F.Contains('u', StringComparison.Ordinal); var options = RegexOptions.ECMAScript; if (F.Contains('m', StringComparison.Ordinal)) { options |= RegexOptions.Multiline; } if (F.Contains('s', StringComparison.Ordinal)) { options |= RegexOptions.Singleline; options &= ~RegexOptions.ECMAScript; } if (F.Contains('i', StringComparison.Ordinal)) { options |= RegexOptions.IgnoreCase; } if (options.HasFlag(RegexOptions.Multiline)) { int index = 0; var newPattern = P; while ((index = newPattern.IndexOf("$", index, StringComparison.Ordinal)) != -1) { if (index > 0 && newPattern[index - 1] != '\\') { newPattern = newPattern.Substring(0, index) + @"\r?" + newPattern.Substring(index); index += 4; } } P = newPattern; } Regex regex; try { regex = new Regex(P, options); } catch { return(Completion.ThrowSyntaxError("Invalid RegEx")); } var obj = new RegExpObject(P, F, regex); var set = obj.Set("lastIndex", new NumberValue(0), true); if (set.IsAbrupt()) { return(set); } return(Completion.NormalCompletion(obj)); }
public static CompletionOr <PropertyDescriptor?> FromObject(Object Obj) { var desc = new PropertyDescriptor(); var hasEnumerable = Obj.HasProperty("enumerable"); if (hasEnumerable.IsAbrupt()) { return(hasEnumerable.WithEmpty <PropertyDescriptor?>()); } if (hasEnumerable.Other) { var enumerable = Obj.Get("enumerable"); if (enumerable.IsAbrupt()) { return(enumerable.WithEmpty <PropertyDescriptor?>()); } desc.Enumerable = enumerable.value !.ToBoolean().boolean; } var hasConfigurable = Obj.HasProperty("configurable"); if (hasConfigurable.IsAbrupt()) { return(hasConfigurable.WithEmpty <PropertyDescriptor?>()); } if (hasConfigurable.Other) { var configurable = Obj.Get("configurable"); if (configurable.IsAbrupt()) { return(configurable.WithEmpty <PropertyDescriptor?>()); } desc.Configurable = configurable.value !.ToBoolean().boolean; } var hasValue = Obj.HasProperty("value"); if (hasValue.IsAbrupt()) { return(hasValue.WithEmpty <PropertyDescriptor?>()); } if (hasValue.Other) { var value = Obj.Get("value"); if (value.IsAbrupt()) { return(value.WithEmpty <PropertyDescriptor?>()); } desc.Value = value.value !; } var hasWritable = Obj.HasProperty("writable"); if (hasWritable.IsAbrupt()) { return(hasWritable.WithEmpty <PropertyDescriptor?>()); } if (hasWritable.Other) { var writable = Obj.Get("writable"); if (writable.IsAbrupt()) { return(writable.WithEmpty <PropertyDescriptor?>()); } desc.Writable = writable.value !.ToBoolean().boolean; } var hasGet = Obj.HasProperty("get"); if (hasGet.IsAbrupt()) { return(hasGet.WithEmpty <PropertyDescriptor?>()); } if (hasGet.Other) { var get = Obj.Get("get"); if (get.IsAbrupt()) { return(get.WithEmpty <PropertyDescriptor?>()); } if (get.value != UndefinedValue.Instance) { if (!(get.value is Callable callable)) { return(Completion.ThrowTypeError("get property is not callable").WithEmpty <PropertyDescriptor?>()); } desc.Get = callable; } } var hasSet = Obj.HasProperty("set"); if (hasSet.IsAbrupt()) { return(hasSet.WithEmpty <PropertyDescriptor?>()); } if (hasSet.Other) { var set = Obj.Get("set"); if (set.IsAbrupt()) { return(set.WithEmpty <PropertyDescriptor?>()); } if (set.value != UndefinedValue.Instance) { if (!(set.value is Callable callable)) { return(Completion.ThrowTypeError("set property is not callable").WithEmpty <PropertyDescriptor?>()); } desc.Set = callable; } } if ((desc.Get != null || desc.Set != null) && (desc.Value != null || desc.Writable.HasValue)) { return(Completion.ThrowTypeError("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute").WithEmpty <PropertyDescriptor?>()); } return(Completion.NormalWith(desc)); }
private static Completion EvalDeclarationInstantiation(ScriptStatementList body, LexicalEnvironment varEnv, LexicalEnvironment lexEnv, bool strict) { var varNames = body.VarDeclaredNames(); var varDeclarations = body.VarScopedDeclarations(); var lexEnvRec = lexEnv.EnvironmentRecord; var varEnvRec = varEnv.EnvironmentRecord; if (!strict) { if (varEnvRec is GlobalEnvironmentRecord g) { foreach (var name in varNames) { if (g.HasLexicalDeclaration(name)) { return(Completion.ThrowSyntaxError("Spec 18.2.1.3 step 5ai1")); } } } LexicalEnvironment?thisLex = lexEnv; while (thisLex != varEnv) { var thisEnvRec = thisLex.EnvironmentRecord; if (!(thisEnvRec is ObjectEnvironmentRecord)) { foreach (var name in varNames) { if (thisEnvRec.HasBinding(name).Other) { return(Completion.ThrowSyntaxError("Spec 18.2.1.3 step 5dii2ai")); } } } thisLex = thisLex.Outer; if (thisLex == null) { throw new InvalidOperationException("thisLex and varEnv never matched"); } } } var functionsToInitialize = new List <FunctionDeclaration>(); var declaredFunctionNames = new List <string>(); foreach (var d in varDeclarations.Reverse()) { if (!(d is VariableDeclaration) && !(d is ForBinding)) { if (!(d is FunctionDeclaration f)) { throw new InvalidOperationException("Spec 18.2.1.3 step 8ai"); } var fn = f.BoundNames()[0]; if (!declaredFunctionNames.Contains(fn)) { if (varEnvRec is GlobalEnvironmentRecord g) { var fnDefinable = g.CanDeclareGlobalFunction(fn); if (fnDefinable.IsAbrupt()) { return(fnDefinable); } if (!fnDefinable.Other) { return(Completion.ThrowTypeError($"Function {fn} is not definable in global scope")); } } declaredFunctionNames.Add(fn); functionsToInitialize.Insert(0, f); } } } var declaredVarNames = new List <string>(); foreach (var d in varDeclarations) { IReadOnlyList <string>?boundNames = null; if (d is VariableDeclaration v) { boundNames = v.BoundNames(); } if (d is ForBinding f) { boundNames = f.BoundNames(); } if (boundNames != null) { foreach (var vn in boundNames) { if (!declaredFunctionNames.Contains(vn)) { if (varEnvRec is GlobalEnvironmentRecord g) { var fnDefinable = g.CanDeclareGlobalVar(vn); if (fnDefinable.IsAbrupt()) { return(fnDefinable); } if (!fnDefinable.Other) { return(Completion.ThrowTypeError($"Variable {vn} is not definable in global scope")); } } if (!declaredVarNames.Contains(vn)) { declaredVarNames.Add(vn); } } } } } var lexDeclarations = body.LexicallyScopedDeclarations(); foreach (var d in lexDeclarations) { foreach (var dn in d.BoundNames()) { Completion comp; if (d.IsConstantDeclaration()) { comp = lexEnvRec.CreateImmutableBinding(dn, true); } else { comp = lexEnvRec.CreateMutableBinding(dn, false); } if (comp.IsAbrupt()) { return(comp); } } } foreach (var f in functionsToInitialize) { var fn = f.BoundNames()[0]; var fo = f.InstantiateFunctionObject(lexEnv); if (varEnvRec is GlobalEnvironmentRecord g) { var comp = g.CreateGlobalFunctionBinding(fn, fo, true); if (comp.IsAbrupt()) { return(comp); } } else { var bindingExists = varEnvRec.HasBinding(fn); if (!bindingExists.Other) { var status = varEnvRec.CreateMutableBinding(fn, true); if (status.IsAbrupt()) { throw new InvalidOperationException("Spec 18.2.1.3 Step 15dii2"); } varEnvRec.InitializeBinding(fn, fo); } else { varEnvRec.SetMutableBinding(fn, fo, false); } } } foreach (var vn in declaredVarNames) { if (varEnvRec is GlobalEnvironmentRecord g) { var comp = g.CreateGlobalVarBinding(vn, true); if (comp.IsAbrupt()) { return(comp); } } else { var bindingExists = varEnvRec.HasBinding(vn); if (!bindingExists.Other) { var status = varEnvRec.CreateMutableBinding(vn, true); if (status.IsAbrupt()) { throw new InvalidOperationException("Spec 18.2.1.3 Step 16bii2"); } varEnvRec.InitializeBinding(vn, UndefinedValue.Instance); } } } return(Completion.NormalCompletion()); }