use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Debug, Fail)]
pub enum ReferenceError {
#[fail(display = "ReferenceError: Invalid left-hand side in assignment")]
InvalidLeftHandSide,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Position {
pub line: usize,
pub column: usize,
}
impl From<(usize, usize)> for Position {
fn from((line, column): (usize, usize)) -> Position {
Position { line, column }
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct SourceLocation {
pub start: Position,
pub end: Position,
}
impl<P: Into<Position>> From<(P, P)> for SourceLocation {
fn from((start, end): (P, P)) -> SourceLocation {
SourceLocation {
start: start.into(),
end: end.into(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Identifier(pub Option<SourceLocation>, pub String);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum Literal {
NullLiteral(NullLiteral),
BooleanLiteral(BooleanLiteral),
NumericLiteral(NumericLiteral),
StringLiteral(StringLiteral),
RegExpLiteral(RegExpLiteral),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NullLiteral;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct BooleanLiteral(pub bool);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NumericLiteral(pub f64);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct StringLiteral(pub String);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct RegExpLiteral {
pub pattern: String,
pub flags: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct TemplateElement {
pub cooked: Option<String>,
pub raw: String,
pub loc: Option<SourceLocation>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum Expression {
Identifier {
name: String,
loc: Option<SourceLocation>,
},
Literal {
value: Literal,
loc: Option<SourceLocation>,
},
ThisExpression {
loc: Option<SourceLocation>,
},
ArrayExpression {
elements: Vec<ExpressionListItem>,
loc: Option<SourceLocation>,
},
ObjectExpression {
properties: Vec<ObjectExpressionProperty>,
loc: Option<SourceLocation>,
},
FunctionExpression {
id: Option<Identifier>,
params: Vec<Pattern>,
body: Vec<FunctionBodyStatement>,
async: bool,
generator: bool,
},
UnaryExpression {
operator: UnaryOperator,
prefix: bool,
argument: Box<Expression>,
},
UpdateExpression {
operator: UpdateOperator,
argument: Box<Expression>,
prefix: bool,
},
BinaryExpression {
operator: BinaryOperator,
left: Box<Expression>,
right: Box<Expression>,
},
AssignmentExpression {
operator: AssignmentOperator,
left: Box<Pattern>,
right: Box<Expression>,
},
LogicalExpression {
operator: LogicalOperator,
left: Box<Expression>,
right: Box<Expression>,
},
MemberExpression {
object: Box<SuperExpression>,
property: Box<Expression>,
computed: bool,
},
ConditionalExpression {
test: Box<Expression>,
alternate: Box<Expression>,
consequent: Box<Expression>,
loc: Option<SourceLocation>,
},
CallExpression {
callee: Box<SuperExpression>,
arguments: Vec<ExpressionListItem>,
},
NewExpression {
callee: Box<Expression>,
arguments: Vec<ExpressionListItem>,
},
SequenceExpression {
expressions: Vec<Expression>,
},
ArrowFunctionExpression {
body: Box<ArrowFunctionBody>,
expression: bool,
},
Yield {
argument: Option<Box<Expression>>,
delegate: bool, },
TemplateLiteral {
quasis: Vec<TemplateElement>,
expressions: Vec<Expression>,
loc: Option<SourceLocation>,
},
TaggedTemplateExpression {
tag: Box<Expression>,
quasi: Box<Expression>,
},
AwaitExpression {
argument: Box<Expression>,
loc: Option<SourceLocation>,
},
MetaProperty,
JSXElement {
name: String,
attributes: Vec<JsxAttribute>,
children: Vec<Expression>,
loc: Option<SourceLocation>,
},
JsxFragment {
children: Vec<Expression>,
loc: Option<SourceLocation>,
},
}
impl Expression {
pub fn into_pattern(self) -> Result<Pattern, ReferenceError> {
match self {
Expression::Identifier { name, loc } => Ok(Pattern::Identifier { name, loc }),
_ => Err(ReferenceError::InvalidLeftHandSide),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum ExpressionListItem {
Expression(Expression),
Spread(SpreadElement),
#[serde(rename = "null")]
Null,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum SpreadElement {
SpreadElement {
argument: Expression,
loc: Option<SourceLocation>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Property {
pub key: Expression,
pub value: Expression,
pub kind: PropertyKind,
pub method: bool,
pub shorthand: bool,
pub computed: bool,
pub loc: Option<SourceLocation>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum PropertyKind {
Init,
Get,
Set,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum ObjectExpressionProperty {
Property(Property),
SpreadElement(SpreadElement),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum Pattern {
Identifier {
name: String,
loc: Option<SourceLocation>,
},
ObjectPattern {
properties: Vec<ObjectPatternProperty>,
loc: Option<SourceLocation>,
},
ArrayPattern {
elements: Vec<Pattern>,
loc: Option<SourceLocation>,
},
RestElement {
argument: Box<Pattern>,
loc: Option<SourceLocation>,
},
AssignmentPattern {
left: Box<Pattern>,
argument: Expression,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum ObjectPatternProperty {
#[serde(rename = "Property")]
AssignmentProperty {
key: Expression,
value: Pattern,
},
RestElement {
argument: Box<Pattern>,
loc: Option<SourceLocation>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum TemplateLiteralElement {
TemplateElement(TemplateElement),
Expression(Expression),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum UpdateOperator {
Increment,
Decrement,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum UnaryOperator {
Minus,
Plus,
Not,
BitwiseNot,
Typeof,
Void,
Delete,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum BinaryOperator {
EqEq,
NotEq,
EqEqEq,
NotEqEq,
Lt,
Lte,
Gt,
Gte,
Shl,
Shr,
UnsignedShr,
Plus,
Minus,
Multiply,
Divide,
Mod,
BitwiseOr,
Or,
BitwiseXor,
BitwiseAnd,
And,
In,
InstanceOf,
Exponentiation,
}
#[derive(Debug, Clone, PartialEq)]
pub enum AssignmentOperator {
Eq,
PlusEq,
MinusEq,
MultiplyEq,
DivideEq,
ModEq,
ShlEq,
ShrEq,
UnsignedShrEq,
BitwiseOrEq,
BitwiseXorEq,
BitwiseAndEq,
ExponentiationEq,
}
impl Serialize for AssignmentOperator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let string = match self {
AssignmentOperator::Eq => "=",
AssignmentOperator::PlusEq => "+=",
AssignmentOperator::MinusEq => "-=",
AssignmentOperator::MultiplyEq => "*=",
AssignmentOperator::DivideEq => "/=",
AssignmentOperator::ModEq => "%=",
AssignmentOperator::ShlEq => "<<=",
AssignmentOperator::ShrEq => ">>=",
AssignmentOperator::UnsignedShrEq => ">>>=",
AssignmentOperator::BitwiseOrEq => "|=",
AssignmentOperator::BitwiseXorEq => "^=",
AssignmentOperator::BitwiseAndEq => "&=",
AssignmentOperator::ExponentiationEq => "**=",
};
serializer.serialize_str(string)
}
}
struct AssignmentOperatorVisitor;
impl<'de> Visitor<'de> for AssignmentOperatorVisitor {
type Value = AssignmentOperator;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("one of =")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
match value {
"=" => Ok(AssignmentOperator::Eq),
"+=" => Ok(AssignmentOperator::PlusEq),
"-=" => Ok(AssignmentOperator::MinusEq),
"*=" => Ok(AssignmentOperator::MultiplyEq),
"/=" => Ok(AssignmentOperator::DivideEq),
"%=" => Ok(AssignmentOperator::ModEq),
"<<=" => Ok(AssignmentOperator::ShlEq),
">>=" => Ok(AssignmentOperator::ShrEq),
">>>=" => Ok(AssignmentOperator::UnsignedShrEq),
"|=" => Ok(AssignmentOperator::BitwiseOrEq),
"^=" => Ok(AssignmentOperator::BitwiseAndEq),
"&=" => Ok(AssignmentOperator::BitwiseAndEq),
"**=" => Ok(AssignmentOperator::ExponentiationEq),
_ => Err(E::custom(format!("{} is not an operator", value))),
}
}
}
impl<'de> Deserialize<'de> for AssignmentOperator {
fn deserialize<D>(deserializer: D) -> Result<AssignmentOperator, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(AssignmentOperatorVisitor)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum LogicalOperator {
Or,
And,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum JsxAttribute {
JsxSpreadAttribute {
expression: Expression,
},
JsxAttribute {
name: String,
value: Option<Expression>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum Super {
#[serde(rename_all = "camelCase")]
Super {
loc: Option<SourceLocation>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum SuperExpression {
Super(Super),
Expression(Expression),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum FunctionBodyStatement {
Statement(Statement),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum ArrowFunctionBody {
FunctionBody(Vec<FunctionBodyStatement>),
Expression(Expression),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum Statement {
ExpressionStatement {
expression: Expression,
loc: Option<SourceLocation>,
},
VariableDeclaration {
declarations: Vec<VariableDeclarator>,
kind: VariableDeclarationKind,
loc: Option<SourceLocation>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct VariableDeclarator {
pub id: Pattern,
pub init: VariableDeclaratorInit,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum VariableDeclaratorInit {
#[serde(rename = "lowercase")]
Null,
Expression(Expression),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged, rename_all = "lowercase")]
pub enum VariableDeclarationKind {
Var,
Let,
Const,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum Program {
#[serde(rename_all = "camelCase")]
Program {
body: Vec<Statement>,
source_type: SourceType,
loc: Option<SourceLocation>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum SourceType {
Script,
Module,
}