diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-04-27 15:46:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-27 15:46:39 +0200 |
commit | 1f52d180c08b5fc060ecf9d24e4d7f31377479b7 (patch) | |
tree | d2540ce182ded4b5bd3d542c76403e03a381c369 /cli/swc_util.rs | |
parent | 8e9ab9e33ea2c972762cc345c584391c37731b33 (diff) |
refactor: factor out AstParser from DocParser (#4923)
Diffstat (limited to 'cli/swc_util.rs')
-rw-r--r-- | cli/swc_util.rs | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/cli/swc_util.rs b/cli/swc_util.rs new file mode 100644 index 000000000..2086a5ded --- /dev/null +++ b/cli/swc_util.rs @@ -0,0 +1,164 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::swc_common; +use crate::swc_common::comments::Comments; +use crate::swc_common::errors::Diagnostic; +use crate::swc_common::errors::DiagnosticBuilder; +use crate::swc_common::errors::Emitter; +use crate::swc_common::errors::Handler; +use crate::swc_common::errors::HandlerFlags; +use crate::swc_common::FileName; +use crate::swc_common::Globals; +use crate::swc_common::SourceMap; +use crate::swc_common::Span; +use crate::swc_ecma_ast; +use crate::swc_ecma_parser::lexer::Lexer; +use crate::swc_ecma_parser::JscTarget; +use crate::swc_ecma_parser::Parser; +use crate::swc_ecma_parser::Session; +use crate::swc_ecma_parser::SourceFileInput; +use crate::swc_ecma_parser::Syntax; +use crate::swc_ecma_parser::TsConfig; + +use std::error::Error; +use std::fmt; +use std::sync::Arc; +use std::sync::RwLock; + +#[derive(Clone, Debug)] +pub struct SwcDiagnosticBuffer { + pub diagnostics: Vec<Diagnostic>, +} + +impl Error for SwcDiagnosticBuffer {} + +impl fmt::Display for SwcDiagnosticBuffer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = self + .diagnostics + .iter() + .map(|d| d.message()) + .collect::<Vec<String>>() + .join(","); + + f.pad(&msg) + } +} + +#[derive(Clone)] +pub struct SwcErrorBuffer(Arc<RwLock<SwcDiagnosticBuffer>>); + +impl SwcErrorBuffer { + pub fn default() -> Self { + Self(Arc::new(RwLock::new(SwcDiagnosticBuffer { + diagnostics: vec![], + }))) + } +} + +impl Emitter for SwcErrorBuffer { + fn emit(&mut self, db: &DiagnosticBuilder) { + self.0.write().unwrap().diagnostics.push((**db).clone()); + } +} + +impl From<SwcErrorBuffer> for SwcDiagnosticBuffer { + fn from(buf: SwcErrorBuffer) -> Self { + let s = buf.0.read().unwrap(); + s.clone() + } +} + +/// Low-level utility structure with common AST parsing functions. +/// +/// Allows to build more complicated parser by providing a callback +/// to `parse_module`. +pub struct AstParser { + pub buffered_error: SwcErrorBuffer, + pub source_map: Arc<SourceMap>, + pub handler: Handler, + pub comments: Comments, + pub globals: Globals, +} + +impl AstParser { + pub fn new() -> Self { + let buffered_error = SwcErrorBuffer::default(); + + let handler = Handler::with_emitter_and_flags( + Box::new(buffered_error.clone()), + HandlerFlags { + dont_buffer_diagnostics: true, + can_emit_warnings: true, + ..Default::default() + }, + ); + + AstParser { + buffered_error, + source_map: Arc::new(SourceMap::default()), + handler, + comments: Comments::default(), + globals: Globals::new(), + } + } + + pub fn parse_module<F, R>( + &self, + file_name: &str, + source_code: &str, + callback: F, + ) -> R + where + F: FnOnce(Result<swc_ecma_ast::Module, SwcDiagnosticBuffer>) -> R, + { + swc_common::GLOBALS.set(&self.globals, || { + let swc_source_file = self.source_map.new_source_file( + FileName::Custom(file_name.to_string()), + source_code.to_string(), + ); + + let buffered_err = self.buffered_error.clone(); + let session = Session { + handler: &self.handler, + }; + + let mut ts_config = TsConfig::default(); + ts_config.dynamic_import = true; + let syntax = Syntax::Typescript(ts_config); + + let lexer = Lexer::new( + session, + syntax, + JscTarget::Es2019, + SourceFileInput::from(&*swc_source_file), + Some(&self.comments), + ); + + let mut parser = Parser::new_from(session, lexer); + + let parse_result = + parser + .parse_module() + .map_err(move |mut err: DiagnosticBuilder| { + err.cancel(); + SwcDiagnosticBuffer::from(buffered_err) + }); + + callback(parse_result) + }) + } + + pub fn get_span_location(&self, span: Span) -> swc_common::Loc { + self.source_map.lookup_char_pos(span.lo()) + } + + pub fn get_span_comments( + &self, + span: Span, + ) -> Vec<swc_common::comments::Comment> { + self + .comments + .take_leading_comments(span.lo()) + .unwrap_or_else(|| vec![]) + } +} |