use crate::error::SyntaxError;
use crate::error::SyntaxErrorType;
use crate::flag::flag_bitfield;
use crate::flag::Flag;
use crate::flag::Flags;
use crate::num::JsNumber;
use crate::operator::OperatorName;
use crate::session::Session;
use crate::session::SessionString;
use crate::session::SessionVec;
use crate::source::SourceRange;
use crate::symbol::Scope;
use core::fmt::Debug;
use std::fmt;
use std::fmt::Formatter;
use std::ops::BitOr;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum NodeFlag {
HasClassDecl, HasConstVarDeclWithIdentifierPattern, HasConstVarDeclWithNonIdentifierPattern, HasFunctionDecl, HasLetVarDeclWithIdentifierPattern, HasLetVarDeclWithNonIdentifierPattern, HasNonExprStmtOrVarDecl, HasVarVarDeclWithIdentifierPattern, HasVarVarDeclWithNonIdentifierPattern, UnconditionallyBreaks, UnconditionallyContinues, UnconditionallyReturns, UnconditionallyThrows, Unreachable, }
impl Flag for NodeFlag {
fn bitfield(self) -> u64 {
flag_bitfield!(self)
}
}
impl BitOr for NodeFlag {
type Output = Flags<NodeFlag>;
fn bitor(self, rhs: Self) -> Self::Output {
Flags::from_raw(self.bitfield() | rhs.bitfield())
}
}
pub const NODE_FLAG_UNCONDITIONAL_FLOWS: Flags<NodeFlag> = Flags::from_raw(
flag_bitfield!(NodeFlag::UnconditionallyBreaks)
| flag_bitfield!(NodeFlag::UnconditionallyContinues)
| flag_bitfield!(NodeFlag::UnconditionallyReturns)
| flag_bitfield!(NodeFlag::UnconditionallyThrows),
);
pub struct NodeData<'a> {
pub loc: SourceRange<'a>,
pub stx: Syntax<'a>,
pub scope: Scope<'a>,
pub flags: Flags<NodeFlag>,
}
impl<'a> NodeData<'a> {
pub fn take(&mut self, session: &'a Session) -> &'a mut NodeData<'a> {
self.replace(session, Syntax::_TakenNode {})
}
pub fn replace(&mut self, session: &'a Session, stx: Syntax<'a>) -> &'a mut NodeData<'a> {
let dummy = NodeData {
loc: self.loc,
scope: self.scope,
stx,
flags: self.flags,
};
let taken = core::mem::replace(self, dummy);
session.get_allocator().alloc(taken)
}
pub fn error(&self, typ: SyntaxErrorType) -> SyntaxError<'a> {
self.loc.error(typ, None)
}
}
impl<'a> Debug for Node<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.stx.fmt(f)
}
}
#[cfg(feature = "serialize")]
impl<'a> serde::Serialize for NodeData<'a> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.stx.serialize(serializer)
}
}
pub type Node<'a> = &'a mut NodeData<'a>;
pub fn new_node_with_flags<'a>(
session: &'a Session,
scope: Scope<'a>,
loc: SourceRange<'a>,
stx: Syntax<'a>,
flags: Flags<NodeFlag>,
) -> Node<'a> {
session.mem.alloc(NodeData {
loc,
stx,
scope,
flags,
})
}
pub fn new_node_with_flag<'a>(
session: &'a Session,
scope: Scope<'a>,
loc: SourceRange<'a>,
stx: Syntax<'a>,
flag: NodeFlag,
) -> Node<'a> {
new_node_with_flags(session, scope, loc, stx, Flags::new() | flag)
}
pub fn new_node<'a>(
session: &'a Session,
scope: Scope<'a>,
loc: SourceRange<'a>,
stx: Syntax<'a>,
) -> Node<'a> {
new_node_with_flags(session, scope, loc, stx, Flags::new())
}
type Declaration<'a> = Node<'a>;
type Expression<'a> = Node<'a>;
type Pattern<'a> = Node<'a>;
type Statement<'a> = Node<'a>;
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum VarDeclMode {
Const,
Let,
Var,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ArrayElement<'a> {
Single(Expression<'a>),
Rest(Expression<'a>),
Empty,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ClassOrObjectMemberKey<'a> {
Direct(SourceRange<'a>),
Computed(Expression<'a>),
}
impl<'a> ClassOrObjectMemberKey<'a> {
pub fn take(&mut self) -> ClassOrObjectMemberKey<'a> {
core::mem::replace(
self,
ClassOrObjectMemberKey::Direct(SourceRange::from_slice(b"")),
)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ClassOrObjectMemberValue<'a> {
Getter {
body: Statement<'a>,
},
Method {
is_async: bool,
generator: bool,
signature: Node<'a>,
body: Statement<'a>,
},
Property {
initializer: Option<Expression<'a>>,
},
Setter {
body: Statement<'a>,
parameter: Pattern<'a>,
},
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub struct ClassMember<'a> {
pub key: ClassOrObjectMemberKey<'a>,
pub statik: bool,
pub value: ClassOrObjectMemberValue<'a>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ObjectMemberType<'a> {
Valued {
key: ClassOrObjectMemberKey<'a>,
value: ClassOrObjectMemberValue<'a>,
},
Shorthand {
identifier: Node<'a>, },
Rest {
value: Expression<'a>,
},
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub struct ArrayPatternElement<'a> {
pub target: Pattern<'a>,
pub default_value: Option<Expression<'a>>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub struct ExportName<'a> {
pub target: SourceRange<'a>,
pub alias: Pattern<'a>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ExportNames<'a> {
All(Option<Pattern<'a>>),
Specific(SessionVec<'a, ExportName<'a>>),
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub struct VariableDeclarator<'a> {
pub pattern: Pattern<'a>,
pub initializer: Option<Expression<'a>>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ForThreeInit<'a> {
None,
Expression(Expression<'a>),
Declaration(Declaration<'a>),
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ForInOfStmtHeaderLhs<'a> {
Declaration(Declaration<'a>),
Pattern(Pattern<'a>),
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum ForStmtHeader<'a> {
Three {
init: ForThreeInit<'a>,
condition: Option<Expression<'a>>,
post: Option<Expression<'a>>,
},
InOf {
of: bool,
lhs: ForInOfStmtHeaderLhs<'a>,
rhs: Expression<'a>,
},
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum LiteralTemplatePart<'a> {
Substitution(Expression<'a>),
String(&'a str),
}
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, strum_macros::Display))]
#[cfg_attr(feature = "serialize", serde(tag = "$t"))]
pub enum Syntax<'a> {
IdentifierPattern {
name: SourceRange<'a>,
},
ArrayPattern {
elements: SessionVec<'a, Option<ArrayPatternElement<'a>>>,
rest: Option<Pattern<'a>>,
},
ObjectPattern {
properties: SessionVec<'a, Node<'a>>,
rest: Option<Pattern<'a>>,
},
ClassOrFunctionName {
name: SourceRange<'a>,
},
FunctionSignature {
parameters: SessionVec<'a, Declaration<'a>>,
},
ClassDecl {
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
export: bool,
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
export_default: bool,
name: Option<Node<'a>>, extends: Option<Expression<'a>>,
members: SessionVec<'a, ClassMember<'a>>,
},
FunctionDecl {
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
export: bool,
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
export_default: bool,
generator: bool,
is_async: bool,
name: Option<Node<'a>>, signature: Node<'a>,
body: Statement<'a>,
},
ParamDecl {
rest: bool,
pattern: Pattern<'a>,
default_value: Option<Expression<'a>>,
},
VarDecl {
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
export: bool,
mode: VarDeclMode,
declarators: SessionVec<'a, VariableDeclarator<'a>>,
},
ArrowFunctionExpr {
parenthesised: bool,
is_async: bool,
signature: Node<'a>,
body: Node<'a>,
},
BinaryExpr {
parenthesised: bool,
operator: OperatorName,
left: Expression<'a>,
right: Expression<'a>,
},
CallExpr {
optional_chaining: bool,
parenthesised: bool,
callee: Expression<'a>,
arguments: SessionVec<'a, Node<'a>>,
},
ClassExpr {
parenthesised: bool,
name: Option<Node<'a>>,
extends: Option<Expression<'a>>,
members: SessionVec<'a, ClassMember<'a>>,
},
ConditionalExpr {
parenthesised: bool,
test: Expression<'a>,
consequent: Expression<'a>,
alternate: Expression<'a>,
},
ComputedMemberExpr {
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
assignment_target: bool,
optional_chaining: bool,
object: Expression<'a>,
member: Expression<'a>,
},
FunctionExpr {
parenthesised: bool,
is_async: bool,
generator: bool,
name: Option<Node<'a>>,
signature: Node<'a>,
body: Statement<'a>,
},
IdentifierExpr {
name: SourceRange<'a>,
},
ImportExpr {
module: Expression<'a>,
},
ImportMeta {},
JsxAttribute {
name: Expression<'a>, value: Option<Expression<'a>>, },
JsxElement {
name: Option<Expression<'a>>, attributes: SessionVec<'a, Expression<'a>>, children: SessionVec<'a, Expression<'a>>, },
JsxExpressionContainer {
value: Expression<'a>,
},
JsxMemberExpression {
base: Node<'a>, path: SessionVec<'a, SourceRange<'a>>,
},
JsxName {
namespace: Option<SourceRange<'a>>,
name: SourceRange<'a>,
},
JsxSpreadAttribute {
value: Expression<'a>,
},
JsxText {
value: SourceRange<'a>,
},
LiteralArrayExpr {
elements: SessionVec<'a, ArrayElement<'a>>,
},
LiteralBigIntExpr {
value: SessionString<'a>,
},
LiteralBooleanExpr {
value: bool,
},
LiteralNull {},
LiteralNumberExpr {
value: JsNumber,
},
LiteralObjectExpr {
members: SessionVec<'a, Node<'a>>,
},
LiteralRegexExpr {},
LiteralStringExpr {
value: &'a str,
},
LiteralTemplateExpr {
parts: SessionVec<'a, LiteralTemplatePart<'a>>,
},
MemberExpr {
parenthesised: bool,
optional_chaining: bool,
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
assignment_target: bool,
left: Expression<'a>,
right: SourceRange<'a>,
},
SuperExpr {},
ThisExpr {},
UnaryExpr {
parenthesised: bool,
operator: OperatorName,
argument: Expression<'a>,
},
UnaryPostfixExpr {
parenthesised: bool,
operator: OperatorName,
argument: Expression<'a>,
},
BlockStmt {
body: SessionVec<'a, Statement<'a>>,
},
BreakStmt {
label: Option<SourceRange<'a>>,
},
ContinueStmt {
label: Option<SourceRange<'a>>,
},
DebuggerStmt {},
DoWhileStmt {
condition: Expression<'a>,
body: Statement<'a>,
},
EmptyStmt {},
ExportDefaultExprStmt {
expression: Expression<'a>,
},
ExportListStmt {
names: ExportNames<'a>,
from: Option<&'a str>,
},
ExpressionStmt {
expression: Expression<'a>,
},
IfStmt {
test: Expression<'a>,
consequent: Statement<'a>,
alternate: Option<Statement<'a>>,
},
ImportStmt {
default: Option<Pattern<'a>>,
names: Option<ExportNames<'a>>,
module: &'a str,
},
ForStmt {
header: ForStmtHeader<'a>,
body: Statement<'a>,
},
LabelStmt {
name: SourceRange<'a>,
statement: Statement<'a>,
},
ReturnStmt {
value: Option<Expression<'a>>,
},
SwitchStmt {
test: Expression<'a>,
branches: SessionVec<'a, Node<'a>>,
},
ThrowStmt {
value: Expression<'a>,
},
TryStmt {
wrapped: Statement<'a>,
catch: Option<Node<'a>>,
finally: Option<Statement<'a>>,
},
WhileStmt {
condition: Expression<'a>,
body: Statement<'a>,
},
TopLevel {
body: SessionVec<'a, Statement<'a>>,
},
CallArg {
spread: bool,
value: Expression<'a>,
},
CatchBlock {
parameter: Option<Pattern<'a>>,
body: Statement<'a>,
},
ObjectMember {
typ: ObjectMemberType<'a>,
},
ObjectPatternProperty {
key: ClassOrObjectMemberKey<'a>,
target: Pattern<'a>,
#[cfg_attr(feature = "serialize", serde(default))]
#[cfg_attr(
feature = "serialize",
serde(skip_serializing_if = "core::ops::Not::not")
)]
shorthand: bool,
default_value: Option<Expression<'a>>,
},
SwitchBranch {
case: Option<Expression<'a>>,
body: SessionVec<'a, Statement<'a>>,
},
_TakenNode {},
}