use serde::{Serialize, Serializer};
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(untagged)]
pub enum LiteralValue {
String(String),
Boolean(bool),
Null,
Number(f64),
RegExp(String),
}
impl LiteralValue {
pub fn into_node_kind<'a>(self) -> NodeKind<'a> {
self.into()
}
}
impl<'a> From<LiteralValue> for NodeKind<'a> {
fn from(value: LiteralValue) -> Self {
NodeKind::Literal { value }
}
}
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct Function<'a> {
pub id: Box<Option<Node<'a>>>,
pub params: Vec<Node<'a>>,
pub body: Box<Node<'a>>,
#[serde(rename = "async")]
pub is_async: bool,
}
#[derive(Debug, PartialEq, Clone)]
pub enum VariableDeclarationKind {
Var,
}
impl Serialize for VariableDeclarationKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
VariableDeclarationKind::Var => "var",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum PropertyKind {
Init,
Get,
Set,
}
impl Serialize for PropertyKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
PropertyKind::Init => "init",
PropertyKind::Get => "get",
PropertyKind::Set => "set",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum UnaryOperator {
Minus,
Plus,
LogicalNot,
BitwiseNot,
Typeof,
Void,
Delete,
}
impl Serialize for UnaryOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
UnaryOperator::Minus => "-",
UnaryOperator::Plus => "+",
UnaryOperator::LogicalNot => "!",
UnaryOperator::BitwiseNot => "~",
UnaryOperator::Typeof => "typeof",
UnaryOperator::Void => "void",
UnaryOperator::Delete => "delete",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum UpdateOperator {
Increment,
Decrement,
}
impl Serialize for UpdateOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
UpdateOperator::Increment => "++",
UpdateOperator::Decrement => "--",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum BinaryOperator {
EqualsEquals,
NotEquals,
TripleEquals,
TripleNotEquals,
LessThan,
LessThanEquals,
GreaterThan,
GreaterThanEquals,
ZeroFillLeftShift,
SignedRightShift,
ZeroFillRightShift,
Exponentiation,
Plus,
Minus,
Asterisk,
Slash,
Percent,
BitwiseOr,
BitwiseXor,
BitwiseAnd,
In,
Instanceof,
}
impl Serialize for BinaryOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
BinaryOperator::EqualsEquals => "==",
BinaryOperator::NotEquals => "!=",
BinaryOperator::TripleEquals => "===",
BinaryOperator::TripleNotEquals => "!==",
BinaryOperator::LessThan => "<",
BinaryOperator::LessThanEquals => "<=",
BinaryOperator::GreaterThan => ">",
BinaryOperator::GreaterThanEquals => ">=",
BinaryOperator::ZeroFillLeftShift => "<<",
BinaryOperator::SignedRightShift => ">>",
BinaryOperator::ZeroFillRightShift => ">>>",
BinaryOperator::Plus => "+",
BinaryOperator::Minus => "-",
BinaryOperator::Exponentiation => "**",
BinaryOperator::Asterisk => "*",
BinaryOperator::Slash => "/",
BinaryOperator::Percent => "%",
BinaryOperator::BitwiseOr => "|",
BinaryOperator::BitwiseXor => "^",
BinaryOperator::BitwiseAnd => "&",
BinaryOperator::In => "in",
BinaryOperator::Instanceof => "instanceof",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum AssignmentOperator {
Equals,
PlusEquals,
MinusEquals,
ExponentEquals,
AsteriskEquals,
SlashEquals,
PercentEquals,
ZeroFillLeftShiftEquals,
SignedRightShiftEquals,
ZeroFillRightShiftEquals,
BitwiseOrEquals,
BitwiseXorEquals,
BitwiseAndEquals,
}
impl Serialize for AssignmentOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
AssignmentOperator::Equals => "=",
AssignmentOperator::PlusEquals => "+=",
AssignmentOperator::MinusEquals => "-=",
AssignmentOperator::ExponentEquals => "**=",
AssignmentOperator::AsteriskEquals => "*=",
AssignmentOperator::SlashEquals => "/=",
AssignmentOperator::PercentEquals => "%=",
AssignmentOperator::ZeroFillLeftShiftEquals => "<<=",
AssignmentOperator::SignedRightShiftEquals => ">>=",
AssignmentOperator::ZeroFillRightShiftEquals => ">>>=",
AssignmentOperator::BitwiseOrEquals => "|=",
AssignmentOperator::BitwiseXorEquals => "^=",
AssignmentOperator::BitwiseAndEquals => "&=",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum LogicalOperator {
LogicalOr,
LogicalAnd,
}
impl Serialize for LogicalOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
LogicalOperator::LogicalOr => "||",
LogicalOperator::LogicalAnd => "&&",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(tag = "type")]
pub enum NodeKind<'a> {
Identifier {
name: String,
},
Literal {
value: LiteralValue,
},
Program {
body: Vec<Node<'a>>,
},
ExpressionStatement {
expression: Box<Node<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
directive: Option<String>,
},
BlockStatement {
body: Vec<Node<'a>>,
},
EmptyStatement,
DebuggerStatement,
WithStatement {
object: Box<Node<'a>>,
body: Box<Node<'a>>,
},
ReturnStatement {
argument: Box<Option<Node<'a>>>,
},
LabeledStatement {
label: Box<Node<'a>>,
body: Box<Node<'a>>,
},
BreakStatement {
label: Box<Option<Node<'a>>>,
},
ContinueStatement {
label: Box<Option<Node<'a>>>,
},
IfStatement {
test: Box<Node<'a>>,
consequent: Box<Node<'a>>,
alternate: Box<Option<Node<'a>>>,
},
SwitchStatement {
discriminant: Box<Node<'a>>,
cases: Vec<Node<'a>>,
},
SwitchCase {
test: Box<Option<Node<'a>>>,
consequent: Vec<Node<'a>>,
},
ThrowStatement {
argument: Box<Node<'a>>,
},
TryStatement {
block: Box<Node<'a>>,
handler: Box<Option<Node<'a>>>,
finalizer: Box<Option<Node<'a>>>,
},
CatchClause {
param: Box<Node<'a>>,
body: Box<Node<'a>>,
},
WhileStatement {
test: Box<Node<'a>>,
body: Box<Node<'a>>,
},
DoWhileStatement {
body: Box<Node<'a>>,
test: Box<Node<'a>>,
},
ForStatement {
init: Box<Option<Node<'a>>>,
test: Box<Option<Node<'a>>>,
update: Box<Option<Node<'a>>>,
body: Box<Node<'a>>,
},
ForInStatement {
left: Box<Node<'a>>,
right: Box<Node<'a>>,
body: Box<Node<'a>>,
},
FunctionDeclaration {
#[serde(flatten)]
function: Function<'a>,
},
VariableDeclaration {
declarations: Vec<Node<'a>>,
kind: VariableDeclarationKind,
},
VariableDeclarator {
id: Box<Node<'a>>,
init: Box<Option<Node<'a>>>,
},
ThisExpression,
ArrayExpression {
elements: Vec<Option<Node<'a>>>,
},
ObjectExpression {
properties: Vec<Node<'a>>,
},
Property {
key: Box<Node<'a>>,
value: Box<Node<'a>>,
kind: PropertyKind,
},
FunctionExpression {
#[serde(flatten)]
function: Function<'a>,
},
UnaryExpression {
operator: UnaryOperator,
prefix: bool,
argument: Box<Node<'a>>,
},
UpdateExpression {
operator: UpdateOperator,
argument: Box<Node<'a>>,
prefix: bool,
},
AwaitExpression {
argument: Box<Node<'a>>,
},
BinaryExpression {
operator: BinaryOperator,
left: Box<Node<'a>>,
right: Box<Node<'a>>,
},
AssignmentExpression {
operator: AssignmentOperator,
left: Box<Node<'a>>,
right: Box<Node<'a>>,
},
LogicalExpression {
operator: LogicalOperator,
left: Box<Node<'a>>,
right: Box<Node<'a>>,
},
MemberExpression {
object: Box<Node<'a>>,
property: Box<Node<'a>>,
computed: bool,
},
ConditionalExpression {
test: Box<Node<'a>>,
consequent: Box<Node<'a>>,
alternate: Box<Node<'a>>,
},
CallExpression {
callee: Box<Node<'a>>,
arguments: Vec<Node<'a>>,
},
NewExpression {
callee: Box<Node<'a>>,
arguments: Vec<Node<'a>>,
},
SequenceExpression {
expressions: Vec<Node<'a>>,
},
Pattern,
Error,
}
impl<'a> NodeKind<'a> {
pub fn with_pos(
self,
start: crate::parser::Span<'a>,
end: crate::parser::Span<'a>,
) -> Node<'a> {
Node {
kind: self,
start,
end,
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct Node<'a> {
#[serde(flatten)]
pub kind: NodeKind<'a>,
#[serde(serialize_with = "serialize_span")]
pub start: crate::parser::Span<'a>,
#[serde(serialize_with = "serialize_span")]
pub end: crate::parser::Span<'a>,
}
fn serialize_span<S>(pos: &crate::parser::Span, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(pos.location_offset() as u64)
}
impl<'a> Node<'a> {
pub fn len(&self) -> usize {
self.end.location_offset() - self.start.location_offset()
}
}