#![allow(dead_code, unused_variables)]
#![deny(non_snake_case)]
pub use self::input::{Capturing, Tokens, TokensInput};
use self::{input::Buffer, util::ParseObject};
use crate::{
error::{ErrorToDiag, SyntaxError},
lexer::Lexer,
token::{Token, Word},
Context, JscTarget, Session, Syntax,
};
use std::ops::{Deref, DerefMut};
use swc_atoms::JsWord;
use swc_common::{comments::Comments, errors::DiagnosticBuilder, input::Input, BytePos, Span};
use swc_ecma_ast::*;
use swc_ecma_parser_macros::parser;
#[cfg(test)]
extern crate test;
#[cfg(test)]
use test::Bencher;
#[macro_use]
mod macros;
mod class_and_fn;
mod expr;
mod ident;
pub mod input;
mod jsx;
mod object;
mod pat;
mod stmt;
mod typescript;
mod util;
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
#[derive(Clone)]
pub struct Parser<'a, I: Tokens> {
session: Session<'a>,
state: State,
input: Buffer<I>,
}
#[derive(Clone, Default)]
struct State {
labels: Vec<JsWord>,
potential_arrow_start: Option<BytePos>,
}
impl<'a, I: Input> Parser<'a, Lexer<'a, I>> {
pub fn new(
session: Session<'a>,
syntax: Syntax,
input: I,
comments: Option<&'a Comments>,
) -> Self {
Self::new_from(
session,
Lexer::new(session, syntax, Default::default(), input, comments),
)
}
}
#[parser]
impl<'a, I: Tokens> Parser<'a, I> {
pub fn new_from(session: Session<'a>, input: I) -> Self {
Self::new_with(session, input)
}
pub fn new_with(session: Session<'a>, input: I) -> Self {
Parser {
session,
input: Buffer::new(input),
state: Default::default(),
}
}
pub(crate) fn target(&self) -> JscTarget {
self.input.target()
}
pub fn parse_script(&mut self) -> PResult<'a, Script> {
let ctx = Context {
module: false,
..self.ctx()
};
self.set_ctx(ctx);
let start = cur_pos!();
let shebang = self.parse_shebang()?;
self.parse_block_body(true, true, None).map(|body| Script {
span: span!(start),
body,
shebang,
})
}
pub fn parse_typescript_module(&mut self) -> PResult<'a, Module> {
debug_assert!(self.syntax().typescript());
let ctx = Context {
module: true,
..self.ctx()
};
self.set_ctx(ctx);
let start = cur_pos!();
let shebang = self.parse_shebang()?;
self.parse_block_body(true, true, None).map(|body| Module {
span: span!(start),
body,
shebang,
})
}
pub fn parse_module(&mut self) -> PResult<'a, Module> {
let ctx = Context {
module: true,
strict: true,
..self.ctx()
};
self.set_ctx(ctx);
let start = cur_pos!();
let shebang = self.parse_shebang()?;
self.parse_block_body(true, true, None).map(|body| Module {
span: span!(start),
body,
shebang,
})
}
fn parse_shebang(&mut self) -> PResult<'a, Option<JsWord>> {
match cur!(false) {
Ok(&Token::Shebang(..)) => match bump!() {
Token::Shebang(v) => Ok(Some(v)),
_ => unreachable!(),
},
_ => Ok(None),
}
}
fn ctx(&self) -> Context {
self.input.get_ctx()
}
fn emit_err(&self, span: Span, error: SyntaxError) {
DiagnosticBuilder::from(ErrorToDiag {
handler: self.session.handler,
span,
error,
})
.emit();
}
}
#[cfg(test)]
pub fn test_parser<F, Ret>(s: &'static str, syntax: Syntax, f: F) -> Ret
where
F: for<'a> FnOnce(&'a mut Parser<'a, Lexer<'a, crate::SourceFileInput<'_>>>) -> Result<Ret, ()>,
{
crate::with_test_sess(s, |sess, input| {
f(&mut Parser::new(sess, syntax, input, None))
})
.unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{}\n{}", s, output))
}
#[cfg(test)]
pub fn bench_parser<F>(b: &mut Bencher, s: &'static str, syntax: Syntax, mut f: F)
where
F: for<'a> FnMut(&'a mut Parser<'a, Lexer<'a, crate::SourceFileInput<'_>>>) -> PResult<'a, ()>,
{
b.bytes = s.len() as u64;
let _ = crate::with_test_sess(s, |sess, input| {
b.iter(|| {
let _ = f(&mut Parser::new(sess, syntax, input.clone(), None)).map_err(|mut err| {
err.emit();
});
});
Ok(())
});
}