refactor: Organize source code for readability
This commit is contained in:
parent
21fc4af83a
commit
15f397348a
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
|
|
Loading…
Reference in New Issue