Files
completion-viz/engine262/src/abstract-ops/reference-operations.mjs
T

143 lines
4.1 KiB
JavaScript

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);
}