using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Jint.Native;
namespace Jint.Runtime.Environments;
///
/// Base implementation of an Environment Record
/// https://tc39.es/ecma262/#sec-environment-records
///
[DebuggerTypeProxy(typeof(EnvironmentDebugView))]
internal abstract class Environment : JsValue
{
protected internal readonly Engine _engine;
protected internal Environment? _outerEnv;
protected Environment(Engine engine) : base(InternalTypes.ObjectEnvironmentRecord)
{
_engine = engine;
}
///
/// Determines if an environment record has a binding for an identifier.
///
/// The identifier of the binding
/// true if it does and false if it does not.
internal abstract bool HasBinding(Key name);
internal abstract bool HasBinding(BindingName name);
internal abstract bool TryGetBinding(BindingName name, bool strict, [NotNullWhen(true)] out JsValue? value);
///
/// Creates a new mutable binding in an environment record.
///
/// The identifier of the binding.
/// true if the binding may be subsequently deleted.
internal abstract void CreateMutableBinding(Key name, bool canBeDeleted = false);
///
/// Creates a new but uninitialized immutable binding in an environment record.
///
/// The identifier of the binding.
/// false if the binding may used before it's been initialized.
internal abstract void CreateImmutableBinding(Key name, bool strict = true);
///
/// Set the value of an already existing but uninitialized binding in an Environment Record.
///
/// The text of the bound name
/// The value for the binding.
/// Disposal type hint
internal abstract void InitializeBinding(Key name, JsValue value, DisposeHint hint);
///
/// Sets the value of an already existing mutable binding in an environment record.
///
/// The identifier of the binding
/// The value of the binding.
/// The identify strict mode references.
internal abstract void SetMutableBinding(Key name, JsValue value, bool strict);
internal abstract void SetMutableBinding(BindingName name, JsValue value, bool strict);
///
/// Returns the value of an already existing binding from an environment record.
///
/// The identifier of the binding
/// The identify strict mode references.
/// The value of an already existing binding from an environment record.
internal abstract JsValue GetBindingValue(Key name, bool strict);
///
/// Delete a binding from an environment record. The String value N is the text of the bound name If a binding for N exists, remove the binding and return true. If the binding exists but cannot be removed return false. If the binding does not exist return true.
///
/// The identifier of the binding
/// true if the deletion is successfull.
internal abstract bool DeleteBinding(Key name);
internal abstract bool HasThisBinding();
internal abstract bool HasSuperBinding();
internal abstract JsValue WithBaseObject();
internal abstract bool HasBindings();
///
/// Returns an array of all the defined binding names
///
/// The array of all defined bindings
internal abstract string[] GetAllBindingNames();
public override object ToObject()
{
Throw.NotSupportedException();
return null;
}
public override bool Equals(JsValue? other)
{
Throw.NotSupportedException();
return false;
}
internal abstract JsValue GetThisBinding();
internal JsValue? NewTarget { get; set; }
internal virtual Completion DisposeResources(Completion c) => c;
///
/// Helper to cache JsString/Key when environments use different lookups.
///
[DebuggerDisplay("\"{Key.Name}\"")]
internal sealed class BindingName
{
public readonly Key Key;
public readonly JsString Value;
public readonly JsValue? CalculatedValue;
public BindingName(string value)
{
var key = (Key) value;
Key = key;
Value = JsString.Create(value);
if (key == KnownKeys.Undefined)
{
CalculatedValue = Undefined;
}
}
public BindingName(JsString value)
{
var key = (Key) value.ToString();
Key = key;
Value = value;
if (key == KnownKeys.Undefined)
{
CalculatedValue = Undefined;
}
}
}
private sealed class EnvironmentDebugView
{
private readonly Environment _record;
public EnvironmentDebugView(Environment record)
{
_record = record;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair[] Entries
{
get
{
var bindingNames = _record.GetAllBindingNames();
var bindings = new KeyValuePair[bindingNames.Length];
var i = 0;
foreach (var key in bindingNames)
{
bindings[i++] = new KeyValuePair(key, _record.GetBindingValue(key, false));
}
return bindings;
}
}
}
}