diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..f343b1f --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,18 @@ +name: Rust + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: fmt check + run: cargo fmt --check + - name: clippy + run: cargo clippy -- -Dwarnings + - name: Build + run: cargo build + diff --git a/Cargo.toml b/Cargo.toml index 8496f7c..4f1a51a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "resast" -version = "0.6.0-alpha.3" +version = "0.6.0-alpha.5" authors = ["rfm "] -edition = "2018" +edition = "2021" description = "Rusty-ECMAScript Abstract Syntax Tree" repository = "https://github.com/rusty-ecma/resast" license = "MIT" @@ -10,15 +10,8 @@ keywords = ["JavaScript", "parsing", "JS", "ES", "ECMA"] categories = ["parsing", "text-processing", "web-programming"] [dependencies] -serde = { version = "1", optional = true } -serde_derive = { version = "1", optional = true } - -[dev-dependencies] -serde_json = "1" -ressa = "0.7.0-beta-6" -pretty_env_logger = "0.3" +serde = { version = "1", optional = true, features = ["derive"] } [features] default = [] -serialization = ["serde", "serde_derive"] -esprima = ["serialization"] +serde = ["dep:serde"] diff --git a/src/decl.rs b/src/decl.rs index 30b6f49..41117c0 100644 --- a/src/decl.rs +++ b/src/decl.rs @@ -1,184 +1,309 @@ -use crate::expr::{Expr, Lit}; -use crate::pat::Pat; -use crate::VarKind; -use crate::{Class, Func, Ident}; - -/// The declaration of a variable, function, class, import or export -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub enum Decl { - /// A variable declaration - /// ```js - /// var x, b; - /// let y, a = 0; - /// const q = 100 - /// ``` - Var(VarKind, Vec>), - /// A function declaration - /// ```js - /// function thing() {} - /// ``` - Func(Func), - /// A class declaration - /// ```js - /// class Thing {} - /// ``` - Class(Class), - /// An import declaration - /// ```js - /// import * as moment from 'moment'; - /// import Thing, {thing} from 'stuff'; - /// ``` - Import(Box>), - /// An export declaration - /// ```js - /// export function thing() {} - /// ``` - Export(Box>), -} - -/// The identifier and optional value of a variable declaration -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub struct VarDecl { - pub id: Pat, - pub init: Option>, -} - -/// A declaration that imports exported -/// members of another module -/// -/// ```js -/// import {Thing} from './stuff.js'; -/// ``` -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -pub struct ModImport { - pub specifiers: Vec>, - pub source: Lit, -} - -/// The name of the thing being imported -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub enum ImportSpecifier { - /// A specifier in curly braces, this might - /// have a local alias - /// - /// ```js - /// import {Thing} from './stuff.js'; - /// import {People as Persons} from './places.js'; - /// ``` - Normal(Vec>), - /// A specifier that has been exported with the - /// default keyword, this should not be wrapped in - /// curly braces. - /// ```js - /// import DefaultThing from './stuff/js'; - /// ``` - Default(Ident), - /// Import all exported members from a module - /// in a namespace. - /// - /// ```js - /// import * as Moment from 'moment.js'; - /// ``` - Namespace(Ident), -} -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -pub struct NormalImportSpec { - pub alias: Option>, - pub imported: Ident, -} - -/// Something exported from this module -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub enum ModExport { - /// ```js - /// export default function() {}; - /// //or - /// export default 1; - /// ``` - Default(DefaultExportDecl), - ///```js - /// export {foo} from 'mod'; - /// //or - /// export {foo as bar} from 'mod'; - /// //or - /// export var foo = 1; - /// //or - /// export function bar() { - /// } - /// ``` - Named(NamedExportDecl), - /// ```js - /// export * from 'mod'; - /// ``` - All { - alias: Option>, - name: Lit, - }, -} - -/// An export that has a name -/// ```js -/// export function thing() {} -/// export {stuff} from 'place'; -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -pub enum NamedExportDecl { - Decl(Decl), - Specifier(Vec>, Option>), -} - -/// A default export -/// ```js -/// export default class Thing {} -/// ``` -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub enum DefaultExportDecl { - Decl(Decl), - Expr(Expr), -} - -/// The name of the thing being exported -/// this might include an alias -/// ```js -/// //no-alias -/// export {Thing} from 'place'; -/// //aliased -/// export {Stuff as NewThing} from 'place' -/// ``` -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub struct ExportSpecifier { - pub local: Ident, - pub alias: Option>, -} +use crate::expr::{Expr, Lit}; +use crate::pat::Pat; +use crate::{Class, Func, Ident}; +use crate::{IntoAllocated, VarKind}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The declaration of a variable, function, class, import or export +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub enum Decl { + /// A variable declaration + /// ```js + /// var x, b; + /// let y, a = 0; + /// const q = 100 + /// ``` + Var(VarKind, Vec>), + /// A function declaration + /// ```js + /// function thing() {} + /// ``` + Func(Func), + /// A class declaration + /// ```js + /// class Thing {} + /// ``` + Class(Class), + /// An import declaration + /// ```js + /// import * as moment from 'moment'; + /// import Thing, {thing} from 'stuff'; + /// ``` + Import(Box>), + /// An export declaration + /// ```js + /// export function thing() {} + /// ``` + Export(Box>), +} + +impl IntoAllocated for Decl +where + T: ToString, +{ + type Allocated = Decl; + + fn into_allocated(self) -> Self::Allocated { + match self { + Decl::Var(k, decls) => { + Decl::Var(k, decls.into_iter().map(|d| d.into_allocated()).collect()) + } + Decl::Func(inner) => Decl::Func(inner.into_allocated()), + Decl::Class(inner) => Decl::Class(inner.into_allocated()), + Decl::Import(inner) => Decl::Import(inner.into_allocated()), + Decl::Export(inner) => Decl::Export(inner.into_allocated()), + } + } +} + +/// The identifier and optional value of a variable declaration +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct VarDecl { + pub id: Pat, + pub init: Option>, +} + +impl IntoAllocated for VarDecl +where + T: ToString, +{ + type Allocated = VarDecl; + + fn into_allocated(self) -> Self::Allocated { + VarDecl { + id: self.id.into_allocated(), + init: self.init.map(|i| i.into_allocated()), + } + } +} + +/// A declaration that imports exported +/// members of another module +/// +/// ```js +/// import {Thing} from './stuff.js'; +/// ``` +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ModImport { + pub specifiers: Vec>, + pub source: Lit, +} + +impl IntoAllocated for ModImport +where + T: ToString, +{ + type Allocated = ModImport; + + fn into_allocated(self) -> Self::Allocated { + ModImport { + specifiers: self + .specifiers + .into_iter() + .map(|s| s.into_allocated()) + .collect(), + source: self.source.into_allocated(), + } + } +} + +/// The name of the thing being imported +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub enum ImportSpecifier { + /// A specifier in curly braces, this might + /// have a local alias + /// + /// ```js + /// import {Thing} from './stuff.js'; + /// import {People as Persons} from './places.js'; + /// ``` + Normal(Vec>), + /// A specifier that has been exported with the + /// default keyword, this should not be wrapped in + /// curly braces. + /// ```js + /// import DefaultThing from './stuff/js'; + /// ``` + Default(Ident), + /// Import all exported members from a module + /// in a namespace. + /// + /// ```js + /// import * as Moment from 'moment.js'; + /// ``` + Namespace(Ident), +} + +impl IntoAllocated for ImportSpecifier +where + T: ToString, +{ + type Allocated = ImportSpecifier; + + fn into_allocated(self) -> Self::Allocated { + match self { + ImportSpecifier::Normal(inner) => { + ImportSpecifier::Normal(inner.into_iter().map(|n| n.into_allocated()).collect()) + } + ImportSpecifier::Default(inner) => ImportSpecifier::Default(inner.into_allocated()), + ImportSpecifier::Namespace(inner) => ImportSpecifier::Namespace(inner.into_allocated()), + } + } +} + +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct NormalImportSpec { + pub alias: Option>, + pub imported: Ident, +} + +impl IntoAllocated for NormalImportSpec +where + T: ToString, +{ + type Allocated = NormalImportSpec; + + fn into_allocated(self) -> Self::Allocated { + NormalImportSpec { + alias: self.alias.map(|i| i.into_allocated()), + imported: self.imported.into_allocated(), + } + } +} + +/// Something exported from this module +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub enum ModExport { + /// ```js + /// export default function() {}; + /// //or + /// export default 1; + /// ``` + Default(DefaultExportDecl), + ///```js + /// export {foo} from 'mod'; + /// //or + /// export {foo as bar} from 'mod'; + /// //or + /// export var foo = 1; + /// //or + /// export function bar() { + /// } + /// ``` + Named(NamedExportDecl), + /// ```js + /// export * from 'mod'; + /// ``` + All { + alias: Option>, + name: Lit, + }, +} + +impl IntoAllocated for ModExport +where + T: ToString, +{ + type Allocated = ModExport; + + fn into_allocated(self) -> Self::Allocated { + match self { + ModExport::Default(inner) => ModExport::Default(inner.into_allocated()), + ModExport::Named(inner) => ModExport::Named(inner.into_allocated()), + ModExport::All { alias, name } => ModExport::All { + alias: alias.map(|i| i.into_allocated()), + name: name.into_allocated(), + }, + } + } +} + +/// An export that has a name +/// ```js +/// export function thing() {} +/// export {stuff} from 'place'; +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub enum NamedExportDecl { + Decl(Decl), + Specifier(Vec>, Option>), +} + +impl IntoAllocated for NamedExportDecl +where + T: ToString, +{ + type Allocated = NamedExportDecl; + + fn into_allocated(self) -> Self::Allocated { + match self { + NamedExportDecl::Decl(inner) => NamedExportDecl::Decl(inner.into_allocated()), + NamedExportDecl::Specifier(specs, lit) => NamedExportDecl::Specifier( + specs.into_iter().map(|s| s.into_allocated()).collect(), + lit.map(|l| l.into_allocated()), + ), + } + } +} + +/// A default export +/// ```js +/// export default class Thing {} +/// ``` +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub enum DefaultExportDecl { + Decl(Decl), + Expr(Expr), +} + +impl IntoAllocated for DefaultExportDecl +where + T: ToString, +{ + type Allocated = DefaultExportDecl; + + fn into_allocated(self) -> Self::Allocated { + match self { + DefaultExportDecl::Decl(inner) => DefaultExportDecl::Decl(inner.into_allocated()), + DefaultExportDecl::Expr(inner) => DefaultExportDecl::Expr(inner.into_allocated()), + } + } +} + +/// The name of the thing being exported +/// this might include an alias +/// ```js +/// //no-alias +/// export {Thing} from 'place'; +/// //aliased +/// export {Stuff as NewThing} from 'place' +/// ``` +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct ExportSpecifier { + pub local: Ident, + pub alias: Option>, +} + +impl IntoAllocated for ExportSpecifier +where + T: ToString, +{ + type Allocated = ExportSpecifier; + + fn into_allocated(self) -> Self::Allocated { + ExportSpecifier { + local: self.local.into_allocated(), + alias: self.alias.map(|a| a.into_allocated()), + } + } +} diff --git a/src/expr.rs b/src/expr.rs index 6dc3d41..5a9f69b 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,14 +1,13 @@ use crate::pat::Pat; -use crate::{AssignOp, BinaryOp, LogicalOp, PropKind, SourceText, UnaryOp, UpdateOp}; +use crate::{AssignOp, BinaryOp, IntoAllocated, LogicalOp, PropKind, UnaryOp, UpdateOp}; use crate::{Class, Func, FuncArg, FuncBody, Ident}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// A slightly more granular program part that a statement #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Expr { /// `[0,,]` Array(ArrayExpr), @@ -92,11 +91,56 @@ pub enum Expr { Yield(YieldExpr), } +impl IntoAllocated for Expr +where + T: ToString, +{ + type Allocated = Expr; + + fn into_allocated(self) -> Self::Allocated { + match self { + Expr::Array(inner) => Expr::Array( + inner + .into_iter() + .map(|o| o.map(|e| e.into_allocated())) + .collect(), + ), + Expr::ArrowFunc(inner) => Expr::ArrowFunc(inner.into_allocated()), + Expr::ArrowParamPlaceHolder(args, is_async) => Expr::ArrowParamPlaceHolder( + args.into_iter().map(|a| a.into_allocated()).collect(), + is_async, + ), + Expr::Assign(inner) => Expr::Assign(inner.into_allocated()), + Expr::Await(inner) => Expr::Await(inner.into_allocated()), + Expr::Binary(inner) => Expr::Binary(inner.into_allocated()), + Expr::Class(inner) => Expr::Class(inner.into_allocated()), + Expr::Call(inner) => Expr::Call(inner.into_allocated()), + Expr::Conditional(inner) => Expr::Conditional(inner.into_allocated()), + Expr::Func(inner) => Expr::Func(inner.into_allocated()), + Expr::Ident(inner) => Expr::Ident(inner.into_allocated()), + Expr::Lit(inner) => Expr::Lit(inner.into_allocated()), + Expr::Logical(inner) => Expr::Logical(inner.into_allocated()), + Expr::Member(inner) => Expr::Member(inner.into_allocated()), + Expr::MetaProp(inner) => Expr::MetaProp(inner.into_allocated()), + Expr::New(inner) => Expr::New(inner.into_allocated()), + Expr::Obj(inner) => Expr::Obj(inner.into_iter().map(|p| p.into_allocated()).collect()), + Expr::Sequence(inner) => { + Expr::Sequence(inner.into_iter().map(|e| e.into_allocated()).collect()) + } + Expr::Spread(inner) => Expr::Spread(inner.into_allocated()), + Expr::Super => Expr::Super, + Expr::TaggedTemplate(inner) => Expr::TaggedTemplate(inner.into_allocated()), + Expr::This => Expr::This, + Expr::Unary(inner) => Expr::Unary(inner.into_allocated()), + Expr::Update(inner) => Expr::Update(inner.into_allocated()), + Expr::Yield(inner) => Expr::Yield(inner.into_allocated()), + } + } +} + impl Expr { pub fn ident_from(inner: T) -> Self { - Self::Ident(Ident { - name: SourceText(inner), - }) + Self::Ident(Ident { name: inner }) } } @@ -106,20 +150,29 @@ pub type ArrayExpr = Vec>>; pub type ObjExpr = Vec>; /// A single part of an object literal #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ObjProp { Prop(Prop), Spread(Expr), } +impl IntoAllocated for ObjProp +where + T: ToString, +{ + type Allocated = ObjProp; + + fn into_allocated(self) -> Self::Allocated { + match self { + ObjProp::Prop(inner) => ObjProp::Prop(inner.into_allocated()), + ObjProp::Spread(inner) => ObjProp::Spread(inner.into_allocated()), + } + } +} + /// A single part of an object literal or class #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Prop { pub key: PropKey, pub value: PropValue, @@ -130,131 +183,332 @@ pub struct Prop { pub is_static: bool, } +impl IntoAllocated for Prop +where + T: ToString, +{ + type Allocated = Prop; + + fn into_allocated(self) -> Self::Allocated { + Prop { + key: self.key.into_allocated(), + value: self.value.into_allocated(), + kind: self.kind, + method: self.method, + computed: self.computed, + short_hand: self.short_hand, + is_static: self.is_static, + } + } +} + /// An object literal or class property identifier #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum PropKey { Lit(Lit), Expr(Expr), Pat(Pat), } +impl IntoAllocated for PropKey +where + T: ToString, +{ + type Allocated = PropKey; + + fn into_allocated(self) -> Self::Allocated { + match self { + PropKey::Lit(inner) => PropKey::Lit(inner.into_allocated()), + PropKey::Expr(inner) => PropKey::Expr(inner.into_allocated()), + PropKey::Pat(inner) => PropKey::Pat(inner.into_allocated()), + } + } +} + /// The value of an object literal or class property #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum PropValue { Expr(Expr), Pat(Pat), None, } +impl IntoAllocated for PropValue +where + T: ToString, +{ + type Allocated = PropValue; + + fn into_allocated(self) -> Self::Allocated { + match self { + PropValue::Expr(inner) => PropValue::Expr(inner.into_allocated()), + PropValue::Pat(inner) => PropValue::Pat(inner.into_allocated()), + PropValue::None => PropValue::None, + } + } +} + /// An operation that takes one argument #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct UnaryExpr { pub operator: UnaryOp, pub prefix: bool, pub argument: Box>, } +impl IntoAllocated for UnaryExpr +where + T: ToString, +{ + type Allocated = UnaryExpr; + + fn into_allocated(self) -> Self::Allocated { + UnaryExpr { + operator: self.operator, + prefix: self.prefix, + argument: self.argument.into_allocated(), + } + } +} + /// Increment or decrementing a value #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct UpdateExpr { pub operator: UpdateOp, pub argument: Box>, pub prefix: bool, } +impl IntoAllocated for UpdateExpr +where + T: ToString, +{ + type Allocated = UpdateExpr; + + fn into_allocated(self) -> Self::Allocated { + UpdateExpr { + operator: self.operator, + argument: self.argument.into_allocated(), + prefix: self.prefix, + } + } +} + /// An operation that requires 2 arguments #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BinaryExpr { pub operator: BinaryOp, pub left: Box>, pub right: Box>, } +impl IntoAllocated for BinaryExpr +where + T: ToString, +{ + type Allocated = BinaryExpr; + + fn into_allocated(self) -> Self::Allocated { + BinaryExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + /// An assignment or update + assignment operation #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct AssignExpr { pub operator: AssignOp, pub left: AssignLeft, pub right: Box>, } +impl IntoAllocated for AssignExpr +where + T: ToString, +{ + type Allocated = AssignExpr; + + fn into_allocated(self) -> Self::Allocated { + AssignExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + /// The value being assigned to #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum AssignLeft { Pat(Pat), Expr(Box>), } +impl IntoAllocated for AssignLeft +where + T: ToString, +{ + type Allocated = AssignLeft; + + fn into_allocated(self) -> Self::Allocated { + match self { + AssignLeft::Pat(inner) => AssignLeft::Pat(inner.into_allocated()), + AssignLeft::Expr(inner) => AssignLeft::Expr(inner.into_allocated()), + } + } +} + /// A specialized `BinaryExpr` for logical evaluation /// ```js /// true && true /// false || true /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LogicalExpr { pub operator: LogicalOp, pub left: Box>, pub right: Box>, } +impl IntoAllocated for LogicalExpr +where + T: ToString, +{ + type Allocated = LogicalExpr; + + fn into_allocated(self) -> Self::Allocated { + LogicalExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + /// Accessing the member of a value /// ```js /// b['thing']; /// c.stuff; /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct MemberExpr { pub object: Box>, pub property: Box>, pub computed: bool, } +impl IntoAllocated for MemberExpr +where + T: ToString, +{ + type Allocated = MemberExpr; + + fn into_allocated(self) -> Self::Allocated { + MemberExpr { + object: self.object.into_allocated(), + property: self.property.into_allocated(), + computed: self.computed, + } + } +} + /// A ternery expression /// ```js /// var a = true ? 'stuff' : 'things'; /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ConditionalExpr { pub test: Box>, pub alternate: Box>, pub consequent: Box>, } +impl IntoAllocated for ConditionalExpr +where + T: ToString, +{ + type Allocated = ConditionalExpr; + + fn into_allocated(self) -> Self::Allocated { + ConditionalExpr { + test: self.test.into_allocated(), + alternate: self.alternate.into_allocated(), + consequent: self.consequent.into_allocated(), + } + } +} + /// Calling a function or method /// ```js /// Math.random() /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct CallExpr { pub callee: Box>, pub arguments: Vec>, } +impl IntoAllocated for CallExpr +where + T: ToString, +{ + type Allocated = CallExpr; + + fn into_allocated(self) -> Self::Allocated { + CallExpr { + callee: self.callee.into_allocated(), + arguments: self + .arguments + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + } + } +} + /// Calling a constructor /// ```js /// new Uint8Array(32); /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NewExpr { pub callee: Box>, pub arguments: Vec>, } +impl IntoAllocated for NewExpr +where + T: ToString, +{ + type Allocated = NewExpr; + + fn into_allocated(self) -> Self::Allocated { + NewExpr { + callee: self.callee.into_allocated(), + arguments: self + .arguments + .into_iter() + .map(|a| a.into_allocated()) + .collect(), + } + } +} + /// A collection of `Exprs` separated by commas pub type SequenceExpr = Vec>; @@ -266,7 +520,7 @@ pub type SequenceExpr = Vec>; /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrowFuncExpr { pub id: Option>, pub params: Vec>, @@ -276,14 +530,50 @@ pub struct ArrowFuncExpr { pub is_async: bool, } +impl IntoAllocated for ArrowFuncExpr +where + T: ToString, +{ + type Allocated = ArrowFuncExpr; + + fn into_allocated(self) -> Self::Allocated { + ArrowFuncExpr { + id: self.id.map(|i| i.into_allocated()), + params: self + .params + .into_iter() + .map(|p| p.into_allocated()) + .collect(), + body: self.body.into_allocated(), + expression: self.expression, + generator: self.generator, + is_async: self.is_async, + } + } +} + /// The body portion of an arrow function can be either an expression or a block of statements #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ArrowFuncBody { FuncBody(FuncBody), Expr(Box>), } +impl IntoAllocated for ArrowFuncBody +where + T: ToString, +{ + type Allocated = ArrowFuncBody; + + fn into_allocated(self) -> Self::Allocated { + match self { + ArrowFuncBody::FuncBody(inner) => ArrowFuncBody::FuncBody(inner.into_allocated()), + ArrowFuncBody::Expr(inner) => ArrowFuncBody::Expr(inner.into_allocated()), + } + } +} + /// yield a value from inside of a generator function /// ```js /// function *gen() { @@ -293,42 +583,83 @@ pub enum ArrowFuncBody { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct YieldExpr { pub argument: Option>>, pub delegate: bool, } +impl IntoAllocated for YieldExpr +where + T: ToString, +{ + type Allocated = YieldExpr; + + fn into_allocated(self) -> Self::Allocated { + YieldExpr { + delegate: self.delegate, + argument: self.argument.map(IntoAllocated::into_allocated), + } + } +} /// A Template literal preceded by a function identifier /// see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates) for more details #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TaggedTemplateExpr { pub tag: Box>, pub quasi: TemplateLit, } +impl IntoAllocated for TaggedTemplateExpr +where + T: ToString, +{ + type Allocated = TaggedTemplateExpr; + + fn into_allocated(self) -> Self::Allocated { + TaggedTemplateExpr { + tag: self.tag.into_allocated(), + quasi: self.quasi.into_allocated(), + } + } +} + /// A template string literal /// ```js /// `I own ${0} birds`; /// ``` #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TemplateLit { pub quasis: Vec>, pub expressions: Vec>, } +impl IntoAllocated for TemplateLit +where + T: ToString, +{ + type Allocated = TemplateLit; + + fn into_allocated(self) -> Self::Allocated { + TemplateLit { + quasis: self + .quasis + .into_iter() + .map(|e| e.into_allocated()) + .collect(), + expressions: self + .expressions + .into_iter() + .map(|e| e.into_allocated()) + .collect(), + } + } +} + #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum QuasiQuote { /// ` BackTick, @@ -340,18 +671,29 @@ pub enum QuasiQuote { /// The text part of a `TemplateLiteral` #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TemplateElement { pub open_quote: QuasiQuote, /// The non-quoted version - pub content: SourceText, + pub content: T, pub close_quote: QuasiQuote, } +impl IntoAllocated for TemplateElement +where + T: ToString, +{ + type Allocated = TemplateElement; + + fn into_allocated(self) -> Self::Allocated { + TemplateElement { + open_quote: self.open_quote, + content: self.content.to_string(), + close_quote: self.close_quote, + } + } +} + impl TemplateElement { pub fn is_tail(&self) -> bool { matches!( @@ -372,19 +714,29 @@ impl TemplateElement { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct MetaProp { pub meta: Ident, pub property: Ident, } +impl IntoAllocated for MetaProp +where + T: ToString, +{ + type Allocated = MetaProp; + + fn into_allocated(self) -> Self::Allocated { + MetaProp { + meta: self.meta.into_allocated(), + property: self.property.into_allocated(), + } + } +} + /// A literal value #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Lit { /// `null` Null, @@ -399,7 +751,7 @@ pub enum Lit { /// `0xf` /// `0o7` /// `0b1` - Number(SourceText), + Number(T), /// `true` /// `false` Boolean(bool), @@ -411,9 +763,27 @@ pub enum Lit { Template(TemplateLit), } +impl IntoAllocated for Lit +where + T: ToString, +{ + type Allocated = Lit; + + fn into_allocated(self) -> Self::Allocated { + match self { + Lit::Null => Lit::Null, + Lit::String(inner) => Lit::String(inner.into_allocated()), + Lit::Number(inner) => Lit::Number(inner.to_string()), + Lit::Boolean(inner) => Lit::Boolean(inner), + Lit::RegEx(inner) => Lit::RegEx(inner.into_allocated()), + Lit::Template(inner) => Lit::Template(inner.into_allocated()), + } + } +} + impl Lit { pub fn number_from(s: T) -> Self { - Lit::Number(SourceText(s)) + Lit::Number(s) } pub fn single_string_from(s: T) -> Self { Lit::String(StringLit::single_from(s)) @@ -424,18 +794,32 @@ impl Lit { } #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum StringLit { - Double(SourceText), - Single(SourceText), + Double(T), + Single(T), +} + +impl IntoAllocated for StringLit +where + T: ToString, +{ + type Allocated = StringLit; + + fn into_allocated(self) -> Self::Allocated { + match self { + StringLit::Double(inner) => StringLit::Double(inner.to_string()), + StringLit::Single(inner) => StringLit::Single(inner.to_string()), + } + } } impl StringLit { pub fn double_from(s: T) -> StringLit { - StringLit::Double(SourceText(s)) + StringLit::Double(s) } pub fn single_from(s: T) -> StringLit { - StringLit::Single(SourceText(s)) + StringLit::Single(s) } } impl StringLit @@ -444,8 +828,8 @@ where { pub fn clone_inner(&self) -> T { match self { - StringLit::Single(ref s) => s.0.clone(), - StringLit::Double(ref s) => s.0.clone(), + StringLit::Single(ref s) => s.clone(), + StringLit::Double(ref s) => s.clone(), } } } @@ -456,25 +840,38 @@ where { pub fn inner_matches(&self, o: &str) -> bool { match self { - StringLit::Single(ref s) => o.eq(s.0.as_ref()), - StringLit::Double(ref d) => o.eq(d.0.as_ref()), + StringLit::Single(ref s) => o.eq(s.as_ref()), + StringLit::Double(ref d) => o.eq(d.as_ref()), } } } /// A regular expression literal #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serialization"), serde(rename_all = "camelCase"))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RegEx { - pub pattern: SourceText, - pub flags: Option>, + pub pattern: T, + pub flags: Option, +} + +impl IntoAllocated for RegEx +where + T: ToString, +{ + type Allocated = RegEx; + + fn into_allocated(self) -> Self::Allocated { + RegEx { + pattern: self.pattern.to_string(), + flags: self.flags.map(|f| f.to_string()), + } + } } impl RegEx { pub fn from(p: T, f: Option) -> Self { RegEx { - pattern: SourceText(p), - flags: f.map(SourceText), + pattern: p, + flags: f, } } } diff --git a/src/lib.rs b/src/lib.rs index 9774678..0908e4a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,118 +1,53 @@ -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde_derive; - pub mod decl; pub mod expr; pub mod pat; -#[cfg(feature = "esprima")] -pub mod serde; pub mod spanned; pub mod stmt; -use std::{borrow::Cow, fmt::Debug, ops::Deref}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use std::{borrow::Cow, fmt::Debug}; use decl::Decl; use expr::{Expr, Lit, Prop}; use pat::Pat; use stmt::Stmt; -#[derive(Clone, Default)] -pub struct SourceText(pub T); - -impl From for SourceText { - fn from(value: T) -> Self { - Self(value) - } -} - -impl Deref for SourceText<&str> { - type Target = str; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl Deref for SourceText { - type Target = str; - fn deref(&self) -> &Self::Target { - self.0.as_str() - } -} - -impl AsRef for SourceText -where - T: AsRef, -{ - fn as_ref(&self) -> &str { - self.0.as_ref() - } -} - -impl std::fmt::Display for SourceText -where - T: std::fmt::Display, -{ - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.0) - } +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct Ident { + pub name: T, } -impl std::cmp::PartialEq for SourceText +impl IntoAllocated for Ident where - U: PartialEq, + T: ToString, { - fn eq(&self, other: &U) -> bool { - other.eq(&self.0) - } -} + type Allocated = Ident; -impl<'a> std::cmp::PartialEq> for &'a str { - fn eq(&self, other: &SourceText<&'a str>) -> bool { - (&other.0).eq(self) - } -} - -impl std::fmt::Debug for SourceText -where - T: std::fmt::Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", &self.0) + fn into_allocated(self) -> Self::Allocated { + Ident { + name: self.name.to_string(), + } } } -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -pub struct Ident { - pub name: SourceText, -} - impl<'a> From<&'a str> for Ident<&'a str> { fn from(value: &'a str) -> Self { - Self { - name: SourceText(value), - } + Self { name: value } } } impl From for Ident { fn from(value: String) -> Self { - Self { - name: SourceText(value), - } + Self { name: value } } } impl<'a> From> for Ident> { fn from(value: Cow<'a, str>) -> Self { - Self { - name: SourceText(value), - } + Self { name: value } } } @@ -122,11 +57,7 @@ impl<'a> From> for Ident> { /// with a flag denoting if the representation is /// a ES6 Mod or a Script. #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Program { /// An ES6 Mod Mod(Vec>), @@ -134,6 +65,24 @@ pub enum Program { Script(Vec>), } +impl IntoAllocated for Program +where + T: ToString, +{ + type Allocated = Program; + + fn into_allocated(self) -> Self::Allocated { + match self { + Program::Mod(inner) => { + Program::Mod(inner.into_iter().map(|p| p.into_allocated()).collect()) + } + Program::Script(inner) => { + Program::Script(inner.into_iter().map(|p| p.into_allocated()).collect()) + } + } + } +} + impl Program { pub fn module(parts: Vec>) -> Self { Program::Mod(parts) @@ -146,12 +95,7 @@ impl Program { /// A single part of a Javascript program. /// This will be either a Directive, Decl or a Stmt #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ProgramPart { /// A Directive like `'use strict';` Dir(Dir), @@ -161,6 +105,21 @@ pub enum ProgramPart { Stmt(Stmt), } +impl IntoAllocated for ProgramPart +where + T: ToString, +{ + type Allocated = ProgramPart; + + fn into_allocated(self) -> Self::Allocated { + match self { + ProgramPart::Dir(inner) => ProgramPart::Dir(inner.into_allocated()), + ProgramPart::Decl(inner) => ProgramPart::Decl(inner.into_allocated()), + ProgramPart::Stmt(inner) => ProgramPart::Stmt(inner.into_allocated()), + } + } +} + impl ProgramPart { pub fn decl(inner: Decl) -> Self { ProgramPart::Decl(inner) @@ -173,14 +132,24 @@ impl ProgramPart { /// pretty much always `'use strict'`, this can appear at the /// top of a file or function #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Dir { pub expr: Lit, - pub dir: SourceText, + pub dir: T, +} + +impl IntoAllocated for Dir +where + T: ToString, +{ + type Allocated = Dir; + + fn into_allocated(self) -> Self::Allocated { + Dir { + expr: self.expr.into_allocated(), + dir: self.dir.to_string(), + } + } } /// A function, this will be part of either a function @@ -194,7 +163,7 @@ pub struct Dir { /// let y = function q() {} /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Func { pub id: Option>, pub params: Vec>, @@ -203,6 +172,27 @@ pub struct Func { pub is_async: bool, } +impl IntoAllocated for Func +where + T: ToString, +{ + type Allocated = Func; + + fn into_allocated(self) -> Self::Allocated { + Func { + id: self.id.map(IntoAllocated::into_allocated), + params: self + .params + .into_iter() + .map(|p| p.into_allocated()) + .collect(), + body: self.body.into_allocated(), + generator: self.generator, + is_async: self.is_async, + } + } +} + impl Func { pub fn new( id: Option>, @@ -223,17 +213,26 @@ impl Func { /// A single function argument from a function signature #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum FuncArg { Expr(Expr), Pat(Pat), } +impl IntoAllocated for FuncArg +where + T: ToString, +{ + type Allocated = FuncArg; + + fn into_allocated(self) -> Self::Allocated { + match self { + FuncArg::Expr(inner) => FuncArg::Expr(inner.into_allocated()), + FuncArg::Pat(inner) => FuncArg::Pat(inner.into_allocated()), + } + } +} + impl FuncArg { pub fn expr(expr: Expr) -> FuncArg { FuncArg::Expr(expr) @@ -245,12 +244,20 @@ impl FuncArg { /// The block statement that makes up the function's body #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct FuncBody(pub Vec>); + +impl IntoAllocated for FuncBody +where + T: ToString, +{ + type Allocated = FuncBody; + + fn into_allocated(self) -> Self::Allocated { + FuncBody(self.0.into_iter().map(|p| p.into_allocated()).collect()) + } +} + /// A way to declare object templates /// ```js /// class Thing { @@ -278,20 +285,48 @@ pub struct FuncBody(pub Vec>); /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Class { pub id: Option>, pub super_class: Option>>, pub body: ClassBody, } + +impl IntoAllocated for Class +where + T: ToString, +{ + type Allocated = Class; + + fn into_allocated(self) -> Self::Allocated { + Class { + id: self.id.map(IntoAllocated::into_allocated), + super_class: self.super_class.map(IntoAllocated::into_allocated), + body: self.body.into_allocated(), + } + } +} + #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ClassBody(pub Vec>); +impl IntoAllocated for ClassBody +where + T: ToString, +{ + type Allocated = ClassBody; + + fn into_allocated(self) -> Self::Allocated { + ClassBody( + self.0 + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + ) + } +} + impl Class { pub fn new(id: Option>, super_class: Option>, body: Vec>) -> Class { Class { @@ -304,11 +339,7 @@ impl Class { /// The kind of variable being defined (`var`/`let`/`const`) #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr( all(feature = "serde", feature = "esprima"), serde(rename_all = "camelCase", untagged) @@ -321,11 +352,7 @@ pub enum VarKind { /// The available operators for assignment Exprs #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum AssignOp { Equal, PlusEqual, @@ -344,11 +371,7 @@ pub enum AssignOp { /// The available logical operators #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LogicalOp { Or, And, @@ -356,11 +379,7 @@ pub enum LogicalOp { /// The available operations for `Binary` Exprs #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum BinaryOp { Equal, NotEqual, @@ -388,11 +407,7 @@ pub enum BinaryOp { /// `++` or `--` #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum UpdateOp { Increment, Decrement, @@ -401,11 +416,7 @@ pub enum UpdateOp { /// The allowed operators for an Expr /// to be `Unary` #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum UnaryOp { Minus, Plus, @@ -418,11 +429,7 @@ pub enum UnaryOp { /// A flag for determining what kind of property #[derive(Debug, Clone, PartialEq, Copy)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum PropKind { /// A property with a value Init, @@ -436,6 +443,33 @@ pub enum PropKind { Method, } +pub trait IntoAllocated { + type Allocated; + + fn into_allocated(self) -> Self::Allocated; +} + +impl IntoAllocated for Box +where + T: IntoAllocated, +{ + type Allocated = Box; + + fn into_allocated(self) -> Self::Allocated { + Box::new((*self).into_allocated()) + } +} + +impl IntoAllocated for Option +where + T: IntoAllocated, +{ + type Allocated = Option; + fn into_allocated(self) -> Self::Allocated { + self.map(IntoAllocated::into_allocated) + } +} + pub mod prelude { pub use crate::decl::{ Decl, DefaultExportDecl, ExportSpecifier, ImportSpecifier, ModExport, ModImport, diff --git a/src/pat.rs b/src/pat.rs index b1e31c2..f7bce99 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -1,14 +1,13 @@ use crate::expr::{Expr, Prop}; -use crate::Ident; +use crate::{Ident, IntoAllocated}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// All of the different ways you can declare an identifier /// and/or value #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Pat { Ident(Ident), Obj(ObjPat), @@ -17,41 +16,97 @@ pub enum Pat { Assign(AssignPat), } +impl IntoAllocated for Pat +where + T: ToString, +{ + type Allocated = Pat; + + fn into_allocated(self) -> Self::Allocated { + match self { + Pat::Ident(inner) => Pat::Ident(inner.into_allocated()), + Pat::Obj(inner) => Pat::Obj(inner.into_iter().map(|a| a.into_allocated()).collect()), + Pat::Array(inner) => Pat::Array( + inner + .into_iter() + .map(|o| o.map(|a| a.into_allocated())) + .collect(), + ), + Pat::RestElement(inner) => Pat::RestElement(inner.into_allocated()), + Pat::Assign(inner) => Pat::Assign(inner.into_allocated()), + } + } +} + impl Pat { pub fn ident_from(inner: T) -> Self { - Self::Ident(Ident { - name: crate::SourceText(inner), - }) + Self::Ident(Ident { name: inner }) } } #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ArrayPatPart { Pat(Pat), Expr(Expr), } +impl IntoAllocated for ArrayPatPart +where + T: ToString, +{ + type Allocated = ArrayPatPart; + + fn into_allocated(self) -> Self::Allocated { + match self { + ArrayPatPart::Pat(inner) => ArrayPatPart::Pat(inner.into_allocated()), + ArrayPatPart::Expr(inner) => ArrayPatPart::Expr(inner.into_allocated()), + } + } +} + /// similar to an `ObjectExpr` pub type ObjPat = Vec>; /// A single part of an ObjectPat #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] -#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ObjPatPart { Assign(Prop), Rest(Box>), } +impl IntoAllocated for ObjPatPart +where + T: ToString, +{ + type Allocated = ObjPatPart; + + fn into_allocated(self) -> Self::Allocated { + match self { + ObjPatPart::Assign(inner) => ObjPatPart::Assign(inner.into_allocated()), + ObjPatPart::Rest(inner) => ObjPatPart::Rest(inner.into_allocated()), + } + } +} + /// An assignment as a pattern #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct AssignPat { pub left: Box>, pub right: Box>, } + +impl IntoAllocated for AssignPat +where + T: ToString, +{ + type Allocated = AssignPat; + + fn into_allocated(self) -> Self::Allocated { + AssignPat { + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} diff --git a/src/serde/de.rs b/src/serde/de.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/serde/de.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/serde/mod.rs b/src/serde/mod.rs deleted file mode 100644 index 864d0aa..0000000 --- a/src/serde/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod ser; -pub use ser::*; -pub mod de; -pub use de::*; diff --git a/src/serde/ser.rs b/src/serde/ser.rs deleted file mode 100644 index 7f54632..0000000 --- a/src/serde/ser.rs +++ /dev/null @@ -1,1244 +0,0 @@ -use crate::prelude::*; -use serde::ser::{Serialize, SerializeStruct, Serializer}; - -impl<'a> Serialize for Program<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "Program")?; - match self { - Program::Script(ref body) => { - state.serialize_field("sourceType", "script")?; - state.serialize_field("body", &body)?; - } - Program::Mod(ref body) => { - state.serialize_field("sourceType", "module")?; - state.serialize_field("body", body)?; - } - } - state.end() - } -} - -impl<'a> Serialize for ProgramPart<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - ProgramPart::Decl(ref d) => d.serialize(serializer), - ProgramPart::Dir(ref d) => d.serialize(serializer), - ProgramPart::Stmt(ref s) => s.serialize(serializer), - } - } -} -impl<'a> Serialize for Dir<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "ExpressionStatement")?; - state.serialize_field("expression", &self.expr)?; - if let Lit::String(ref sl) = self.expr { - match sl { - StringLit::Double(ref s) => { - if !s.is_empty() { - state.serialize_field("directive", &self.dir)?; - } - } - StringLit::Single(ref s) => { - if !s.is_empty() { - state.serialize_field("directive", &self.dir)?; - } - } - } - } - state.end() - } -} -impl<'a> Serialize for Decl<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Decl::Func(ref f) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "FunctionDeclaration")?; - state.serialize_field("id", &f.id)?; - state.serialize_field("body", &f.body)?; - state.serialize_field("generator", &f.generator)?; - state.serialize_field("async", &f.is_async)?; - state.serialize_field("expression", &false)?; - state.serialize_field("params", &f.params)?; - state.end() - } - Decl::Class(ref c) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "ClassDeclaration")?; - state.serialize_field("body", &c.body)?; - state.serialize_field("id", &c.id)?; - state.serialize_field("superClass", &c.super_class)?; - state.end() - } - Decl::Var(ref kind, ref vs) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "VariableDeclaration")?; - state.serialize_field("kind", kind)?; - state.serialize_field("declarations", vs)?; - state.end() - } - Decl::Import(ref imp) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ImportDeclaration")?; - state.serialize_field("specifiers", &imp.specifiers)?; - state.serialize_field("source", &imp.source)?; - state.end() - } - Decl::Export(ref exp) => exp.serialize(serializer), - } - } -} - -impl<'a> Serialize for ModExport<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - ModExport::All(ref source) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ExportAllDeclaration")?; - state.serialize_field("source", source)?; - state.end() - } - ModExport::Default(ref def) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ExportDefaultDeclaration")?; - state.serialize_field("declaration", def)?; - state.end() - } - ModExport::Named(ref named) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ExportNamedDeclaration")?; - match named { - NamedExportDecl::Decl(ref d) => { - let specs: Vec<()> = Vec::new(); - let source: Option<()> = None; - state.serialize_field("declaration", d)?; - state.serialize_field("specifiers", &specs)?; - state.serialize_field("source", &source)?; - } - NamedExportDecl::Specifier(ref specs, source) => { - let decl: Option<()> = None; - state.serialize_field("declaration", &decl)?; - state.serialize_field("specifiers", specs)?; - state.serialize_field("source", source)?; - } - } - state.end() - } - } - } -} - -impl<'a> Serialize for DefaultExportDecl<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - DefaultExportDecl::Decl(ref d) => d.serialize(serializer), - DefaultExportDecl::Expr(ref e) => e.serialize(serializer), - } - } -} - -impl<'a> Serialize for ImportSpecifier<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - ImportSpecifier::Default(ref d) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ImportDefaultSpecifier")?; - state.serialize_field("local", d)?; - state.end() - } - ImportSpecifier::Namespace(ref n) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ImportNamespaceSpecifier")?; - state.serialize_field("local", n)?; - state.end() - } - ImportSpecifier::Normal(ref n) => { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ImportSpecifier")?; - // state.serialize_field("local", &n.)?; - // state.serialize_field("imported", &n.imported)?; - state.end() - } - } - } -} -impl<'a> Serialize for ExportSpecifier<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ExportSpecifier")?; - state.serialize_field("exported", &self.exported)?; - state.serialize_field("local", &self.local)?; - state.end() - } -} -impl<'a> Serialize for FuncArg<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - FuncArg::Expr(ref ex) => ex.serialize(serializer), - FuncArg::Pat(ref pat) => pat.serialize(serializer), - } - } -} - -impl<'a> Serialize for ClassBody<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 7)?; - state.serialize_field("type", "ClassBody")?; - let body: Vec = self.0.iter().map(MethodDef).collect(); - state.serialize_field("body", &body)?; - state.end() - } -} - -impl Serialize for VarKind { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - VarKind::Const => "const", - VarKind::Let => "let", - VarKind::Var => "var", - }; - serializer.serialize_str(s) - } -} -impl<'a> Serialize for Ident<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "Identifier")?; - let unescaped = unescaper(&self.name).unwrap_or_else(|| self.name.to_string()); - state.serialize_field("name", &unescaped)?; - state.end() - } -} - -impl<'a> Serialize for VarDecl<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "VariableDeclarator")?; - state.serialize_field("id", &self.id)?; - state.serialize_field("init", &self.init)?; - state.end() - } -} - -impl<'a> Serialize for FuncBody<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "BlockStatement")?; - state.serialize_field("body", &self.0)?; - state.end() - } -} - -impl<'a> Serialize for Stmt<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Stmt::Labeled(ref l) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "LabeledStatement")?; - state.serialize_field("label", &l.label)?; - state.serialize_field("body", &l.body)?; - state.end() - } - Stmt::Block(ref b) => b.serialize(serializer), - Stmt::Break(ref b) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "BreakStatement")?; - state.serialize_field("label", &b)?; - state.end() - } - Stmt::Continue(ref c) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ContinueStatement")?; - state.serialize_field("label", &c)?; - state.end() - } - Stmt::Debugger => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "DebuggerStatement")?; - state.end() - } - Stmt::DoWhile(ref d) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "DoWhileStatement")?; - state.serialize_field("test", &d.test)?; - state.serialize_field("body", &d.body)?; - state.end() - } - Stmt::Empty => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "EmptyStatement")?; - state.end() - } - Stmt::Expr(ref e) => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "ExpressionStatement")?; - state.serialize_field("expression", e)?; - state.end() - } - Stmt::For(ref f) => { - let mut state = serializer.serialize_struct("Node", 5)?; - state.serialize_field("type", "ForStatement")?; - state.serialize_field("init", &f.init)?; - state.serialize_field("test", &f.test)?; - state.serialize_field("update", &f.update)?; - state.serialize_field("body", &f.body)?; - state.end() - } - Stmt::ForIn(ref f) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "ForInStatement")?; - state.serialize_field("left", &f.left)?; - state.serialize_field("right", &f.right)?; - state.serialize_field("body", &f.body)?; - state.serialize_field("each", &false)?; - state.end() - } - Stmt::ForOf(ref f) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "ForOfStatement")?; - state.serialize_field("left", &f.left)?; - state.serialize_field("right", &f.right)?; - state.serialize_field("body", &f.body)?; - state.end() - } - Stmt::If(ref f) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "IfStatement")?; - state.serialize_field("test", &f.test)?; - state.serialize_field("consequent", &f.consequent)?; - state.serialize_field("alternate", &f.alternate)?; - state.end() - } - Stmt::Return(ref r) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ReturnStatement")?; - state.serialize_field("argument", r)?; - state.end() - } - Stmt::Switch(ref s) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "SwitchStatement")?; - state.serialize_field("discriminant", &s.discriminant)?; - state.serialize_field("cases", &s.cases)?; - state.end() - } - Stmt::Throw(ref t) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ThrowStatement")?; - state.serialize_field("argument", t)?; - state.end() - } - Stmt::Try(ref t) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "TryStatement")?; - state.serialize_field("block", &t.block)?; - state.serialize_field("handler", &t.handler)?; - state.serialize_field("finalizer", &t.finalizer)?; - state.end() - } - Stmt::Var(ref v) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "VariableStatement")?; - state.serialize_field("decls", &v)?; - state.end() - } - Stmt::While(ref w) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "WhileStatement")?; - state.serialize_field("test", &w.test)?; - state.serialize_field("body", &w.body)?; - state.end() - } - Stmt::With(ref w) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "WithStatement")?; - state.serialize_field("object", &w.object)?; - state.serialize_field("body", &w.body)?; - state.end() - } - } - } -} - -impl<'a> Serialize for Lit<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Lit::Number(ref n) => serialize_number(serializer, n), - Lit::String(ref sl) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "Literal")?; - let (quote, value) = match sl { - StringLit::Double(ref s) => ('"', s), - StringLit::Single(ref s) => ('\'', s), - }; - let quoted = format!("{0}{1}{0}", quote, value); - let inner = if let Some(esc) = unescaper("ed) { - if esc.trim_matches(quote) != "\n" { - esc - } else { - format!("{0}{0}", quote) - } - } else { - value.to_string() - }; - state.serialize_field("value", &inner[1..inner.len() - 1])?; - state.serialize_field("raw", "ed)?; - state.end() - } - Lit::RegEx(ref r) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "Literal")?; - state.serialize_field("raw", &format!("/{}/{}", r.pattern, r.flags))?; - state.serialize_field("value", &format_regex_value(r))?; - state.serialize_field("regex", r)?; - state.end() - } - Lit::Null => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "Literal")?; - state.serialize_field("raw", "null")?; - let value: Option<()> = None; - state.serialize_field("value", &value)?; - state.end() - } - Lit::Boolean(ref b) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "Literal")?; - let raw = if *b { "true" } else { "false" }; - state.serialize_field("raw", raw)?; - state.serialize_field("value", b)?; - state.end() - } - Lit::Template(ref t) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "TemplateLiteral")?; - state.serialize_field("quasis", &t.quasis)?; - state.serialize_field("expressions", &t.expressions)?; - state.end() - } - } - } -} - -fn format_regex_value(r: &RegEx) -> String { - let mut ret = String::from("/"); - let mut escaped = false; - for c in r.pattern.chars() { - if c == '\\' { - escaped = true; - ret.push(c); - } else if !escaped && c == '/' { - ret.push_str(r"\/"); - } else { - ret.push(c); - } - } - ret.push('/'); - if r.flags.is_empty() { - return ret; - } - if r.flags.contains('g') { - ret.push('g'); - } - if r.flags.contains('i') { - ret.push('i'); - } - if r.flags.contains('m') { - ret.push('m'); - } - if r.flags.contains('u') { - ret.push('u') - } - if r.flags.contains('y') { - ret.push('y') - } - ret.push_str(&r.flags.replace( - |c| c == 'g' || c == 'i' || c == 'm' || c == 'u' || c == 'y', - "", - )); - ret -} - -fn serialize_number(s: S, n: &str) -> Result -where - S: Serializer, -{ - let mut state = s.serialize_struct("Node", 3)?; - state.serialize_field("type", "Literal")?; - state.serialize_field("raw", &n)?; - if n.starts_with("0") { - if n.len() == 1 { - serialize_int(&mut state, 10, n)?; - } else if n[1..2].eq_ignore_ascii_case("x") { - serialize_int(&mut state, 16, &n[2..])?; - } else if n[1..2].eq_ignore_ascii_case("o") { - serialize_int(&mut state, 8, &n[2..])?; - } else if n[1..2].eq_ignore_ascii_case("b") { - serialize_int(&mut state, 2, &n[2..])?; - } else if n.chars().all(|c| c.is_digit(8)) { - serialize_int(&mut state, 8, n)?; - } else if n.contains('E') || n.contains('e') || n.contains('.') { - serialize_float(&mut state, n)?; - } else { - serialize_int(&mut state, 10, n)?; - } - } else if n.contains('E') || n.contains('e') || n.contains('.') { - serialize_float(&mut state, n)?; - } else { - serialize_int(&mut state, 10, n)?; - } - state.end() -} - -fn serialize_int(state: &mut T, radix: u32, n: &str) -> Result<(), T::Error> -where - T: SerializeStruct, -{ - if let Ok(value) = i128::from_str_radix(n, radix) { - if value < ::std::i32::MAX as i128 { - state.serialize_field("value", &(value as i32)) - } else { - state.serialize_field("value", &(value as f64)) - } - } else { - state.serialize_field("value", &::std::f32::NAN) - } -} -fn serialize_float(state: &mut T, n: &str) -> Result<(), T::Error> -where - T: SerializeStruct, -{ - if let Ok(value) = n.parse::() { - if value % 1.0 == 0.0 { - state.serialize_field("value", &(value as i32)) - } else { - state.serialize_field("value", &value) - } - } else { - state.serialize_field("value", &::std::f32::NAN) - } -} - -impl<'a> Serialize for Expr<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Expr::Array(ref a) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ArrayExpression")?; - state.serialize_field("elements", a)?; - state.end() - } - Expr::ArrowFunc(ref a) => { - let mut state = serializer.serialize_struct("Node", 6)?; - state.serialize_field("type", "ArrowFunctionExpression")?; - state.serialize_field("id", &a.id)?; - state.serialize_field("expression", &a.expression)?; - state.serialize_field("generator", &a.generator)?; - state.serialize_field("params", &a.params)?; - state.serialize_field("async", &a.is_async)?; - match a.body { - ArrowFuncBody::Expr(ref e) => { - state.serialize_field("body", e)?; - } - ArrowFuncBody::FuncBody(ref b) => { - state.serialize_field("body", b)?; - } - } - state.end() - } - Expr::ArrowParamPlaceHolder(_, _) => { - unreachable!("ArrowParamPlaceHolder Expression should never be returned by the parsing process"); - } - Expr::Assign(ref a) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "AssignmentExpression")?; - state.serialize_field("left", &a.left)?; - state.serialize_field("operator", &a.operator)?; - state.serialize_field("right", &a.right)?; - state.end() - } - Expr::Await(ref a) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "AwaitExpression")?; - state.serialize_field("expression", a)?; - state.end() - } - Expr::Binary(ref b) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "BinaryExpression")?; - state.serialize_field("left", &b.left)?; - state.serialize_field("operator", &b.operator)?; - state.serialize_field("right", &b.right)?; - state.end() - } - Expr::Call(ref c) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "CallExpression")?; - state.serialize_field("callee", &c.callee)?; - state.serialize_field("arguments", &c.arguments)?; - state.end() - } - Expr::Class(ref c) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "ClassExpression")?; - state.serialize_field("id", &c.id)?; - state.serialize_field("superClass", &c.super_class)?; - state.serialize_field("body", &c.body)?; - state.end() - } - Expr::Conditional(ref c) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "ConditionalExpression")?; - state.serialize_field("test", &c.test)?; - state.serialize_field("consequent", &c.consequent)?; - state.serialize_field("alternate", &c.alternate)?; - state.end() - } - Expr::Func(ref f) => { - let mut state = serializer.serialize_struct("Node", 6)?; - state.serialize_field("type", "FunctionExpression")?; - state.serialize_field("id", &f.id)?; - state.serialize_field("params", &f.params)?; - state.serialize_field("body", &f.body)?; - state.serialize_field("generator", &f.generator)?; - state.serialize_field("async", &f.is_async)?; - state.serialize_field("expression", &false)?; - state.end() - } - Expr::Ident(ref i) => i.serialize(serializer), - Expr::Lit(ref l) => l.serialize(serializer), - Expr::Logical(ref l) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "LogicalExpression")?; - state.serialize_field("left", &l.left)?; - state.serialize_field("operator", &l.operator)?; - state.serialize_field("right", &l.right)?; - state.end() - } - Expr::Member(ref m) => { - let mut state = serializer.serialize_struct("Node", 4)?; - state.serialize_field("type", "MemberExpression")?; - state.serialize_field("object", &m.object)?; - state.serialize_field("property", &m.property)?; - state.serialize_field("computed", &m.computed)?; - state.end() - } - Expr::MetaProp(ref m) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "MetaProperty")?; - state.serialize_field("meta", &m.meta)?; - state.serialize_field("property", &m.property)?; - state.end() - } - Expr::New(ref n) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "NewExpression")?; - state.serialize_field("callee", &n.callee)?; - state.serialize_field("arguments", &n.arguments)?; - state.end() - } - Expr::Obj(ref o) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "ObjectExpression")?; - state.serialize_field("properties", o)?; - state.end() - } - Expr::Sequence(ref s) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "SequenceExpression")?; - state.serialize_field("expressions", s)?; - state.end() - } - Expr::Spread(ref s) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "SpreadElement")?; - state.serialize_field("argument", s)?; - state.end() - } - Expr::Super => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "Super")?; - state.end() - } - Expr::TaggedTemplate(ref t) => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "TaggedTemplateExpression")?; - state.serialize_field("tag", &t.tag)?; - state.serialize_field("quasi", &t.quasi)?; - state.end() - } - Expr::This => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "ThisExpression")?; - state.end() - } - Expr::Unary(ref u) => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "UnaryExpression")?; - state.serialize_field("argument", &u.argument)?; - state.serialize_field("operator", &u.operator)?; - state.serialize_field("prefix", &u.prefix)?; - state.end() - } - Expr::Update(ref u) => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "UpdateExpression")?; - state.serialize_field("argument", &u.argument)?; - state.serialize_field("operator", &u.operator)?; - state.serialize_field("prefix", &u.prefix)?; - state.end() - } - Expr::Yield(ref y) => { - let mut state = serializer.serialize_struct("Node", 1)?; - state.serialize_field("type", "YieldExpression")?; - state.serialize_field("argument", &y.argument)?; - state.serialize_field("delegate", &y.delegate)?; - state.end() - } - } - } -} - -impl<'a> Serialize for Pat<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Pat::Array(ref a) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ArrayPattern")?; - state.serialize_field("elements", a)?; - state.end() - } - Pat::Assign(ref a) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "AssignmentPattern")?; - state.serialize_field("left", &a.left)?; - state.serialize_field("right", &a.right)?; - state.end() - } - Pat::Ident(ref i) => i.serialize(serializer), - Pat::Obj(ref o) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "ObjectPattern")?; - state.serialize_field("properties", o)?; - state.end() - } - Pat::RestElement(ref r) => { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "RestElement")?; - state.serialize_field("argument", r)?; - state.end() - } - } - } -} - -impl Serialize for PropKind { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - PropKind::Ctor => serializer.serialize_str("constructor"), - PropKind::Get => serializer.serialize_str("get"), - PropKind::Init => serializer.serialize_str("init"), - PropKind::Method => serializer.serialize_str("method"), - PropKind::Set => serializer.serialize_str("set"), - } - } -} - -impl<'a> Serialize for Prop<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "Property")?; - state.serialize_field("key", &self.key)?; - state.serialize_field("computed", &self.computed)?; - state.serialize_field("kind", &self.kind)?; - state.serialize_field("method", &self.method)?; - state.serialize_field("shorthand", &self.short_hand)?; - if self.short_hand && self.value == PropValue::None { - state.serialize_field("value", &self.key)?; - } else { - state.serialize_field("value", &self.value)?; - } - if self.is_static { - state.serialize_field("static", &self.is_static)?; - } - state.end() - } -} - -struct MethodDef<'a>(pub &'a Prop<'a>); - -impl<'a> Serialize for MethodDef<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "MethodDefinition")?; - state.serialize_field("static", &self.0.is_static)?; - state.serialize_field("static", &self.0.is_static)?; - state.serialize_field("value", &self.0.value)?; - state.serialize_field("computed", &self.0.computed)?; - state.serialize_field("kind", &self.0.kind)?; - state.serialize_field("key", &self.0.key)?; - state.end() - } -} - -impl<'a> Serialize for TemplateLit<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "TemplateLiteral")?; - state.serialize_field("expressions", &self.expressions)?; - state.serialize_field("quasis", &self.quasis)?; - state.end() - } -} - -impl<'a> Serialize for TemplateElement<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "TemplateElement")?; - state.serialize_field("tail", &self.tail)?; - let mut value = ::std::collections::HashMap::new(); - let cooked = if let Some(s) = unescaper(&self.cooked) { - s - } else { - self.cooked.to_string() - }; - value.insert("cooked", cooked.as_str()); - let end_len = if self.raw.ends_with("${") { 2 } else { 1 }; - value.insert("raw", &self.raw[1..self.raw.len() - end_len]); - state.serialize_field("value", &value)?; - state.end() - } -} -impl<'a> Serialize for BlockStmt<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "BlockStatement")?; - state.serialize_field("body", &self.0)?; - state.end() - } -} - -impl<'a> Serialize for CatchClause<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 2)?; - state.serialize_field("type", "CatchClause")?; - state.serialize_field("param", &self.param)?; - state.serialize_field("body", &self.body)?; - state.end() - } -} -impl<'a> Serialize for SwitchCase<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "SwitchCase")?; - state.serialize_field("test", &self.test)?; - state.serialize_field("consequent", &self.consequent)?; - state.end() - } -} - -impl Serialize for AssignOp { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - AssignOp::Equal => "=", - AssignOp::PlusEqual => "+=", - AssignOp::MinusEqual => "-=", - AssignOp::TimesEqual => "*=", - AssignOp::DivEqual => "/=", - AssignOp::ModEqual => "%=", - AssignOp::LeftShiftEqual => "<<=", - AssignOp::RightShiftEqual => ">>=", - AssignOp::UnsignedRightShiftEqual => ">>>=", - AssignOp::OrEqual => "|=", - AssignOp::XOrEqual => "^=", - AssignOp::AndEqual => "&=", - AssignOp::PowerOfEqual => "**=", - }; - serializer.serialize_str(s) - } -} -impl Serialize for BinaryOp { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - BinaryOp::Equal => "==", - BinaryOp::NotEqual => "!=", - BinaryOp::StrictEqual => "===", - BinaryOp::StrictNotEqual => "!==", - BinaryOp::LessThan => "<", - BinaryOp::GreaterThan => ">", - BinaryOp::LessThanEqual => "<=", - BinaryOp::GreaterThanEqual => ">=", - BinaryOp::LeftShift => "<<", - BinaryOp::RightShift => ">>", - BinaryOp::UnsignedRightShift => ">>>", - BinaryOp::Plus => "+", - BinaryOp::Minus => "-", - BinaryOp::Times => "*", - BinaryOp::Over => "/", - BinaryOp::Mod => "%", - BinaryOp::Or => "|", - BinaryOp::XOr => "^", - BinaryOp::And => "&", - BinaryOp::In => "in", - BinaryOp::InstanceOf => "instanceof", - BinaryOp::PowerOf => "**", - }; - serializer.serialize_str(s) - } -} -impl Serialize for LogicalOp { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - LogicalOp::And => "&&", - LogicalOp::Or => "||", - }; - serializer.serialize_str(s) - } -} -impl Serialize for UnaryOp { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - UnaryOp::Minus => "-", - UnaryOp::Plus => "+", - UnaryOp::Not => "!", - UnaryOp::Tilde => "~", - UnaryOp::TypeOf => "typeof", - UnaryOp::Void => "void", - UnaryOp::Delete => "delete", - }; - serializer.serialize_str(s) - } -} -impl Serialize for UpdateOp { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = match self { - UpdateOp::Increment => "++", - UpdateOp::Decrement => "--", - }; - serializer.serialize_str(s) - } -} -impl<'a> Serialize for LoopLeft<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - LoopLeft::Expr(ref e) => e.serialize(serializer), - LoopLeft::Pat(ref p) => p.serialize(serializer), - LoopLeft::Variable(ref kind, ref v) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "VariableDeclaration")?; - state.serialize_field("kind", kind)?; - state.serialize_field("declarations", &[v])?; - state.end() - } - } - } -} -impl<'a> Serialize for LoopInit<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - LoopInit::Expr(ref e) => e.serialize(serializer), - LoopInit::Variable(ref kind, ref v) => { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "VariableDeclaration")?; - state.serialize_field("kind", kind)?; - state.serialize_field("declarations", v)?; - state.end() - } - } - } -} -impl<'a> Serialize for AssignPat<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Node", 3)?; - state.serialize_field("type", "AssignmentPattern")?; - state.serialize_field("left", &self.left)?; - state.serialize_field("right", &self.right)?; - state.end() - } -} - -use std::collections::VecDeque; -fn unescaper(s: &str) -> Option { - let mut queue: VecDeque<_> = String::from(s).chars().collect(); - let mut s = String::new(); - - while let Some(c) = queue.pop_front() { - if c != '\\' { - s.push(c); - continue; - } - - match queue.pop_front() { - Some('b') => s.push('\u{0008}'), - Some('f') => s.push('\u{000C}'), - Some('n') => s.push('\n'), - Some('r') => s.push('\r'), - Some('t') => s.push('\t'), - Some('v') => s.push('\u{000b}'), - Some('\'') => s.push('\''), - Some('\"') => s.push('\"'), - Some('\\') => s.push('\\'), - Some('u') => { - if let Some(x) = unescape_unicode(&mut queue) { - s.push(x); - } else { - return None; - } - } - Some('x') => { - if let Some(x) = unescape_byte(&mut queue) { - s.push(x) - } else { - return None; - } - } - Some('\0') => s.push('\0'), - Some(c) => { - if c.is_digit(8) { - if let Some(x) = unescape_octal(c, &mut queue) { - s.push(x); - } else { - return None; - } - } else { - s.push(c) - } - } - _ => return None, - }; - } - - Some(s) -} - -fn unescape_unicode(queue: &mut VecDeque) -> Option { - let ret = hex_char_code(queue)?; - ::std::char::from_u32(ret) -} - -fn hex_char_code(queue: &mut VecDeque) -> Option { - if let Some(c) = queue.pop_front() { - if c == '{' { - let mut x = 0; - while let Some(c) = queue.pop_front() { - if c == '}' { - break; - } - x = x * 16 + c.to_digit(16)?; - } - Some(x) - } else { - let mut x = c.to_digit(16)?; - for _ in 0..3 { - if let Some(u) = queue.pop_front() { - x = x * 16 + u.to_digit(16)?; - } - } - if x >= 0xD800 && x <= 0xDBFF { - debug_assert!(queue.pop_front() == Some('\\')); - debug_assert!(queue.pop_front() == Some('u')); - let high = (x - 0xD800) * 0x400; - let low = hex_char_code(queue)? - 0xDC00; - x = 0x10000 + high + low; - } - Some(x) - } - } else { - None - } -} - -fn unescape_byte(queue: &mut VecDeque) -> Option { - let mut s = String::new(); - - for _ in 0..2 { - if let Some(c) = queue.pop_front() { - s.push(c) - } else { - return None; - } - } - match u32::from_str_radix(&s, 16) { - Ok(u) => ::std::char::from_u32(u), - Err(e) => { - panic!("{}", e); - } - } -} - -fn unescape_octal(c: char, queue: &mut VecDeque) -> Option { - let (ret, ct) = if let Some(next) = queue.get(0) { - if !next.is_digit(8) { - let d = c.to_digit(8)?; - return std::char::from_u32(d); - } else if c >= '0' && c < '4' { - let s = if let Some(third) = queue.get(1) { - if !third.is_digit(8) { - format!("{}{}", c, next) - } else { - format!("{}{}{}", c, next, third) - } - } else { - format!("{}{}", c, next) - }; - let ct = s.len().saturating_sub(1); - match u32::from_str_radix(&s, 8) { - Ok(r) => (::std::char::from_u32(r), ct), - Err(e) => panic!("{}", e), - } - } else { - match u32::from_str_radix(&format!("{}{}", c, next), 8) { - Ok(r) => (::std::char::from_u32(r), 1), - Err(e) => panic!("{}", e), - } - } - } else { - (Some(c), 0) - }; - for _ in 0..ct { - let _ = queue.pop_front(); - } - ret -} - -#[cfg(test)] -mod test { - use super::*; - #[test] - fn four_hundred() { - let js = r#""\1\00\400\000\""#; - let expectation = "\"\u{1}\u{0} 0\u{0}\""; - assert_eq!(unescaper(js).unwrap(), expectation.to_string()); - } - #[test] - fn escape_lots() { - let js = "\"\\'\\\"\\\\\\b\\f\\n\\r\\t\\v\\0\""; - let expectation = "\"'\"\\\u{8}\u{c}\n\r\t\u{b}\u{0}\""; - assert_eq!(unescaper(js).unwrap(), expectation.to_string()); - } - - #[test] - fn escaped_new_line() { - let js = r#""\\\n""#; - let expectation = "\"\\\n\""; - assert_eq!(unescaper(js).unwrap(), expectation.to_string()); - } - - #[test] - fn unicode_ident() { - let js = "φ"; - let expectation = "φ"; - assert_eq!(unescaper(js).unwrap(), expectation.to_string()); - } - - #[test] - fn unicode_string() { - let js = r#""\uD834\uDF06\u2603\u03C6 \u{0000001F4a9}\u{1D306}\u{2603}\u{3c6} 𝌆☃φ""#; - let expectation = "\"𝌆☃φ 💩𝌆☃φ 𝌆☃φ\""; - assert_eq!(unescaper(js).unwrap(), expectation.to_string()); - } -} diff --git a/src/spanned/convert.rs b/src/spanned/convert.rs index 84c79fc..2be8578 100644 --- a/src/spanned/convert.rs +++ b/src/spanned/convert.rs @@ -1,30 +1,29 @@ //! All conversions from spanned into non-spanned types //! -use crate::{ - spanned::{ - decl::{ - Alias, Decl, DefaultExportDeclValue, DefaultImportSpec, ExportSpecifier, - ImportSpecifier, ModExport, ModExportSpecifier, ModImport, NamedExportDecl, - NamespaceImportSpec, NormalImportSpec, VarDecl, - }, - expr::{ - ArrowFuncBody, ArrowFuncExpr, AssignExpr, AssignLeft, BinaryExpr, CallExpr, - ConditionalExpr, Expr, Lit, LogicalExpr, MemberExpr, MetaProp, NewExpr, ObjProp, Prop, - PropInitKey, PropKey, PropMethod, PropValue, RegEx, SequenceExprEntry, StringLit, - TaggedTemplateExpr, TemplateElement, TemplateLit, UnaryExpr, UpdateExpr, YieldExpr, - }, - pat::{ArrayElement, ArrayPat, ArrayPatPart, AssignPat, ObjPat, ObjPatPart, Pat}, - stmt::{ - BlockStmt, CatchClause, DoWhileStmt, FinallyClause, ForInStmt, ForOfStmt, ForStmt, - IfStmt, LabeledStmt, LoopInit, LoopLeft, Stmt, SwitchCase, SwitchStmt, TryStmt, - WhileStmt, WithStmt, - }, - tokens::{AssignOp, BinaryOp, LogicalOp, UnaryOp, UpdateOp}, - Class, ClassBody, Dir, Func, FuncArg, FuncArgEntry, FuncBody, Ident, Program, ProgramPart, - Slice, VarKind, +use std::borrow::Cow; + +use crate::spanned::{ + decl::{ + Alias, Decl, DefaultExportDeclValue, DefaultImportSpec, ExportSpecifier, ImportSpecifier, + ModExport, ModExportSpecifier, ModImport, NamedExportDecl, NamespaceImportSpec, + NormalImportSpec, VarDecl, + }, + expr::{ + ArrowFuncBody, ArrowFuncExpr, AssignExpr, AssignLeft, BinaryExpr, CallExpr, + ConditionalExpr, Expr, Lit, LogicalExpr, MemberExpr, MetaProp, NewExpr, ObjProp, Prop, + PropInitKey, PropKey, PropMethod, PropValue, RegEx, SequenceExprEntry, StringLit, + TaggedTemplateExpr, TemplateElement, TemplateLit, UnaryExpr, UpdateExpr, YieldExpr, }, - SourceText, + pat::{ArrayElement, ArrayPat, ArrayPatPart, AssignPat, ObjPat, ObjPatPart, Pat}, + stmt::{ + BlockStmt, CatchClause, DoWhileStmt, FinallyClause, ForInStmt, ForOfStmt, ForStmt, IfStmt, + LabeledStmt, LoopInit, LoopLeft, Stmt, SwitchCase, SwitchStmt, TryStmt, WhileStmt, + WithStmt, + }, + tokens::{AssignOp, BinaryOp, LogicalOp, UnaryOp, UpdateOp}, + Class, ClassBody, Dir, Func, FuncArg, FuncArgEntry, FuncBody, Ident, Program, ProgramPart, + Slice, VarKind, }; mod decl { @@ -157,7 +156,7 @@ mod decl { fn from(other: ExportSpecifier) -> Self { let local: crate::Ident = other.local.into(); Self { - local: local, + local, alias: other.alias.map(|a| a.ident.into()), } } @@ -362,12 +361,11 @@ mod expr { impl From> for crate::expr::UpdateExpr { fn from(other: UpdateExpr) -> Self { - let ret = Self { + Self { prefix: other.prefix(), operator: other.operator.into(), argument: Box::new(From::from(*other.argument)), - }; - ret + } } } @@ -513,7 +511,7 @@ mod expr { fn from(other: TemplateElement) -> Self { Self { open_quote: other.open_quote.into(), - content: other.content.into(), + content: other.content.source, close_quote: other.close_quote.into(), } } @@ -1006,8 +1004,38 @@ mod stmt { } } -impl From> for SourceText { - fn from(other: Slice) -> Self { +impl From> for String { + fn from(other: Slice) -> Self { + other.source + } +} + +impl<'a> From> for &'a str { + fn from(other: Slice<&'a str>) -> &'a str { + other.source + } +} + +impl<'a> From>> for Cow<'a, str> { + fn from(other: Slice>) -> Cow<'a, str> { + other.source + } +} + +impl<'a> From> for &'a [u8] { + fn from(other: Slice<&'a [u8]>) -> &'a [u8] { + other.source + } +} + +impl<'a> From>> for Cow<'a, [u8]> { + fn from(other: Slice>) -> Cow<'a, [u8]> { + other.source + } +} + +impl From>> for Vec { + fn from(other: Slice>) -> Self { other.source } } diff --git a/src/spanned/decl.rs b/src/spanned/decl.rs index 89fb7db..d358f42 100644 --- a/src/spanned/decl.rs +++ b/src/spanned/decl.rs @@ -2,14 +2,19 @@ use crate::spanned::expr::{Expr, Lit}; use crate::spanned::pat::Pat; use crate::spanned::VarKind; use crate::spanned::{Class, Func, Ident}; +use crate::IntoAllocated; use super::tokens::{ As, Asterisk, CloseBrace, Default, Equal, Export, From, Import, OpenBrace, Semicolon, Token, }; use super::{ListEntry, Node, SourceLocation}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// The declaration of a variable, function, class, import or export #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Decl { /// A variable declaration /// ```js @@ -50,6 +55,31 @@ pub enum Decl { }, } +impl IntoAllocated for Decl +where + T: ToString, +{ + type Allocated = Decl; + fn into_allocated(self) -> Decl { + match self { + Decl::Var { decls, semi_colon } => Decl::Var { + decls: decls.into_allocated(), + semi_colon, + }, + Decl::Func(f) => Decl::Func(f.into_allocated()), + Decl::Class(c) => Decl::Class(c.into_allocated()), + Decl::Import { import, semi_colon } => Decl::Import { + import: import.into_allocated(), + semi_colon, + }, + Decl::Export { export, semi_colon } => Decl::Export { + export: export.into_allocated(), + semi_colon, + }, + } + } +} + impl Node for Decl { fn loc(&self) -> super::SourceLocation { match self { @@ -87,11 +117,25 @@ impl Node for Decl { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct VarDecls { pub keyword: VarKind, pub decls: Vec>>, } +impl IntoAllocated for VarDecls +where + T: ToString, +{ + type Allocated = VarDecls; + fn into_allocated(self) -> VarDecls { + VarDecls { + keyword: self.keyword, + decls: self.decls.into_iter().map(|d| d.into_allocated()).collect(), + } + } +} + impl Node for VarDecls { fn loc(&self) -> SourceLocation { if let Some(last) = self.decls.last() { @@ -107,12 +151,27 @@ impl Node for VarDecls { /// The identifier and optional value of a variable declaration #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct VarDecl { pub id: Pat, pub eq: Option, pub init: Option>, } +impl IntoAllocated for VarDecl +where + T: ToString, +{ + type Allocated = VarDecl; + fn into_allocated(self) -> VarDecl { + VarDecl { + id: self.id.into_allocated(), + eq: self.eq, + init: self.init.map(|i| i.into_allocated()), + } + } +} + impl Node for VarDecl { fn loc(&self) -> SourceLocation { if let Some(init) = &self.init { @@ -130,11 +189,25 @@ impl Node for VarDecl { /// in an ES Mod, it would be either an import or /// export at the top level #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ModDecl { Import(ModImport), Export(ModExport), } +impl IntoAllocated for ModDecl +where + T: ToString, +{ + type Allocated = ModDecl; + fn into_allocated(self) -> ModDecl { + match self { + ModDecl::Import(inner) => ModDecl::Import(inner.into_allocated()), + ModDecl::Export(inner) => ModDecl::Export(inner.into_allocated()), + } + } +} + impl Node for ModDecl { fn loc(&self) -> SourceLocation { match self { @@ -151,6 +224,7 @@ impl Node for ModDecl { /// import {Thing} from './stuff.js'; /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ModImport { pub keyword_import: Import, pub specifiers: Vec>>, @@ -158,6 +232,25 @@ pub struct ModImport { pub source: Lit, } +impl IntoAllocated for ModImport +where + T: ToString, +{ + type Allocated = ModImport; + fn into_allocated(self) -> ModImport { + ModImport { + keyword_import: self.keyword_import, + specifiers: self + .specifiers + .into_iter() + .map(|s| s.into_allocated()) + .collect(), + keyword_from: self.keyword_from, + source: self.source.into_allocated(), + } + } +} + impl Node for ModImport { fn loc(&self) -> SourceLocation { SourceLocation { @@ -169,6 +262,7 @@ impl Node for ModImport { /// The name of the thing being imported #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ImportSpecifier { /// A specifier in curly braces, this might /// have a local alias @@ -196,6 +290,20 @@ pub enum ImportSpecifier { Namespace(NamespaceImportSpec), } +impl IntoAllocated for ImportSpecifier +where + T: ToString, +{ + type Allocated = ImportSpecifier; + fn into_allocated(self) -> ImportSpecifier { + match self { + ImportSpecifier::Normal(inner) => ImportSpecifier::Normal(inner.into_allocated()), + ImportSpecifier::Default(inner) => ImportSpecifier::Default(inner.into_allocated()), + ImportSpecifier::Namespace(inner) => ImportSpecifier::Namespace(inner.into_allocated()), + } + } +} + impl Node for ImportSpecifier { fn loc(&self) -> SourceLocation { match self { @@ -207,12 +315,27 @@ impl Node for ImportSpecifier { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NormalImportSpecs { pub open_brace: OpenBrace, pub specs: Vec>>, pub close_brace: CloseBrace, } +impl IntoAllocated for NormalImportSpecs +where + T: ToString, +{ + type Allocated = NormalImportSpecs; + fn into_allocated(self) -> NormalImportSpecs { + NormalImportSpecs { + open_brace: self.open_brace, + specs: self.specs.into_iter().map(|s| s.into_allocated()).collect(), + close_brace: self.close_brace, + } + } +} + impl Node for NormalImportSpecs { fn loc(&self) -> SourceLocation { SourceLocation { @@ -223,11 +346,25 @@ impl Node for NormalImportSpecs { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NormalImportSpec { pub imported: Ident, pub alias: Option>, } +impl IntoAllocated for NormalImportSpec +where + T: ToString, +{ + type Allocated = NormalImportSpec; + fn into_allocated(self) -> NormalImportSpec { + NormalImportSpec { + imported: self.imported.into_allocated(), + alias: self.alias.map(|a| a.into_allocated()), + } + } +} + impl Node for NormalImportSpec { fn loc(&self) -> SourceLocation { if let Some(alias) = &self.alias { @@ -242,10 +379,23 @@ impl Node for NormalImportSpec { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct DefaultImportSpec { pub id: Ident, } +impl IntoAllocated for DefaultImportSpec +where + T: ToString, +{ + type Allocated = DefaultImportSpec; + fn into_allocated(self) -> DefaultImportSpec { + DefaultImportSpec { + id: self.id.into_allocated(), + } + } +} + impl Node for DefaultImportSpec { fn loc(&self) -> SourceLocation { self.id.loc() @@ -253,12 +403,27 @@ impl Node for DefaultImportSpec { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NamespaceImportSpec { pub star: Asterisk, pub keyword: As, pub ident: Ident, } +impl IntoAllocated for NamespaceImportSpec +where + T: ToString, +{ + type Allocated = NamespaceImportSpec; + fn into_allocated(self) -> NamespaceImportSpec { + NamespaceImportSpec { + star: self.star, + keyword: self.keyword, + ident: self.ident.into_allocated(), + } + } +} + impl Node for NamespaceImportSpec { fn loc(&self) -> SourceLocation { SourceLocation { @@ -269,11 +434,25 @@ impl Node for NamespaceImportSpec { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ModExport { pub keyword: Export, pub spec: ModExportSpecifier, } +impl IntoAllocated for ModExport +where + T: ToString, +{ + type Allocated = ModExport; + fn into_allocated(self) -> ModExport { + ModExport { + keyword: self.keyword, + spec: self.spec.into_allocated(), + } + } +} + impl Node for ModExport { fn loc(&self) -> SourceLocation { SourceLocation { @@ -285,6 +464,7 @@ impl Node for ModExport { /// Something exported from this module #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ModExportSpecifier { /// ```js /// export default function() {}; @@ -317,6 +497,33 @@ pub enum ModExportSpecifier { }, } +impl IntoAllocated for ModExportSpecifier +where + T: ToString, +{ + type Allocated = ModExportSpecifier; + fn into_allocated(self) -> ModExportSpecifier { + match self { + ModExportSpecifier::Default { keyword, value } => ModExportSpecifier::Default { + keyword, + value: value.into_allocated(), + }, + ModExportSpecifier::Named(inner) => ModExportSpecifier::Named(inner.into_allocated()), + ModExportSpecifier::All { + star, + alias, + keyword, + name, + } => ModExportSpecifier::All { + star, + alias: alias.map(|a| a.into_allocated()), + keyword, + name: name.into_allocated(), + }, + } + } +} + impl Node for ModExportSpecifier { fn loc(&self) -> SourceLocation { match self { @@ -338,11 +545,25 @@ impl Node for ModExportSpecifier { /// export function thing() {} /// export {stuff} from 'place'; #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum NamedExportDecl { Decl(Decl), Specifier(NamedExportSpec), } +impl IntoAllocated for NamedExportDecl +where + T: ToString, +{ + type Allocated = NamedExportDecl; + fn into_allocated(self) -> NamedExportDecl { + match self { + NamedExportDecl::Decl(inner) => NamedExportDecl::Decl(inner.into_allocated()), + NamedExportDecl::Specifier(inner) => NamedExportDecl::Specifier(inner.into_allocated()), + } + } +} + impl Node for NamedExportDecl { fn loc(&self) -> SourceLocation { match self { @@ -353,11 +574,25 @@ impl Node for NamedExportDecl { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct DefaultExportDecl { pub keyword: Default, pub value: DefaultExportDeclValue, } +impl IntoAllocated for DefaultExportDecl +where + T: ToString, +{ + type Allocated = DefaultExportDecl; + fn into_allocated(self) -> DefaultExportDecl { + DefaultExportDecl { + keyword: self.keyword, + value: self.value.into_allocated(), + } + } +} + impl Node for DefaultExportDecl { fn loc(&self) -> SourceLocation { SourceLocation { @@ -372,12 +607,27 @@ impl Node for DefaultExportDecl { /// export default class Thing {} /// ``` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ExportDeclValue { Decl(Decl), Expr(Expr), List(ExportList), } +impl IntoAllocated for ExportDeclValue +where + T: ToString, +{ + type Allocated = ExportDeclValue; + fn into_allocated(self) -> ExportDeclValue { + match self { + ExportDeclValue::Decl(inner) => ExportDeclValue::Decl(inner.into_allocated()), + ExportDeclValue::Expr(inner) => ExportDeclValue::Expr(inner.into_allocated()), + ExportDeclValue::List(inner) => ExportDeclValue::List(inner.into_allocated()), + } + } +} + impl Node for ExportDeclValue { fn loc(&self) -> SourceLocation { match self { @@ -389,11 +639,29 @@ impl Node for ExportDeclValue { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum DefaultExportDeclValue { Decl(Decl), Expr(Expr), } +impl IntoAllocated for DefaultExportDeclValue +where + T: ToString, +{ + type Allocated = DefaultExportDeclValue; + fn into_allocated(self) -> DefaultExportDeclValue { + match self { + DefaultExportDeclValue::Decl(inner) => { + DefaultExportDeclValue::Decl(inner.into_allocated()) + } + DefaultExportDeclValue::Expr(inner) => { + DefaultExportDeclValue::Expr(inner.into_allocated()) + } + } + } +} + impl Node for DefaultExportDeclValue { fn loc(&self) -> SourceLocation { match self { @@ -404,11 +672,25 @@ impl Node for DefaultExportDeclValue { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NamedExportSpec { pub list: ExportList, pub source: Option>, } +impl IntoAllocated for NamedExportSpec +where + T: ToString, +{ + type Allocated = NamedExportSpec; + fn into_allocated(self) -> NamedExportSpec { + NamedExportSpec { + list: self.list.into_allocated(), + source: self.source.map(|s| s.into_allocated()), + } + } +} + impl Node for NamedExportSpec { fn loc(&self) -> SourceLocation { if let Some(source) = &self.source { @@ -423,11 +705,25 @@ impl Node for NamedExportSpec { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NamedExportSource { pub keyword_from: From, pub module: Lit, } +impl IntoAllocated for NamedExportSource +where + T: ToString, +{ + type Allocated = NamedExportSource; + fn into_allocated(self) -> NamedExportSource { + NamedExportSource { + keyword_from: self.keyword_from, + module: self.module.into_allocated(), + } + } +} + impl Node for NamedExportSource { fn loc(&self) -> SourceLocation { SourceLocation { @@ -438,12 +734,31 @@ impl Node for NamedExportSource { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ExportList { pub open_brace: OpenBrace, pub elements: Vec>>, pub close_brace: CloseBrace, } +impl IntoAllocated for ExportList +where + T: ToString, +{ + type Allocated = ExportList; + fn into_allocated(self) -> ExportList { + ExportList { + open_brace: self.open_brace, + elements: self + .elements + .into_iter() + .map(|e| e.into_allocated()) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for ExportList { fn loc(&self) -> SourceLocation { SourceLocation { @@ -462,11 +777,26 @@ impl Node for ExportList { /// export {Stuff as NewThing} from 'place' /// ``` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ExportSpecifier { pub local: Ident, pub alias: Option>, } +impl IntoAllocated for ExportSpecifier +where + T: ToString, +{ + type Allocated = ExportSpecifier; + + fn into_allocated(self) -> Self::Allocated { + ExportSpecifier { + local: self.local.into_allocated(), + alias: self.alias.map(|a| a.into_allocated()), + } + } +} + impl Node for ExportSpecifier { fn loc(&self) -> SourceLocation { if let Some(alias) = &self.alias { @@ -481,11 +811,26 @@ impl Node for ExportSpecifier { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Alias { pub keyword: As, pub ident: Ident, } +impl IntoAllocated for Alias +where + T: ToString, +{ + type Allocated = Alias; + + fn into_allocated(self) -> Self::Allocated { + Alias { + keyword: self.keyword, + ident: self.ident.into_allocated(), + } + } +} + impl Node for Alias { fn loc(&self) -> SourceLocation { SourceLocation { diff --git a/src/spanned/expr.rs b/src/spanned/expr.rs index a7ae64d..ba3cb33 100644 --- a/src/spanned/expr.rs +++ b/src/spanned/expr.rs @@ -1,5 +1,6 @@ use crate::spanned::pat::Pat; use crate::spanned::{Class, Func, FuncArg, FuncBody, Ident}; +use crate::IntoAllocated; use super::tokens::{ AssignOp, Asterisk, Async, Await, BinaryOp, CloseBrace, CloseBracket, CloseParen, Colon, Comma, @@ -8,9 +9,12 @@ use super::tokens::{ UnaryOp, UpdateOp, Yield, }; use super::{FuncArgEntry, ListEntry, Node, Slice, SourceLocation}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; /// A slightly more granular program part that a statement #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Expr { /// `[0,,]` Array(ArrayExpr), @@ -95,6 +99,50 @@ pub enum Expr { Yield(YieldExpr), } +impl IntoAllocated for Expr +where + T: ToString, +{ + type Allocated = Expr; + fn into_allocated(self) -> Self::Allocated { + match self { + Expr::Array(inner) => Expr::Array(inner.into_allocated()), + Expr::ArrowFunc(inner) => Expr::ArrowFunc(inner.into_allocated()), + Expr::ArrowParamPlaceHolder(inner) => { + Expr::ArrowParamPlaceHolder(inner.into_allocated()) + } + Expr::Assign(inner) => Expr::Assign(inner.into_allocated()), + Expr::Await(inner) => Expr::Await(inner.into_allocated()), + Expr::Binary(inner) => Expr::Binary(inner.into_allocated()), + Expr::Class(inner) => Expr::Class(inner.into_allocated()), + Expr::Call(inner) => Expr::Call(inner.into_allocated()), + Expr::Conditional(inner) => Expr::Conditional(inner.into_allocated()), + Expr::Func(inner) => Expr::Func(inner.into_allocated()), + Expr::Ident(inner) => Expr::Ident(inner.into_allocated()), + Expr::Lit(inner) => Expr::Lit(inner.into_allocated()), + Expr::Logical(inner) => Expr::Logical(inner.into_allocated()), + Expr::Member(inner) => Expr::Member(inner.into_allocated()), + Expr::MetaProp(inner) => Expr::MetaProp(inner.into_allocated()), + Expr::New(inner) => Expr::New(inner.into_allocated()), + Expr::Obj(inner) => Expr::Obj(inner.into_allocated()), + Expr::Sequence(inner) => Expr::Sequence( + inner + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + ), + Expr::Spread(inner) => Expr::Spread(inner.into_allocated()), + Expr::Super(inner) => Expr::Super(inner), + Expr::TaggedTemplate(inner) => Expr::TaggedTemplate(inner.into_allocated()), + Expr::This(inner) => Expr::This(inner), + Expr::Unary(inner) => Expr::Unary(inner.into_allocated()), + Expr::Update(inner) => Expr::Update(inner.into_allocated()), + Expr::Wrapped(inner) => Expr::Wrapped(inner.into_allocated()), + Expr::Yield(inner) => Expr::Yield(inner.into_allocated()), + } + } +} + impl Node for Expr { fn loc(&self) -> SourceLocation { match self { @@ -132,12 +180,31 @@ type ArrayExprEntry = ListEntry>>; /// `[a, b, c]` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrayExpr { pub open_bracket: OpenBracket, pub elements: Vec>, pub close_bracket: CloseBracket, } +impl IntoAllocated for ArrayExpr +where + T: ToString, +{ + type Allocated = ArrayExpr; + fn into_allocated(self) -> Self::Allocated { + ArrayExpr { + open_bracket: self.open_bracket, + elements: self + .elements + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_bracket: self.close_bracket, + } + } +} + impl Node for ArrayExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -149,12 +216,32 @@ impl Node for ArrayExpr { /// `{a: 'b', c, ...d}` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ObjExpr { pub open_brace: OpenBrace, pub props: Vec>>, pub close_brace: CloseBrace, } +impl IntoAllocated for ObjExpr +where + T: ToString, +{ + type Allocated = ObjExpr; + + fn into_allocated(self) -> Self::Allocated { + ObjExpr { + open_brace: self.open_brace, + props: self + .props + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for ObjExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -166,11 +253,25 @@ impl Node for ObjExpr { /// A single part of an object literal #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ObjProp { Prop(Prop), Spread(SpreadExpr), } +impl IntoAllocated for ObjProp +where + T: ToString, +{ + type Allocated = ObjProp; + fn into_allocated(self) -> Self::Allocated { + match self { + ObjProp::Prop(inner) => ObjProp::Prop(inner.into_allocated()), + ObjProp::Spread(inner) => ObjProp::Spread(inner.into_allocated()), + } + } +} + impl Node for ObjProp { fn loc(&self) -> SourceLocation { match self { @@ -181,11 +282,25 @@ impl Node for ObjProp { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SpreadExpr { pub dots: Ellipsis, pub expr: Expr, } +impl IntoAllocated for SpreadExpr +where + T: ToString, +{ + type Allocated = SpreadExpr; + fn into_allocated(self) -> Self::Allocated { + SpreadExpr { + dots: self.dots, + expr: self.expr.into_allocated(), + } + } +} + impl Node for SpreadExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -196,6 +311,7 @@ impl Node for SpreadExpr { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Prop { Init(PropInit), Method(PropMethod), @@ -204,6 +320,22 @@ pub enum Prop { Set(PropSet), } +impl IntoAllocated for Prop +where + T: ToString, +{ + type Allocated = Prop; + fn into_allocated(self) -> Self::Allocated { + match self { + Prop::Init(inner) => Prop::Init(inner.into_allocated()), + Prop::Method(inner) => Prop::Method(inner.into_allocated()), + Prop::Ctor(inner) => Prop::Ctor(inner.into_allocated()), + Prop::Get(inner) => Prop::Get(inner.into_allocated()), + Prop::Set(inner) => Prop::Set(inner.into_allocated()), + } + } +} + impl Node for Prop { fn loc(&self) -> SourceLocation { match self { @@ -241,12 +373,27 @@ impl Prop { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropInit { pub key: PropInitKey, pub colon: Option, pub value: Option>, } +impl IntoAllocated for PropInit +where + T: ToString, +{ + type Allocated = PropInit; + fn into_allocated(self) -> Self::Allocated { + PropInit { + key: self.key.into_allocated(), + colon: self.colon, + value: self.value.into_allocated(), + } + } +} + impl Node for PropInit { fn loc(&self) -> SourceLocation { if let Some(value) = &self.value { @@ -270,11 +417,25 @@ impl PropInit { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropInitKey { pub value: PropKey, pub brackets: Option<(OpenBracket, CloseBracket)>, } +impl IntoAllocated for PropInitKey +where + T: ToString, +{ + type Allocated = PropInitKey; + fn into_allocated(self) -> Self::Allocated { + PropInitKey { + value: self.value.into_allocated(), + brackets: self.brackets, + } + } +} + impl Node for PropInitKey { fn loc(&self) -> SourceLocation { if let Some((open, close)) = &self.brackets { @@ -289,6 +450,7 @@ impl Node for PropInitKey { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropMethod { pub keyword_static: Option, pub keyword_async: Option, @@ -300,6 +462,29 @@ pub struct PropMethod { pub body: FuncBody, } +impl IntoAllocated for PropMethod +where + T: ToString, +{ + type Allocated = PropMethod; + fn into_allocated(self) -> Self::Allocated { + PropMethod { + keyword_static: self.keyword_static, + keyword_async: self.keyword_async, + id: self.id.into_allocated(), + star: self.star, + open_paren: self.open_paren, + params: self + .params + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for PropMethod { fn loc(&self) -> SourceLocation { let start = if let Some(keyword) = &self.keyword_async { @@ -317,6 +502,7 @@ impl Node for PropMethod { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropCtor { pub keyword: PropInitKey, pub open_paren: OpenParen, @@ -325,6 +511,26 @@ pub struct PropCtor { pub body: FuncBody, } +impl IntoAllocated for PropCtor +where + T: ToString, +{ + type Allocated = PropCtor; + fn into_allocated(self) -> Self::Allocated { + PropCtor { + keyword: self.keyword.into_allocated(), + open_paren: self.open_paren, + params: self + .params + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for PropCtor { fn loc(&self) -> SourceLocation { SourceLocation { @@ -335,6 +541,7 @@ impl Node for PropCtor { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropGet { pub keyword_static: Option, pub keyword_get: Get, @@ -344,6 +551,23 @@ pub struct PropGet { pub body: FuncBody, } +impl IntoAllocated for PropGet +where + T: ToString, +{ + type Allocated = PropGet; + fn into_allocated(self) -> Self::Allocated { + PropGet { + keyword_static: self.keyword_static, + keyword_get: self.keyword_get, + id: self.id.into_allocated(), + open_paren: self.open_paren, + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for PropGet { fn loc(&self) -> SourceLocation { if let Some(keyword_static) = &self.keyword_static { @@ -360,6 +584,7 @@ impl Node for PropGet { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct PropSet { pub keyword_static: Option, pub keyword_set: Set, @@ -370,6 +595,24 @@ pub struct PropSet { pub body: FuncBody, } +impl IntoAllocated for PropSet +where + T: ToString, +{ + type Allocated = PropSet; + fn into_allocated(self) -> Self::Allocated { + PropSet { + keyword_static: self.keyword_static, + keyword_set: self.keyword_set, + id: self.id.into_allocated(), + open_paren: self.open_paren, + arg: self.arg.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for PropSet { fn loc(&self) -> SourceLocation { if let Some(keyword_static) = &self.keyword_static { @@ -387,12 +630,27 @@ impl Node for PropSet { /// An object literal or class property identifier #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum PropKey { Lit(Lit), Expr(Expr), Pat(Pat), } +impl IntoAllocated for PropKey +where + T: ToString, +{ + type Allocated = PropKey; + fn into_allocated(self) -> Self::Allocated { + match self { + PropKey::Lit(inner) => PropKey::Lit(inner.into_allocated()), + PropKey::Expr(inner) => PropKey::Expr(inner.into_allocated()), + PropKey::Pat(inner) => PropKey::Pat(inner.into_allocated()), + } + } +} + impl Node for PropKey { fn loc(&self) -> SourceLocation { match self { @@ -405,12 +663,27 @@ impl Node for PropKey { /// The value of an object literal or class property #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum PropValue { Expr(Expr), Pat(Pat), Method(PropMethod), } +impl IntoAllocated for PropValue +where + T: ToString, +{ + type Allocated = PropValue; + fn into_allocated(self) -> Self::Allocated { + match self { + PropValue::Expr(inner) => PropValue::Expr(inner.into_allocated()), + PropValue::Pat(inner) => PropValue::Pat(inner.into_allocated()), + PropValue::Method(inner) => PropValue::Method(inner.into_allocated()), + } + } +} + impl Node for PropValue { fn loc(&self) -> SourceLocation { match self { @@ -423,11 +696,25 @@ impl Node for PropValue { /// An operation that takes one argument #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct UnaryExpr { pub operator: UnaryOp, pub argument: Box>, } +impl IntoAllocated for UnaryExpr +where + T: ToString, +{ + type Allocated = UnaryExpr; + fn into_allocated(self) -> Self::Allocated { + UnaryExpr { + operator: self.operator, + argument: self.argument.into_allocated(), + } + } +} + impl UnaryExpr { pub fn prefix(&self) -> bool { self.operator.loc() < self.argument.loc() @@ -447,11 +734,25 @@ impl Node for UnaryExpr { /// Increment or decrementing a value #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct UpdateExpr { pub operator: UpdateOp, pub argument: Box>, } +impl IntoAllocated for UpdateExpr +where + T: ToString, +{ + type Allocated = UpdateExpr; + fn into_allocated(self) -> Self::Allocated { + UpdateExpr { + operator: self.operator, + argument: self.argument.into_allocated(), + } + } +} + impl UpdateExpr { pub fn prefix(&self) -> bool { self.operator.loc().start < self.argument.loc().start @@ -478,12 +779,27 @@ impl Node for UpdateExpr { /// An operation that requires 2 arguments #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BinaryExpr { pub operator: BinaryOp, pub left: Box>, pub right: Box>, } +impl IntoAllocated for BinaryExpr +where + T: ToString, +{ + type Allocated = BinaryExpr; + fn into_allocated(self) -> Self::Allocated { + BinaryExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + impl Node for BinaryExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -495,12 +811,27 @@ impl Node for BinaryExpr { /// An assignment or update + assignment operation #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct AssignExpr { pub operator: AssignOp, pub left: AssignLeft, pub right: Box>, } +impl IntoAllocated for AssignExpr +where + T: ToString, +{ + type Allocated = AssignExpr; + fn into_allocated(self) -> Self::Allocated { + AssignExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + impl Node for AssignExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -511,11 +842,25 @@ impl Node for AssignExpr { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct AwaitExpr { pub keyword: Await, pub expr: Expr, } +impl IntoAllocated for AwaitExpr +where + T: ToString, +{ + type Allocated = AwaitExpr; + fn into_allocated(self) -> Self::Allocated { + AwaitExpr { + keyword: self.keyword, + expr: self.expr.into_allocated(), + } + } +} + impl Node for AwaitExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -527,11 +872,25 @@ impl Node for AwaitExpr { /// The value being assigned to #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum AssignLeft { Pat(Pat), Expr(Box>), } +impl IntoAllocated for AssignLeft +where + T: ToString, +{ + type Allocated = AssignLeft; + fn into_allocated(self) -> Self::Allocated { + match self { + AssignLeft::Pat(inner) => AssignLeft::Pat(inner.into_allocated()), + AssignLeft::Expr(inner) => AssignLeft::Expr(inner.into_allocated()), + } + } +} + impl Node for AssignLeft { fn loc(&self) -> SourceLocation { match self { @@ -547,12 +906,27 @@ impl Node for AssignLeft { /// false || true /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LogicalExpr { pub operator: LogicalOp, pub left: Box>, pub right: Box>, } +impl IntoAllocated for LogicalExpr +where + T: ToString, +{ + type Allocated = LogicalExpr; + fn into_allocated(self) -> Self::Allocated { + LogicalExpr { + operator: self.operator, + left: self.left.into_allocated(), + right: self.right.into_allocated(), + } + } +} + impl Node for LogicalExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -568,12 +942,28 @@ impl Node for LogicalExpr { /// c.stuff; /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct MemberExpr { pub object: Box>, pub property: Box>, pub indexer: MemberIndexer, } +impl IntoAllocated for MemberExpr +where + T: ToString, +{ + type Allocated = MemberExpr; + + fn into_allocated(self) -> Self::Allocated { + MemberExpr { + object: self.object.into_allocated(), + property: self.property.into_allocated(), + indexer: self.indexer, + } + } +} + impl MemberExpr { pub fn computed(&self) -> bool { matches!(self.indexer, MemberIndexer::Computed { .. }) @@ -593,7 +983,8 @@ impl Node for MemberExpr { } } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum MemberIndexer { Period(Period), Computed { @@ -622,6 +1013,7 @@ impl Node for MemberIndexer { /// var a = true ? 'stuff' : 'things'; /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ConditionalExpr { pub test: Box>, pub question_mark: QuestionMark, @@ -630,6 +1022,22 @@ pub struct ConditionalExpr { pub consequent: Box>, } +impl IntoAllocated for ConditionalExpr +where + T: ToString, +{ + type Allocated = ConditionalExpr; + fn into_allocated(self) -> Self::Allocated { + ConditionalExpr { + test: self.test.into_allocated(), + question_mark: self.question_mark, + alternate: self.alternate.into_allocated(), + colon: self.colon, + consequent: self.consequent.into_allocated(), + } + } +} + impl Node for ConditionalExpr { fn loc(&self) -> SourceLocation { let start = self.test.loc().start; @@ -643,6 +1051,7 @@ impl Node for ConditionalExpr { /// Math.random() /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct CallExpr { pub callee: Box>, pub open_paren: OpenParen, @@ -650,6 +1059,26 @@ pub struct CallExpr { pub close_paren: CloseParen, } +impl IntoAllocated for CallExpr +where + T: ToString, +{ + type Allocated = CallExpr; + + fn into_allocated(self) -> Self::Allocated { + CallExpr { + callee: self.callee.into_allocated(), + open_paren: self.open_paren, + arguments: self + .arguments + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + } + } +} + impl Node for CallExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -664,6 +1093,7 @@ impl Node for CallExpr { /// new Uint8Array(32); /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct NewExpr { pub keyword: New, pub callee: Box>, @@ -672,6 +1102,27 @@ pub struct NewExpr { pub close_paren: Option, } +impl IntoAllocated for NewExpr +where + T: ToString, +{ + type Allocated = NewExpr; + + fn into_allocated(self) -> Self::Allocated { + NewExpr { + keyword: self.keyword, + callee: self.callee.into_allocated(), + open_paren: self.open_paren, + arguments: self + .arguments + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + } + } +} + impl Node for NewExpr { fn loc(&self) -> SourceLocation { let end = if let Some(close) = &self.close_paren { @@ -683,7 +1134,7 @@ impl Node for NewExpr { }; SourceLocation { start: self.keyword.start(), - end: end, + end, } } } @@ -711,6 +1162,7 @@ impl Node for SequenceExpr { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrowParamPlaceHolder { // async keyword pub keyword: Option, @@ -719,6 +1171,25 @@ pub struct ArrowParamPlaceHolder { pub close_paren: Option, } +impl IntoAllocated for ArrowParamPlaceHolder +where + T: ToString, +{ + type Allocated = ArrowParamPlaceHolder; + fn into_allocated(self) -> Self::Allocated { + ArrowParamPlaceHolder { + keyword: self.keyword, + open_paren: self.open_paren, + args: self + .args + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + } + } +} + impl Node for ArrowParamPlaceHolder { fn loc(&self) -> SourceLocation { let start = if let Some(keyword) = &self.keyword { @@ -749,6 +1220,7 @@ impl Node for ArrowParamPlaceHolder { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrowFuncExpr { pub keyword: Option, pub star: Option, @@ -759,6 +1231,28 @@ pub struct ArrowFuncExpr { pub body: ArrowFuncBody, } +impl IntoAllocated for ArrowFuncExpr +where + T: ToString, +{ + type Allocated = ArrowFuncExpr; + fn into_allocated(self) -> Self::Allocated { + ArrowFuncExpr { + keyword: self.keyword, + star: self.star, + open_paren: self.open_paren, + params: self + .params + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_paren: self.close_paren, + arrow: self.arrow, + body: self.body.into_allocated(), + } + } +} + impl Node for ArrowFuncExpr { fn loc(&self) -> SourceLocation { let start = if let Some(keyword) = &self.keyword { @@ -779,11 +1273,25 @@ impl Node for ArrowFuncExpr { /// The body portion of an arrow function can be either an expression or a block of statements #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ArrowFuncBody { FuncBody(FuncBody), Expr(Box>), } +impl IntoAllocated for ArrowFuncBody +where + T: ToString, +{ + type Allocated = ArrowFuncBody; + fn into_allocated(self) -> Self::Allocated { + match self { + ArrowFuncBody::FuncBody(inner) => ArrowFuncBody::FuncBody(inner.into_allocated()), + ArrowFuncBody::Expr(inner) => ArrowFuncBody::Expr(inner.into_allocated()), + } + } +} + impl Node for ArrowFuncBody { fn loc(&self) -> SourceLocation { match self { @@ -802,12 +1310,27 @@ impl Node for ArrowFuncBody { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct YieldExpr { pub keyword: Yield, pub argument: Option>>, pub star: Option, } +impl IntoAllocated for YieldExpr +where + T: ToString, +{ + type Allocated = YieldExpr; + fn into_allocated(self) -> Self::Allocated { + YieldExpr { + keyword: self.keyword, + argument: self.argument.into_allocated(), + star: self.star, + } + } +} + impl Node for YieldExpr { fn loc(&self) -> SourceLocation { let end = if let Some(arg) = &self.argument { @@ -825,11 +1348,25 @@ impl Node for YieldExpr { /// A Template literal preceded by a function identifier /// see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates) for more details #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TaggedTemplateExpr { pub tag: Box>, pub quasi: TemplateLit, } +impl IntoAllocated for TaggedTemplateExpr +where + T: ToString, +{ + type Allocated = TaggedTemplateExpr; + fn into_allocated(self) -> Self::Allocated { + TaggedTemplateExpr { + tag: self.tag.into_allocated(), + quasi: self.quasi.into_allocated(), + } + } +} + impl Node for TaggedTemplateExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -844,11 +1381,33 @@ impl Node for TaggedTemplateExpr { /// `I own ${0} birds`; /// ``` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TemplateLit { pub quasis: Vec>, pub expressions: Vec>, } +impl IntoAllocated for TemplateLit +where + T: ToString, +{ + type Allocated = TemplateLit; + fn into_allocated(self) -> Self::Allocated { + TemplateLit { + quasis: self + .quasis + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + expressions: self + .expressions + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + } + } +} + impl Node for TemplateLit { fn loc(&self) -> SourceLocation { let start = self @@ -870,12 +1429,27 @@ impl Node for TemplateLit { /// The text part of a `TemplateLiteral` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TemplateElement { pub open_quote: QuasiQuote, pub content: Slice, pub close_quote: QuasiQuote, } +impl IntoAllocated for TemplateElement +where + T: ToString, +{ + type Allocated = TemplateElement; + fn into_allocated(self) -> Self::Allocated { + TemplateElement { + open_quote: self.open_quote, + content: self.content.into_allocated(), + close_quote: self.close_quote, + } + } +} + impl TemplateElement where T: AsRef, @@ -908,12 +1482,27 @@ impl Node for TemplateElement { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct MetaProp { pub meta: Ident, pub dot: Period, pub property: Ident, } +impl IntoAllocated for MetaProp +where + T: ToString, +{ + type Allocated = MetaProp; + fn into_allocated(self) -> Self::Allocated { + MetaProp { + meta: self.meta.into_allocated(), + dot: self.dot, + property: self.property.into_allocated(), + } + } +} + impl Node for MetaProp { fn loc(&self) -> SourceLocation { SourceLocation { @@ -925,6 +1514,7 @@ impl Node for MetaProp { /// A literal value #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Lit { /// `null` Null(Null), @@ -951,6 +1541,23 @@ pub enum Lit { Template(TemplateLit), } +impl IntoAllocated for Lit +where + T: ToString, +{ + type Allocated = Lit; + fn into_allocated(self) -> Self::Allocated { + match self { + Lit::Null(inner) => Lit::Null(inner), + Lit::String(inner) => Lit::String(inner.into_allocated()), + Lit::Number(inner) => Lit::Number(inner.into_allocated()), + Lit::Boolean(inner) => Lit::Boolean(inner), + Lit::RegEx(inner) => Lit::RegEx(inner.into_allocated()), + Lit::Template(inner) => Lit::Template(inner.into_allocated()), + } + } +} + impl Lit { pub fn new_true(line: u32, column: u32) -> Self { Self::Boolean(Boolean::new_true(line, column)) @@ -962,6 +1569,7 @@ impl Lit { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Boolean { True(True), False(False), @@ -1014,12 +1622,27 @@ impl Node for Lit { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct StringLit { pub open_quote: Quote, pub content: Slice, pub close_quote: Quote, } +impl IntoAllocated for StringLit +where + T: ToString, +{ + type Allocated = StringLit; + fn into_allocated(self) -> Self::Allocated { + StringLit { + open_quote: self.open_quote, + content: self.content.into_allocated(), + close_quote: self.close_quote, + } + } +} + impl Node for StringLit { fn loc(&self) -> SourceLocation { SourceLocation { @@ -1031,6 +1654,7 @@ impl Node for StringLit { /// A regular expression literal #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RegEx { pub open_slash: ForwardSlash, pub pattern: Slice, @@ -1038,6 +1662,21 @@ pub struct RegEx { pub flags: Option>, } +impl IntoAllocated for RegEx +where + T: ToString, +{ + type Allocated = RegEx; + fn into_allocated(self) -> Self::Allocated { + RegEx { + open_slash: self.open_slash, + pattern: self.pattern.into_allocated(), + close_slash: self.close_slash, + flags: self.flags.into_allocated(), + } + } +} + impl Node for RegEx { fn loc(&self) -> SourceLocation { let end = if let Some(flags) = &self.flags { @@ -1053,12 +1692,27 @@ impl Node for RegEx { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct WrappedExpr { pub open_paren: OpenParen, pub expr: Expr, pub close_paren: CloseParen, } +impl IntoAllocated for WrappedExpr +where + T: ToString, +{ + type Allocated = WrappedExpr; + fn into_allocated(self) -> Self::Allocated { + WrappedExpr { + open_paren: self.open_paren, + expr: self.expr.into_allocated(), + close_paren: self.close_paren, + } + } +} + impl Node for WrappedExpr { fn loc(&self) -> SourceLocation { SourceLocation { @@ -1069,11 +1723,25 @@ impl Node for WrappedExpr { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SequenceExprEntry { pub expr: Expr, pub comma: Option, } +impl IntoAllocated for SequenceExprEntry +where + T: ToString, +{ + type Allocated = SequenceExprEntry; + fn into_allocated(self) -> Self::Allocated { + SequenceExprEntry { + expr: self.expr.into_allocated(), + comma: self.comma, + } + } +} + impl SequenceExprEntry { pub fn no_comma(expr: Expr) -> Self { Self { expr, comma: None } diff --git a/src/spanned/mod.rs b/src/spanned/mod.rs index 80d7096..d65e13a 100644 --- a/src/spanned/mod.rs +++ b/src/spanned/mod.rs @@ -10,7 +10,10 @@ use expr::{Expr, Lit, Prop}; use pat::Pat; use stmt::Stmt; -use crate::SourceText; +use crate::IntoAllocated; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; use self::{ pat::RestPat, @@ -25,6 +28,7 @@ pub trait Node { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Ident { pub slice: Slice, } @@ -39,6 +43,18 @@ where } } +impl IntoAllocated for Ident +where + T: ToString, +{ + type Allocated = Ident; + fn into_allocated(self) -> Ident { + Ident { + slice: self.slice.into_allocated(), + } + } +} + impl Node for Ident { fn loc(&self) -> SourceLocation { self.slice.loc @@ -53,7 +69,7 @@ impl From> for Ident { impl Ident { pub fn name(&self) -> &T { - &self.slice.source.0 + &self.slice.source } } @@ -63,6 +79,7 @@ impl Ident { /// with a flag denoting if the representation is /// a ES6 Mod or a Script. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Program { /// An ES6 Mod Mod(Vec>), @@ -70,6 +87,29 @@ pub enum Program { Script(Vec>), } +impl IntoAllocated for Program +where + T: ToString, +{ + type Allocated = Program; + fn into_allocated(self) -> Program { + match self { + Program::Mod(parts) => Program::Mod( + parts + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + ), + Program::Script(parts) => Program::Script( + parts + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + ), + } + } +} + impl Node for Program { fn loc(&self) -> SourceLocation { match self { @@ -105,6 +145,7 @@ impl Node for Vec> { /// A single part of a Javascript program. /// This will be either a Directive, Decl or a Stmt #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ProgramPart { /// A Directive like `'use strict';` Dir(Dir), @@ -114,6 +155,20 @@ pub enum ProgramPart { Stmt(Stmt), } +impl IntoAllocated for ProgramPart +where + T: ToString, +{ + type Allocated = ProgramPart; + fn into_allocated(self) -> ProgramPart { + match self { + ProgramPart::Dir(part) => ProgramPart::Dir(part.into_allocated()), + ProgramPart::Decl(part) => ProgramPart::Decl(part.into_allocated()), + ProgramPart::Stmt(part) => ProgramPart::Stmt(part.into_allocated()), + } + } +} + impl Node for ProgramPart { fn loc(&self) -> SourceLocation { match self { @@ -136,12 +191,27 @@ impl ProgramPart { /// pretty much always `'use strict'`, this can appear at the /// top of a file or function #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Dir { pub expr: Lit, - pub dir: SourceText, + pub dir: T, pub semi_colon: Option, } +impl IntoAllocated for Dir +where + T: ToString, +{ + type Allocated = Dir; + fn into_allocated(self) -> Dir { + Dir { + expr: self.expr.into_allocated(), + dir: self.dir.to_string(), + semi_colon: self.semi_colon, + } + } +} + impl Node for Dir { fn loc(&self) -> SourceLocation { let expr_loc = self.expr.loc(); @@ -166,6 +236,7 @@ impl Node for Dir { /// let y = function q() {} /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Func { pub keyword: Function, pub id: Option>, @@ -186,6 +257,29 @@ impl Func { } } +impl IntoAllocated for Func +where + T: ToString, +{ + type Allocated = Func; + fn into_allocated(self) -> Func { + Func { + keyword: self.keyword, + id: self.id.map(|i| i.into_allocated()), + open_paren: self.open_paren, + params: self + .params + .into_iter() + .map(|p| p.into_allocated()) + .collect(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + star: self.star, + keyword_async: self.keyword_async, + } + } +} + impl Node for Func { fn loc(&self) -> SourceLocation { let start = if let Some(keyword) = self.keyword_async { @@ -199,11 +293,25 @@ impl Node for Func { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct FuncArgEntry { pub value: FuncArg, pub comma: Option, } +impl IntoAllocated for FuncArgEntry +where + T: ToString, +{ + type Allocated = FuncArgEntry; + fn into_allocated(self) -> FuncArgEntry { + FuncArgEntry { + value: self.value.into_allocated(), + comma: self.comma, + } + } +} + impl Node for FuncArgEntry { fn loc(&self) -> SourceLocation { if let Some(comma) = &self.comma { @@ -218,12 +326,27 @@ impl Node for FuncArgEntry { /// A single function argument from a function signature #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum FuncArg { Expr(Expr), Pat(Pat), Rest(Box>), } +impl IntoAllocated for FuncArg +where + T: ToString, +{ + type Allocated = FuncArg; + fn into_allocated(self) -> FuncArg { + match self { + FuncArg::Expr(inner) => FuncArg::Expr(inner.into_allocated()), + FuncArg::Pat(inner) => FuncArg::Pat(inner.into_allocated()), + FuncArg::Rest(inner) => FuncArg::Rest(inner.into_allocated()), + } + } +} + impl Node for FuncArg { fn loc(&self) -> SourceLocation { match self { @@ -236,12 +359,27 @@ impl Node for FuncArg { /// The block statement that makes up the function's body #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct FuncBody { pub open_brace: OpenBrace, pub stmts: Vec>, pub close_brace: CloseBrace, } +impl IntoAllocated for FuncBody +where + T: ToString, +{ + type Allocated = FuncBody; + fn into_allocated(self) -> FuncBody { + FuncBody { + open_brace: self.open_brace, + stmts: self.stmts.into_iter().map(|s| s.into_allocated()).collect(), + close_brace: self.close_brace, + } + } +} + impl Node for FuncBody { fn loc(&self) -> SourceLocation { SourceLocation { @@ -278,6 +416,7 @@ impl Node for FuncBody { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Class { pub keyword: tokens::Class, pub id: Option>, @@ -285,6 +424,21 @@ pub struct Class { pub body: ClassBody, } +impl IntoAllocated for Class +where + T: ToString, +{ + type Allocated = Class; + fn into_allocated(self) -> Class { + Class { + keyword: self.keyword, + id: self.id.map(|i| i.into_allocated()), + super_class: self.super_class.map(|s| s.into_allocated()), + body: self.body.into_allocated(), + } + } +} + impl Node for Class { fn loc(&self) -> SourceLocation { SourceLocation { @@ -295,18 +449,51 @@ impl Node for Class { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SuperClass { pub keyword_extends: Extends, pub expr: Expr, } +impl IntoAllocated for SuperClass +where + T: ToString, +{ + type Allocated = SuperClass; + fn into_allocated(self) -> SuperClass { + SuperClass { + keyword_extends: self.keyword_extends, + expr: self.expr.into_allocated(), + } + } +} + #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ClassBody { pub open_brace: OpenBrace, pub props: Vec>, pub close_brace: CloseBrace, } +impl IntoAllocated for ClassBody +where + T: ToString, +{ + type Allocated = ClassBody; + fn into_allocated(self) -> ClassBody { + ClassBody { + open_brace: self.open_brace, + props: self + .props + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for ClassBody { fn loc(&self) -> SourceLocation { let start = self.open_brace.start(); @@ -317,6 +504,7 @@ impl Node for ClassBody { /// The kind of variable being defined (`var`/`let`/`const`) #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum VarKind { Var(Option), Let(Let), @@ -346,24 +534,43 @@ impl VarKind { VarKind::Const(_) => 4, } } + + pub const fn is_empty(&self) -> bool { + matches!(self, VarKind::Var(None)) + } } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Slice { - pub source: SourceText, + pub source: T, pub loc: SourceLocation, } +impl IntoAllocated for Slice +where + T: ToString, +{ + type Allocated = Slice; + fn into_allocated(self) -> Slice { + Slice { + loc: self.loc, + source: self.source.to_string(), + } + } +} + impl Slice { pub fn new(source: T, start_line: u32, start_col: u32, end_line: u32, end_column: u32) -> Self { Self { - source: SourceText(source), + source, loc: SourceLocation::new(start_line, start_col, end_line, end_column), } } } #[derive(Debug, Clone, PartialEq, Copy)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SourceLocation { pub start: Position, pub end: Position, @@ -398,6 +605,7 @@ impl core::cmp::PartialOrd for SourceLocation { } #[derive(Debug, Clone, PartialEq, Copy)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Position { pub line: u32, pub column: u32, @@ -464,11 +672,26 @@ impl std::ops::Sub for Position { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ListEntry { pub item: Item, pub comma: Option, } +impl IntoAllocated for ListEntry +where + Item: IntoAllocated, +{ + type Allocated = ListEntry; + + fn into_allocated(self) -> Self::Allocated { + ListEntry { + item: self.item.into_allocated(), + comma: self.comma, + } + } +} + impl ListEntry { pub fn no_comma(item: Item) -> Self { Self { item, comma: None } diff --git a/src/spanned/pat.rs b/src/spanned/pat.rs index 5b9e965..6a5eacd 100644 --- a/src/spanned/pat.rs +++ b/src/spanned/pat.rs @@ -1,11 +1,16 @@ use crate::spanned::expr::{Expr, Prop}; use crate::spanned::Ident; +use crate::IntoAllocated; use super::tokens::{CloseBrace, CloseBracket, Comma, Ellipsis, OpenBrace, OpenBracket, Token}; use super::{AssignOp, ListEntry, Node, SourceLocation}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// All of the different ways you can declare an identifier /// and/or value #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Pat { Ident(Ident), Obj(ObjPat), @@ -13,6 +18,21 @@ pub enum Pat { Assign(AssignPat), } +impl IntoAllocated for Pat +where + T: ToString, +{ + type Allocated = Pat; + fn into_allocated(self) -> Self::Allocated { + match self { + Pat::Ident(inner) => Pat::Ident(inner.into_allocated()), + Pat::Obj(inner) => Pat::Obj(inner.into_allocated()), + Pat::Array(inner) => Pat::Array(inner.into_allocated()), + Pat::Assign(inner) => Pat::Assign(inner.into_allocated()), + } + } +} + impl Node for Pat { fn loc(&self) -> super::SourceLocation { match self { @@ -25,12 +45,31 @@ impl Node for Pat { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrayPat { pub open_bracket: OpenBracket, pub elements: Vec>>>, pub close_bracket: CloseBracket, } +impl IntoAllocated for ArrayPat +where + T: ToString, +{ + type Allocated = ArrayPat; + fn into_allocated(self) -> Self::Allocated { + ArrayPat { + open_bracket: self.open_bracket, + elements: self + .elements + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_bracket: self.close_bracket, + } + } +} + impl Node for ArrayPat { fn loc(&self) -> super::SourceLocation { SourceLocation { @@ -41,18 +80,47 @@ impl Node for ArrayPat { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ArrayElement { pub part: Option>, pub comma: Option, } +impl IntoAllocated for ArrayElement +where + T: ToString, +{ + type Allocated = ArrayElement; + fn into_allocated(self) -> Self::Allocated { + ArrayElement { + part: self.part.into_allocated(), + comma: self.comma, + } + } +} + #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ArrayPatPart { Pat(Pat), Expr(Expr), Rest(RestPat), } +impl IntoAllocated for ArrayPatPart +where + T: ToString, +{ + type Allocated = ArrayPatPart; + fn into_allocated(self) -> Self::Allocated { + match self { + ArrayPatPart::Pat(inner) => ArrayPatPart::Pat(inner.into_allocated()), + ArrayPatPart::Expr(inner) => ArrayPatPart::Expr(inner.into_allocated()), + ArrayPatPart::Rest(inner) => ArrayPatPart::Rest(inner.into_allocated()), + } + } +} + impl Node for ArrayPatPart { fn loc(&self) -> SourceLocation { match self { @@ -67,12 +135,31 @@ type ObjEntry = ListEntry>; /// similar to an `ObjectExpr` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ObjPat { pub open_brace: OpenBrace, pub props: Vec>, pub close_brace: CloseBrace, } +impl IntoAllocated for ObjPat +where + T: ToString, +{ + type Allocated = ObjPat; + fn into_allocated(self) -> Self::Allocated { + ObjPat { + open_brace: self.open_brace, + props: self + .props + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for ObjPat { fn loc(&self) -> SourceLocation { SourceLocation { @@ -84,11 +171,25 @@ impl Node for ObjPat { /// A single part of an ObjectPat #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum ObjPatPart { Assign(Prop), Rest(Box>), } +impl IntoAllocated for ObjPatPart +where + T: ToString, +{ + type Allocated = ObjPatPart; + fn into_allocated(self) -> Self::Allocated { + match self { + ObjPatPart::Assign(inner) => ObjPatPart::Assign(inner.into_allocated()), + ObjPatPart::Rest(inner) => ObjPatPart::Rest(inner.into_allocated()), + } + } +} + impl Node for ObjPatPart { fn loc(&self) -> SourceLocation { match self { @@ -99,11 +200,25 @@ impl Node for ObjPatPart { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RestPat { pub dots: Ellipsis, pub pat: Pat, } +impl IntoAllocated for RestPat +where + T: ToString, +{ + type Allocated = RestPat; + fn into_allocated(self) -> Self::Allocated { + RestPat { + dots: self.dots, + pat: self.pat.into_allocated(), + } + } +} + impl Node for RestPat { fn loc(&self) -> SourceLocation { SourceLocation { @@ -115,12 +230,27 @@ impl Node for RestPat { /// An assignment as a pattern #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct AssignPat { pub left: Box>, pub operator: AssignOp, pub right: Box>, } +impl IntoAllocated for AssignPat +where + T: ToString, +{ + type Allocated = AssignPat; + fn into_allocated(self) -> Self::Allocated { + AssignPat { + left: self.left.into_allocated(), + operator: self.operator, + right: self.right.into_allocated(), + } + } +} + impl Node for AssignPat { fn loc(&self) -> SourceLocation { SourceLocation { diff --git a/src/spanned/stmt.rs b/src/spanned/stmt.rs index b3dee92..d5233a2 100644 --- a/src/spanned/stmt.rs +++ b/src/spanned/stmt.rs @@ -3,6 +3,7 @@ use crate::spanned::expr::Expr; use crate::spanned::pat::Pat; use crate::spanned::VarKind; use crate::spanned::{Ident, ProgramPart}; +use crate::IntoAllocated; use super::decl::VarDecls; use super::tokens::{ @@ -11,9 +12,12 @@ use super::tokens::{ While, With, }; use super::{ListEntry, Node, SourceLocation}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; /// A slightly more granular part of an es program than ProgramPart #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Stmt { /// Any expression Expr { @@ -95,7 +99,7 @@ pub enum Stmt { /// An if statement /// ```js /// if (1 < 2) { - /// console.log(Tlways true'); + /// console.log('Always true'); /// } else { /// console.log('Never true'); /// } @@ -205,6 +209,80 @@ pub enum Stmt { }, } +impl IntoAllocated for Stmt +where + T: ToString, +{ + type Allocated = Stmt; + fn into_allocated(self) -> Self::Allocated { + match self { + Stmt::Expr { expr, semi_colon } => Stmt::Expr { + expr: expr.into_allocated(), + semi_colon, + }, + Stmt::Block(inner) => Stmt::Block(inner.into_allocated()), + Stmt::Empty(inner) => Stmt::Empty(inner), + Stmt::Debugger { + keyword, + semi_colon, + } => Stmt::Debugger { + keyword, + semi_colon, + }, + Stmt::With(inner) => Stmt::With(inner.into_allocated()), + Stmt::Return { + keyword, + value, + semi_colon, + } => Stmt::Return { + keyword, + value: value.into_allocated(), + semi_colon, + }, + Stmt::Labeled(inner) => Stmt::Labeled(inner.into_allocated()), + Stmt::Break { + keyword, + label, + semi_colon, + } => Stmt::Break { + keyword, + label: label.into_allocated(), + semi_colon, + }, + Stmt::Continue { + keyword, + label, + semi_colon, + } => Stmt::Continue { + keyword, + label: label.into_allocated(), + semi_colon, + }, + Stmt::If(inner) => Stmt::If(inner.into_allocated()), + Stmt::Switch(inner) => Stmt::Switch(inner.into_allocated()), + Stmt::Throw { + keyword, + expr, + semi_colon, + } => Stmt::Throw { + keyword, + expr: expr.into_allocated(), + semi_colon, + }, + Stmt::Try(inner) => Stmt::Try(inner.into_allocated()), + Stmt::While(inner) => Stmt::While(inner.into_allocated()), + Stmt::DoWhile(inner) => Stmt::DoWhile(inner.into_allocated()), + Stmt::For(inner) => Stmt::For(inner.into_allocated()), + Stmt::ForIn(inner) => Stmt::ForIn(inner.into_allocated()), + Stmt::ForOf(inner) => Stmt::ForOf(inner.into_allocated()), + Stmt::Var { decls, semi_colon } => Stmt::Var { + decls: decls.into_allocated(), + semi_colon, + }, + } + } +} + impl Node for Stmt { fn loc(&self) -> SourceLocation { match self { @@ -341,6 +419,7 @@ impl Node for Stmt { /// //rand !== 0 /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct WithStmt { pub keyword: With, pub open_paren: OpenParen, @@ -349,6 +428,21 @@ pub struct WithStmt { pub body: Box>, } +impl IntoAllocated for WithStmt +where + T: ToString, +{ + type Allocated = WithStmt; + fn into_allocated(self) -> Self::Allocated { + WithStmt { + keyword: self.keyword, + open_paren: self.open_paren, + object: self.object.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} impl Node for WithStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -367,12 +461,28 @@ impl Node for WithStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LabeledStmt { pub label: Ident, pub colon: Colon, pub body: Box>, } +impl IntoAllocated for LabeledStmt +where + T: ToString, +{ + type Allocated = LabeledStmt; + + fn into_allocated(self) -> Self::Allocated { + LabeledStmt { + label: self.label.into_allocated(), + colon: self.colon, + body: self.body.into_allocated(), + } + } +} + impl Node for LabeledStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -385,12 +495,13 @@ impl Node for LabeledStmt { /// An if statement /// ```js /// if (1 < 2) { -/// console.log(Tlways true'); +/// console.log('Always true'); /// } else { /// console.log('Never true'); /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct IfStmt { pub keyword: If, pub open_paren: OpenParen, @@ -400,6 +511,24 @@ pub struct IfStmt { pub alternate: Option>>, } +impl IntoAllocated for IfStmt +where + T: ToString, +{ + type Allocated = IfStmt; + + fn into_allocated(self) -> Self::Allocated { + IfStmt { + keyword: self.keyword, + open_paren: self.open_paren, + test: self.test.into_allocated(), + close_paren: self.close_paren, + consequent: self.consequent.into_allocated(), + alternate: self.alternate.into_allocated(), + } + } +} + impl Node for IfStmt { fn loc(&self) -> SourceLocation { let start = self.keyword.start(); @@ -413,11 +542,26 @@ impl Node for IfStmt { } #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ElseStmt { pub keyword: Else, pub body: Stmt, } +impl IntoAllocated for ElseStmt +where + T: ToString, +{ + type Allocated = ElseStmt; + + fn into_allocated(self) -> Self::Allocated { + ElseStmt { + keyword: self.keyword, + body: self.body.into_allocated(), + } + } +} + impl Node for ElseStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -442,6 +586,7 @@ impl Node for ElseStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SwitchStmt { pub keyword: Switch, pub open_paren: OpenParen, @@ -452,6 +597,29 @@ pub struct SwitchStmt { pub close_brace: CloseBrace, } +impl IntoAllocated for SwitchStmt +where + T: ToString, +{ + type Allocated = SwitchStmt; + + fn into_allocated(self) -> Self::Allocated { + SwitchStmt { + keyword: self.keyword, + open_paren: self.open_paren, + discriminant: self.discriminant.into_allocated(), + close_paren: self.close_paren, + open_brace: self.open_brace, + cases: self + .cases + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for SwitchStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -463,6 +631,7 @@ impl Node for SwitchStmt { /// A single case part of a switch statement #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SwitchCase { pub keyword: SwitchCaseKeyword, pub test: Option>, @@ -484,14 +653,54 @@ impl Node for SwitchCase { } } +impl IntoAllocated for SwitchCase +where + T: ToString, +{ + type Allocated = SwitchCase; + + fn into_allocated(self) -> Self::Allocated { + SwitchCase { + keyword: self.keyword, + colon: self.colon, + consequent: self + .consequent + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + test: self.test.into_allocated(), + } + } +} + /// A collection of program parts wrapped in curly braces #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BlockStmt { pub open_brace: OpenBrace, pub stmts: Vec>, pub close_brace: CloseBrace, } +impl IntoAllocated for BlockStmt +where + T: ToString, +{ + type Allocated = BlockStmt; + + fn into_allocated(self) -> Self::Allocated { + BlockStmt { + open_brace: self.open_brace, + stmts: self + .stmts + .into_iter() + .map(IntoAllocated::into_allocated) + .collect(), + close_brace: self.close_brace, + } + } +} + impl Node for BlockStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -512,6 +721,7 @@ impl Node for BlockStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TryStmt { pub keyword: Try, pub block: BlockStmt, @@ -519,6 +729,21 @@ pub struct TryStmt { pub finalizer: Option>, } +impl IntoAllocated for TryStmt +where + T: ToString, +{ + type Allocated = TryStmt; + fn into_allocated(self) -> Self::Allocated { + TryStmt { + keyword: self.keyword, + block: self.block.into_allocated(), + handler: self.handler.into_allocated(), + finalizer: self.finalizer.into_allocated(), + } + } +} + impl Node for TryStmt { fn loc(&self) -> SourceLocation { let end = if let Some(finalizer) = &self.finalizer { @@ -537,12 +762,28 @@ impl Node for TryStmt { /// The error handling part of a `TryStmt` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct CatchClause { pub keyword: Catch, pub param: Option>, pub body: BlockStmt, } +impl IntoAllocated for CatchClause +where + T: ToString, +{ + type Allocated = CatchClause; + + fn into_allocated(self) -> Self::Allocated { + CatchClause { + keyword: self.keyword, + param: self.param.into_allocated(), + body: self.body.into_allocated(), + } + } +} + impl Node for CatchClause { fn loc(&self) -> SourceLocation { SourceLocation { @@ -553,12 +794,28 @@ impl Node for CatchClause { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct CatchArg { pub open_paren: OpenParen, pub param: Pat, pub close_paren: CloseParen, } +impl IntoAllocated for CatchArg +where + T: ToString, +{ + type Allocated = CatchArg; + + fn into_allocated(self) -> Self::Allocated { + CatchArg { + open_paren: self.open_paren, + param: self.param.into_allocated(), + close_paren: self.close_paren, + } + } +} + impl Node for CatchArg { fn loc(&self) -> SourceLocation { SourceLocation { @@ -569,11 +826,25 @@ impl Node for CatchArg { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct FinallyClause { pub keyword: Finally, pub body: BlockStmt, } +impl IntoAllocated for FinallyClause +where + T: ToString, +{ + type Allocated = FinallyClause; + fn into_allocated(self) -> Self::Allocated { + FinallyClause { + keyword: self.keyword, + body: self.body.into_allocated(), + } + } +} + impl Node for FinallyClause { fn loc(&self) -> SourceLocation { SourceLocation { @@ -598,6 +869,7 @@ impl Node for FinallyClause { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct WhileStmt { pub keyword: While, pub open_paren: OpenParen, @@ -606,6 +878,23 @@ pub struct WhileStmt { pub body: Box>, } +impl IntoAllocated for WhileStmt +where + T: ToString, +{ + type Allocated = WhileStmt; + + fn into_allocated(self) -> Self::Allocated { + WhileStmt { + keyword: self.keyword, + open_paren: self.open_paren, + test: self.test.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for WhileStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -622,6 +911,7 @@ impl Node for WhileStmt { /// } while (Math.floor(Math.random() * 100) < 75) /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct DoWhileStmt { pub keyword_do: Do, pub body: Box>, @@ -632,6 +922,25 @@ pub struct DoWhileStmt { pub semi_colon: Option, } +impl IntoAllocated for DoWhileStmt +where + T: ToString, +{ + type Allocated = DoWhileStmt; + + fn into_allocated(self) -> Self::Allocated { + DoWhileStmt { + keyword_do: self.keyword_do, + body: self.body.into_allocated(), + keyword_while: self.keyword_while, + open_paren: self.open_paren, + test: self.test.into_allocated(), + close_paren: self.close_paren, + semi_colon: self.semi_colon, + } + } +} + impl Node for DoWhileStmt { fn loc(&self) -> SourceLocation { let end = self @@ -654,6 +963,7 @@ impl Node for DoWhileStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForStmt { pub keyword: For, pub open_paren: OpenParen, @@ -666,6 +976,27 @@ pub struct ForStmt { pub body: Box>, } +impl IntoAllocated for ForStmt +where + T: ToString, +{ + type Allocated = ForStmt; + + fn into_allocated(self) -> Self::Allocated { + ForStmt { + keyword: self.keyword, + open_paren: self.open_paren, + init: self.init.into_allocated(), + semi1: self.semi1, + test: self.test.into_allocated(), + semi2: self.semi2, + update: self.update.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for ForStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -680,11 +1011,28 @@ impl Node for ForStmt { /// // vvvvvvvvv /// for (var i = 0;i < 100; i++) #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LoopInit { Variable(VarKind, Vec>>), Expr(Expr), } +impl IntoAllocated for LoopInit +where + T: ToString, +{ + type Allocated = LoopInit; + fn into_allocated(self) -> Self::Allocated { + match self { + LoopInit::Variable(k, v) => LoopInit::Variable( + k, + v.into_iter().map(IntoAllocated::into_allocated).collect(), + ), + LoopInit::Expr(inner) => LoopInit::Expr(inner.into_allocated()), + } + } +} + impl Node for LoopInit { fn loc(&self) -> SourceLocation { match self { @@ -716,6 +1064,7 @@ impl Node for LoopInit { /// //prints a, b /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForInStmt { pub keyword_for: For, pub open_paren: OpenParen, @@ -726,6 +1075,25 @@ pub struct ForInStmt { pub body: Box>, } +impl IntoAllocated for ForInStmt +where + T: ToString, +{ + type Allocated = ForInStmt; + + fn into_allocated(self) -> Self::Allocated { + ForInStmt { + keyword_for: self.keyword_for, + open_paren: self.open_paren, + left: self.left.into_allocated(), + keyword_in: self.keyword_in, + right: self.right.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + } + } +} + impl Node for ForInStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -744,6 +1112,7 @@ impl Node for ForInStmt { /// //prints 2, 3, 4, 5, 6 /// ``` #[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForOfStmt { pub keyword_for: For, pub open_paren: OpenParen, @@ -755,6 +1124,26 @@ pub struct ForOfStmt { pub is_await: bool, } +impl IntoAllocated for ForOfStmt +where + T: ToString, +{ + type Allocated = ForOfStmt; + + fn into_allocated(self) -> Self::Allocated { + ForOfStmt { + keyword_for: self.keyword_for, + open_paren: self.open_paren, + left: self.left.into_allocated(), + keyword_of: self.keyword_of, + right: self.right.into_allocated(), + close_paren: self.close_paren, + body: self.body.into_allocated(), + is_await: self.is_await, + } + } +} + impl Node for ForOfStmt { fn loc(&self) -> SourceLocation { SourceLocation { @@ -767,12 +1156,27 @@ impl Node for ForOfStmt { /// The values on the left hand side of the keyword /// in a for in or for of loop #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LoopLeft { Expr(Expr), Variable(VarKind, VarDecl), Pat(Pat), } +impl IntoAllocated for LoopLeft +where + T: ToString, +{ + type Allocated = LoopLeft; + fn into_allocated(self) -> Self::Allocated { + match self { + LoopLeft::Expr(inner) => LoopLeft::Expr(inner.into_allocated()), + LoopLeft::Variable(k, v) => LoopLeft::Variable(k, v.into_allocated()), + LoopLeft::Pat(inner) => LoopLeft::Pat(inner.into_allocated()), + } + } +} + impl Node for LoopLeft { fn loc(&self) -> SourceLocation { match self { diff --git a/src/spanned/tokens.rs b/src/spanned/tokens.rs index be41d5d..72e6da6 100644 --- a/src/spanned/tokens.rs +++ b/src/spanned/tokens.rs @@ -1,6 +1,8 @@ //! This modules contains a collection of discrete tokens use crate::spanned::{Node, Position, SourceLocation}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; macro_rules! impl_token { ($what:ty, $s:expr) => { @@ -20,9 +22,9 @@ macro_rules! impl_token { Self(other) } } - impl std::convert::Into for $what { - fn into(self) -> Position { - self.0 + impl std::convert::From<$what> for Position { + fn from(other: $what) -> Position { + other.0 } } impl std::cmp::PartialEq for $what { @@ -71,6 +73,7 @@ macro_rules! impl_token { macro_rules! define_token { ($name:ident, $s:expr) => { #[derive(Debug, Clone, Copy, PartialEq)] + #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[doc = $s] pub struct $name(Position); impl_token!($name, $s); @@ -199,6 +202,7 @@ define_token!(TripleGreaterThan, ">>>"); define_token!(TripleGreaterThanEqual, ">>>="); #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Quote { Double(DoubleQuote), Single(SingleQuote), @@ -228,6 +232,7 @@ impl Token for Quote { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum QuasiQuote { BackTick(BackTick), CloseBrace(CloseBrace), @@ -262,6 +267,7 @@ impl Token for QuasiQuote { /// The available operators for assignment Exprs #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum AssignOp { Equal(Equal), PlusEqual(PlusEqual), @@ -300,6 +306,7 @@ impl Node for AssignOp { /// The available logical operators #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LogicalOp { Or(DoublePipe), And(DoubleAmpersand), @@ -316,6 +323,7 @@ impl Node for LogicalOp { /// The available operations for `Binary` Exprs #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum BinaryOp { Equal(DoubleEqual), NotEqual(BangEqual), @@ -373,6 +381,7 @@ define_token!(DoublePlus, "++"); define_token!(DoubleMinus, "--"); /// `++` or `--` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum UpdateOp { Increment(DoublePlus), Decrement(DoubleMinus), @@ -390,6 +399,7 @@ impl Node for UpdateOp { /// The allowed operators for an Expr /// to be `Unary` #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum UnaryOp { Minus(Minus), Plus(Plus), @@ -415,6 +425,7 @@ impl Node for UnaryOp { } #[derive(Debug, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum SwitchCaseKeyword { Case(Case), Default(Default), diff --git a/src/stmt.rs b/src/stmt.rs index 6f265da..e4e65ba 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -1,15 +1,15 @@ use crate::decl::VarDecl; use crate::expr::Expr; use crate::pat::Pat; -use crate::VarKind; use crate::{Ident, ProgramPart}; +use crate::{IntoAllocated, VarKind}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// A slightly more granular part of an es program than ProgramPart #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum Stmt { /// Any expression Expr(Expr), @@ -73,7 +73,7 @@ pub enum Stmt { /// An if statement /// ```js /// if (1 < 2) { - /// console.log(Tlways true'); + /// console.log('Always true'); /// } else { /// console.log('Never true'); /// } @@ -176,6 +176,37 @@ pub enum Stmt { Var(Vec>), } +impl IntoAllocated for Stmt +where + T: ToString, +{ + type Allocated = Stmt; + + fn into_allocated(self) -> Self::Allocated { + match self { + Stmt::Expr(inner) => Stmt::Expr(inner.into_allocated()), + Stmt::Block(inner) => Stmt::Block(inner.into_allocated()), + Stmt::Empty => Stmt::Empty, + Stmt::Debugger => Stmt::Debugger, + Stmt::With(inner) => Stmt::With(inner.into_allocated()), + Stmt::Return(inner) => Stmt::Return(inner.map(IntoAllocated::into_allocated)), + Stmt::Labeled(inner) => Stmt::Labeled(inner.into_allocated()), + Stmt::Break(inner) => Stmt::Break(inner.map(IntoAllocated::into_allocated)), + Stmt::Continue(inner) => Stmt::Continue(inner.map(IntoAllocated::into_allocated)), + Stmt::If(inner) => Stmt::If(inner.into_allocated()), + Stmt::Switch(inner) => Stmt::Switch(inner.into_allocated()), + Stmt::Throw(inner) => Stmt::Throw(inner.into_allocated()), + Stmt::Try(inner) => Stmt::Try(inner.into_allocated()), + Stmt::While(inner) => Stmt::While(inner.into_allocated()), + Stmt::DoWhile(inner) => Stmt::DoWhile(inner.into_allocated()), + Stmt::For(inner) => Stmt::For(inner.into_allocated()), + Stmt::ForIn(inner) => Stmt::ForIn(inner.into_allocated()), + Stmt::ForOf(inner) => Stmt::ForOf(inner.into_allocated()), + Stmt::Var(inner) => Stmt::Var(inner.into_iter().map(|v| v.into_allocated()).collect()), + } + } +} + /// A with statement, this puts one object at the top of /// the identifier search tree. /// > note: this cannot be used in a strict context @@ -190,12 +221,26 @@ pub enum Stmt { /// //rand !== 0 /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct WithStmt { pub object: Expr, pub body: Box>, } +impl IntoAllocated for WithStmt +where + T: ToString, +{ + type Allocated = WithStmt; + + fn into_allocated(self) -> Self::Allocated { + WithStmt { + object: self.object.into_allocated(), + body: self.body.into_allocated(), + } + } +} + /// A break statement /// ```js /// label: { @@ -206,28 +251,57 @@ pub struct WithStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LabeledStmt { pub label: Ident, pub body: Box>, } +impl IntoAllocated for LabeledStmt +where + T: ToString, +{ + type Allocated = LabeledStmt; + + fn into_allocated(self) -> Self::Allocated { + LabeledStmt { + label: self.label.into_allocated(), + body: self.body.into_allocated(), + } + } +} + /// An if statement /// ```js /// if (1 < 2) { -/// console.log(Tlways true'); +/// console.log('Always true'); /// } else { /// console.log('Never true'); /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct IfStmt { pub test: Expr, pub consequent: Box>, pub alternate: Option>>, } +impl IntoAllocated for IfStmt +where + T: ToString, +{ + type Allocated = IfStmt; + + fn into_allocated(self) -> Self::Allocated { + IfStmt { + test: self.test.into_allocated(), + consequent: self.consequent.into_allocated(), + alternate: self.alternate.map(IntoAllocated::into_allocated), + } + } +} + /// A switch statement /// ```js /// switch (Math.floor(Math.random()) * 10) { @@ -243,33 +317,68 @@ pub struct IfStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SwitchStmt { pub discriminant: Expr, pub cases: Vec>, } +impl IntoAllocated for SwitchStmt +where + T: ToString, +{ + type Allocated = SwitchStmt; + + fn into_allocated(self) -> Self::Allocated { + SwitchStmt { + discriminant: self.discriminant.into_allocated(), + cases: self.cases.into_iter().map(|c| c.into_allocated()).collect(), + } + } +} + /// A single case part of a switch statement #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct SwitchCase { pub test: Option>, pub consequent: Vec>, } +impl IntoAllocated for SwitchCase +where + T: ToString, +{ + type Allocated = SwitchCase; + + fn into_allocated(self) -> Self::Allocated { + SwitchCase { + test: self.test.map(IntoAllocated::into_allocated), + consequent: self + .consequent + .into_iter() + .map(|c| c.into_allocated()) + .collect(), + } + } +} + /// A collection of program parts wrapped in curly braces #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BlockStmt(pub Vec>); +impl IntoAllocated for BlockStmt +where + T: ToString, +{ + type Allocated = BlockStmt; + + fn into_allocated(self) -> Self::Allocated { + BlockStmt(self.0.into_iter().map(|s| s.into_allocated()).collect()) + } +} + /// A try/catch block /// ```js /// try { @@ -281,25 +390,50 @@ pub struct BlockStmt(pub Vec>); /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TryStmt { pub block: BlockStmt, pub handler: Option>, pub finalizer: Option>, } +impl IntoAllocated for TryStmt +where + T: ToString, +{ + type Allocated = TryStmt; + + fn into_allocated(self) -> Self::Allocated { + TryStmt { + block: self.block.into_allocated(), + handler: self.handler.map(|h| h.into_allocated()), + finalizer: self.finalizer.map(|f| f.into_allocated()), + } + } +} + /// The error handling part of a `TryStmt` #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct CatchClause { pub param: Option>, pub body: BlockStmt, } +impl IntoAllocated for CatchClause +where + T: ToString, +{ + type Allocated = CatchClause; + + fn into_allocated(self) -> Self::Allocated { + CatchClause { + param: self.param.map(IntoAllocated::into_allocated), + body: self.body.into_allocated(), + } + } +} + /// A while loop /// ```js /// while (false) { @@ -315,12 +449,26 @@ pub struct CatchClause { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct WhileStmt { pub test: Expr, pub body: Box>, } +impl IntoAllocated for WhileStmt +where + T: ToString, +{ + type Allocated = WhileStmt; + + fn into_allocated(self) -> Self::Allocated { + WhileStmt { + test: self.test.into_allocated(), + body: self.body.into_allocated(), + } + } +} + /// A while loop that executes its body first /// ```js /// do { @@ -328,12 +476,26 @@ pub struct WhileStmt { /// } while (Math.floor(Math.random() * 100) < 75) /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct DoWhileStmt { pub test: Expr, pub body: Box>, } +impl IntoAllocated for DoWhileStmt +where + T: ToString, +{ + type Allocated = DoWhileStmt; + + fn into_allocated(self) -> Self::Allocated { + DoWhileStmt { + test: self.test.into_allocated(), + body: self.body.into_allocated(), + } + } +} + /// A "c-style" for loop /// ```js /// for (var i = 0; i < 100; i++) console.log(i); @@ -342,7 +504,7 @@ pub struct DoWhileStmt { /// } /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForStmt { pub init: Option>, pub test: Option>, @@ -350,21 +512,49 @@ pub struct ForStmt { pub body: Box>, } +impl IntoAllocated for ForStmt +where + T: ToString, +{ + type Allocated = ForStmt; + + fn into_allocated(self) -> Self::Allocated { + ForStmt { + init: self.init.map(|i| i.into_allocated()), + test: self.test.map(|t| t.into_allocated()), + update: self.update.map(|u| u.into_allocated()), + body: self.body.into_allocated(), + } + } +} + /// The left most triple of a for loops parenthetical /// ```js /// // vvvvvvvvv /// for (var i = 0;i < 100; i++) #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LoopInit { Variable(VarKind, Vec>), Expr(Expr), } +impl IntoAllocated for LoopInit +where + T: ToString, +{ + type Allocated = LoopInit; + + fn into_allocated(self) -> Self::Allocated { + match self { + LoopInit::Variable(k, v) => { + LoopInit::Variable(k, v.into_iter().map(|v| v.into_allocated()).collect()) + } + LoopInit::Expr(inner) => LoopInit::Expr(inner.into_allocated()), + } + } +} + /// A for in statement, this kind of for statement /// will extract each key from an indexable thing /// ```js @@ -378,13 +568,28 @@ pub enum LoopInit { /// //prints a, b /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForInStmt { pub left: LoopLeft, pub right: Expr, pub body: Box>, } +impl IntoAllocated for ForInStmt +where + T: ToString, +{ + type Allocated = ForInStmt; + + fn into_allocated(self) -> Self::Allocated { + ForInStmt { + left: self.left.into_allocated(), + right: self.right.into_allocated(), + body: self.body.into_allocated(), + } + } +} + /// A for of statement, this kind of for statement /// will extract the value from a generator or iterator /// ```js @@ -394,7 +599,7 @@ pub struct ForInStmt { /// //prints 2, 3, 4, 5, 6 /// ``` #[derive(PartialEq, Debug, Clone)] -#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct ForOfStmt { pub left: LoopLeft, pub right: Expr, @@ -402,16 +607,43 @@ pub struct ForOfStmt { pub is_await: bool, } +impl IntoAllocated for ForOfStmt +where + T: ToString, +{ + type Allocated = ForOfStmt; + + fn into_allocated(self) -> Self::Allocated { + ForOfStmt { + left: self.left.into_allocated(), + right: self.right.into_allocated(), + body: self.body.into_allocated(), + is_await: self.is_await, + } + } +} + /// The values on the left hand side of the keyword /// in a for in or for of loop #[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(feature = "serde", not(feature = "esprima")), - derive(Deserialize, Serialize) -)] -#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub enum LoopLeft { Expr(Expr), Variable(VarKind, VarDecl), Pat(Pat), } + +impl IntoAllocated for LoopLeft +where + T: ToString, +{ + type Allocated = LoopLeft; + + fn into_allocated(self) -> Self::Allocated { + match self { + LoopLeft::Expr(inner) => LoopLeft::Expr(inner.into_allocated()), + LoopLeft::Variable(k, v) => LoopLeft::Variable(k, v.into_allocated()), + LoopLeft::Pat(inner) => LoopLeft::Pat(inner.into_allocated()), + } + } +} diff --git a/tests/serde.rs b/tests/serde.rs deleted file mode 100644 index b36a886..0000000 --- a/tests/serde.rs +++ /dev/null @@ -1,169 +0,0 @@ -#![cfg(feature = "esprima")] -use pretty_env_logger::try_init; -use ressa::*; - -use resast::prelude::*; -use serde_json::{from_str, to_string_pretty, Value}; -use std::{fs::read_to_string, path::Path}; -#[test] -fn serde1() { - let ast = Program::Script(vec![ProgramPart::Decl(Decl::Func(Func { - id: Some(Ident::from("f")), - body: FuncBody(vec![]), - is_async: false, - generator: false, - params: vec![FuncArg::Expr(Expr::Ident(Ident::from("a")))], - }))]); - let json = to_string_pretty(&ast).expect("Failed to serialize ast"); - let expectation = r#"{ - "type": "Program", - "body": [ - { - "type": "FunctionDeclaration", - "id": { - "type": "Identifier", - "name": "f" - }, - "params": [ - { - "type": "Identifier", - "name": "a" - } - ], - "body": { - "type": "BlockStatement", - "body": [] - }, - "generator": false, - "expression": false, - "async": false - } - ], - "sourceType": "script" -} -"#; - - let r: serde_json::Value = serde_json::from_str(&json).expect("failed to deserialize json"); - let j: serde_json::Value = - serde_json::from_str(&expectation).expect("failed to deserialize expectation"); - assert_eq!(r, j); -} - -#[test] -fn serde_es5() { - let json = run_rs_parse("node_modules/everything.js/es5.js"); - let esparsed = esparse("node_modules/everything.js/es5.js"); - check_jsons("es5", json, esparsed); -} -#[test] -fn serde_es2015_script() { - let json = run_rs_parse("node_modules/everything.js/es2015-script.js"); - let esparsed = esparse("node_modules/everything.js/es2015-script.js"); - check_jsons("es2015-script", json, esparsed); -} -#[test] -fn serde_es2015_module() { - let json = run_rs_parse("node_modules/everything.js/es2015-module.js"); - let esparsed = esparse("node_modules/everything.js/es2015-module.js"); - check_jsons("es2015-module", json, esparsed); -} - -fn run_rs_parse(path: impl AsRef) -> Value { - let module = path.as_ref().ends_with("es2015-module.js"); - eprintln!("working on {:?} -> {}", path.as_ref(), module); - let js = get_js_file(path); - let mut b = Builder::new(); - b.set_module(module); - let mut parser = b.js(&js).build().expect("failed to create parser"); - let parsed = parser.parse().expect("failed to parse js"); - let raw = to_string_pretty(&parsed).expect("failed to convert to json string"); - from_str(&raw).expect("failed to revert to Value") -} - -fn check_jsons(name: &str, lhs: Value, rhs: Value) { - if lhs != rhs { - let f1 = - ::std::fs::File::create(&format!("{}.rs.json", name)).expect("failed to write rs.json"); - serde_json::to_writer_pretty(f1, &lhs).expect(""); - let f2 = - ::std::fs::File::create(&format!("{}.js.json", name)).expect("failed to write js.json"); - serde_json::to_writer_pretty(f2, &rhs).expect(""); - panic!("json doesn't match"); - } -} - -pub fn npm_install() { - let mut c = ::std::process::Command::new("npm"); - c.arg("i"); - c.output().expect("failed to run npm install"); -} - -pub fn get_js_file(path: impl AsRef<::std::path::Path>) -> String { - let path = path.as_ref(); - if !path.exists() { - npm_install(); - if !path.exists() { - panic!("npm install failed to make {:?} available", path); - } - } - read_to_string(path).expect(&format!("failed to read {} to a string", path.display())) -} - -pub fn esparse(path: impl AsRef<::std::path::Path>) -> Value { - let path = path.as_ref(); - if !path.exists() { - npm_install(); - if !path.exists() { - panic!("npm install failed to make {:?} available", path); - } - } - let esparse = ::std::process::Command::new("node") - .arg("run_es_parse.js") - .arg(path) - .output() - .expect("failed to execute run_es_parse.js"); - let json = String::from_utf8_lossy(&esparse.stdout).to_string(); - from_str(&json).expect(&format!("failed to convert {} to Value", path.display())) -} - -#[test] -fn func_args() { - let js = "function f(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){}"; - let mut parser = Parser::new(&js).expect(""); - let parsed = parser.parse().expect(""); - let raw = to_string_pretty(&parsed).expect("failed to convert ron to string"); - let json: Value = from_str(&raw).expect("failed to convert string to json"); - ::std::fs::write("args.js", js).expect("failed to write args.js"); - let esparsed = esparse("args.js"); - let _ = ::std::fs::remove_file("args.js"); - if json != esparsed { - let f1 = ::std::fs::File::create("func_args.rs.json").expect("failed to create rs.json"); - serde_json::to_writer_pretty(f1, &json).expect("failed to write rs.json"); - let f2 = ::std::fs::File::create("func_args.js.json").expect("failed to create js.json"); - serde_json::to_writer_pretty(f2, &esparsed).expect("failed to write js.json"); - panic!("json doesn't match"); - } -} - -#[test] -fn arrow_func_args() { - let _ = try_init(); - let js = "({i = 0}, ...k) => {;};"; - let mut parser = Parser::new(&js).expect(""); - let parsed = parser.parse().expect(""); - let raw = to_string_pretty(&parsed).expect("failed to convert ron to string"); - let json: Value = from_str(&raw).expect("failed to convert string to json"); - ::std::fs::write("arrow-args.js", js).expect("failed to write args.js"); - let esparsed = esparse("arrow-args.js"); - let _ = ::std::fs::remove_file("arrow-args.js"); - if json != esparsed { - let f1 = - ::std::fs::File::create("arrow_func_args.rs.json").expect("failed to create rs.json"); - serde_json::to_writer_pretty(f1, &json).expect("failed to write rs.json"); - let f2 = - ::std::fs::File::create("arrow_func_args.js.json").expect("failed to create js.json"); - serde_json::to_writer_pretty(f2, &esparsed).expect("failed to write js.json"); - let _ = ::std::fs::write("arrow_func_args2.ron", &format!("{:#?}", parsed)); - panic!("json doesn't match"); - } -}