Skip to content

Commit

Permalink
If statement
Browse files Browse the repository at this point in the history
  • Loading branch information
morenol committed May 30, 2020
1 parent ebddfe6 commit da31dae
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 57 deletions.
2 changes: 0 additions & 2 deletions src/expression_evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::error::Result;
use crate::renderer::Render;
use crate::value::visitors;
use crate::value::Value;
Expand All @@ -7,7 +6,6 @@ use std::io::Write;
pub trait Evaluate {
fn evaluate(&self) -> Value;
}

#[derive(Debug)]
pub enum BinaryOperation {
Plus,
Expand Down
6 changes: 2 additions & 4 deletions src/expression_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl ExpressionParser {
Ok(ExpressionRenderer::new(evaluator))
}

fn full_expresion_parser<'a>(
pub fn full_expresion_parser<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<FullExpressionEvaluator> {
let mut evaluator = FullExpressionEvaluator::new();
Expand Down Expand Up @@ -160,9 +160,7 @@ impl ExpressionParser {
));
}

fn parse_unary_plus_min<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
fn parse_unary_plus_min<'a>(lexer: &mut Peekable<Lexer<'a, Token<'a>>>) -> Result<Expression> {
let unary_op = match lexer.peek() {
Some(Token::Plus) => Some(UnaryOperation::Plus),
Some(Token::Minus) => Some(UnaryOperation::Minus),
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod expression_parser;
mod keyword;
mod lexer;
mod renderer;
mod statement;
mod template;
mod template_env;
mod template_parser;
Expand Down
150 changes: 150 additions & 0 deletions src/statement/mod.rs
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>>;
94 changes: 94 additions & 0 deletions src/statement/parser.rs
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(())
}
}
Loading

0 comments on commit da31dae

Please sign in to comment.