using System;
using System.Runtime.CompilerServices;
using Jint.Native;
using Jint.Runtime.Environments;
using Environment = Jint.Runtime.Environments.Environment;
namespace Jint.Runtime;
///
/// https://tc39.es/ecma262/#sec-reference-record-specification-type
///
public sealed class Reference
{
private JsValue _base;
private JsValue _referencedName;
internal bool _strict;
private JsValue? _thisValue;
internal Reference(JsValue baseValue, JsValue referencedName, bool strict, JsValue? thisValue = null)
{
_base = baseValue;
_referencedName = referencedName;
_thisValue = thisValue;
}
///
/// The value or Environment Record which holds the binding. A [[Base]] of unresolvable indicates that the binding could not be resolved.
///
public JsValue Base
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _base;
}
///
/// The value or Environment Record which holds the binding. A [[Base]] of unresolvable indicates that the binding could not be resolved.
///
public JsValue ReferencedName
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _referencedName;
}
///
/// true if the Reference Record originated in strict mode code, false otherwise.
///
public bool Strict
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _strict;
}
public bool HasPrimitiveBase
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (_base._type & InternalTypes.Primitive) != InternalTypes.Empty;
}
public bool IsUnresolvableReference
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _base._type == InternalTypes.Undefined;
}
public bool IsSuperReference => _thisValue is not null;
// https://tc39.es/ecma262/#sec-ispropertyreference
public bool IsPropertyReference
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (_base._type & (InternalTypes.Primitive | InternalTypes.Object)) != InternalTypes.Empty;
}
public JsValue ThisValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => IsSuperReference ? _thisValue! : Base;
}
public bool IsPrivateReference
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _referencedName._type == InternalTypes.PrivateName;
}
internal Reference Reassign(JsValue baseValue, JsValue name, bool strict, JsValue? thisValue)
{
_base = baseValue;
_referencedName = name;
_strict = strict;
_thisValue = thisValue;
return this;
}
internal void AssertValid(Realm realm)
{
if (_strict
&& (_base._type & InternalTypes.ObjectEnvironmentRecord) != InternalTypes.Empty
&& (CommonProperties.Eval.Equals(_referencedName) || CommonProperties.Arguments.Equals(_referencedName)))
{
Throw.SyntaxError(realm);
}
}
internal void InitializeReferencedBinding(JsValue value, DisposeHint hint)
{
((Environment) _base).InitializeBinding(TypeConverter.ToString(_referencedName), value, hint);
}
internal void EvaluateAndCachePropertyKey()
{
if (!(_referencedName.IsInteger() && _base.IsIntegerIndexedArray))
{
_referencedName = Runtime.TypeConverter.ToPropertyKey(_referencedName);
}
}
}
internal enum DisposeHint
{
Normal,
Sync,
Async,
}