import { surroundingAgent } from '../engine.mjs'; import { PrimitiveValue, Type, Value } from '../value.mjs'; import { NormalCompletion, Q, ReturnIfAbrupt, X, } from '../completion.mjs'; import { Assert, GetGlobalObject, ToObject, Set, } from './all.mjs'; // 6.2.4.1 #sec-getbase export function GetBase(V) { Assert(Type(V) === 'Reference'); return V.BaseValue; } // 6.2.4.2 #sec-getreferencedname export function GetReferencedName(V) { Assert(Type(V) === 'Reference'); return V.ReferencedName; } // 6.2.4.3 #sec-isstrictreference export function IsStrictReference(V) { Assert(Type(V) === 'Reference'); return V.StrictReference; } // 6.2.4.4 #sec-hasprimitivebase export function HasPrimitiveBase(V) { Assert(Type(V) === 'Reference'); if (V.BaseValue instanceof PrimitiveValue) { return Value.true; } return Value.false; } // 6.2.4.5 #sec-ispropertyreference export function IsPropertyReference(V) { Assert(Type(V) === 'Reference'); if (Type(V.BaseValue) === 'Object' || HasPrimitiveBase(V) === Value.true) { return Value.true; } return Value.false; } // 6.2.4.6 #sec-isunresolvablereference export function IsUnresolvableReference(V) { Assert(Type(V) === 'Reference'); if (V.BaseValue === Value.undefined) { return Value.true; } return Value.false; } // 6.2.4.7 #sec-issuperreference export function IsSuperReference(V) { // 1. Assert: Type(V) is Reference. Assert(Type(V) === 'Reference'); // 2. If V has a thisValue component, return true; otherwise return false. return 'thisValue' in V ? Value.true : Value.false; } // 6.2.4.8 #sec-getvalue export function GetValue(V) { ReturnIfAbrupt(V); if (Type(V) !== 'Reference') { return V; } let base = GetBase(V); if (IsUnresolvableReference(V) === Value.true) { return surroundingAgent.Throw('ReferenceError', 'NotDefined', GetReferencedName(V)); } if (IsPropertyReference(V) === Value.true) { if (HasPrimitiveBase(V) === Value.true) { Assert(base !== Value.undefined && base !== Value.null); base = X(ToObject(base)); } return Q(base.Get(GetReferencedName(V), GetThisValue(V))); } else { return Q(base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))); } } // 6.2.4.9 #sec-putvalue export function PutValue(V, W) { ReturnIfAbrupt(V); ReturnIfAbrupt(W); if (Type(V) !== 'Reference') { return surroundingAgent.Throw('ReferenceError', 'NotDefined', V); } let base = GetBase(V); if (IsUnresolvableReference(V) === Value.true) { if (IsStrictReference(V) === Value.true) { return surroundingAgent.Throw('ReferenceError', 'NotDefined', GetReferencedName(V)); } const globalObj = GetGlobalObject(); return Q(Set(globalObj, GetReferencedName(V), W, Value.false)); } else if (IsPropertyReference(V) === Value.true) { if (HasPrimitiveBase(V) === Value.true) { Assert(Type(base) !== 'Undefined' && Type(base) !== 'Null'); base = X(ToObject(base)); } const succeeded = Q(base.Set(GetReferencedName(V), W, GetThisValue(V))); if (succeeded === Value.false && IsStrictReference(V) === Value.true) { return surroundingAgent.Throw('TypeError', 'CannotSetProperty', GetReferencedName(V), base); } return NormalCompletion(Value.undefined); } else { return Q(base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V))); } } // 6.2.4.10 #sec-getthisvalue export function GetThisValue(V) { // 1. Assert: IsPropertyReference(V) is true. Assert(IsPropertyReference(V) === Value.true); // 2. If IsSuperReference(V) is true, then if (IsSuperReference(V) === Value.true) { // a. Return the value of the thisValue component of the reference V. return V.thisValue; } // 3. Return GetBase(V). return GetBase(V); } // 6.2.4.11 #sec-initializereferencedbinding export function InitializeReferencedBinding(V, W) { ReturnIfAbrupt(V); ReturnIfAbrupt(W); Assert(Type(V) === 'Reference'); Assert(IsUnresolvableReference(V) === Value.false); const base = GetBase(V); Assert(Type(base) === 'EnvironmentRecord'); return base.InitializeBinding(GetReferencedName(V), W); }