use crate::ns::*;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Expression {
QualifiedIdentifier(QualifiedIdentifier),
Paren(ParenExpression),
NullLiteral(NullLiteral),
BooleanLiteral(BooleanLiteral),
NumericLiteral(NumericLiteral),
StringLiteral(StringLiteral),
ThisLiteral(ThisLiteral),
RegExpLiteral(RegExpLiteral),
Xml(XmlExpression),
XmlMarkup(XmlMarkupExpression),
XmlList(XmlListExpression),
ArrayLiteral(ArrayLiteral),
VectorLiteral(VectorLiteral),
ObjectInitializer(ObjectInitializer),
Function(FunctionExpression),
ImportMeta(ImportMeta),
New(NewExpression),
Member(MemberExpression),
ComputedMember(ComputedMemberExpression),
Descendants(DescendantsExpression),
Filter(FilterExpression),
Super(SuperExpression),
Call(CallExpression),
WithTypeArguments(ExpressionWithTypeArguments),
Unary(UnaryExpression),
OptionalChaining(OptionalChainingExpression),
OptionalChainingPlaceholder(OptionalChainingPlaceholder),
Binary(BinaryExpression),
Conditional(ConditionalExpression),
Assignment(AssignmentExpression),
Sequence(SequenceExpression),
NullableType(NullableTypeExpression),
NonNullableType(NonNullableTypeExpression),
AnyType(AnyTypeExpression),
VoidType(VoidTypeExpression),
ArrayType(ArrayTypeExpression),
TupleType(TupleTypeExpression),
FunctionType(FunctionTypeExpression),
Invalidated(InvalidatedNode),
ReservedNamespace(ReservedNamespaceExpression),
}
impl Expression {
pub fn location(&self) -> Location {
match self {
Self::QualifiedIdentifier(e) => e.location.clone(),
Self::Paren(e) => e.location.clone(),
Self::NullLiteral(e) => e.location.clone(),
Self::BooleanLiteral(e) => e.location.clone(),
Self::NumericLiteral(e) => e.location.clone(),
Self::StringLiteral(e) => e.location.clone(),
Self::ThisLiteral(e) => e.location.clone(),
Self::RegExpLiteral(e) => e.location.clone(),
Self::Xml(e) => e.location.clone(),
Self::XmlMarkup(e) => e.location.clone(),
Self::XmlList(e) => e.location.clone(),
Self::ArrayLiteral(e) => e.location.clone(),
Self::VectorLiteral(e) => e.location.clone(),
Self::ObjectInitializer(e) => e.location.clone(),
Self::Function(e) => e.location.clone(),
Self::ImportMeta(e) => e.location.clone(),
Self::New(e) => e.location.clone(),
Self::Member(e) => e.location.clone(),
Self::ComputedMember(e) => e.location.clone(),
Self::Descendants(e) => e.location.clone(),
Self::Filter(e) => e.location.clone(),
Self::Super(e) => e.location.clone(),
Self::Call(e) => e.location.clone(),
Self::WithTypeArguments(e) => e.location.clone(),
Self::Unary(e) => e.location.clone(),
Self::OptionalChaining(e) => e.location.clone(),
Self::OptionalChainingPlaceholder(e) => e.location.clone(),
Self::Binary(e) => e.location.clone(),
Self::Conditional(e) => e.location.clone(),
Self::Assignment(e) => e.location.clone(),
Self::Sequence(e) => e.location.clone(),
Self::NullableType(e) => e.location.clone(),
Self::NonNullableType(e) => e.location.clone(),
Self::AnyType(e) => e.location.clone(),
Self::VoidType(e) => e.location.clone(),
Self::ArrayType(e) => e.location.clone(),
Self::TupleType(e) => e.location.clone(),
Self::FunctionType(e) => e.location.clone(),
Self::Invalidated(e) => e.location.clone(),
Self::ReservedNamespace(e) => e.location(),
}
}
pub(crate) fn to_metadata(&self, parser: &Parser) -> Result<Option<Vec<Attribute>>, MetadataRefineError1> {
match self {
Self::ArrayLiteral(ArrayLiteral { elements, asdoc, .. }) => {
if elements.len() != 1 {
return Ok(None);
}
if let Element::Expression(ref exp) = elements[0] {
Ok(Some(vec![Attribute::Metadata(parser.refine_metadata(exp, asdoc.clone()).map_err(|e| MetadataRefineError1(e, exp.location()))?)]))
} else {
Ok(None)
}
},
Self::ComputedMember(ComputedMemberExpression { base, asdoc, key, .. }) => {
let a = base.to_metadata(parser)?;
if a.is_none() {
return Ok(None);
}
let mut a = a.unwrap();
if matches!(key.as_ref(), Self::Sequence(_)) {
return Ok(None);
}
a.push(Attribute::Metadata(parser.refine_metadata(key, asdoc.clone()).map_err(|e| MetadataRefineError1(e, key.location()))?));
Ok(Some(a))
},
_ => Ok(None),
}
}
pub fn to_identifier_name_or_asterisk(&self) -> Option<(String, Location)> {
match self {
Self::QualifiedIdentifier(id) => id.to_identifier_name_or_asterisk(),
_ => None,
}
}
pub fn to_identifier_name(&self) -> Option<(String, Location)> {
match self {
Self::QualifiedIdentifier(id) => id.to_identifier_name(),
_ => None,
}
}
pub fn valid_access_modifier(&self) -> bool {
match self {
Self::QualifiedIdentifier(id) => id.is_identifier_token(),
Self::Member(e) => e.base.valid_access_modifier(),
Self::ComputedMember(e) => e.base.valid_access_modifier(),
_ => false,
}
}
pub(crate) fn to_reserved_namespace_string(&self) -> Option<String> {
if let Self::ReservedNamespace(e) = self {
Some(e.to_string())
} else {
None
}
}
pub(crate) fn to_reserved_namespace_attribute(&self) -> Option<Attribute> {
if let Self::ReservedNamespace(e) = self {
Some(e.to_attribute())
} else {
None
}
}
pub fn is_invalidated(&self) -> bool {
matches!(self, Self::Invalidated(_))
}
pub fn is_non_null_operation(&self) -> bool {
match self {
Self::Unary(expr) => expr.operator == Operator::NonNull,
_ => false,
}
}
pub fn is_valid_assignment_left_hand_side(&self) -> bool {
match self {
Self::Invalidated(_) => true,
Self::Unary(e) => if e.operator == Operator::NonNull {
e.expression.is_valid_assignment_left_hand_side()
} else {
true
},
Self::ArrayLiteral(_) | Self::ObjectInitializer(_) => self.is_valid_destructuring(),
_ => true,
}
}
pub fn is_valid_destructuring(&self) -> bool {
match self {
Self::Invalidated(_) => true,
Self::QualifiedIdentifier(id) => !id.attribute && id.qualifier.is_none() && match &id.id {
QualifiedIdentifierIdentifier::Id(id) => id.0 != "*",
_ => false,
},
Self::ArrayLiteral(expr) => {
for el in &expr.elements {
match el {
Element::Elision => {},
Element::Expression(expr) => {
if !expr.is_valid_destructuring() {
return false;
}
},
Element::Rest((expr, _)) => {
if !expr.is_valid_destructuring() {
return false;
}
},
}
}
true
},
Self::ObjectInitializer(init) => {
for field in init.fields.iter() {
match field.as_ref() {
InitializerField::Field { value, .. } => {
if let Some(val) = value {
if !val.is_valid_destructuring() {
return false;
}
}
},
InitializerField::Rest((expr, _)) => {
if !expr.is_valid_destructuring() {
return false;
}
},
}
}
true
},
Self::Unary(expr) => expr.operator == Operator::NonNull && expr.expression.is_valid_destructuring(),
_ => false,
}
}
pub(crate) fn to_normal_configuration_identifier(&self, parser: &Parser) -> Result<Option<((String, Location), (String, Location), Vec<Attribute>)>, MetadataRefineError1> {
if let Self::QualifiedIdentifier(id) = self {
if id.attribute {
return Ok(None);
}
if let Some(q) = &id.qualifier {
if let Some(q) = q.to_identifier_name() {
if let QualifiedIdentifierIdentifier::Id(id) = &id.id {
return Ok(Some((q, id.clone(), vec![])));
}
}
}
}
if let Self::ComputedMember(ComputedMemberExpression { base, asdoc, key, .. }) = self {
let a = base.to_normal_configuration_identifier(parser)?;
if a.is_none() {
return Ok(None);
}
let (ns, name, mut a) = a.unwrap();
if matches!(key.as_ref(), Self::Sequence(_)) {
return Ok(None);
}
a.push(Attribute::Metadata(parser.refine_metadata(key, asdoc.clone()).map_err(|e| MetadataRefineError1(e, key.location()))?));
return Ok(Some((ns, name, a)));
}
Ok(None)
}
pub(crate) fn to_normal_configuration_identifier_no_metadata(&self) -> Option<((String, Location), (String, Location))> {
if let Self::QualifiedIdentifier(id) = self {
if id.attribute {
return None;
}
if let Some(q) = &id.qualifier {
if let Some(q) = q.to_identifier_name() {
if let QualifiedIdentifierIdentifier::Id(id) = &id.id {
return Some((q, id.clone()));
}
}
}
}
None
}
pub fn search_optional_chaining_placeholder(self: &Rc<Self>) -> Option<Rc<Expression>> {
match self.as_ref() {
Self::OptionalChainingPlaceholder(_) => Some(self.clone()),
Self::Member(e) => e.base.search_optional_chaining_placeholder(),
Self::ComputedMember(e) => e.base.search_optional_chaining_placeholder(),
Self::Descendants(e) => e.base.search_optional_chaining_placeholder(),
Self::Filter(e) => e.base.search_optional_chaining_placeholder(),
Self::Unary(e) => e.expression.search_optional_chaining_placeholder(),
Self::Call(e) => e.base.search_optional_chaining_placeholder(),
Self::WithTypeArguments(e) => e.base.search_optional_chaining_placeholder(),
_ => None,
}
}
}