mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 21:31:46 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import { ReferenceRecord, Value } from '../value.mts';
|
||||
import { Evaluate, type ExpressionEvaluator } from '../evaluator.mts';
|
||||
import { Q, X } from '../completion.mts';
|
||||
import { IsInTailPosition, StringValue } from '../static-semantics/all.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
EvaluateCall,
|
||||
EvaluatePropertyAccessWithExpressionKey,
|
||||
EvaluatePropertyAccessWithIdentifierKey,
|
||||
} from './all.mts';
|
||||
import { GetValue, MakePrivateReference } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-optional-chaining-evaluation */
|
||||
// OptionalExpression :
|
||||
// MemberExpression OptionalChain
|
||||
// CallExpression OptionalChain
|
||||
// OptionalExpression OptionalChain
|
||||
export function* Evaluate_OptionalExpression({ MemberExpression, OptionalChain }: ParseNode.OptionalExpression) {
|
||||
// 1. Let baseReference be the result of evaluating MemberExpression.
|
||||
const baseReference = Q(yield* Evaluate(MemberExpression));
|
||||
// 2. Let baseValue be ? GetValue(baseReference).
|
||||
const baseValue = Q(yield* GetValue(baseReference));
|
||||
// 3. If baseValue is undefined or null, then
|
||||
if (baseValue === Value.undefined || baseValue === Value.null) {
|
||||
// a. Return undefined.
|
||||
return Value.undefined;
|
||||
}
|
||||
// 4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.
|
||||
return yield* ChainEvaluation(OptionalChain, baseValue, X(baseReference));
|
||||
}
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-optional-chaining-chain-evaluation */
|
||||
// OptionalChain :
|
||||
// `?.` Arguments
|
||||
// `?.` `[` Expression `]`
|
||||
// `?.` IdentifierName
|
||||
// `?.` PrivateIdentifier
|
||||
// OptionalChain Arguments
|
||||
// OptionalChain `[` Expression `]`
|
||||
// OptionalChain `.` IdentifierName
|
||||
// OptionalChain `.` PrivateIdentifier
|
||||
function* ChainEvaluation(node: ParseNode.OptionalChain, baseValue: Value, baseReference: Value | ReferenceRecord): ExpressionEvaluator {
|
||||
const {
|
||||
OptionalChain,
|
||||
Arguments,
|
||||
Expression,
|
||||
IdentifierName,
|
||||
PrivateIdentifier,
|
||||
} = node;
|
||||
if (Arguments) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. Let thisChain be this OptionalChain.
|
||||
const thisChain = node;
|
||||
// 5. Let tailCall be IsInTailPosition(thisChain).
|
||||
const tailCall = IsInTailPosition(thisChain);
|
||||
// 6. Return ? EvaluateCall(newValue, newReference, Arguments, tailCall).
|
||||
return Q(yield* EvaluateCall(newValue, newReference, Arguments, tailCall));
|
||||
}
|
||||
// 1. Let thisChain be this OptionalChain.
|
||||
const thisChain = node;
|
||||
// 2. Let tailCall be IsInTailPosition(thisChain).
|
||||
const tailCall = IsInTailPosition(thisChain);
|
||||
// 3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
|
||||
return Q(yield* EvaluateCall(baseValue, baseReference, Arguments, tailCall));
|
||||
}
|
||||
if (Expression) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 5. Return ? EvaluatePropertyAccessWithExpressionKey(newValue, Expression, strict).
|
||||
return Q(yield* EvaluatePropertyAccessWithExpressionKey(newValue, Expression, strict));
|
||||
}
|
||||
// 1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 2. Return ? EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict).
|
||||
return Q(yield* EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict));
|
||||
}
|
||||
if (IdentifierName) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 5. Return ! EvaluatePropertyAccessWithIdentifierKey(newValue, IdentifierName, strict).
|
||||
return X(EvaluatePropertyAccessWithIdentifierKey(newValue, IdentifierName, strict));
|
||||
}
|
||||
// 1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
|
||||
const strict = node.strict;
|
||||
// 2. Return ! EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict).
|
||||
return X(EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict));
|
||||
}
|
||||
if (PrivateIdentifier) {
|
||||
if (OptionalChain) {
|
||||
// 1. Let optionalChain be OptionalChain.
|
||||
const optionalChain = OptionalChain;
|
||||
// 2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
|
||||
const newReference = Q(yield* ChainEvaluation(optionalChain, baseValue, baseReference));
|
||||
// 3. Let newValue be ? GetValue(newReference).
|
||||
const newValue = Q(yield* GetValue(newReference));
|
||||
// 4. Let fieldNameString be the StringValue of PrivateIdentifier.
|
||||
const fieldNameString = StringValue(PrivateIdentifier);
|
||||
// 5. Return ! MakePrivateReference(nv, fieldNameString).
|
||||
return X(MakePrivateReference(newValue, fieldNameString));
|
||||
}
|
||||
// 1. Let fieldNameString be the StringValue of PrivateIdentifier.
|
||||
const fieldNameString = StringValue(PrivateIdentifier);
|
||||
// 2. Return ! MakePrivateReference(bv, fieldNameString).
|
||||
return X(MakePrivateReference(baseValue, fieldNameString));
|
||||
}
|
||||
throw new OutOfRange('ChainEvaluation', node);
|
||||
}
|
||||
Reference in New Issue
Block a user