-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
328 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
use crate::lexer::Token; | ||
use std::io::Write; | ||
|
||
use crate::expression_evaluator::Evaluate; | ||
use crate::renderer::ComposedRenderer; | ||
use crate::renderer::Render; | ||
use crate::value::Value; | ||
use std::rc::Rc; | ||
pub mod parser; | ||
pub struct IfStatement<'a> { | ||
expression: Box<dyn Evaluate + 'a>, | ||
body: Option<Rc<ComposedRenderer<'a>>>, | ||
else_branches: Vec<Statement<'a>>, | ||
} | ||
impl<'a> IfStatement<'a> { | ||
pub fn new(expression: Box<dyn Evaluate + 'a>) -> Self { | ||
Self { | ||
expression, | ||
body: None, | ||
else_branches: vec![], | ||
} | ||
} | ||
fn set_main_body(&mut self, body: Rc<ComposedRenderer<'a>>) { | ||
let if_body = body.clone(); | ||
self.body = Some(if_body); | ||
} | ||
pub fn add_else_branch(&mut self, branch: Statement<'a>) { | ||
self.else_branches.push(branch); | ||
} | ||
} | ||
impl<'a> Render for IfStatement<'a> { | ||
fn render(&self, out: &mut dyn Write) { | ||
let value = self.expression.evaluate(); | ||
if let Value::Boolean(true) = value { | ||
self.body.as_ref().unwrap().render(out) | ||
} else { | ||
for branch in &self.else_branches { | ||
if let Statement::Else(else_branch) = branch { | ||
if else_branch.should_render() { | ||
branch.render(out); | ||
break; | ||
} | ||
} else { | ||
todo!() | ||
} | ||
} | ||
}; | ||
} | ||
} | ||
|
||
pub struct ElseStatement<'a> { | ||
expression: Option<Box<dyn Evaluate + 'a>>, | ||
body: Option<Rc<ComposedRenderer<'a>>>, | ||
} | ||
|
||
impl<'a> ElseStatement<'a> { | ||
pub fn new() -> Self { | ||
Self { | ||
expression: None, | ||
body: None, | ||
} | ||
} | ||
fn set_main_body(&mut self, body: Rc<ComposedRenderer<'a>>) { | ||
let else_body = body.clone(); | ||
self.body = Some(else_body); | ||
} | ||
|
||
fn should_render(&self) -> bool { | ||
self.expression.is_none() | ||
|| match self.expression.as_ref().unwrap().evaluate() { | ||
Value::Boolean(boolean) => boolean, | ||
_ => todo!(), | ||
} | ||
} | ||
} | ||
impl<'a> Render for ElseStatement<'a> { | ||
fn render(&self, out: &mut dyn Write) { | ||
self.body.as_ref().unwrap().render(out); | ||
} | ||
} | ||
|
||
pub enum Statement<'a> { | ||
If(IfStatement<'a>), | ||
Else(ElseStatement<'a>), | ||
} | ||
impl<'a> Statement<'a> { | ||
pub fn set_main_body(&mut self, body: Rc<ComposedRenderer<'a>>) { | ||
match self { | ||
Statement::If(statement) => statement.set_main_body(body), | ||
Statement::Else(statement) => statement.set_main_body(body), | ||
} | ||
} | ||
pub fn add_else_branch(&mut self, branch: Statement<'a>) { | ||
match self { | ||
Statement::If(statement) => statement.add_else_branch(branch), | ||
Statement::Else(statement) => todo!(), | ||
} | ||
} | ||
} | ||
impl<'a> Render for Statement<'a> { | ||
fn render(&self, out: &mut dyn Write) { | ||
match self { | ||
Statement::If(statement) => statement.render(out), | ||
Statement::Else(statement) => statement.render(out), | ||
} | ||
} | ||
} | ||
|
||
pub struct StatementInfo<'a> { | ||
mode: StatementInfoType, | ||
pub current_composition: Rc<ComposedRenderer<'a>>, | ||
compositions: Vec<Rc<ComposedRenderer<'a>>>, | ||
token: Token<'a>, | ||
renderer: Option<Statement<'a>>, | ||
} | ||
|
||
pub enum StatementInfoType { | ||
TemplateRoot, | ||
IfStatement, | ||
ElseIfStatement, | ||
ForStatement, | ||
SetStatement, | ||
ExtendsStatement, | ||
BlockStatement, | ||
ParentBlockStatement, | ||
MacroStatement, | ||
MacroCallStatement, | ||
WithStatement, | ||
FilterStatement, | ||
} | ||
|
||
impl<'a> StatementInfo<'a> { | ||
pub fn new( | ||
mode: StatementInfoType, | ||
token: Token<'a>, | ||
renderers: Rc<ComposedRenderer<'a>>, | ||
) -> Self { | ||
let current_composition = renderers.clone(); | ||
let compositions = vec![renderers]; | ||
Self { | ||
mode, | ||
token, | ||
current_composition, | ||
compositions, | ||
renderer: None, | ||
} | ||
} | ||
} | ||
|
||
pub type StatementInfoList<'a> = Vec<StatementInfo<'a>>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
use super::{ | ||
ElseStatement, IfStatement, Statement, StatementInfo, StatementInfoList, StatementInfoType, | ||
}; | ||
use crate::error::{Error, ErrorKind, Result, SourceLocation}; | ||
use crate::expression_parser::ExpressionParser; | ||
use crate::lexer::Token; | ||
use crate::renderer::ComposedRenderer; | ||
use logos::{Lexer, Logos}; | ||
use std::iter::Peekable; | ||
pub struct StatementParser; | ||
use std::rc::Rc; | ||
|
||
impl StatementParser { | ||
pub fn parse<'a, 'b>( | ||
text: &'a str, | ||
mut statementinfo_list: &mut StatementInfoList<'a>, | ||
) -> Result<()> { | ||
let lexer: Lexer<Token<'a>> = Token::lexer(text); | ||
let mut lexer: Peekable<Lexer<Token<'a>>> = lexer.peekable(); | ||
let tok = lexer.next(); | ||
|
||
let result = match tok { | ||
Some(Token::If) => StatementParser::parse_if(&mut lexer, &mut statementinfo_list), | ||
Some(Token::Else) => StatementParser::parse_else(&mut statementinfo_list), | ||
Some(Token::EndIf) => StatementParser::parse_endif(&mut statementinfo_list), | ||
_ => todo!(), | ||
}; | ||
|
||
result | ||
} | ||
fn parse_if<'a>( | ||
lexer: &mut Peekable<Lexer<'a, Token<'a>>>, | ||
statementinfo_list: &mut StatementInfoList, | ||
) -> Result<()> { | ||
let value = ExpressionParser::full_expresion_parser(lexer)?; | ||
let composed_renderer = Rc::new(ComposedRenderer::new()); | ||
let renderer = Statement::If(IfStatement::new(Box::new(value))); | ||
let mut statement_info = | ||
StatementInfo::new(StatementInfoType::IfStatement, Token::If, composed_renderer); | ||
statement_info.renderer = Some(renderer); | ||
|
||
statementinfo_list.push(statement_info); | ||
Ok(()) | ||
} | ||
|
||
fn parse_else<'a>(statementinfo_list: &mut StatementInfoList) -> Result<()> { | ||
let composed_renderer = Rc::new(ComposedRenderer::new()); | ||
let renderer = Statement::Else(ElseStatement::new()); | ||
let mut statement_info = StatementInfo::new( | ||
StatementInfoType::ElseIfStatement, | ||
Token::Else, | ||
composed_renderer, | ||
); | ||
statement_info.renderer = Some(renderer); | ||
statementinfo_list.push(statement_info); | ||
Ok(()) | ||
} | ||
fn parse_endif<'a>(statementinfo_list: &mut StatementInfoList<'a>) -> Result<()> { | ||
if statementinfo_list.len() <= 1 { | ||
return Err(Error::from(ErrorKind::UnexpectedStatement( | ||
SourceLocation::new(110, 220), | ||
))); | ||
} | ||
let mut info; | ||
let mut else_branches = vec![]; | ||
loop { | ||
info = statementinfo_list.pop().unwrap(); | ||
match info.mode { | ||
StatementInfoType::IfStatement => { | ||
break; | ||
} | ||
StatementInfoType::ElseIfStatement => { | ||
let mut renderer = info.renderer.unwrap(); | ||
renderer.set_main_body(info.compositions.remove(0)); | ||
else_branches.push(renderer); | ||
} | ||
_ => todo!(), | ||
} | ||
} | ||
let mut renderer = info.renderer.unwrap(); | ||
let body = info.compositions.remove(0); | ||
renderer.set_main_body(body); | ||
|
||
for else_branch in else_branches { | ||
renderer.add_else_branch(else_branch); | ||
} | ||
statementinfo_list | ||
.last_mut() | ||
.unwrap() | ||
.current_composition | ||
.add_renderer(Box::new(renderer)); | ||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.