refactor: Organize source code for readability

This commit is contained in:
Kogia-sima 2020-12-18 23:00:40 +09:00
parent 21fc4af83a
commit 15f397348a
4 changed files with 223 additions and 223 deletions

View File

@ -13,15 +13,15 @@ use crate::resolver::Resolver;
use crate::translator::{TranslatedSource, Translator};
use crate::util::{read_to_string, rustfmt_block};
pub struct CompilationReport {
pub deps: Vec<PathBuf>,
}
#[derive(Default)]
pub struct Compiler {
config: Config,
}
pub struct CompilationReport {
pub deps: Vec<PathBuf>,
}
impl Compiler {
pub fn new() -> Self {
Self::default()

View File

@ -3,59 +3,33 @@ use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::visit_mut::VisitMut;
use syn::{Block, Expr, ExprBreak, ExprContinue, ExprMacro, Ident, LitStr, Stmt, Token};
struct RenderTextMacroArgument {
#[allow(dead_code)]
context: Ident,
arg: LitStr,
pub struct Optimizer {
rm_whitespace: bool,
}
impl Parse for RenderTextMacroArgument {
fn parse(s: ParseStream) -> ParseResult<Self> {
let context = s.parse()?;
s.parse::<Token![,]>()?;
let arg = s.parse()?;
Ok(Self { context, arg })
}
}
fn get_rendertext_value(i: &ExprMacro) -> Option<String> {
let mut it = i.mac.path.segments.iter();
if it.next().map_or(false, |s| s.ident == "__sf_rt")
&& it.next().map_or(false, |s| s.ident == "render_text")
&& it.next().is_none()
{
let tokens = i.mac.tokens.clone();
if let Ok(macro_arg) = syn::parse2::<RenderTextMacroArgument>(tokens) {
return Some(macro_arg.arg.value());
impl Optimizer {
#[inline]
pub fn new() -> Self {
Self {
rm_whitespace: false,
}
}
None
}
#[derive(Default)]
struct ContinueBreakFinder {
found: bool,
}
impl VisitMut for ContinueBreakFinder {
fn visit_expr_continue_mut(&mut self, _: &mut ExprContinue) {
self.found = true;
#[inline]
pub fn rm_whitespace(mut self, new: bool) -> Self {
self.rm_whitespace = new;
self
}
fn visit_expr_break_mut(&mut self, _: &mut ExprBreak) {
self.found = true;
#[inline]
pub fn optimize(&self, i: &mut Block) {
OptmizerImpl {
rm_whitespace: self.rm_whitespace,
}
.visit_block_mut(i);
}
}
fn block_has_continue_or_break(i: &mut Block) -> bool {
let mut finder = ContinueBreakFinder::default();
finder.visit_block_mut(i);
finder.found
}
struct OptmizerImpl {
rm_whitespace: bool,
}
@ -145,29 +119,55 @@ impl VisitMut for OptmizerImpl {
}
}
pub struct Optimizer {
rm_whitespace: bool,
}
fn get_rendertext_value(i: &ExprMacro) -> Option<String> {
struct RenderTextMacroArgument {
#[allow(dead_code)]
context: Ident,
arg: LitStr,
}
impl Optimizer {
#[inline]
pub fn new() -> Self {
Self {
rm_whitespace: false,
impl Parse for RenderTextMacroArgument {
fn parse(s: ParseStream) -> ParseResult<Self> {
let context = s.parse()?;
s.parse::<Token![,]>()?;
let arg = s.parse()?;
Ok(Self { context, arg })
}
}
#[inline]
pub fn rm_whitespace(mut self, new: bool) -> Self {
self.rm_whitespace = new;
self
let mut it = i.mac.path.segments.iter();
if it.next().map_or(false, |s| s.ident == "__sf_rt")
&& it.next().map_or(false, |s| s.ident == "render_text")
&& it.next().is_none()
{
let tokens = i.mac.tokens.clone();
if let Ok(macro_arg) = syn::parse2::<RenderTextMacroArgument>(tokens) {
return Some(macro_arg.arg.value());
}
}
#[inline]
pub fn optimize(&self, i: &mut Block) {
OptmizerImpl {
rm_whitespace: self.rm_whitespace,
}
.visit_block_mut(i);
}
None
}
fn block_has_continue_or_break(i: &mut Block) -> bool {
#[derive(Default)]
struct ContinueBreakFinder {
found: bool,
}
impl VisitMut for ContinueBreakFinder {
fn visit_expr_continue_mut(&mut self, _: &mut ExprContinue) {
self.found = true;
}
fn visit_expr_break_mut(&mut self, _: &mut ExprBreak) {
self.found = true;
}
}
let mut finder = ContinueBreakFinder::default();
finder.visit_block_mut(i);
finder.found
}

View File

@ -23,6 +23,53 @@ macro_rules! return_if_some {
};
}
#[derive(Clone)]
pub struct Resolver<'h> {
include_handler: Arc<dyn 'h + Fn(&Path) -> Result<Block, Error>>,
}
impl<'h> Resolver<'h> {
pub fn new() -> Self {
Self {
include_handler: Arc::new(|_| {
Err(make_error!(ErrorKind::AnalyzeError(
"You cannot use `include` macro inside templates".to_owned()
)))
}),
}
}
#[inline]
pub fn include_handler(
mut self,
new: Arc<dyn 'h + Fn(&Path) -> Result<Block, Error>>,
) -> Resolver<'h> {
self.include_handler = new;
self
}
#[inline]
pub fn resolve(
&self,
input_file: &Path,
ast: &mut Block,
) -> Result<ResolveReport, Error> {
let mut child = ResolverImpl {
path_stack: vec![input_file.to_owned()],
deps: Vec::new(),
error: None,
include_handler: Arc::clone(&self.include_handler),
};
child.visit_block_mut(ast);
if let Some(e) = child.error {
Err(e)
} else {
Ok(ResolveReport { deps: child.deps })
}
}
}
pub struct ResolveReport {
pub deps: Vec<PathBuf>,
}
@ -117,50 +164,3 @@ impl<'h> VisitMut for ResolverImpl<'h> {
}
}
}
#[derive(Clone)]
pub struct Resolver<'h> {
include_handler: Arc<dyn 'h + Fn(&Path) -> Result<Block, Error>>,
}
impl<'h> Resolver<'h> {
pub fn new() -> Self {
Self {
include_handler: Arc::new(|_| {
Err(make_error!(ErrorKind::AnalyzeError(
"You cannot use `include` macro inside templates".to_owned()
)))
}),
}
}
#[inline]
pub fn include_handler(
mut self,
new: Arc<dyn 'h + Fn(&Path) -> Result<Block, Error>>,
) -> Resolver<'h> {
self.include_handler = new;
self
}
#[inline]
pub fn resolve(
&self,
input_file: &Path,
ast: &mut Block,
) -> Result<ResolveReport, Error> {
let mut child = ResolverImpl {
path_stack: vec![input_file.to_owned()],
deps: Vec::new(),
error: None,
include_handler: Arc::clone(&self.include_handler),
};
child.visit_block_mut(ast);
if let Some(e) = child.error {
Err(e)
} else {
Ok(ResolveReport { deps: child.deps })
}
}
}

View File

@ -7,81 +7,46 @@ use syn::{BinOp, Block, Expr};
use crate::error::*;
use crate::parser::{ParseStream, Token, TokenKind};
enum Filter {
Ident(syn::Ident),
Call(syn::ExprCall),
// translate tokens into Rust code
#[derive(Clone, Debug, Default)]
pub struct Translator {
escape: bool,
}
impl Spanned for Filter {
fn span(&self) -> Span {
match *self {
Filter::Ident(ref i) => i.span(),
Filter::Call(ref c) => c.span(),
}
impl Translator {
#[inline]
pub fn new() -> Self {
Self { escape: true }
}
#[inline]
pub fn escape(mut self, new: bool) -> Self {
self.escape = new;
self
}
pub fn translate<'a>(
&self,
token_iter: ParseStream<'a>,
) -> Result<TranslatedSource, Error> {
let original_source = token_iter.original_source;
let mut ps = SourceBuilder::new(self.escape);
ps.reserve(original_source.len());
ps.feed_tokens(token_iter)?;
Ok(ps.finalize()?)
}
}
struct CodeBlock {
#[allow(dead_code)]
expr: Box<Expr>,
filter: Option<Filter>,
pub struct TranslatedSource {
pub ast: Block,
pub source_map: SourceMap,
}
impl Parse for CodeBlock {
fn parse(s: SynParseStream) -> ParseResult<Self> {
let main = s.parse::<Expr>()?;
let code_block = match main {
Expr::Binary(b) if matches!(b.op, BinOp::BitOr(_)) => {
match *b.right {
Expr::Call(c) => {
if let Expr::Path(ref p) = *c.func {
if p.path.get_ident().is_some() {
CodeBlock {
expr: b.left,
filter: Some(Filter::Call(c)),
}
} else {
return Err(syn::Error::new_spanned(
p,
"Invalid filter name",
));
}
} else {
// if function in right side is not a path, fallback to
// normal evaluation block
CodeBlock {
expr: b.left,
filter: None,
}
}
}
Expr::Path(p) => {
if let Some(i) = p.path.get_ident() {
CodeBlock {
expr: b.left,
filter: Some(Filter::Ident(i.clone())),
}
} else {
return Err(syn::Error::new_spanned(
p,
"Invalid filter name",
));
}
}
_ => {
return Err(syn::Error::new_spanned(b, "Expected filter"));
}
}
}
_ => CodeBlock {
expr: Box::new(main),
filter: None,
},
};
Ok(code_block)
}
#[derive(Default)]
pub struct SourceMap {
entries: Vec<SourceMapEntry>,
}
#[derive(Clone)]
@ -91,11 +56,6 @@ pub struct SourceMapEntry {
pub length: usize,
}
#[derive(Default)]
pub struct SourceMap {
entries: Vec<SourceMapEntry>,
}
impl SourceMap {
// #[inline]
// pub fn entries(&self) -> &[SourceMapEntry] {
@ -289,6 +249,83 @@ impl SourceBuilder {
}
}
enum Filter {
Ident(syn::Ident),
Call(syn::ExprCall),
}
impl Spanned for Filter {
fn span(&self) -> Span {
match *self {
Filter::Ident(ref i) => i.span(),
Filter::Call(ref c) => c.span(),
}
}
}
struct CodeBlock {
#[allow(dead_code)]
expr: Box<Expr>,
filter: Option<Filter>,
}
impl Parse for CodeBlock {
fn parse(s: SynParseStream) -> ParseResult<Self> {
let main = s.parse::<Expr>()?;
let code_block = match main {
Expr::Binary(b) if matches!(b.op, BinOp::BitOr(_)) => {
match *b.right {
Expr::Call(c) => {
if let Expr::Path(ref p) = *c.func {
if p.path.get_ident().is_some() {
CodeBlock {
expr: b.left,
filter: Some(Filter::Call(c)),
}
} else {
return Err(syn::Error::new_spanned(
p,
"Invalid filter name",
));
}
} else {
// if function in right side is not a path, fallback to
// normal evaluation block
CodeBlock {
expr: b.left,
filter: None,
}
}
}
Expr::Path(p) => {
if let Some(i) = p.path.get_ident() {
CodeBlock {
expr: b.left,
filter: Some(Filter::Ident(i.clone())),
}
} else {
return Err(syn::Error::new_spanned(
p,
"Invalid filter name",
));
}
}
_ => {
return Err(syn::Error::new_spanned(b, "Expected filter"));
}
}
}
_ => CodeBlock {
expr: Box::new(main),
filter: None,
},
};
Ok(code_block)
}
}
fn into_offset(source: &str, span: Span) -> Option<usize> {
let lc = span.start();
if lc.line > 0 {
@ -304,43 +341,6 @@ fn into_offset(source: &str, span: Span) -> Option<usize> {
}
}
pub struct TranslatedSource {
pub ast: Block,
pub source_map: SourceMap,
}
// translate tokens into Rust code
#[derive(Clone, Debug, Default)]
pub struct Translator {
escape: bool,
}
impl Translator {
#[inline]
pub fn new() -> Self {
Self { escape: true }
}
#[inline]
pub fn escape(mut self, new: bool) -> Self {
self.escape = new;
self
}
pub fn translate<'a>(
&self,
token_iter: ParseStream<'a>,
) -> Result<TranslatedSource, Error> {
let original_source = token_iter.original_source;
let mut ps = SourceBuilder::new(self.escape);
ps.reserve(original_source.len());
ps.feed_tokens(token_iter)?;
Ok(ps.finalize()?)
}
}
#[cfg(test)]
mod tests {
use super::*;