feat: add dependency
This commit is contained in:
371
javascript-engine/external/boa/boa_ast/src/property.rs
vendored
Normal file
371
javascript-engine/external/boa/boa_ast/src/property.rs
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
//! Property definition related types, used in object literals and class definitions.
|
||||
|
||||
use crate::function::PrivateName;
|
||||
use crate::try_break;
|
||||
use crate::visitor::{VisitWith, Visitor, VisitorMut};
|
||||
use boa_interner::{Interner, Sym, ToInternedString};
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
use super::{
|
||||
expression::{literal::Literal, Identifier},
|
||||
function::{AsyncFunction, AsyncGenerator, Function, Generator},
|
||||
Expression,
|
||||
};
|
||||
|
||||
/// Describes the definition of a property within an object literal.
|
||||
///
|
||||
/// A property has a name (a string) and a value (primitive, method, or object reference).
|
||||
/// Note that when we say that "a property holds an object", that is shorthand for "a property holds an object reference".
|
||||
/// This distinction matters because the original referenced object remains unchanged when you change the property's value.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript
|
||||
// TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PropertyDefinition {
|
||||
/// Puts a variable into an object.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-IdentifierReference
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions
|
||||
IdentifierReference(Identifier),
|
||||
|
||||
/// Binds a property name to a JavaScript value.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions
|
||||
Property(PropertyName, Expression),
|
||||
|
||||
/// A property of an object can also refer to a function or a getter or setter method.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions
|
||||
MethodDefinition(PropertyName, MethodDefinition),
|
||||
|
||||
/// The Rest/Spread Properties for ECMAScript proposal (stage 4) adds spread properties to object literals.
|
||||
/// It copies own enumerable properties from a provided object onto a new object.
|
||||
///
|
||||
/// Shallow-cloning (excluding `prototype`) or merging objects is now possible using a shorter syntax than `Object.assign()`.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Spread_properties
|
||||
SpreadObject(Expression),
|
||||
|
||||
/// Cover grammar for when an object literal is used as an object binding pattern.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-CoverInitializedName
|
||||
CoverInitializedName(Identifier, Expression),
|
||||
}
|
||||
|
||||
impl VisitWith for PropertyDefinition {
|
||||
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::IdentifierReference(id) => visitor.visit_identifier(id),
|
||||
Self::Property(pn, expr) => {
|
||||
try_break!(visitor.visit_property_name(pn));
|
||||
visitor.visit_expression(expr)
|
||||
}
|
||||
Self::MethodDefinition(pn, md) => {
|
||||
try_break!(visitor.visit_property_name(pn));
|
||||
visitor.visit_method_definition(md)
|
||||
}
|
||||
Self::SpreadObject(expr) => visitor.visit_expression(expr),
|
||||
Self::CoverInitializedName(id, expr) => {
|
||||
try_break!(visitor.visit_identifier(id));
|
||||
visitor.visit_expression(expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: VisitorMut<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::IdentifierReference(id) => visitor.visit_identifier_mut(id),
|
||||
Self::Property(pn, expr) => {
|
||||
try_break!(visitor.visit_property_name_mut(pn));
|
||||
visitor.visit_expression_mut(expr)
|
||||
}
|
||||
Self::MethodDefinition(pn, md) => {
|
||||
try_break!(visitor.visit_property_name_mut(pn));
|
||||
visitor.visit_method_definition_mut(md)
|
||||
}
|
||||
Self::SpreadObject(expr) => visitor.visit_expression_mut(expr),
|
||||
Self::CoverInitializedName(id, expr) => {
|
||||
try_break!(visitor.visit_identifier_mut(id));
|
||||
visitor.visit_expression_mut(expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Method definition.
|
||||
///
|
||||
/// Starting with ECMAScript 2015, a shorter syntax for method definitions on objects initializers is introduced.
|
||||
/// It is a shorthand for a function assigned to the method's name.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum MethodDefinition {
|
||||
/// The `get` syntax binds an object property to a function that will be called when that property is looked up.
|
||||
///
|
||||
/// Sometimes it is desirable to allow access to a property that returns a dynamically computed value,
|
||||
/// or you may want to reflect the status of an internal variable without requiring the use of explicit method calls.
|
||||
/// In JavaScript, this can be accomplished with the use of a getter.
|
||||
///
|
||||
/// It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value,
|
||||
/// although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
|
||||
Get(Function),
|
||||
|
||||
/// The `set` syntax binds an object property to a function to be called when there is an attempt to set that property.
|
||||
///
|
||||
/// In JavaScript, a setter can be used to execute a function whenever a specified property is attempted to be changed.
|
||||
/// Setters are most often used in conjunction with getters to create a type of pseudo-property.
|
||||
/// It is not possible to simultaneously have a setter on a property that holds an actual value.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set
|
||||
Set(Function),
|
||||
|
||||
/// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Method_definition_syntax
|
||||
Ordinary(Function),
|
||||
|
||||
/// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#generator_methods
|
||||
Generator(Generator),
|
||||
|
||||
/// Async generators can be used to define a method
|
||||
///
|
||||
/// More information
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorMethod
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_generator_methods
|
||||
AsyncGenerator(AsyncGenerator),
|
||||
|
||||
/// Async function can be used to define a method
|
||||
///
|
||||
/// More information
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_methods
|
||||
Async(AsyncFunction),
|
||||
}
|
||||
|
||||
impl VisitWith for MethodDefinition {
|
||||
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function(f),
|
||||
Self::Generator(g) => visitor.visit_generator(g),
|
||||
Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag),
|
||||
Self::Async(af) => visitor.visit_async_function(af),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: VisitorMut<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function_mut(f),
|
||||
Self::Generator(g) => visitor.visit_generator_mut(g),
|
||||
Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag),
|
||||
Self::Async(af) => visitor.visit_async_function_mut(af),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `PropertyName` can be either a literal or computed.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-PropertyName
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PropertyName {
|
||||
/// A `Literal` property name can be either an identifier, a string or a numeric literal.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-LiteralPropertyName
|
||||
Literal(Sym),
|
||||
|
||||
/// A `Computed` property name is an expression that gets evaluated and converted into a property name.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-ComputedPropertyName
|
||||
Computed(Expression),
|
||||
}
|
||||
|
||||
impl PropertyName {
|
||||
/// Returns the literal property name if it exists.
|
||||
#[must_use]
|
||||
pub const fn literal(&self) -> Option<Sym> {
|
||||
if let Self::Literal(sym) = self {
|
||||
Some(*sym)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the expression if the property name is computed.
|
||||
#[must_use]
|
||||
pub const fn computed(&self) -> Option<&Expression> {
|
||||
if let Self::Computed(expr) = self {
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns either the literal property name or the computed const string property name.
|
||||
#[must_use]
|
||||
pub const fn prop_name(&self) -> Option<Sym> {
|
||||
match self {
|
||||
Self::Literal(sym) | Self::Computed(Expression::Literal(Literal::String(sym))) => {
|
||||
Some(*sym)
|
||||
}
|
||||
Self::Computed(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToInternedString for PropertyName {
|
||||
fn to_interned_string(&self, interner: &Interner) -> String {
|
||||
match self {
|
||||
Self::Literal(key) => interner.resolve_expect(*key).to_string(),
|
||||
Self::Computed(key) => key.to_interned_string(interner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sym> for PropertyName {
|
||||
fn from(name: Sym) -> Self {
|
||||
Self::Literal(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Expression> for PropertyName {
|
||||
fn from(name: Expression) -> Self {
|
||||
Self::Computed(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitWith for PropertyName {
|
||||
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::Literal(sym) => visitor.visit_sym(sym),
|
||||
Self::Computed(expr) => visitor.visit_expression(expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
|
||||
where
|
||||
V: VisitorMut<'a>,
|
||||
{
|
||||
match self {
|
||||
Self::Literal(sym) => visitor.visit_sym_mut(sym),
|
||||
Self::Computed(expr) => visitor.visit_expression_mut(expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ClassElementName` can be either a property name or a private identifier.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-ClassElementName
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ClassElementName {
|
||||
/// A public property.
|
||||
PropertyName(PropertyName),
|
||||
/// A private property.
|
||||
PrivateIdentifier(PrivateName),
|
||||
}
|
||||
|
||||
impl ClassElementName {
|
||||
/// Returns the property name if it exists.
|
||||
#[must_use]
|
||||
pub const fn literal(&self) -> Option<Sym> {
|
||||
if let Self::PropertyName(name) = self {
|
||||
name.literal()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user