diff --git a/Cargo.toml b/Cargo.toml index 6349c08..078f1e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,14 @@ readme = "./README.md" repository = "https://github.com/rusty-ecma/RESW" [dependencies] -resast = "0.5.0-alpha.3" +resast = "0.6.0-alpha.3" log = "0.4" ress = "0.11" [dev-dependencies] rayon = { version = "1"} -ressa = "0.8.0-alpha.5" +# ressa = "0.9.0-alpha.1" +ressa = { git = "https://github.com/rusty-ecma/RESSA", branch = "feat/smaller-ast" } pretty_env_logger = "0.4" thiserror = "1" diff --git a/examples/insert_logging.rs b/examples/insert_logging.rs index 69529cc..0591516 100644 --- a/examples/insert_logging.rs +++ b/examples/insert_logging.rs @@ -1,7 +1,8 @@ -use resast::prelude::*; +use resast::{prelude::*, SourceText}; use ressa::Parser; use resw::Writer; use std::{ + borrow::Cow, fs::{read_to_string, File}, io::BufWriter, }; @@ -22,7 +23,10 @@ fn main() { } } -fn map_part<'a>(args: Vec>, part: ProgramPart<'a>) -> ProgramPart<'a> { +fn map_part<'a>( + args: Vec>>, + part: ProgramPart>, +) -> ProgramPart> { match part { ProgramPart::Decl(decl) => ProgramPart::Decl(map_decl(args, decl)), ProgramPart::Stmt(stmt) => ProgramPart::Stmt(map_stmt(args, stmt)), @@ -30,7 +34,7 @@ fn map_part<'a>(args: Vec>, part: ProgramPart<'a>) -> ProgramPart<'a> { } } -fn map_decl<'a>(mut args: Vec>, decl: Decl<'a>) -> Decl<'a> { +fn map_decl<'a>(mut args: Vec>>, decl: Decl>) -> Decl> { match decl { Decl::Func(f) => Decl::Func(map_func(args, f)), Decl::Class(class) => Decl::Class(map_class(args, class)), @@ -52,14 +56,14 @@ fn map_decl<'a>(mut args: Vec>, decl: Decl<'a>) -> Decl<'a> { } } -fn map_stmt<'a>(args: Vec>, stmt: Stmt<'a>) -> Stmt<'a> { +fn map_stmt<'a>(args: Vec>>, stmt: Stmt>) -> Stmt> { match stmt { Stmt::Expr(expr) => Stmt::Expr(map_expr(args, expr)), _ => stmt.clone(), } } -fn map_expr<'a>(mut args: Vec>, expr: Expr<'a>) -> Expr<'a> { +fn map_expr<'a>(mut args: Vec>>, expr: Expr>) -> Expr> { match expr { Expr::Func(f) => Expr::Func(map_func(args, f)), Expr::Class(c) => Expr::Class(map_class(args, c)), @@ -75,7 +79,10 @@ fn map_expr<'a>(mut args: Vec>, expr: Expr<'a>) -> Expr<'a> { } } -fn map_func<'a>(mut args: Vec>, mut func: Func<'a>) -> Func<'a> { +fn map_func<'a>( + mut args: Vec>>, + mut func: Func>, +) -> Func> { if let Some(ref id) = &func.id { args.push(ident_to_string_lit(id)); } @@ -99,7 +106,10 @@ fn map_func<'a>(mut args: Vec>, mut func: Func<'a>) -> Func<'a> { func } -fn map_class<'a>(mut args: Vec>, mut class: Class<'a>) -> Class<'a> { +fn map_class<'a>( + mut args: Vec>>, + mut class: Class>, +) -> Class> { if let Some(ref id) = class.id { args.push(ident_to_string_lit(id)) } @@ -111,26 +121,29 @@ fn map_class<'a>(mut args: Vec>, mut class: Class<'a>) -> Class<'a> { class } -fn map_class_prop<'a>(mut args: Vec>, mut prop: Prop<'a>) -> Prop<'a> { +fn map_class_prop<'a>( + mut args: Vec>>, + mut prop: Prop>, +) -> Prop> { match prop.kind { PropKind::Ctor => { args.insert( args.len().saturating_sub(1), - Expr::Lit(Lit::String(StringLit::single_from("new"))), + Expr::Lit(Lit::String(StringLit::single_from("new".into()))), ); } PropKind::Get => { - args.push(Expr::Lit(Lit::String(StringLit::single_from("get")))); + args.push(Expr::Lit(Lit::String(StringLit::single_from("get".into())))); } PropKind::Set => { - args.push(Expr::Lit(Lit::String(StringLit::single_from("set")))); + args.push(Expr::Lit(Lit::String(StringLit::single_from("set".into())))); } _ => (), }; match &prop.key { PropKey::Expr(ref expr) => match expr { Expr::Ident(ref i) => { - if i.name != "constructor" { + if i.name.as_ref() != "constructor" { args.push(ident_to_string_lit(i)); } } @@ -141,9 +154,9 @@ fn map_class_prop<'a>(mut args: Vec>, mut prop: Prop<'a>) -> Prop<'a> { args.push(Expr::Lit(l.clone())) } Lit::Null => { - args.push(Expr::Lit(Lit::String(StringLit::Single( + args.push(Expr::Lit(Lit::String(StringLit::Single(SourceText( ::std::borrow::Cow::Owned(String::from("null")), - )))); + ))))); } _ => (), }, @@ -158,7 +171,10 @@ fn map_class_prop<'a>(mut args: Vec>, mut prop: Prop<'a>) -> Prop<'a> { prop } -fn map_arrow_func<'a>(mut args: Vec>, mut f: ArrowFuncExpr<'a>) -> ArrowFuncExpr<'a> { +fn map_arrow_func<'a>( + mut args: Vec>>, + mut f: ArrowFuncExpr>, +) -> ArrowFuncExpr> { args.extend(extract_idents_from_args(&f.params)); match &mut f.body { ArrowFuncBody::FuncBody(ref mut body) => { @@ -174,7 +190,7 @@ fn map_arrow_func<'a>(mut args: Vec>, mut f: ArrowFuncExpr<'a>) -> Arro f } -fn assign_left_to_string_lit<'a>(left: &AssignLeft<'a>) -> Option> { +fn assign_left_to_string_lit<'a>(left: &AssignLeft>) -> Option>> { match left { AssignLeft::Expr(expr) => expr_to_string_lit(expr), AssignLeft::Pat(pat) => match pat { @@ -184,7 +200,7 @@ fn assign_left_to_string_lit<'a>(left: &AssignLeft<'a>) -> Option> { } } -fn extract_idents_from_args<'a>(args: &[FuncArg<'a>]) -> Vec> { +fn extract_idents_from_args<'a>(args: &[FuncArg>]) -> Vec>> { let mut ret = vec![]; for arg in args { match arg { @@ -195,14 +211,14 @@ fn extract_idents_from_args<'a>(args: &[FuncArg<'a>]) -> Vec> { ret.into_iter().filter_map(|e| e).collect() } -fn extract_ident_from_expr<'a>(expr: &Expr<'a>) -> Option> { +fn extract_ident_from_expr<'a>(expr: &Expr>) -> Option>> { match expr { Expr::Ident(ident) => Some(Expr::Ident(ident.clone())), _ => None, } } -fn extract_idents_from_pat<'a>(pat: &Pat<'a>) -> Vec>> { +fn extract_idents_from_pat<'a>(pat: &Pat>) -> Vec>>> { match pat { Pat::Ident(i) => { vec![Some(Expr::Ident(i.clone()))] @@ -239,14 +255,14 @@ fn extract_idents_from_pat<'a>(pat: &Pat<'a>) -> Vec>> { } } -fn expr_to_string_lit<'a>(e: &Expr<'a>) -> Option> { +fn expr_to_string_lit<'a>(e: &Expr>) -> Option>> { let inner = expr_to_string(e)?; - Some(Expr::Lit(Lit::String(StringLit::Single( + Some(Expr::Lit(Lit::String(StringLit::Single(SourceText( ::std::borrow::Cow::Owned(inner), - )))) + ))))) } -fn expr_to_string(expr: &Expr) -> Option { +fn expr_to_string<'a>(expr: &Expr>) -> Option { match expr { Expr::Ident(ref ident) => Some(ident.name.to_string()), Expr::This => Some("this".to_string()), @@ -266,7 +282,13 @@ fn expr_to_string(expr: &Expr) -> Option { Expr::Lit(lit) => match lit { Lit::String(s) => Some(s.clone_inner().to_string()), Lit::Number(n) => Some(n.to_string()), - Lit::RegEx(r) => Some(format!("/{}/{}", r.pattern, r.flags)), + Lit::RegEx(r) => { + if let Some(flags) = &r.flags { + Some(format!("/{}/{}", r.pattern, flags)) + } else { + Some(format!("/{}/", r.pattern)) + } + } Lit::Boolean(b) => Some(b.to_string()), Lit::Null => Some("null".to_string()), _ => None, @@ -275,24 +297,27 @@ fn expr_to_string(expr: &Expr) -> Option { } } -fn ident_to_string_lit<'a>(i: &Ident<'a>) -> Expr<'a> { +fn ident_to_string_lit<'a>(i: &Ident>) -> Expr> { Expr::Lit(Lit::String(StringLit::Single(i.name.clone()))) } -fn insert_expr_into_func<'a>(expr: ProgramPart<'a>, func: &mut Func<'a>) { +fn insert_expr_into_func<'a>(expr: ProgramPart>, func: &mut Func>) { insert_expr_into_func_body(expr, &mut func.body); } -fn insert_expr_into_func_body<'a>(expr: ProgramPart<'a>, body: &mut FuncBody<'a>) { +fn insert_expr_into_func_body<'a>( + expr: ProgramPart>, + body: &mut FuncBody>, +) { body.0.insert(0, expr); } -pub fn console_log<'a>(args: Vec>) -> ProgramPart<'a> { +pub fn console_log<'a>(args: Vec>>) -> ProgramPart> { ProgramPart::Stmt(Stmt::Expr(Expr::Call(CallExpr { callee: Box::new(Expr::Member(MemberExpr { computed: false, - object: Box::new(Expr::ident_from("console")), - property: Box::new(Expr::ident_from("log")), + object: Box::new(Expr::Ident(Cow::Borrowed("console").into())), + property: Box::new(Expr::Ident(Cow::Borrowed("log").into())), })), arguments: args, }))) diff --git a/src/lib.rs b/src/lib.rs index bf85091..4837c2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,12 @@ #[macro_use] extern crate log; -use resast::prelude::*; +use resast::{expr::QuasiQuote, prelude::*}; use ress::{prelude::Comment, tokens::CommentKind}; -use std::io::{Error as IoError, Write}; +use std::{ + fmt::Debug, + io::{Error as IoError, Write}, +}; pub mod spanned; pub mod write_str; @@ -130,7 +133,7 @@ impl Writer { /// > conjunction with `ressa` you will need to call the `AsConcrete` /// > trait method `as_concrete` to convert the output into /// > the right type for input here. - pub fn write_program(&mut self, program: &Program) -> Res { + pub fn write_program + Debug>(&mut self, program: &Program) -> Res { let parts = match program { Program::Script(ref parts) => parts, Program::Mod(ref parts) => parts, @@ -141,7 +144,7 @@ impl Writer { Ok(()) } /// This will attempt to write a single `ProgramPart` - pub fn write_part(&mut self, part: &ProgramPart) -> Res { + pub fn write_part + Debug>(&mut self, part: &ProgramPart) -> Res { trace!("write_part: {:#?}", part); self.at_top_level = true; self._write_part(part)?; @@ -150,7 +153,7 @@ impl Writer { } /// Internal program part writer to help with top level /// detection, new lines and whitespace writing - fn _write_part(&mut self, part: &ProgramPart) -> Res { + fn _write_part + Debug>(&mut self, part: &ProgramPart) -> Res { trace!("_write_part"); self.write_leading_whitespace()?; match part { @@ -161,7 +164,7 @@ impl Writer { Ok(()) } /// Attempt to write a `Declaration` to the `impl Write` - pub fn write_decl(&mut self, decl: &Decl) -> Res { + pub fn write_decl + Debug>(&mut self, decl: &Decl) -> Res { trace!("write_decl"); match decl { Decl::Var(ref kind, ref decls) => self.write_variable_decls(kind, decls)?, @@ -186,7 +189,11 @@ impl Writer { /// const f = "stuff"; /// var g, h, i, j = "places"; /// ``` - pub fn write_variable_decls(&mut self, kind: &VarKind, decls: &[VarDecl]) -> Res { + pub fn write_variable_decls + Debug>( + &mut self, + kind: &VarKind, + decls: &[VarDecl], + ) -> Res { trace!("write_variable_decls"); self.write_variable_kind(kind)?; let mut after_first = false; @@ -224,7 +231,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_class(&mut self, class: &Class) -> Res { + pub fn write_class + Debug>(&mut self, class: &Class) -> Res { trace!("write_class"); self.write("class ")?; if let Some(ref id) = class.id { @@ -254,11 +261,11 @@ impl Writer { /// export * from 'module'; /// export {Stuff} from 'other_module'; /// ``` - pub fn write_export_decl(&mut self, exp: &ModExport) -> Res { + pub fn write_export_decl + Debug>(&mut self, exp: &ModExport) -> Res { trace!("write_export_decl"); self.write("export ")?; match exp { - ModExport::All(ref a) => self.write_all_export(a)?, + ModExport::All { name, alias } => self.write_all_export(name, alias.as_ref())?, ModExport::Default(ref d) => self.write_default_export(d)?, ModExport::Named(ref n) => self.write_named_export(n)?, } @@ -268,9 +275,18 @@ impl Writer { /// ```js /// export * from 'module' /// ``` - pub fn write_all_export(&mut self, exp: &Lit) -> Res { + pub fn write_all_export + Debug>( + &mut self, + exp: &Lit, + alias: Option<&Ident>, + ) -> Res { trace!("write_all_export"); - self.write("* from ")?; + self.write_char('*')?; + if let Some(alias) = alias { + self.write(" as ")?; + self.write_ident(alias)?; + } + self.write(" from ")?; self.write_literal(exp)?; Ok(()) } @@ -279,7 +295,10 @@ impl Writer { /// export default function Thing() { /// } /// ``` - pub fn write_default_export(&mut self, exp: &DefaultExportDecl) -> Res { + pub fn write_default_export + Debug>( + &mut self, + exp: &DefaultExportDecl, + ) -> Res { trace!("write_default_export"); self.write("default ")?; match exp { @@ -292,7 +311,10 @@ impl Writer { /// export function Thing { /// } /// export {Stuff} from 'module'; - pub fn write_named_export(&mut self, exp: &NamedExportDecl) -> Res { + pub fn write_named_export + Debug>( + &mut self, + exp: &NamedExportDecl, + ) -> Res { trace!("write_named_export"); match exp { NamedExportDecl::Decl(ref d) => self.write_decl(d)?, @@ -305,10 +327,10 @@ impl Writer { /// export {Stuff as Things} from 'module' /// export {Places} from 'other_module' /// ``` - pub fn write_export_specifiers( + pub fn write_export_specifiers + Debug>( &mut self, - specifiers: &[ExportSpecifier], - from: &Option, + specifiers: &[ExportSpecifier], + from: &Option>, ) -> Res { trace!("write_export_specifiers"); self.write("{")?; @@ -318,8 +340,10 @@ impl Writer { self.write(", ")?; } self.write_ident(&s.local)?; - self.write(" as ")?; - self.write(&s.exported.name)?; + if let Some(alias) = &s.alias { + self.write(" as ")?; + self.write(&alias.name)?; + } after_first = true; } self.write("}")?; @@ -335,7 +359,7 @@ impl Writer { /// import {Thing, Place} from 'module'; /// import Stuff from 'other_module'; /// ``` - pub fn write_import_decl(&mut self, imp: &ModImport) -> Res { + pub fn write_import_decl + Debug>(&mut self, imp: &ModImport) -> Res { trace!("write_import_decl"); self.write("import ")?; @@ -362,7 +386,10 @@ impl Writer { /// import {Thing, Place} from 'module'; /// import Stuff from 'other_module'; /// ``` - pub fn write_import_specificer(&mut self, spec: &ImportSpecifier) -> Res { + pub fn write_import_specificer + Debug>( + &mut self, + spec: &ImportSpecifier, + ) -> Res { trace!("write_import_specificer"); match spec { ImportSpecifier::Default(ref i) => self.write_ident(i)?, @@ -375,14 +402,17 @@ impl Writer { /// ```js /// import * as Moment from 'moment'; /// ``` - pub fn write_namespace_import(&mut self, name: &Ident) -> Res { + pub fn write_namespace_import + Debug>(&mut self, name: &Ident) -> Res { trace!("write_namespace_import"); self.write("* as ")?; self.write_ident(name)?; Ok(()) } - pub fn write_normal_imports(&mut self, imports: &[NormalImportSpec]) -> Res { + pub fn write_normal_imports + Debug>( + &mut self, + imports: &[NormalImportSpec], + ) -> Res { trace!("write_normal_imports"); self.write("{")?; let mut past_first = false; @@ -392,7 +422,7 @@ impl Writer { } else { past_first = true; } - self.write_normal_import(&import.imported, &import.local)?; + self.write_normal_import(&import.imported, import.alias.as_ref())?; } self.write("}")?; Ok(()) @@ -402,10 +432,14 @@ impl Writer { /// ```js /// import {Thing as Stuff} from 'module'; /// ``` - pub fn write_normal_import(&mut self, name: &Ident, local: &Ident) -> Res { + pub fn write_normal_import + Debug>( + &mut self, + name: &Ident, + local: Option<&Ident>, + ) -> Res { trace!("write_normal_import"); self.write_ident(&name)?; - if name != local { + if let Some(local) = local { self.write(" as ")?; self.write_ident(&local)?; } @@ -415,7 +449,7 @@ impl Writer { /// ```js /// 'use strict'; /// ``` - pub fn write_directive(&mut self, dir: &Dir) -> Res { + pub fn write_directive + Debug>(&mut self, dir: &Dir) -> Res { trace!("write_directive"); self.write_literal(&dir.expr)?; self.write_empty_stmt()?; @@ -428,7 +462,7 @@ impl Writer { /// } /// var a, b, c, d = 'things'; /// ``` - pub fn write_variable_decl(&mut self, decl: &VarDecl) -> Res { + pub fn write_variable_decl + Debug>(&mut self, decl: &VarDecl) -> Res { trace!("write_variable_decl"); self.write_pattern(&decl.id)?; if let Some(ref init) = decl.init { @@ -448,7 +482,7 @@ impl Writer { self.write(s) } /// Attempts to write the contents of a `Stmt` - pub fn write_stmt(&mut self, stmt: &Stmt) -> Res { + pub fn write_stmt + Debug>(&mut self, stmt: &Stmt) -> Res { trace!("write_stmt"); let mut semi = true; let mut new_line = true; @@ -546,7 +580,7 @@ impl Writer { /// var x = 0; /// } /// ``` - pub fn write_block_stmt(&mut self, block: &[ProgramPart]) -> Res { + pub fn write_block_stmt + Debug>(&mut self, block: &[ProgramPart]) -> Res { trace!("write_block_stmt"); self.write_open_brace()?; if block.len() == 0 { @@ -567,7 +601,7 @@ impl Writer { /// var y = random() * 100; /// } /// ``` - pub fn write_with_stmt(&mut self, expr: &WithStmt) -> Res { + pub fn write_with_stmt + Debug>(&mut self, expr: &WithStmt) -> Res { trace!("write_with_stmt"); self.write("with (")?; self.write_expr(&expr.object)?; @@ -584,7 +618,7 @@ impl Writer { /// return; /// } /// ``` - pub fn write_return_stmt(&mut self, expr: &Option) -> Res { + pub fn write_return_stmt + Debug>(&mut self, expr: &Option>) -> Res { trace!("write_return_stmt"); self.write("return")?; if let Some(ref e) = expr { @@ -601,7 +635,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_labeled_stmt(&mut self, expr: &LabeledStmt) -> Res { + pub fn write_labeled_stmt + Debug>(&mut self, expr: &LabeledStmt) -> Res { trace!("write_labeled_stmt"); self.write_ident(&expr.label)?; self.write(": ")?; @@ -619,7 +653,7 @@ impl Writer { /// break; /// } /// ``` - pub fn write_break_stmt(&mut self, expr: &Option) -> Res { + pub fn write_break_stmt + Debug>(&mut self, expr: &Option>) -> Res { trace!("write_break_stmt"); self.write("break")?; if let Some(ref i) = expr { @@ -641,7 +675,10 @@ impl Writer { /// } /// } /// ``` - pub fn write_continue_stmt(&mut self, expr: &Option) -> Res { + pub fn write_continue_stmt + Debug>( + &mut self, + expr: &Option>, + ) -> Res { trace!("write_continue_stmt"); self.write("continue")?; if let Some(ref i) = expr { @@ -660,7 +697,7 @@ impl Writer { /// /// } /// ``` - pub fn write_if_stmt(&mut self, expr: &IfStmt) -> Res { + pub fn write_if_stmt + Debug>(&mut self, expr: &IfStmt) -> Res { trace!("write_if_stmt"); self.write("if (")?; self.write_expr(&expr.test)?; @@ -679,7 +716,7 @@ impl Writer { /// default: /// } /// ``` - pub fn write_switch_stmt(&mut self, switch: &SwitchStmt) -> Res { + pub fn write_switch_stmt + Debug>(&mut self, switch: &SwitchStmt) -> Res { trace!("write_switch_stmt"); self.write("switch (")?; self.write_expr(&switch.discriminant)?; @@ -707,7 +744,7 @@ impl Writer { /// return 100; /// } /// ``` - pub fn write_switch_case(&mut self, case: &SwitchCase) -> Res { + pub fn write_switch_case + Debug>(&mut self, case: &SwitchCase) -> Res { trace!("write_switch_case"); self.write_leading_whitespace()?; if let Some(ref t) = &case.test { @@ -735,7 +772,7 @@ impl Writer { /// throw new Error('Things'); /// } /// ``` - pub fn write_throw_stmt(&mut self, expr: &Expr) -> Res { + pub fn write_throw_stmt + Debug>(&mut self, expr: &Expr) -> Res { trace!("write_throw_stmt"); self.write("throw ")?; self.write_expr(&expr)?; @@ -751,7 +788,7 @@ impl Writer { /// /// } /// ``` - pub fn write_try_stmt(&mut self, stmt: &TryStmt) -> Res { + pub fn write_try_stmt + Debug>(&mut self, stmt: &TryStmt) -> Res { trace!("write_try_stmt"); self.write("try ")?; self.write_block_stmt(&stmt.block.0)?; @@ -775,7 +812,10 @@ impl Writer { /// while (true) { /// } /// ``` - pub fn write_while_stmt(&mut self, stmt: &WhileStmt) -> Result { + pub fn write_while_stmt + Debug>( + &mut self, + stmt: &WhileStmt, + ) -> Result { trace!("write_while_stmt"); let mut ret = false; self.write("while (")?; @@ -792,7 +832,7 @@ impl Writer { /// do { /// /// } while(true) - pub fn write_do_while_stmt(&mut self, stmt: &DoWhileStmt) -> Res { + pub fn write_do_while_stmt + Debug>(&mut self, stmt: &DoWhileStmt) -> Res { trace!("write_do_while_stmt"); self.write("do")?; if let Stmt::Empty = &*stmt.body { @@ -812,7 +852,10 @@ impl Writer { /// for (;;) { /// break; /// } - pub fn write_for_stmt(&mut self, stmt: &ForStmt) -> Result { + pub fn write_for_stmt + Debug>( + &mut self, + stmt: &ForStmt, + ) -> Result { trace!("write_for_stmt: {:?}", stmt); self.write("for (")?; if let Some(ref init) = &stmt.init { @@ -836,7 +879,7 @@ impl Writer { Ok(ret) } /// Attempts to write the first part of a c-style for loop's parenthetical - pub fn write_loop_init(&mut self, init: &LoopInit) -> Res { + pub fn write_loop_init + Debug>(&mut self, init: &LoopInit) -> Res { self.in_for_init = true; match init { LoopInit::Expr(ref e) => self.write_expr(e)?, @@ -861,7 +904,10 @@ impl Writer { /// /// } /// ``` - pub fn write_for_in_stmt(&mut self, stmt: &ForInStmt) -> Result { + pub fn write_for_in_stmt + Debug>( + &mut self, + stmt: &ForInStmt, + ) -> Result { trace!("write_for_in_stmt"); self.write("for (")?; self.write_loop_left(&stmt.left)?; @@ -882,7 +928,10 @@ impl Writer { /// /// } /// ``` - pub fn write_for_of_stmt(&mut self, stmt: &ForOfStmt) -> Result { + pub fn write_for_of_stmt + Debug>( + &mut self, + stmt: &ForOfStmt, + ) -> Result { trace!("write_for_of_stmt"); self.write("for ")?; if stmt.is_await { @@ -902,7 +951,7 @@ impl Writer { Ok(ret) } /// Attempts to write for first part of a for of or for in loop's parenthetical - pub fn write_loop_left(&mut self, left: &LoopLeft) -> Res { + pub fn write_loop_left + Debug>(&mut self, left: &LoopLeft) -> Res { log::trace!("write_loop_left {:?}", left); match left { @@ -925,7 +974,7 @@ impl Writer { /// var y = x; /// var q, w, e, r = Infinity; /// ``` - pub fn write_var_stmt(&mut self, expr: &[VarDecl]) -> Res { + pub fn write_var_stmt + Debug>(&mut self, expr: &[VarDecl]) -> Res { trace!("write_var_stmt"); self.write("var ")?; let mut after_first = false; @@ -939,7 +988,7 @@ impl Writer { Ok(()) } /// Write the contents of a pattern - pub fn write_pattern(&mut self, pattern: &Pat) -> Res { + pub fn write_pattern + Debug>(&mut self, pattern: &Pat) -> Res { trace!("write_pattern"); match pattern { Pat::Ident(ref i) => self.write(&i.name), @@ -953,7 +1002,7 @@ impl Writer { /// ```js /// let {x, y} = {x: 100, y: 0}; /// ``` - pub fn write_object_pattern(&mut self, obj: &ObjPat) -> Res { + pub fn write_object_pattern + Debug>(&mut self, obj: &ObjPat) -> Res { trace!("write_object_pattern"); if obj.len() == 0 { self.write("{}")?; @@ -977,7 +1026,7 @@ impl Writer { Ok(()) } /// Write an object or class property - pub fn write_property(&mut self, prop: &Prop) -> Res { + pub fn write_property + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_property"); if prop.is_static { self.write("static ")?; @@ -1002,11 +1051,11 @@ impl Writer { /// a: 100, /// } /// ``` - pub fn write_init_property(&mut self, prop: &Prop) -> Res { + pub fn write_init_property + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_init_property: {:?}", prop); if !prop.short_hand || matches!(&prop.value, PropValue::None) { self.write_property_key(&prop.key, prop.computed)?; - if prop.value != PropValue::None { + if !matches!(prop.value, PropValue::None) { self.write(": ")?; } } @@ -1026,7 +1075,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_get_property(&mut self, prop: &Prop) -> Res { + pub fn write_get_property + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_get_property"); self.write("get ")?; self.write_property_method(prop) @@ -1039,7 +1088,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_set_property(&mut self, prop: &Prop) -> Res { + pub fn write_set_property + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_set_property"); self.write("set ")?; self.write_property_method(prop) @@ -1052,7 +1101,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_property_method(&mut self, prop: &Prop) -> Res { + pub fn write_property_method + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_property_method"); if let PropValue::Expr(Expr::Func(ref func)) = prop.value { if func.is_async { @@ -1074,7 +1123,7 @@ impl Writer { /// function(arg1, arg2) { /// } /// ``` - pub fn write_function_args(&mut self, args: &[FuncArg]) -> Res { + pub fn write_function_args + Debug>(&mut self, args: &[FuncArg]) -> Res { trace!("write_function_args"); self.write("(")?; let mut after_first = false; @@ -1090,7 +1139,7 @@ impl Writer { Ok(()) } /// Write a single function arg - pub fn write_function_arg(&mut self, arg: &FuncArg) -> Res { + pub fn write_function_arg + Debug>(&mut self, arg: &FuncArg) -> Res { trace!("write_function_arg: {:?}", arg); match arg { FuncArg::Expr(Expr::Assign(assignment)) => { @@ -1102,7 +1151,7 @@ impl Writer { Ok(()) } /// Write the block statement that makes up a function's body - pub fn write_function_body(&mut self, body: &FuncBody) -> Res { + pub fn write_function_body + Debug>(&mut self, body: &FuncBody) -> Res { trace!("write_function_body"); if body.0.len() == 0 { self.write("{ ")?; @@ -1127,7 +1176,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_ctor_property(&mut self, prop: &Prop) -> Res { + pub fn write_ctor_property + Debug>(&mut self, prop: &Prop) -> Res { trace!("write_ctor_property"); self.write_property_key(&prop.key, false)?; if let PropValue::Expr(Expr::Func(ref func)) = prop.value { @@ -1140,7 +1189,11 @@ impl Writer { } /// Write a property key, taking into account of it should be wrapped in [] for "computed" /// properties - pub fn write_property_key(&mut self, key: &PropKey, computed: bool) -> Res { + pub fn write_property_key + Debug>( + &mut self, + key: &PropKey, + computed: bool, + ) -> Res { trace!("write_property_key"); if computed { self.write("[")?; @@ -1156,7 +1209,7 @@ impl Writer { Ok(()) } /// Write the value for a property - pub fn write_property_value(&mut self, value: &PropValue) -> Res { + pub fn write_property_value + Debug>(&mut self, value: &PropValue) -> Res { trace!("write_property_value"); match value { PropValue::Expr(ref e) => self.write_expr(e)?, @@ -1169,7 +1222,7 @@ impl Writer { /// ```js /// let x = [...y]; /// ``` - pub fn write_rest_pattern_part(&mut self, pat: &Pat) -> Res { + pub fn write_rest_pattern_part + Debug>(&mut self, pat: &Pat) -> Res { trace!("write_rest_pattern_part"); self.write("...")?; self.write_pattern(pat)?; @@ -1179,7 +1232,10 @@ impl Writer { /// ```js /// let [x, y] = [1, 2]; /// ``` - pub fn write_array_pattern(&mut self, arr: &[Option]) -> Res { + pub fn write_array_pattern + Debug>( + &mut self, + arr: &[Option>], + ) -> Res { trace!("write_array_pattern"); if arr.len() == 0 { self.write("[]")?; @@ -1193,8 +1249,10 @@ impl Writer { ArrayPatPart::Expr(e) => self.write_expr(e)?, ArrayPatPart::Pat(p) => self.write_pattern(p)?, } - } - if i < last_idx { + if i < last_idx { + self.write(", ")?; + } + } else { self.write(", ")?; } } @@ -1205,14 +1263,17 @@ impl Writer { /// ```js /// let x = [...y]; /// ``` - pub fn write_rest_element(&mut self, pat: &Pat) -> Res { + pub fn write_rest_element + Debug>(&mut self, pat: &Pat) -> Res { trace!("write_rest_element"); self.write("...")?; self.write_pattern(pat)?; Ok(()) } - pub fn write_assignment_pattern(&mut self, assignment: &AssignPat) -> Res { + pub fn write_assignment_pattern + Debug>( + &mut self, + assignment: &AssignPat, + ) -> Res { trace!("write_assignment_pattern"); self.write_pattern(&assignment.left)?; self.write(" = ")?; @@ -1220,14 +1281,14 @@ impl Writer { Ok(()) } - pub fn write_wrapped_expr(&mut self, expr: &Expr) -> Res { + pub fn write_wrapped_expr + Debug>(&mut self, expr: &Expr) -> Res { self.write("(")?; self.write_expr(expr)?; self.write(")")?; Ok(()) } - pub fn write_expr(&mut self, expr: &Expr) -> Res { + pub fn write_expr + Debug>(&mut self, expr: &Expr) -> Res { trace!("write_expr"); let cached_state = self.at_top_level; match expr { @@ -1290,7 +1351,7 @@ impl Writer { /// ```js /// [one,,two,,3, null]; /// ``` - pub fn write_array_expr(&mut self, arr: &ArrayExpr) -> Res { + pub fn write_array_expr + Debug>(&mut self, arr: &ArrayExpr) -> Res { trace!("write_array_expr"); if arr.len() == 0 { self.write("[]")?; @@ -1318,7 +1379,7 @@ impl Writer { /// c: d, /// } /// ``` - pub fn write_object_expr(&mut self, obj: &ObjExpr) -> Res { + pub fn write_object_expr + Debug>(&mut self, obj: &ObjExpr) -> Res { trace!("write_object_expr"); if obj.len() == 0 { self.write("{}")?; @@ -1345,7 +1406,7 @@ impl Writer { } /// Write a function. This is used to write the contents of both a `Declaration::Func` /// and an `Expr::Func` - pub fn write_function(&mut self, func: &Func) -> Res { + pub fn write_function + Debug>(&mut self, func: &Func) -> Res { trace!("write_function"); if func.is_async { self.write("async ")?; @@ -1374,7 +1435,7 @@ impl Writer { /// ~3 /// !true /// ``` - pub fn write_unary_expr(&mut self, unary: &UnaryExpr) -> Res { + pub fn write_unary_expr + Debug>(&mut self, unary: &UnaryExpr) -> Res { trace!("write_unary_expr"); if unary.prefix { self.write_unary_operator(&unary.operator)?; @@ -1416,7 +1477,7 @@ impl Writer { /// a++ /// --b /// ``` - pub fn write_update_expr(&mut self, update: &UpdateExpr) -> Res { + pub fn write_update_expr + Debug>(&mut self, update: &UpdateExpr) -> Res { trace!("write_update_expr"); if update.prefix { self.write_update_operator(&update.operator)?; @@ -1443,7 +1504,7 @@ impl Writer { /// x instanceof y /// x * 100 /// ``` - pub fn write_binary_expr(&mut self, binary: &BinaryExpr) -> Res { + pub fn write_binary_expr + Debug>(&mut self, binary: &BinaryExpr) -> Res { trace!("write_binary_expr {:#?}", binary); let wrap = self.in_for_init && binary.operator == BinaryOp::In; if wrap { @@ -1460,7 +1521,7 @@ impl Writer { Ok(()) } - pub fn write_binary_side(&mut self, side: &Expr) -> Res { + pub fn write_binary_side + Debug>(&mut self, side: &Expr) -> Res { match &*side { Expr::Assign(_) | Expr::Conditional(_) @@ -1506,7 +1567,11 @@ impl Writer { /// b += 8 /// q **= 100 /// ``` - pub fn write_assignment_expr(&mut self, assignment: &AssignExpr, should_wrap: bool) -> Res { + pub fn write_assignment_expr + Debug>( + &mut self, + assignment: &AssignExpr, + should_wrap: bool, + ) -> Res { trace!( "write_assignment_expr: {:?}, should_warp: {}", assignment, @@ -1565,7 +1630,10 @@ impl Writer { /// a && b /// y || q /// ``` - pub fn write_logical_expr(&mut self, logical: &LogicalExpr) -> Res { + pub fn write_logical_expr + Debug>( + &mut self, + logical: &LogicalExpr, + ) -> Res { trace!("write_logical_expr {:#?}", logical); let wrap_left = match &*logical.left { Expr::Logical(ref l) => l.operator == LogicalOp::Or, @@ -1607,7 +1675,7 @@ impl Writer { /// console.log /// console['log'] /// ``` - pub fn write_member_expr(&mut self, member: &MemberExpr) -> Res { + pub fn write_member_expr + Debug>(&mut self, member: &MemberExpr) -> Res { trace!("write_member_expr"); match &*member.object { Expr::Assign(_) @@ -1637,7 +1705,10 @@ impl Writer { /// ```js /// let x = isTrue ? 'yes' : 'no'; /// ``` - pub fn write_conditional_expr(&mut self, conditional: &ConditionalExpr) -> Res { + pub fn write_conditional_expr + Debug>( + &mut self, + conditional: &ConditionalExpr, + ) -> Res { trace!("write_conditional_expr: {:?}", conditional); match &*conditional.test { Expr::Conditional(_) | Expr::Assign(_) => self.write_wrapped_expr(&conditional.test)?, @@ -1660,7 +1731,7 @@ impl Writer { /// (function() { /// })() /// ``` - pub fn write_call_expr(&mut self, call: &CallExpr) -> Res { + pub fn write_call_expr + Debug>(&mut self, call: &CallExpr) -> Res { trace!("write_call_expr: {:?}", call); match &*call.callee { @@ -1679,7 +1750,7 @@ impl Writer { /// ```js /// new Uint8Array(100); /// ``` - pub fn write_new_expr(&mut self, new: &NewExpr) -> Res { + pub fn write_new_expr + Debug>(&mut self, new: &NewExpr) -> Res { trace!("write_new_expr: {:?}", new); self.write("new ")?; match &*new.callee { @@ -1698,7 +1769,7 @@ impl Writer { /// ```js /// a = b, c = d, q * 100 /// ``` - pub fn write_sequence_expr(&mut self, sequence: &[Expr]) -> Res { + pub fn write_sequence_expr + Debug>(&mut self, sequence: &[Expr]) -> Res { trace!("write_sequence_expr"); let mut after_first = false; self.write("(")?; @@ -1717,7 +1788,7 @@ impl Writer { /// function(...args) { /// } /// ``` - pub fn write_spread_expr(&mut self, spread: &Expr) -> Res { + pub fn write_spread_expr + Debug>(&mut self, spread: &Expr) -> Res { trace!("write_spread_expr"); self.write("...")?; self.write_expr(spread)?; @@ -1730,7 +1801,10 @@ impl Writer { /// return x * y; /// } /// ``` - pub fn write_arrow_function_expr(&mut self, func: &ArrowFuncExpr) -> Res { + pub fn write_arrow_function_expr + Debug>( + &mut self, + func: &ArrowFuncExpr, + ) -> Res { trace!("write_arrow_function_expr: {:?}", func); if func.is_async { self.write("async ")?; @@ -1767,7 +1841,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_yield_expr(&mut self, expr: &YieldExpr) -> Res { + pub fn write_yield_expr + Debug>(&mut self, expr: &YieldExpr) -> Res { trace!("write_yield_expr"); self.write("yield")?; if expr.argument.is_some() { @@ -1791,7 +1865,7 @@ impl Writer { /// } /// } /// ``` - pub fn write_meta_property(&mut self, meta: &MetaProp) -> Res { + pub fn write_meta_property + Debug>(&mut self, meta: &MetaProp) -> Res { trace!("write_meta_property"); self.write_ident(&meta.meta)?; self.write(".")?; @@ -1799,14 +1873,14 @@ impl Writer { Ok(()) } /// Write an expression preceded by the await keyword - pub fn write_await_expr(&mut self, expr: &Expr) -> Res { + pub fn write_await_expr + Debug>(&mut self, expr: &Expr) -> Res { trace!("write_await_expr"); self.write("await ")?; self.write_expr(expr)?; Ok(()) } /// Write a plain identifier - pub fn write_ident(&mut self, ident: &Ident<'_>) -> Res { + pub fn write_ident + Debug>(&mut self, ident: &Ident) -> Res { trace!("write_ident"); self.write(&ident.name) } @@ -1814,7 +1888,10 @@ impl Writer { /// ```js /// tag`things ${0} stuff`; /// ``` - pub fn write_tagged_template(&mut self, template: &TaggedTemplateExpr) -> Res { + pub fn write_tagged_template + Debug>( + &mut self, + template: &TaggedTemplateExpr, + ) -> Res { trace!("write_tagged_template"); self.write_expr(&template.tag)?; self.write_template(&template.quasi)?; @@ -1833,7 +1910,7 @@ impl Writer { /// true, /// /.+/g /// `things` - pub fn write_literal(&mut self, lit: &Lit) -> Res { + pub fn write_literal + Debug>(&mut self, lit: &Lit) -> Res { trace!("write_literal"); match lit { Lit::Boolean(b) => self.write_bool(*b), @@ -1854,7 +1931,7 @@ impl Writer { } } /// write a string, re-writes the string if quote configuration is set - pub fn write_string(&mut self, s: &StringLit) -> Res { + pub fn write_string + Debug>(&mut self, s: &StringLit) -> Res { trace!("write_string"); if let Some(c) = self.quote { self.write_char(c)?; @@ -1874,21 +1951,23 @@ impl Writer { Ok(()) } - pub fn write_regex(&mut self, regex: &RegEx) -> Res { + pub fn write_regex + Debug>(&mut self, regex: &RegEx) -> Res { trace!("write_regex {:?}", regex); self.write("/")?; self.write(®ex.pattern)?; self.write("/")?; - self.write(®ex.flags)?; + if let Some(flags) = ®ex.flags { + self.write(flags)?; + } Ok(()) } - pub fn write_template(&mut self, template: &TemplateLit) -> Res { + pub fn write_template + Debug>(&mut self, template: &TemplateLit) -> Res { trace!("write_template"); let mut quasis = template.quasis.iter(); let mut exprs = template.expressions.iter(); while let Some(quasi) = quasis.next() { - self.write(&quasi.raw)?; + self.write_template_element(quasi)?; if let Some(exp) = exprs.next() { self.write_expr(exp)?; } @@ -1896,6 +1975,23 @@ impl Writer { Ok(()) } + pub fn write_template_element + Debug>( + &mut self, + element: &TemplateElement, + ) -> Res { + self.write_quasi_quote(&element.open_quote)?; + self.write(&element.content)?; + self.write_quasi_quote(&element.close_quote) + } + + pub fn write_quasi_quote(&mut self, quote: &QuasiQuote) -> Res { + match quote { + QuasiQuote::BackTick => self.write_char('`'), + QuasiQuote::OpenBrace => self.write("${"), + QuasiQuote::CloseBrace => self.write_char('}'), + } + } + pub fn write_empty_stmt(&mut self) -> Res { trace!("write_empty_stmt"); self.write(";") @@ -1928,8 +2024,8 @@ impl Writer { Ok(()) } - fn write(&mut self, s: &str) -> Res { - let _ = self.out.write(s.as_bytes())?; + fn write(&mut self, s: impl AsRef) -> Res { + let _ = self.out.write(s.as_ref().as_bytes())?; Ok(()) } @@ -2000,7 +2096,7 @@ mod test { w.write_variable_decls( &VarKind::Var, &[VarDecl { - id: Pat::ident_from("thing"), + id: Pat::Ident("thing".into()), init: Some(Expr::Lit(Lit::Boolean(false))), }], ) @@ -2013,15 +2109,15 @@ mod test { &VarKind::Let, &[ VarDecl { - id: Pat::ident_from("stuff"), + id: Pat::Ident("stuff".into()), init: None, }, VarDecl { - id: Pat::ident_from("places"), + id: Pat::Ident("places".into()), init: None, }, VarDecl { - id: Pat::ident_from("thing"), + id: Pat::Ident("thing".into()), init: Some(Expr::Lit(Lit::Boolean(false))), }, ], diff --git a/src/spanned.rs b/src/spanned.rs index 833aeb6..f859495 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -1,6 +1,6 @@ use resast::spanned::{ decl::{ - Decl, DefaultExportDeclValue, DefaultImportSpec, ExportList, ExportSpecifier, + Alias, Decl, DefaultExportDeclValue, DefaultImportSpec, ExportList, ExportSpecifier, ImportSpecifier, ModExport, ModExportSpecifier, ModImport, NamedExportDecl, NamedExportSource, NamedExportSpec, NamespaceImportSpec, NormalImportSpec, NormalImportSpecs, VarDecl, VarDecls, @@ -17,8 +17,9 @@ use resast::spanned::{ self, CatchClause, DoWhileStmt, FinallyClause, ForInStmt, ForOfStmt, ForStmt, IfStmt, LoopInit, LoopLeft, Stmt, SwitchCase, SwitchStmt, WhileStmt, }, - AssignOp, BinaryOp, Class, ClassBody, Dir, Func, FuncArg, FuncBody, Ident, ListEntry, - LogicalOp, Node, Position, Program, ProgramPart, Slice, UnaryOp, UpdateOp, VarKind, + tokens::{AssignOp, BinaryOp, LogicalOp, QuasiQuote, Token, UnaryOp, UpdateOp}, + Class, ClassBody, Dir, Func, FuncArg, FuncBody, Ident, ListEntry, Node, Position, Program, + ProgramPart, Slice, SourceLocation, VarKind, }; use ress::tokens::{Comment, CommentKind}; use std::io::Write; @@ -41,21 +42,21 @@ where } } - pub fn write_program(&mut self, program: &Program) -> Res { + pub fn write_program>(&mut self, program: &Program) -> Res { match program { Program::Mod(inner) => self.write_parts(inner), Program::Script(inner) => self.write_parts(inner), } } - pub fn write_parts(&mut self, parts: &[ProgramPart]) -> Res { + pub fn write_parts>(&mut self, parts: &[ProgramPart]) -> Res { for part in parts { self.write_part(part)?; } Ok(()) } - pub fn write_part(&mut self, part: &ProgramPart) -> Res { + pub fn write_part>(&mut self, part: &ProgramPart) -> Res { match part { ProgramPart::Dir(dir) => self.write_dir(dir), ProgramPart::Decl(decl) => self.write_decl(decl), @@ -63,17 +64,17 @@ where } } - pub fn write_dir(&mut self, dir: &Dir) -> Res { + pub fn write_dir>(&mut self, dir: &Dir) -> Res { self.write_lit(&dir.expr)?; - self.write_maybe_slice(&dir.semi_colon) + self.write_maybe_token(dir.semi_colon.as_ref()) } - pub fn write_decl(&mut self, decl: &Decl) -> Res { + pub fn write_decl>(&mut self, decl: &Decl) -> Res { match decl { Decl::Var { decls, semi_colon } => { self.write_var_decls(decls)?; if let Some(semi) = semi_colon { - self.write_slice(semi)?; + self.write_token(semi)?; } Ok(()) } @@ -81,31 +82,34 @@ where Decl::Class(class) => self.write_class(class), Decl::Import { import, semi_colon } => { self.write_mod_import(import)?; - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Decl::Export { export, semi_colon } => { self.write_mod_export(export)?; - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } } } - pub fn write_mod_import(&mut self, import: &ModImport) -> Res { - self.write_slice(&import.keyword_import)?; + pub fn write_mod_import>(&mut self, import: &ModImport) -> Res { + self.write_token(&import.keyword_import)?; self.write_mod_import_specs(&import.specifiers)?; - self.write_maybe_slice(&import.keyword_from)?; + self.write_maybe_token(import.keyword_from.as_ref())?; self.write_lit(&import.source) } - pub fn write_mod_import_specs(&mut self, specs: &[ListEntry]) -> Res { + pub fn write_mod_import_specs>( + &mut self, + specs: &[ListEntry>], + ) -> Res { for spec in specs { self.write_import_spec(&spec.item)?; - self.write_maybe_slice(&spec.comma)?; + self.write_maybe_token(spec.comma.as_ref())?; } Ok(()) } - pub fn write_import_spec(&mut self, spec: &ImportSpecifier) -> Res { + pub fn write_import_spec>(&mut self, spec: &ImportSpecifier) -> Res { match spec { ImportSpecifier::Normal(normal) => self.write_normal_import_specs(normal), ImportSpecifier::Default(default) => self.write_default_import(default), @@ -113,43 +117,55 @@ where } } - pub fn write_normal_import_specs(&mut self, specs: &NormalImportSpecs) -> Res { - self.write_slice(&specs.open_brace)?; + pub fn write_normal_import_specs>( + &mut self, + specs: &NormalImportSpecs, + ) -> Res { + self.write_token(&specs.open_brace)?; for spec in &specs.specs { self.write_normal_import_spec(&spec.item)?; - self.write_maybe_slice(&spec.comma)?; + self.write_maybe_token(spec.comma.as_ref())?; } - self.write_slice(&specs.close_brace) + self.write_token(&specs.close_brace) } - pub fn write_normal_import_spec(&mut self, spec: &NormalImportSpec) -> Res { + pub fn write_normal_import_spec>( + &mut self, + spec: &NormalImportSpec, + ) -> Res { self.write_ident(&spec.imported)?; if let Some(alias) = &spec.alias { - self.write_slice(&alias.keyword)?; + self.write_token(&alias.keyword)?; self.write_ident(&alias.ident)?; } Ok(()) } - pub fn write_default_import(&mut self, spec: &DefaultImportSpec) -> Res { + pub fn write_default_import>(&mut self, spec: &DefaultImportSpec) -> Res { self.write_ident(&spec.id) } - pub fn write_namespace_import(&mut self, spec: &NamespaceImportSpec) -> Res { - self.write_slice(&spec.star)?; - self.write_slice(&spec.keyword)?; + pub fn write_namespace_import>( + &mut self, + spec: &NamespaceImportSpec, + ) -> Res { + self.write_token(&spec.star)?; + self.write_token(&spec.keyword)?; self.write_ident(&spec.ident) } - pub fn write_mod_export(&mut self, export: &ModExport) -> Res { - self.write_slice(&export.keyword)?; + pub fn write_mod_export>(&mut self, export: &ModExport) -> Res { + self.write_token(&export.keyword)?; self.write_mod_export_spec(&export.spec) } - pub fn write_mod_export_spec(&mut self, spec: &ModExportSpecifier) -> Res { + pub fn write_mod_export_spec>( + &mut self, + spec: &ModExportSpecifier, + ) -> Res { match spec { ModExportSpecifier::Default { keyword, value } => { - self.write_slice(keyword)?; + self.write_token(keyword)?; self.write_default_export_value(value) } ModExportSpecifier::Named(named) => self.write_named_export_decl(named), @@ -157,29 +173,39 @@ where star, keyword, name, + alias, } => { - self.write_slice(star)?; - self.write_slice(keyword)?; + self.write_token(star)?; + if let Some(alias) = alias { + self.write_alias(alias)?; + } + self.write_token(keyword)?; self.write_lit(name) } } } - pub fn write_default_export_value(&mut self, value: &DefaultExportDeclValue) -> Res { + pub fn write_default_export_value>( + &mut self, + value: &DefaultExportDeclValue, + ) -> Res { match value { DefaultExportDeclValue::Decl(decl) => self.write_decl(decl), DefaultExportDeclValue::Expr(expr) => self.write_expr(expr), } } - pub fn write_named_export_decl(&mut self, named: &NamedExportDecl) -> Res { + pub fn write_named_export_decl>( + &mut self, + named: &NamedExportDecl, + ) -> Res { match named { NamedExportDecl::Decl(decl) => self.write_decl(decl), NamedExportDecl::Specifier(spec) => self.write_named_export_spec(spec), } } - pub fn write_named_export_spec(&mut self, spec: &NamedExportSpec) -> Res { + pub fn write_named_export_spec>(&mut self, spec: &NamedExportSpec) -> Res { self.write_export_list(&spec.list)?; if let Some(source) = &spec.source { self.write_named_export_source(source)?; @@ -187,53 +213,56 @@ where Ok(()) } - pub fn write_export_list(&mut self, list: &ExportList) -> Res { - self.write_slice(&list.open_brace)?; + pub fn write_export_list>(&mut self, list: &ExportList) -> Res { + self.write_token(&list.open_brace)?; for spec in &list.elements { self.write_export_spec(&spec.item)?; - self.write_maybe_slice(&spec.comma)?; + self.write_maybe_token(spec.comma.as_ref())?; } - self.write_slice(&list.close_brace) + self.write_token(&list.close_brace) } - pub fn write_named_export_source(&mut self, source: &NamedExportSource) -> Res { - self.write_slice(&source.keyword_from)?; + pub fn write_named_export_source>( + &mut self, + source: &NamedExportSource, + ) -> Res { + self.write_token(&source.keyword_from)?; self.write_lit(&source.module) } - pub fn write_export_spec(&mut self, spec: &ExportSpecifier) -> Res { + pub fn write_export_spec>(&mut self, spec: &ExportSpecifier) -> Res { self.write_ident(&spec.local)?; if let Some(alias) = &spec.alias { - self.write_slice(&alias.keyword)?; + self.write_token(&alias.keyword)?; self.write_ident(&alias.ident)?; } Ok(()) } - pub fn write_stmt(&mut self, stmt: &Stmt) -> Res { + pub fn write_stmt>(&mut self, stmt: &Stmt) -> Res { match stmt { Stmt::Expr { expr, semi_colon } => { self.write_expr(expr)?; - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Stmt::Block(block) => { - self.write_slice(&block.open_brace)?; + self.write_token(&block.open_brace)?; self.write_parts(&block.stmts)?; - self.write_slice(&block.close_brace) + self.write_token(&block.close_brace) } - Stmt::Empty(slice) => self.write_slice(slice), + Stmt::Empty(slice) => self.write_token(slice), Stmt::Debugger { keyword, semi_colon, } => { - self.write_slice(keyword)?; - self.write_maybe_slice(semi_colon) + self.write_token(keyword)?; + self.write_maybe_token(semi_colon.as_ref()) } Stmt::With(with) => { - self.write_slice(&with.keyword)?; - self.write_slice(&with.open_paren)?; + self.write_token(&with.keyword)?; + self.write_token(&with.open_paren)?; self.write_expr(&with.object)?; - self.write_slice(&with.close_paren)?; + self.write_token(&with.close_paren)?; self.write_stmt(&with.body) } Stmt::Return { @@ -241,15 +270,15 @@ where value, semi_colon, } => { - self.write_slice(keyword)?; + self.write_token(keyword)?; if let Some(value) = value { self.write_expr(value)?; } - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Stmt::Labeled(labeled) => { self.write_ident(&labeled.label)?; - self.write_slice(&labeled.colon)?; + self.write_token(&labeled.colon)?; self.write_stmt(&labeled.body) } Stmt::Break { @@ -257,22 +286,22 @@ where label, semi_colon, } => { - self.write_slice(keyword)?; + self.write_token(keyword)?; if let Some(label) = label { self.write_ident(label)?; } - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Stmt::Continue { keyword, label, semi_colon, } => { - self.write_slice(keyword)?; + self.write_token(keyword)?; if let Some(label) = label { self.write_ident(label)?; } - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Stmt::If(stmt) => self.write_if_stmt(stmt), Stmt::Switch(switch) => self.write_switch_stmt(switch), @@ -281,9 +310,9 @@ where expr, semi_colon, } => { - self.write_slice(keyword)?; + self.write_token(keyword)?; self.write_expr(expr)?; - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } Stmt::Try(try_stmt) => self.write_try_stmt(try_stmt), Stmt::While(while_stmt) => self.write_while_stmt(while_stmt), @@ -293,37 +322,37 @@ where Stmt::ForOf(for_of) => self.write_for_of(for_of), Stmt::Var { decls, semi_colon } => { self.write_var_decls(decls)?; - self.write_maybe_slice(semi_colon) + self.write_maybe_token(semi_colon.as_ref()) } } } - pub fn write_var_decls(&mut self, decls: &VarDecls) -> Res { - self.write_var_kind(&decls.keyword)?; + pub fn write_var_decls>(&mut self, decls: &VarDecls) -> Res { + self.write_variable_kind(&decls.keyword)?; self.write_var_decls_(&decls.decls) } - pub fn write_var_kind(&mut self, kind: &VarKind) -> Res { + pub fn write_variable_kind(&mut self, kind: &VarKind) -> Res { match kind { - VarKind::Var(Some(slice)) => self.write_slice(slice), - VarKind::Let(slice) => self.write_slice(slice), - VarKind::Const(slice) => self.write_slice(slice), + VarKind::Var(Some(slice)) => self.write_token(slice), + VarKind::Let(slice) => self.write_token(slice), + VarKind::Const(slice) => self.write_token(slice), _ => Ok(()), } } - fn write_var_decls_(&mut self, decls: &[ListEntry]) -> Res { + fn write_var_decls_>(&mut self, decls: &[ListEntry>]) -> Res { for entry in decls { self.write_var_decl(&entry.item)?; - self.write_maybe_slice(&entry.comma)?; + self.write_maybe_token(entry.comma.as_ref())?; } Ok(()) } - pub fn write_var_decl(&mut self, decl: &VarDecl) -> Res { + pub fn write_var_decl>(&mut self, decl: &VarDecl) -> Res { self.write_pat(&decl.id)?; if let Some(eq) = &decl.eq { - self.write_slice(eq)?; + self.write_token(eq)?; } if let Some(init) = &decl.init { self.write_expr(init)?; @@ -331,54 +360,54 @@ where Ok(()) } - pub fn write_if_stmt(&mut self, if_stmt: &IfStmt) -> Res { - self.write_slice(&if_stmt.keyword)?; - self.write_slice(&if_stmt.open_paren)?; + pub fn write_if_stmt>(&mut self, if_stmt: &IfStmt) -> Res { + self.write_token(&if_stmt.keyword)?; + self.write_token(&if_stmt.open_paren)?; self.write_expr(&if_stmt.test)?; - self.write_slice(&if_stmt.close_paren)?; + self.write_token(&if_stmt.close_paren)?; self.write_stmt(&if_stmt.consequent)?; if let Some(alt) = &if_stmt.alternate { - self.write_slice(&alt.keyword)?; + self.write_token(&alt.keyword)?; self.write_stmt(&alt.body)?; } Ok(()) } - pub fn write_switch_stmt(&mut self, switch: &SwitchStmt) -> Res { - self.write_slice(&switch.keyword)?; - self.write_slice(&switch.open_paren)?; + pub fn write_switch_stmt>(&mut self, switch: &SwitchStmt) -> Res { + self.write_token(&switch.keyword)?; + self.write_token(&switch.open_paren)?; self.write_expr(&switch.discriminant)?; - self.write_slice(&switch.close_paren)?; - self.write_slice(&switch.open_brace)?; + self.write_token(&switch.close_paren)?; + self.write_token(&switch.open_brace)?; for case in &switch.cases { self.write_switch_case(case)?; } - self.write_slice(&switch.close_brace) + self.write_token(&switch.close_brace) } - pub fn write_switch_case(&mut self, case: &SwitchCase) -> Res { - self.write_slice(&case.keyword)?; + pub fn write_switch_case>(&mut self, case: &SwitchCase) -> Res { + self.write_token(&case.keyword)?; if let Some(test) = &case.test { self.write_expr(test)?; } - self.write_slice(&case.colon)?; + self.write_token(&case.colon)?; self.write_parts(&case.consequent) } - pub fn write_class(&mut self, class: &Class) -> Res { - self.write_slice(&class.keyword)?; + pub fn write_class>(&mut self, class: &Class) -> Res { + self.write_token(&class.keyword)?; if let Some(id) = &class.id { self.write_ident(id)?; } if let Some(super_class) = &class.super_class { - self.write_slice(&super_class.keyword_extends)?; + self.write_token(&super_class.keyword_extends)?; self.write_expr(&super_class.expr)?; } self.write_class_body(&class.body) } - pub fn write_try_stmt(&mut self, try_stmt: &stmt::TryStmt) -> Res { - self.write_slice(&try_stmt.keyword)?; + pub fn write_try_stmt>(&mut self, try_stmt: &stmt::TryStmt) -> Res { + self.write_token(&try_stmt.keyword)?; self.write_block_stmt(&try_stmt.block)?; if let Some(catch) = &try_stmt.handler { self.write_catch_clause(catch)? @@ -389,113 +418,113 @@ where Ok(()) } - pub fn write_catch_clause(&mut self, catch: &CatchClause) -> Res { - self.write_slice(&catch.keyword)?; + pub fn write_catch_clause>(&mut self, catch: &CatchClause) -> Res { + self.write_token(&catch.keyword)?; if let Some(param) = &catch.param { - self.write_slice(¶m.open_paren)?; + self.write_token(¶m.open_paren)?; self.write_pat(¶m.param)?; - self.write_slice(¶m.close_paren)?; + self.write_token(¶m.close_paren)?; } self.write_block_stmt(&catch.body) } - pub fn write_finally_clause(&mut self, finally: &FinallyClause) -> Res { - self.write_slice(&finally.keyword)?; + pub fn write_finally_clause>(&mut self, finally: &FinallyClause) -> Res { + self.write_token(&finally.keyword)?; self.write_block_stmt(&finally.body) } - pub fn write_while_stmt(&mut self, while_stmt: &WhileStmt) -> Res { - self.write_slice(&while_stmt.keyword)?; - self.write_slice(&while_stmt.open_paren)?; + pub fn write_while_stmt>(&mut self, while_stmt: &WhileStmt) -> Res { + self.write_token(&while_stmt.keyword)?; + self.write_token(&while_stmt.open_paren)?; self.write_expr(&while_stmt.test)?; - self.write_slice(&while_stmt.close_paren)?; + self.write_token(&while_stmt.close_paren)?; self.write_stmt(&while_stmt.body) } - pub fn write_do_while(&mut self, do_while: &DoWhileStmt) -> Res { - self.write_slice(&do_while.keyword_do)?; + pub fn write_do_while>(&mut self, do_while: &DoWhileStmt) -> Res { + self.write_token(&do_while.keyword_do)?; self.write_stmt(&do_while.body)?; - self.write_slice(&do_while.keyword_while)?; - self.write_slice(&do_while.open_paren)?; + self.write_token(&do_while.keyword_while)?; + self.write_token(&do_while.open_paren)?; self.write_expr(&do_while.test)?; - self.write_slice(&do_while.close_paren)?; - self.write_maybe_slice(&do_while.semi_colon) + self.write_token(&do_while.close_paren)?; + self.write_maybe_token(do_while.semi_colon.as_ref()) } - pub fn write_for_stmt(&mut self, for_stmt: &ForStmt) -> Res { - self.write_slice(&for_stmt.keyword)?; - self.write_slice(&for_stmt.open_paren)?; + pub fn write_for_stmt>(&mut self, for_stmt: &ForStmt) -> Res { + self.write_token(&for_stmt.keyword)?; + self.write_token(&for_stmt.open_paren)?; if let Some(init) = &for_stmt.init { self.write_loop_init(init)?; } - self.write_slice(&for_stmt.semi1)?; + self.write_token(&for_stmt.semi1)?; if let Some(test) = &for_stmt.test { self.write_expr(test)?; } - self.write_slice(&for_stmt.semi2)?; + self.write_token(&for_stmt.semi2)?; if let Some(update) = &for_stmt.update { self.write_expr(update)?; } - self.write_slice(&for_stmt.close_paren)?; + self.write_token(&for_stmt.close_paren)?; self.write_stmt(&for_stmt.body) } - pub fn write_loop_init(&mut self, loop_init: &LoopInit) -> Res { + pub fn write_loop_init>(&mut self, loop_init: &LoopInit) -> Res { match loop_init { LoopInit::Variable(kind, decls) => { - self.write_var_kind(kind)?; + self.write_variable_kind(kind)?; self.write_var_decls_(decls) } LoopInit::Expr(expr) => self.write_expr(expr), } } - pub fn write_for_in(&mut self, for_in: &ForInStmt) -> Res { - self.write_slice(&for_in.keyword_for)?; - self.write_slice(&for_in.open_paren)?; + pub fn write_for_in>(&mut self, for_in: &ForInStmt) -> Res { + self.write_token(&for_in.keyword_for)?; + self.write_token(&for_in.open_paren)?; self.write_loop_left(&for_in.left)?; - self.write_slice(&for_in.keyword_in)?; + self.write_token(&for_in.keyword_in)?; self.write_expr(&for_in.right)?; - self.write_slice(&for_in.close_paren)?; + self.write_token(&for_in.close_paren)?; self.write_stmt(&for_in.body) } - pub fn write_for_of(&mut self, for_of: &ForOfStmt) -> Res { - self.write_slice(&for_of.keyword_for)?; - self.write_slice(&for_of.open_paren)?; + pub fn write_for_of>(&mut self, for_of: &ForOfStmt) -> Res { + self.write_token(&for_of.keyword_for)?; + self.write_token(&for_of.open_paren)?; self.write_loop_left(&for_of.left)?; - self.write_slice(&for_of.keyword_of)?; + self.write_token(&for_of.keyword_of)?; self.write_expr(&for_of.right)?; - self.write_slice(&for_of.close_paren)?; + self.write_token(&for_of.close_paren)?; self.write_stmt(&for_of.body) } - pub fn write_loop_left(&mut self, loop_left: &LoopLeft) -> Res { + pub fn write_loop_left>(&mut self, loop_left: &LoopLeft) -> Res { match loop_left { LoopLeft::Expr(expr) => self.write_expr(expr), LoopLeft::Variable(kind, decl) => { - self.write_var_kind(kind)?; + self.write_variable_kind(kind)?; self.write_var_decl(decl) } LoopLeft::Pat(pat) => self.write_pat(pat), } } - pub fn write_block_stmt(&mut self, block: &stmt::BlockStmt) -> Res { - self.write_slice(&block.open_brace)?; + pub fn write_block_stmt>(&mut self, block: &stmt::BlockStmt) -> Res { + self.write_token(&block.open_brace)?; self.write_parts(&block.stmts)?; - self.write_slice(&block.close_brace) + self.write_token(&block.close_brace) } - pub fn write_class_body(&mut self, body: &ClassBody) -> Res { - self.write_slice(&body.open_brace)?; + pub fn write_class_body>(&mut self, body: &ClassBody) -> Res { + self.write_token(&body.open_brace)?; for prop in &body.props { self.write_prop(prop)?; } - self.write_slice(&body.close_brace) + self.write_token(&body.close_brace) } - pub fn write_prop(&mut self, prop: &Prop) -> Res { + pub fn write_prop>(&mut self, prop: &Prop) -> Res { match prop { Prop::Init(init) => self.write_prop_init(init), Prop::Method(method) => self.write_prop_method(method), @@ -505,10 +534,10 @@ where } } - pub fn write_prop_init(&mut self, prop_init: &PropInit) -> Res { + pub fn write_prop_init>(&mut self, prop_init: &PropInit) -> Res { self.write_prop_init_key(&prop_init.key)?; if let Some(colon) = &prop_init.colon { - self.write_slice(colon)?; + self.write_token(colon)?; } if let Some(init) = &prop_init.value { // special case for `{ i = 0 }` @@ -524,17 +553,17 @@ where Ok(()) } - pub fn write_prop_init_key(&mut self, prop_key: &PropInitKey) -> Res { + pub fn write_prop_init_key>(&mut self, prop_key: &PropInitKey) -> Res { if let Some((open, close)) = &prop_key.brackets { - self.write_slice(open)?; + self.write_token(open)?; self.write_prop_key(&prop_key.value)?; - self.write_slice(close) + self.write_token(close) } else { self.write_prop_key(&prop_key.value) } } - pub fn write_prop_key(&mut self, key: &PropKey) -> Res { + pub fn write_prop_key>(&mut self, key: &PropKey) -> Res { match key { PropKey::Lit(lit) => self.write_lit(lit), PropKey::Expr(expr) => self.write_expr(expr), @@ -542,7 +571,7 @@ where } } - pub fn write_prop_value(&mut self, value: &PropValue) -> Res { + pub fn write_prop_value>(&mut self, value: &PropValue) -> Res { match value { PropValue::Expr(expr) => self.write_expr(expr), PropValue::Pat(pat) => self.write_pat(pat), @@ -550,98 +579,98 @@ where } } - pub fn write_prop_method(&mut self, method: &PropMethod) -> Res { + pub fn write_prop_method>(&mut self, method: &PropMethod) -> Res { if let Some(keyword) = &method.keyword_static { - self.write_slice(keyword)?; + self.write_token(keyword)?; } if let Some(keyword) = &method.keyword_async { - self.write_slice(keyword)?; + self.write_token(keyword)?; } if let Some(star) = &method.star { - self.write_slice(star)?; + self.write_token(star)?; } self.write_prop_init_key(&method.id)?; - self.write_slice(&method.open_paren)?; + self.write_token(&method.open_paren)?; self.write_func_params(&method.params)?; - self.write_slice(&method.close_paren)?; + self.write_token(&method.close_paren)?; self.write_func_body(&method.body) } - pub fn write_ctor(&mut self, ctor: &PropCtor) -> Res { + pub fn write_ctor>(&mut self, ctor: &PropCtor) -> Res { self.write_prop_init_key(&ctor.keyword)?; - self.write_slice(&ctor.open_paren)?; + self.write_token(&ctor.open_paren)?; self.write_func_params(&ctor.params)?; - self.write_slice(&ctor.close_paren)?; + self.write_token(&ctor.close_paren)?; self.write_func_body(&ctor.body) } - pub fn write_prop_get(&mut self, get: &PropGet) -> Res { + pub fn write_prop_get>(&mut self, get: &PropGet) -> Res { if let Some(slice) = &get.keyword_static { - self.write_slice(slice)?; + self.write_token(slice)?; } - self.write_slice(&get.keyword_get)?; + self.write_token(&get.keyword_get)?; self.write_prop_init_key(&get.id)?; - self.write_slice(&get.open_paren)?; - self.write_slice(&get.close_paren)?; + self.write_token(&get.open_paren)?; + self.write_token(&get.close_paren)?; self.write_func_body(&get.body) } - pub fn write_prop_set(&mut self, set: &PropSet) -> Res { + pub fn write_prop_set>(&mut self, set: &PropSet) -> Res { if let Some(slice) = &set.keyword_static { - self.write_slice(slice)?; + self.write_token(slice)?; } - self.write_slice(&set.keyword_set)?; + self.write_token(&set.keyword_set)?; self.write_prop_init_key(&set.id)?; - self.write_slice(&set.open_paren)?; + self.write_token(&set.open_paren)?; self.write_func_arg(&set.arg.item)?; - self.write_maybe_slice(&set.arg.comma)?; - self.write_slice(&set.close_paren)?; + self.write_maybe_token(set.arg.comma.as_ref())?; + self.write_token(&set.close_paren)?; self.write_func_body(&set.body) } - pub fn write_func(&mut self, func: &Func) -> Res { + pub fn write_func>(&mut self, func: &Func) -> Res { if let Some(a) = &func.keyword_async { - self.write_slice(a)?; + self.write_token(a)?; } - self.write_slice(&func.keyword)?; + self.write_token(&func.keyword)?; if let Some(star) = &func.star { - self.write_slice(star)?; + self.write_token(star)?; } if let Some(id) = &func.id { self.write_ident(id)?; } - self.write_slice(&func.open_paren)?; + self.write_token(&func.open_paren)?; self.write_func_params(&func.params)?; - self.write_slice(&func.close_paren)?; + self.write_token(&func.close_paren)?; self.write_func_body(&func.body) } - pub fn write_func_params(&mut self, args: &[ListEntry]) -> Res { + pub fn write_func_params>(&mut self, args: &[ListEntry>]) -> Res { for entry in args { self.write_func_arg(&entry.item)?; - self.write_maybe_slice(&entry.comma)?; + self.write_maybe_token(entry.comma.as_ref())?; } Ok(()) } - pub fn write_func_arg(&mut self, arg: &FuncArg) -> Res { + pub fn write_func_arg>(&mut self, arg: &FuncArg) -> Res { match arg { FuncArg::Expr(expr) => self.write_expr(expr), FuncArg::Pat(pat) => self.write_pat(pat), FuncArg::Rest(rest) => { - self.write_slice(&rest.dots)?; + self.write_token(&rest.dots)?; self.write_pat(&rest.pat) } } } - pub fn write_func_body(&mut self, body: &FuncBody) -> Res { - self.write_slice(&body.open_brace)?; + pub fn write_func_body>(&mut self, body: &FuncBody) -> Res { + self.write_token(&body.open_brace)?; self.write_parts(&body.stmts)?; - self.write_slice(&body.close_brace) + self.write_token(&body.close_brace) } - pub fn write_pat(&mut self, pat: &Pat) -> Res { + pub fn write_pat>(&mut self, pat: &Pat) -> Res { match pat { Pat::Ident(ident) => self.write_ident(ident), Pat::Obj(obj) => self.write_obj_pat(obj), @@ -650,43 +679,49 @@ where } } - pub fn write_obj_pat(&mut self, pat: &ObjPat) -> Res { - self.write_slice(&pat.open_brace)?; + pub fn write_obj_pat>(&mut self, pat: &ObjPat) -> Res { + self.write_token(&pat.open_brace)?; self.write_obj_pat_parts(&pat.props)?; - self.write_slice(&pat.close_brace) + self.write_token(&pat.close_brace) } - pub fn write_obj_pat_parts(&mut self, props: &[ListEntry]) -> Res { + pub fn write_obj_pat_parts>( + &mut self, + props: &[ListEntry>], + ) -> Res { for entry in props { self.write_obj_pat_part(&entry.item)?; - self.write_maybe_slice(&entry.comma)?; + self.write_maybe_token(entry.comma.as_ref())?; } Ok(()) } - pub fn write_obj_pat_part(&mut self, props: &ObjPatPart) -> Res { + pub fn write_obj_pat_part>(&mut self, props: &ObjPatPart) -> Res { match props { ObjPatPart::Assign(pat) => self.write_prop(pat), ObjPatPart::Rest(rest) => self.write_rest_pat(rest), } } - pub fn write_arr_pat(&mut self, arr: &ArrayPat) -> Res { - self.write_slice(&arr.open_bracket)?; + pub fn write_arr_pat>(&mut self, arr: &ArrayPat) -> Res { + self.write_token(&arr.open_bracket)?; self.write_arr_pat_parts(&arr.elements)?; - self.write_slice(&arr.close_bracket) + self.write_token(&arr.close_bracket) } - pub fn write_arr_pat_parts(&mut self, parts: &[ListEntry>]) -> Res { + pub fn write_arr_pat_parts>( + &mut self, + parts: &[ListEntry>>], + ) -> Res { for part in parts { if let Some(part) = &part.item { self.write_arr_pat_part(part)?; } - self.write_maybe_slice(&part.comma)?; + self.write_maybe_token(part.comma.as_ref())?; } Ok(()) } - pub fn write_arr_pat_part(&mut self, part: &ArrayPatPart) -> Res { + pub fn write_arr_pat_part>(&mut self, part: &ArrayPatPart) -> Res { match part { ArrayPatPart::Pat(pat) => self.write_pat(pat), ArrayPatPart::Expr(expr) => self.write_expr(expr), @@ -694,23 +729,23 @@ where } } - pub fn write_assign_pat(&mut self, assign: &AssignPat) -> Res { + pub fn write_assign_pat>(&mut self, assign: &AssignPat) -> Res { self.write_pat(&assign.left)?; self.write_assign_op(&assign.operator)?; self.write_expr(&assign.right) } - pub fn write_rest_pat(&mut self, rest: &RestPat) -> Res { - self.write_slice(&rest.dots)?; + pub fn write_rest_pat>(&mut self, rest: &RestPat) -> Res { + self.write_token(&rest.dots)?; self.write_pat(&rest.pat) } - pub fn write_expr(&mut self, expr: &Expr) -> Res { + pub fn write_expr>(&mut self, expr: &Expr) -> Res { match expr { Expr::Array(arr) => self.write_arr_expr(arr), Expr::ArrowFunc(arrow) => self.write_arrow_func(arrow), - Expr::ArrowParamPlaceHolder(apph) => { - panic!("Write arrow parameter_place_holder...: {:?}", apph) + Expr::ArrowParamPlaceHolder(_apph) => { + panic!("Write arrow parameter_place_holder...: ") } Expr::Assign(assign) => self.write_assign_expr(assign), Expr::Await(await_expr) => self.write_await_expr(await_expr), @@ -728,74 +763,74 @@ where Expr::Obj(obj) => self.write_obj_expr(obj), Expr::Sequence(seq) => self.write_exprs(seq), Expr::Spread(spread) => { - self.write_slice(&spread.dots)?; + self.write_token(&spread.dots)?; self.write_expr(&spread.expr) } - Expr::Super(slice) => self.write_slice(&slice), + Expr::Super(slice) => self.write_token(slice), Expr::TaggedTemplate(temp) => self.write_tagged_template_expr(temp), - Expr::This(slice) => self.write_slice(slice), + Expr::This(slice) => self.write_token(slice), Expr::Unary(unary) => self.write_unary_expr(unary), Expr::Update(update) => self.write_update_expr(update), Expr::Wrapped(wrapped) => { - self.write_slice(&wrapped.open_paren)?; + self.write_token(&wrapped.open_paren)?; self.write_expr(&wrapped.expr)?; - self.write_slice(&wrapped.close_paren) + self.write_token(&wrapped.close_paren) } Expr::Yield(expr) => self.write_yield_expr(expr), } } - pub fn write_arr_expr(&mut self, arr: &ArrayExpr) -> Res { - self.write_slice(&arr.open_bracket)?; + pub fn write_arr_expr>(&mut self, arr: &ArrayExpr) -> Res { + self.write_token(&arr.open_bracket)?; for ele in &arr.elements { if let Some(expr) = &ele.item { self.write_expr(expr)?; } - self.write_maybe_slice(&ele.comma)?; + self.write_maybe_token(ele.comma.as_ref())?; } - self.write_slice(&arr.close_bracket) + self.write_token(&arr.close_bracket) } - pub fn write_arrow_func(&mut self, arrow: &ArrowFuncExpr) -> Res { + pub fn write_arrow_func>(&mut self, arrow: &ArrowFuncExpr) -> Res { if let Some(slice) = &arrow.keyword { - self.write_slice(slice)?; + self.write_token(slice)?; } if let Some(star) = &arrow.star { - self.write_slice(star)?; + self.write_token(star)?; } if let Some(open) = &arrow.open_paren { - self.write_slice(open)?; + self.write_token(open)?; } self.write_func_params(&arrow.params)?; if let Some(close) = &arrow.close_paren { - self.write_slice(close)?; + self.write_token(close)?; } - self.write_slice(&arrow.arrow)?; + self.write_token(&arrow.arrow)?; match &arrow.body { ArrowFuncBody::FuncBody(body) => self.write_func_body(body), ArrowFuncBody::Expr(expr) => self.write_expr(expr), } } - pub fn write_assign_expr(&mut self, assign: &AssignExpr) -> Res { + pub fn write_assign_expr>(&mut self, assign: &AssignExpr) -> Res { self.write_assign_left(&assign.left)?; self.write_assign_op(&assign.operator)?; self.write_expr(&assign.right) } - pub fn write_assign_left(&mut self, assign_left: &AssignLeft) -> Res { + pub fn write_assign_left>(&mut self, assign_left: &AssignLeft) -> Res { match assign_left { AssignLeft::Pat(pat) => self.write_pat(pat), AssignLeft::Expr(expr) => self.write_expr(expr), } } - pub fn write_await_expr(&mut self, await_expr: &AwaitExpr) -> Res { - self.write_slice(&await_expr.keyword)?; + pub fn write_await_expr>(&mut self, await_expr: &AwaitExpr) -> Res { + self.write_token(&await_expr.keyword)?; self.write_expr(&await_expr.expr) } - pub fn write_bin_expr(&mut self, bin: &BinaryExpr) -> Res { + pub fn write_bin_expr>(&mut self, bin: &BinaryExpr) -> Res { self.write_expr(&bin.left)?; self.write_bin_op(&bin.operator)?; self.write_expr(&bin.right) @@ -803,122 +838,124 @@ where pub fn write_bin_op(&mut self, op: &BinaryOp) -> Res { match op { - BinaryOp::Equal(slice) => self.write_slice(slice), - BinaryOp::NotEqual(slice) => self.write_slice(slice), - BinaryOp::StrictEqual(slice) => self.write_slice(slice), - BinaryOp::StrictNotEqual(slice) => self.write_slice(slice), - BinaryOp::LessThan(slice) => self.write_slice(slice), - BinaryOp::GreaterThan(slice) => self.write_slice(slice), - BinaryOp::LessThanEqual(slice) => self.write_slice(slice), - BinaryOp::GreaterThanEqual(slice) => self.write_slice(slice), - BinaryOp::LeftShift(slice) => self.write_slice(slice), - BinaryOp::RightShift(slice) => self.write_slice(slice), - BinaryOp::UnsignedRightShift(slice) => self.write_slice(slice), - BinaryOp::Plus(slice) => self.write_slice(slice), - BinaryOp::Minus(slice) => self.write_slice(slice), - BinaryOp::Times(slice) => self.write_slice(slice), - BinaryOp::Over(slice) => self.write_slice(slice), - BinaryOp::Mod(slice) => self.write_slice(slice), - BinaryOp::Or(slice) => self.write_slice(slice), - BinaryOp::XOr(slice) => self.write_slice(slice), - BinaryOp::And(slice) => self.write_slice(slice), - BinaryOp::In(slice) => self.write_slice(slice), - BinaryOp::InstanceOf(slice) => self.write_slice(slice), - BinaryOp::PowerOf(slice) => self.write_slice(slice), - } - } - - pub fn write_call_expr(&mut self, call: &CallExpr) -> Res { + BinaryOp::Equal(slice) => self.write_token(slice), + BinaryOp::NotEqual(slice) => self.write_token(slice), + BinaryOp::StrictEqual(slice) => self.write_token(slice), + BinaryOp::StrictNotEqual(slice) => self.write_token(slice), + BinaryOp::LessThan(slice) => self.write_token(slice), + BinaryOp::GreaterThan(slice) => self.write_token(slice), + BinaryOp::LessThanEqual(slice) => self.write_token(slice), + BinaryOp::GreaterThanEqual(slice) => self.write_token(slice), + BinaryOp::LeftShift(slice) => self.write_token(slice), + BinaryOp::RightShift(slice) => self.write_token(slice), + BinaryOp::UnsignedRightShift(slice) => self.write_token(slice), + BinaryOp::Plus(slice) => self.write_token(slice), + BinaryOp::Minus(slice) => self.write_token(slice), + BinaryOp::Times(slice) => self.write_token(slice), + BinaryOp::Over(slice) => self.write_token(slice), + BinaryOp::Mod(slice) => self.write_token(slice), + BinaryOp::Or(slice) => self.write_token(slice), + BinaryOp::XOr(slice) => self.write_token(slice), + BinaryOp::And(slice) => self.write_token(slice), + BinaryOp::In(slice) => self.write_token(slice), + BinaryOp::InstanceOf(slice) => self.write_token(slice), + BinaryOp::PowerOf(slice) => self.write_token(slice), + } + } + + pub fn write_call_expr>(&mut self, call: &CallExpr) -> Res { self.write_expr(&call.callee)?; - self.write_slice(&call.open_paren)?; + self.write_token(&call.open_paren)?; self.write_exprs(&call.arguments)?; - self.write_slice(&call.close_paren) + self.write_token(&call.close_paren) } - pub fn write_exprs(&mut self, exprs: &[ListEntry]) -> Res { + pub fn write_exprs>(&mut self, exprs: &[ListEntry>]) -> Res { for expr in exprs { self.write_expr(&expr.item)?; - self.write_maybe_slice(&expr.comma)?; + self.write_maybe_token(expr.comma.as_ref())?; } Ok(()) } - pub fn write_conditional(&mut self, cond: &ConditionalExpr) -> Res { + pub fn write_conditional>(&mut self, cond: &ConditionalExpr) -> Res { self.write_expr(&cond.test)?; - self.write_slice(&cond.question_mark)?; + self.write_token(&cond.question_mark)?; self.write_expr(&cond.consequent)?; - self.write_slice(&cond.colon)?; + self.write_token(&cond.colon)?; self.write_expr(&cond.alternate) } - pub fn write_logical_expr(&mut self, log: &LogicalExpr) -> Res { + pub fn write_logical_expr>(&mut self, log: &LogicalExpr) -> Res { self.write_expr(&log.left)?; - let op = match &log.operator { - LogicalOp::Or(slice) => slice, - LogicalOp::And(slice) => slice, + match &log.operator { + LogicalOp::Or(op) => self.write_token(op)?, + LogicalOp::And(op) => self.write_token(op)?, }; - self.write_slice(op)?; self.write_expr(&log.right) } - pub fn write_member_expr(&mut self, member: &MemberExpr) -> Res { + pub fn write_member_expr>(&mut self, member: &MemberExpr) -> Res { self.write_expr(&member.object)?; match &member.indexer { MemberIndexer::Period(period) => { - self.write_slice(period)?; + self.write_token(period)?; self.write_expr(&member.property) } MemberIndexer::Computed { open_bracket, close_bracket, } => { - self.write_slice(open_bracket)?; + self.write_token(open_bracket)?; self.write_expr(&member.property)?; - self.write_slice(close_bracket) + self.write_token(close_bracket) } } } - pub fn write_meta_prop(&mut self, meta: &MetaProp) -> Res { + pub fn write_meta_prop>(&mut self, meta: &MetaProp) -> Res { self.write_ident(&meta.meta)?; - self.write_slice(&meta.dot)?; + self.write_token(&meta.dot)?; self.write_ident(&meta.property) } - pub fn write_new_expr(&mut self, new: &NewExpr) -> Res { - self.write_slice(&new.keyword)?; + pub fn write_new_expr>(&mut self, new: &NewExpr) -> Res { + self.write_token(&new.keyword)?; self.write_expr(&new.callee)?; - self.write_maybe_slice(&new.open_paren)?; + self.write_maybe_token(new.open_paren.as_ref())?; self.write_exprs(&new.arguments)?; - self.write_maybe_slice(&new.close_paren) + self.write_maybe_token(new.close_paren.as_ref()) } - pub fn write_obj_expr(&mut self, obj: &ObjExpr) -> Res { - self.write_slice(&obj.open_brace)?; + pub fn write_obj_expr>(&mut self, obj: &ObjExpr) -> Res { + self.write_token(&obj.open_brace)?; self.write_obj_props(&obj.props)?; - self.write_slice(&obj.close_brace) + self.write_token(&obj.close_brace) } - pub fn write_obj_props(&mut self, props: &[ListEntry]) -> Res { + pub fn write_obj_props>(&mut self, props: &[ListEntry>]) -> Res { for prop in props { match &prop.item { ObjProp::Prop(prop) => self.write_prop(prop)?, ObjProp::Spread(spread) => { - self.write_slice(&spread.dots)?; + self.write_token(&spread.dots)?; self.write_expr(&spread.expr)?; } } - self.write_maybe_slice(&prop.comma)?; + self.write_maybe_token(prop.comma.as_ref())?; } Ok(()) } - pub fn write_tagged_template_expr(&mut self, temp: &TaggedTemplateExpr) -> Res { + pub fn write_tagged_template_expr>( + &mut self, + temp: &TaggedTemplateExpr, + ) -> Res { self.write_expr(&temp.tag)?; self.write_template_lit(&temp.quasi) } - pub fn write_unary_expr(&mut self, unary: &UnaryExpr) -> Res { + pub fn write_unary_expr>(&mut self, unary: &UnaryExpr) -> Res { if unary.prefix() { self.write_unary_op(&unary.operator)?; self.write_expr(&unary.argument) @@ -930,34 +967,34 @@ where pub fn write_unary_op(&mut self, op: &UnaryOp) -> Res { match op { - UnaryOp::Minus(slice) => self.write_slice(slice), - UnaryOp::Plus(slice) => self.write_slice(slice), - UnaryOp::Not(slice) => self.write_slice(slice), - UnaryOp::Tilde(slice) => self.write_slice(slice), - UnaryOp::TypeOf(slice) => self.write_slice(slice), - UnaryOp::Void(slice) => self.write_slice(slice), - UnaryOp::Delete(slice) => self.write_slice(slice), + UnaryOp::Minus(slice) => self.write_token(slice), + UnaryOp::Plus(slice) => self.write_token(slice), + UnaryOp::Not(slice) => self.write_token(slice), + UnaryOp::Tilde(slice) => self.write_token(slice), + UnaryOp::TypeOf(slice) => self.write_token(slice), + UnaryOp::Void(slice) => self.write_token(slice), + UnaryOp::Delete(slice) => self.write_token(slice), } } - pub fn write_update_expr(&mut self, expr: &UpdateExpr) -> Res { - let op = match &expr.operator { + pub fn write_update_expr>(&mut self, expr: &UpdateExpr) -> Res { + let op: &dyn Token = match &expr.operator { UpdateOp::Increment(slice) => slice, UpdateOp::Decrement(slice) => slice, }; if expr.prefix() { - self.write_slice(op)?; + self.write_token(op)?; self.write_expr(&expr.argument) } else { self.write_expr(&expr.argument)?; - self.write_slice(op) + self.write_token(op) } } - pub fn write_yield_expr(&mut self, expr: &YieldExpr) -> Res { - self.write_slice(&expr.keyword)?; + pub fn write_yield_expr>(&mut self, expr: &YieldExpr) -> Res { + self.write_token(&expr.keyword)?; if let Some(star) = &expr.star { - self.write_slice(star)?; + self.write_token(star)?; } if let Some(arg) = &expr.argument { self.write_expr(arg)?; @@ -965,27 +1002,44 @@ where Ok(()) } - pub fn write_maybe_slice(&mut self, slice: &Option) -> Res { + pub fn write_maybe_token(&mut self, token: Option<&Ast>) -> Res { + if let Some(token) = token { + self.write_token(token)?; + } + Ok(()) + } + + pub fn write_token(&mut self, token: &dyn Token) -> Res { + self.write_raw_slice( + SourceLocation { + start: token.start(), + end: token.end(), + }, + &token.as_str(), + ) + } + + pub fn write_maybe_slice>(&mut self, slice: &Option>) -> Res { if let Some(slice) = slice.as_ref() { self.write_slice(slice)?; } Ok(()) } - pub fn write_lit(&mut self, lit: &Lit) -> Res { + pub fn write_lit>(&mut self, lit: &Lit) -> Res { match lit { - Lit::Null(slice) => self.write_slice(slice), + Lit::Null(slice) => self.write_token(slice), Lit::String(s) => { - self.write_slice(&s.open_quote)?; + self.write_token(&s.open_quote)?; self.write_slice(&s.content)?; - self.write_slice(&s.close_quote) + self.write_token(&s.close_quote) } Lit::Number(slice) => self.write_slice(slice), - Lit::Boolean(slice) => self.write_slice(slice), + Lit::Boolean(slice) => self.write_token(slice), Lit::RegEx(re) => { - self.write_slice(&re.open_slash)?; + self.write_token(&re.open_slash)?; self.write_slice(&re.pattern)?; - self.write_slice(&re.close_slash)?; + self.write_token(&re.close_slash)?; if let Some(flags) = re.flags.as_ref() { self.write_slice(flags)?; } @@ -995,12 +1049,14 @@ where } } - pub fn write_template_lit(&mut self, temp: &TemplateLit) -> Res { + pub fn write_template_lit>(&mut self, temp: &TemplateLit) -> Res { let mut quasi = temp.quasis.iter(); let mut exprs = temp.expressions.iter(); while let Some(quasi) = quasi.next() { - self.write_slice(&quasi.raw)?; - if quasi.raw.source.ends_with('`') { + self.write_token(&quasi.open_quote)?; + self.write_slice(&quasi.content)?; + self.write_token(&quasi.close_quote)?; + if matches!(quasi.close_quote, QuasiQuote::BackTick(_)) { break; } if let Some(expr) = exprs.next() { @@ -1012,42 +1068,64 @@ where pub fn write_assign_op(&mut self, op: &AssignOp) -> Res { match op { - AssignOp::Equal(slice) => self.write_slice(slice), - AssignOp::PlusEqual(slice) => self.write_slice(slice), - AssignOp::MinusEqual(slice) => self.write_slice(slice), - AssignOp::TimesEqual(slice) => self.write_slice(slice), - AssignOp::DivEqual(slice) => self.write_slice(slice), - AssignOp::ModEqual(slice) => self.write_slice(slice), - AssignOp::LeftShiftEqual(slice) => self.write_slice(slice), - AssignOp::RightShiftEqual(slice) => self.write_slice(slice), - AssignOp::UnsignedRightShiftEqual(slice) => self.write_slice(slice), - AssignOp::OrEqual(slice) => self.write_slice(slice), - AssignOp::XOrEqual(slice) => self.write_slice(slice), - AssignOp::AndEqual(slice) => self.write_slice(slice), - AssignOp::PowerOfEqual(slice) => self.write_slice(slice), - } - } - - pub fn write_ident(&mut self, ident: &Ident) -> Res { + AssignOp::Equal(slice) => self.write_token(slice), + AssignOp::PlusEqual(slice) => self.write_token(slice), + AssignOp::MinusEqual(slice) => self.write_token(slice), + AssignOp::TimesEqual(slice) => self.write_token(slice), + AssignOp::DivEqual(slice) => self.write_token(slice), + AssignOp::ModEqual(slice) => self.write_token(slice), + AssignOp::LeftShiftEqual(slice) => self.write_token(slice), + AssignOp::RightShiftEqual(slice) => self.write_token(slice), + AssignOp::UnsignedRightShiftEqual(slice) => self.write_token(slice), + AssignOp::OrEqual(slice) => self.write_token(slice), + AssignOp::XOrEqual(slice) => self.write_token(slice), + AssignOp::AndEqual(slice) => self.write_token(slice), + AssignOp::PowerOfEqual(slice) => self.write_token(slice), + } + } + + pub fn write_ident>(&mut self, ident: &Ident) -> Res { self.write_slice(&ident.slice) } - fn write_slice(&mut self, slice: &Slice) -> Res { - let new_lines = slice.loc.start.line - self.last_out.line; - self.write(&"\n".repeat(new_lines))?; + pub fn write_alias>(&mut self, alias: &Alias) -> Res { + self.write_token(&alias.keyword)?; + self.write_ident(&alias.ident) + } + + fn write_slice>(&mut self, slice: &Slice) -> Res { + self.write_raw_slice(slice.loc, &slice.source) + } + + fn write_raw_slice>(&mut self, loc: SourceLocation, text: &Ast) -> Res { + println!("{loc:?}, {}", text.as_ref()); + let new_lines = loc.start.line - self.last_out.line; + self.write(&"\n".repeat(new_lines as usize))?; let leading = if new_lines == 0 { - " ".repeat(slice.loc.start.column - self.last_out.column) + if self.last_out.column > loc.start.column { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!( + "attempt to subtract with overflow {:?} - {:?} ({:?})", + self.last_out, + loc.start, + text.as_ref() + ), + )); + } + let prefix = loc.start.column - self.last_out.column; + " ".repeat(prefix as usize) } else { - " ".repeat(slice.loc.start.column.saturating_sub(1)) + " ".repeat((loc.start.column.saturating_sub(1)) as usize) }; self.write(&leading)?; - self.last_out = slice.loc.end; - self.write(&slice.source)?; + self.last_out = loc.end; + self.write(text.as_ref())?; Ok(()) } - fn write(&mut self, s: &str) -> Res { - let _ = self.out.write(s.as_bytes())?; + fn write(&mut self, s: impl AsRef) -> Res { + let _ = self.out.write(s.as_ref().as_bytes())?; Ok(()) } diff --git a/tests/common.rs b/tests/common.rs index 00d07cb..e55d873 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,21 +1,32 @@ +use std::borrow::Cow; + use resast::{Program, ProgramPart}; use ressa::Parser; use resw::{write_str::WriteString, Writer}; #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("{0}")] + #[error("{0} <- Ressa")] Ressa(#[from] ressa::Error), - #[error("{0}")] + #[error("{0} <- Io")] Io(#[from] std::io::Error), - #[error("{0}")] + #[error("{0} <- Uft8")] Utf8(#[from] std::string::FromUtf8Error), - #[error("Mismatched parts:\n{left}\n{right}")] + #[error("\n{left}\n{right} <- Mismatched parts")] Mismatched { left: String, right: String }, - #[error("paniced while parsing: {0}")] + #[error("{0} <- Panic")] Panic(String), } +pub struct MismatchedError +where + T: std::fmt::Debug, + U: std::fmt::Debug, +{ + pub left: T, + pub right: U, +} + pub fn double_round_trip(js: &str, module: bool) -> (String, Option) { let mut first_write = WriteString::new(); let mut second_write = WriteString::new(); @@ -74,8 +85,17 @@ pub fn double_round_trip(js: &str, module: bool) -> (String, Option) { pub fn round_trip_validate<'a>(js: &'a str, module: bool, name: &str) -> Result<(), Error> { pretty_env_logger::try_init().ok(); - round_trip_validate_bare(js, module, name)?; - round_trip_validate_spanned(js, module, name) + if std::env::var("RESW_SKIP_BARE_TEST") != Ok("1".to_string()) { + round_trip_validate_bare(js, module, name).map_err(|e| { + println!("Error validating bare!"); + e + })?; + } + round_trip_validate_spanned(js, module, name).map_err(|e| { + println!("Error validating spanned!"); + e + })?; + Ok(()) } pub fn round_trip_validate_bare<'a>(js: &'a str, module: bool, name: &str) -> Result<(), Error> { let write_failures = std::env::var("RESW_WRITE_FAILURES") == Ok("1".to_string()); @@ -99,23 +119,25 @@ pub fn round_trip_validate_bare<'a>(js: &'a str, module: bool, name: &str) -> Re } }; if first_parts != second_parts { - let ret = find_mismatched(&first_parts, &second_parts).unwrap(); + let MismatchedError { left, right } = find_mismatched(&first_parts, &second_parts).unwrap(); if write_failures { - let to_write = if let Error::Mismatched { left, right } = &ret { - format!("//{}\n//{}\n\n{}", left, right, second_js) - } else { - second_js - }; + let to_write = format!("//{:?}\n//{:?}\n\n{}", left, right, second_js); write_failure(name, &to_write, &None); + write_file(&format!("{:#?}", left), &format!("{}.l.ron", name)); + write_file(&format!("{:#?}", right), &format!("{}.r.ron", name)); } - return Err(ret); + return Err(Error::Mismatched { + left: format!("{left:?}"), + right: format!("{right:?}"), + }); } if write_success { write_failure(name, &second_js, &None); } Ok(()) } + pub fn round_trip_validate_spanned<'a>(js: &'a str, module: bool, name: &str) -> Result<(), Error> { use resast::spanned::Program; use ressa::spanned::Parser; @@ -150,20 +172,16 @@ pub fn round_trip_validate_spanned<'a>(js: &'a str, module: bool, name: &str) -> } }; if first_parts != second_parts { - let ret = find_mismatched(&first_parts, &second_parts).unwrap(); + let mismatched = find_mismatched(&first_parts, &second_parts).unwrap(); if write_failures { - let to_write = if let Error::Mismatched { left, right } = &ret { - format!("//{}\n//{}\n\n{}", left, right, second_js) - } else { - second_js - }; let name = format!("{}-spanned", name); - write_failure(&name, &to_write, &None); - write_file(&format!("{:#?}", first_parts), &format!("{}.1.ron", name)); - write_file(&format!("{:#?}", second_parts), &format!("{}.2.ron", name)); + report_mismatch(&name, &second_js, &mismatched); } - return Err(ret); + return Err(Error::Mismatched { + left: format!("{:?}", mismatched.left), + right: format!("{:?}", mismatched.right), + }); } Ok(()) } @@ -186,15 +204,35 @@ pub fn round_trip_validate_spanned<'a>(js: &'a str, module: bool, name: &str) -> Ok(()) } -pub fn find_mismatched(first_parts: &[T], second_parts: &[T]) -> Option +pub fn report_mismatch( + name: &str, + first_js: &str, + mismatched: &MismatchedError, +) { + let MismatchedError { left, right } = mismatched; + let to_write = format!("//{:?}\n//{:?}\n\n{}", left, right, first_js); + let name = format!("{}-spanned", name); + + write_failure(&name, &to_write, &None); + write_file( + &format!("{:#?}", left), + &format!("{}-mismatch.left.ron", name), + ); + write_file( + &format!("{:#?}", right), + &format!("{}-mismatch.right.ron", name), + ); +} + +pub fn find_mismatched(first_parts: &[T], second_parts: &[T]) -> Option> where - T: PartialEq + std::fmt::Debug, + T: PartialEq + std::fmt::Debug + Clone, { for (lhs, rhs) in first_parts.into_iter().zip(second_parts.into_iter()) { if lhs != rhs { - return Some(Error::Mismatched { - left: format!("{:?}", lhs), - right: format!("{:?}", rhs), + return Some(MismatchedError { + left: lhs.clone(), + right: rhs.clone(), }); } } @@ -203,7 +241,7 @@ where pub fn parse<'a>( p: &'a mut Parser<'a, ressa::DefaultCommentHandler>, -) -> Result>, Error> { +) -> Result>>, Error> { match p.parse()? { Program::Mod(parts) => Ok(parts), Program::Script(parts) => Ok(parts), diff --git a/tests/node_modules.rs b/tests/node_modules.rs index 608bd6f..821ae77 100644 --- a/tests/node_modules.rs +++ b/tests/node_modules.rs @@ -1,3 +1,5 @@ +use crate::common::Error; + mod common; #[test] @@ -33,9 +35,17 @@ fn everything_js_es2015_module() { #[test] fn jquery() { ensure_libraries(); - let js = ::std::fs::read_to_string("./node_modules/jquery/dist/jquery.js") - .expect("failed to read js file"); - common::round_trip_validate(&js, false, "jquery").unwrap(); + const PATH: &str = "./node_modules/jquery/dist/jquery.js"; + let js = ::std::fs::read_to_string(PATH).expect("failed to read js file"); + if let Err(e) = common::round_trip_validate(&js, false, "jquery") { + let mut msg = format!("{e:?}"); + if let Error::Ressa(inner) = e { + if let Some(pos) = inner.position() { + msg.push_str(&format!(" {}:{}:{}", PATH, pos.line, pos.column)); + } + } + panic!("{}", msg); + }; let (first, second) = common::double_round_trip(&js, false); check_round_trips("jquery", &first, &second); } diff --git a/tests/snippets.rs b/tests/snippets.rs index 1f41d54..cb77166 100644 --- a/tests/snippets.rs +++ b/tests/snippets.rs @@ -162,3 +162,27 @@ fn double_break_in_switch_case() { }"; common::round_trip_validate(js, false, "double_break_in_switch_case").unwrap(); } + +#[test] +fn for_loop() { + let js = "for (let i = 0; i < 1; i++);"; + common::round_trip_validate(js, false, "for_loop").unwrap(); +} + +#[test] +fn call_args() { + let js = r#"call(/ /, '');"#; + common::round_trip_validate(js, false, "call_args").unwrap(); +} + +#[test] +fn import_all_as_from() { + let js = r#"import * as i1 from 'module'"#; + common::round_trip_validate(js, true, "import_all_as_from").unwrap(); +} + +#[test] +fn array_pat_with_empty_ele() { + let js = r#"let [x,,] = y;"#; + common::round_trip_validate(js, true, "array_pat_with_empty_ele").unwrap(); +}