Use FileMap as an input.

This commit is contained in:
강동윤 2018-01-23 21:38:48 +09:00
parent e2f75ec0a2
commit 9b2a5880bb
8 changed files with 82 additions and 66 deletions

View File

@ -7,5 +7,4 @@ authors = ["강동윤 <kdy1@outlook.kr>"]
swc_ecma_ast = { path = "./ast" } swc_ecma_ast = { path = "./ast" }
swc_ecma_parser = { path = "./parser" } swc_ecma_parser = { path = "./parser" }
[dev-dependencies] [dev-dependencies]

View File

@ -1,5 +1,5 @@
use std::str; use std::str;
use swc_common::BytePos; use swc_common::{BytePos, FileMap};
/// Used inside lexer. /// Used inside lexer.
pub(super) struct LexerInput<I: Input> { pub(super) struct LexerInput<I: Input> {
@ -8,7 +8,7 @@ pub(super) struct LexerInput<I: Input> {
input: I, input: I,
} }
impl<'a, I: Input> LexerInput<I> { impl<I: Input> LexerInput<I> {
pub const fn new(input: I) -> Self { pub const fn new(input: I) -> Self {
LexerInput { LexerInput {
input, input,
@ -57,9 +57,37 @@ impl<'a, I: Input> LexerInput<I> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CharIndices<'a>(pub str::CharIndices<'a>); pub struct FileMapInput<'a> {
fm: &'a FileMap,
start_pos: BytePos,
iter: str::CharIndices<'a>,
}
impl<'a> Input for CharIndices<'a> { impl<'a> From<&'a FileMap> for FileMapInput<'a> {
fn from(fm: &'a FileMap) -> Self {
let src = match fm.src {
Some(ref s) => s,
None => unreachable!("Cannot lex filemap without source: {}", fm.name),
};
FileMapInput {
start_pos: fm.start_pos,
iter: src.char_indices(),
fm,
}
}
}
impl<'a> Iterator for FileMapInput<'a> {
type Item = (BytePos, char);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(i, c)| (BytePos(i as u32 + self.start_pos.0), c))
}
}
impl<'a> Input for FileMapInput<'a> {
fn peek(&mut self) -> Option<(BytePos, char)> { fn peek(&mut self) -> Option<(BytePos, char)> {
self.clone().nth(0) self.clone().nth(0)
} }
@ -75,13 +103,6 @@ impl<'a> Input for CharIndices<'a> {
None None
} }
} }
impl<'a> Iterator for CharIndices<'a> {
type Item = (BytePos, char);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(i, c)| (BytePos(i as _), c))
}
}
pub trait Input: Iterator<Item = (BytePos, char)> { pub trait Input: Iterator<Item = (BytePos, char)> {
fn peek(&mut self) -> Option<(BytePos, char)>; fn peek(&mut self) -> Option<(BytePos, char)>;
@ -94,23 +115,3 @@ pub trait Input: Iterator<Item = (BytePos, char)> {
where where
F: FnMut(char) -> bool; F: FnMut(char) -> bool;
} }
impl<'a, I> Input for &'a mut I
where
I: Input,
{
fn peek(&mut self) -> Option<(BytePos, char)> {
<I as Input>::peek(*self)
}
fn peek_ahead(&mut self) -> Option<(BytePos, char)> {
<I as Input>::peek_ahead(*self)
}
fn uncons_while<F>(&mut self, f: F) -> Option<&str>
where
F: FnMut(char) -> bool,
{
<I as Input>::uncons_while(self, f)
}
}

View File

@ -267,16 +267,16 @@ impl<'a, I: Input> Lexer<'a, I> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use lexer::input::CharIndices; use super::input::FileMapInput;
use std::f64::INFINITY; use std::f64::INFINITY;
use std::panic; use std::panic;
fn lex<F, Ret>(s: &'static str, f: F) -> Ret fn lex<F, Ret>(s: &'static str, f: F) -> Ret
where where
F: FnOnce(&mut Lexer<CharIndices>) -> Ret, F: FnOnce(&mut Lexer<FileMapInput>) -> Ret,
{ {
::with_test_sess(s, |sess| { ::with_test_sess(s, |sess, fm| {
let mut l = Lexer::new(sess, CharIndices(s.char_indices())); let mut l = Lexer::new(sess, fm.into());
f(&mut l) f(&mut l)
}) })
} }
@ -369,9 +369,8 @@ mod tests {
.or_else(|_| case.parse::<f64>()) .or_else(|_| case.parse::<f64>())
.expect("failed to parse `expected` as float using str.parse()"); .expect("failed to parse `expected` as float using str.parse()");
let input = CharIndices(case.char_indices());
let vec = panic::catch_unwind(|| { let vec = panic::catch_unwind(|| {
::with_test_sess(case, |mut sess| { ::with_test_sess(case, |mut sess, input| {
sess.cfg.strict = strict; sess.cfg.strict = strict;
Lexer::new(sess, input) Lexer::new(sess, input)
.map(|ts| ts.token) .map(|ts| ts.token)

View File

@ -1,14 +1,14 @@
use super::*; use super::*;
use super::input::CharIndices; use super::input::FileMapInput;
use std::ops::Range; use std::ops::Range;
use std::str; use std::str;
fn with_lexer<F, Ret>(s: &'static str, f: F) -> Ret fn with_lexer<F, Ret>(s: &'static str, f: F) -> Ret
where where
F: FnOnce(&mut Lexer<CharIndices>) -> Ret, F: FnOnce(&mut Lexer<FileMapInput>) -> Ret,
{ {
::with_test_sess(s, |sess| { ::with_test_sess(s, |sess, fm| {
let mut l = Lexer::new(sess, CharIndices(s.char_indices())); let mut l = Lexer::new(sess, fm);
f(&mut l) f(&mut l)
}) })
} }

View File

@ -25,7 +25,7 @@ pub extern crate swc_macros;
#[macro_use] #[macro_use]
extern crate testing; extern crate testing;
extern crate unicode_xid; extern crate unicode_xid;
pub use self::lexer::input::{CharIndices, Input}; pub use self::lexer::input::{FileMapInput, Input};
pub use self::parser::*; pub use self::parser::*;
use slog::Logger; use slog::Logger;
use swc_common::errors::Handler; use swc_common::errors::Handler;
@ -61,19 +61,30 @@ pub struct Session<'a> {
#[cfg(test)] #[cfg(test)]
fn with_test_sess<F, Ret>(src: &'static str, f: F) -> Ret fn with_test_sess<F, Ret>(src: &'static str, f: F) -> Ret
where where
F: FnOnce(Session) -> Ret, F: FnOnce(Session, FileMapInput) -> Ret,
{ {
use std::rc::Rc;
use swc_common::FileName;
use swc_common::errors::{CodeMap, FilePathMapping};
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let fm = cm.new_filemap(FileName::Real("testing".into()), src.into());
let handler = ::swc_common::errors::Handler::with_tty_emitter( let handler = ::swc_common::errors::Handler::with_tty_emitter(
::swc_common::errors::ColorConfig::Never, ::swc_common::errors::ColorConfig::Auto,
true, true,
false, false,
None, Some(cm),
); );
let logger = ::testing::logger().new(o!("src" => src)); let logger = ::testing::logger().new(o!("src" => src));
f(Session { f(
handler: &handler, Session {
logger: &logger, handler: &handler,
cfg: Default::default(), logger: &logger,
}) cfg: Default::default(),
},
(&*fm).into(),
)
} }

View File

@ -81,11 +81,9 @@ impl<'a, I: Input> Parser<'a, I> {
} }
#[cfg(test)] #[cfg(test)]
fn test_parser<F, Ret>(s: &'static str, f: F) -> Ret pub fn test_parser<F, Ret>(s: &'static str, f: F) -> Ret
where where
F: FnOnce(&mut Parser<::CharIndices>) -> Ret, F: FnOnce(&mut Parser<::FileMapInput>) -> Ret,
{ {
::with_test_sess(s, |session| { ::with_test_sess(s, |sess, input| f(&mut Parser::new(sess, input)))
f(&mut Parser::new(session, ::CharIndices(s.char_indices())))
})
} }

View File

@ -16,11 +16,13 @@ use std::fs::read_dir;
use std::io::{self, Read}; use std::io::{self, Read};
use std::panic::{catch_unwind, resume_unwind}; use std::panic::{catch_unwind, resume_unwind};
use std::path::Path; use std::path::Path;
use std::rc::Rc;
use swc_common::{FoldWith, Folder}; use swc_common::{FoldWith, Folder};
use swc_common::FileName;
use swc_common::Span; use swc_common::Span;
use swc_common::errors::{CodeMap, FilePathMapping};
use swc_common::errors::Handler; use swc_common::errors::Handler;
use swc_ecma_parser::{FileMapInput, PResult, Parser, Session};
use swc_ecma_parser::{CharIndices, PResult, Parser, Session};
use swc_ecma_parser::ast::*; use swc_ecma_parser::ast::*;
use test::{test_main, Options, TestDesc, TestDescAndFn, TestFn, TestName}; use test::{test_main, Options, TestDesc, TestDescAndFn, TestFn, TestName};
use test::ShouldPanic::No; use test::ShouldPanic::No;
@ -179,19 +181,23 @@ fn logger(file_name: &str, src: &str) -> Logger {
} }
struct TestSess { struct TestSess {
cm: Rc<CodeMap>,
handler: Handler, handler: Handler,
logger: Logger, logger: Logger,
} }
impl TestSess { impl TestSess {
fn new() -> Self { fn new() -> Self {
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let handler = ::swc_common::errors::Handler::with_tty_emitter( let handler = ::swc_common::errors::Handler::with_tty_emitter(
::swc_common::errors::ColorConfig::Never, ::swc_common::errors::ColorConfig::Never,
true, true,
false, false,
None, Some(cm.clone()),
); );
TestSess { TestSess {
cm,
handler, handler,
logger: ::testing::logger(), logger: ::testing::logger(),
} }
@ -205,16 +211,19 @@ impl TestSess {
fn with_parser<'a, F, Ret>(&'a mut self, file_name: &str, src: &str, f: F) -> PResult<'a, Ret> fn with_parser<'a, F, Ret>(&'a mut self, file_name: &str, src: &str, f: F) -> PResult<'a, Ret>
where where
F: FnOnce(&mut Parser<'a, CharIndices>) -> PResult<'a, Ret>, F: FnOnce(&mut Parser<'a, FileMapInput>) -> PResult<'a, Ret>,
{ {
self.logger = logger(file_name, src); self.logger = logger(file_name, src);
let fm = self.cm
.new_filemap(FileName::Real(file_name.into()), src.into());
f(&mut Parser::new( f(&mut Parser::new(
Session { Session {
logger: &self.logger, logger: &self.logger,
handler: &self.handler, handler: &self.handler,
cfg: Default::default(), cfg: Default::default(),
}, },
::CharIndices(src.char_indices()), (&*fm).into(),
)) ))
} }
} }

View File

@ -7,9 +7,9 @@ pub extern crate swc_macros;
use slog::Logger; use slog::Logger;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use swc_common::errors::{CodeMap, FilePathMapping, Handler}; use swc_common::errors::{CodeMap, Handler};
use swc_ecmascript::ast::Module; use swc_ecmascript::ast::Module;
use swc_ecmascript::parser::{CharIndices, PResult, Parser, Session as ParseSess}; use swc_ecmascript::parser::{FileMapInput, PResult, Parser, Session as ParseSess};
pub struct Compiler { pub struct Compiler {
codemap: Rc<CodeMap>, codemap: Rc<CodeMap>,
@ -35,10 +35,9 @@ impl Compiler {
/// TODO /// TODO
pub fn parse_js(&self, path: &Path) -> PResult<Module> { pub fn parse_js(&self, path: &Path) -> PResult<Module> {
let file = self.codemap let fm = self.codemap
.load_file_and_lines(path) .load_file_and_lines(path)
.expect("failed to load file"); .expect("failed to load file");
let src = file.src.clone().expect("we loaded this right before");
Parser::new( Parser::new(
ParseSess { ParseSess {
@ -46,7 +45,7 @@ impl Compiler {
logger: &self.logger, logger: &self.logger,
cfg: Default::default(), cfg: Default::default(),
}, },
CharIndices(src.char_indices()), FileMapInput::from(&*fm),
).parse_module() ).parse_module()
} }
} }