Skip to content

Commit

Permalink
Merge b00dcf0 into dc78e78
Browse files Browse the repository at this point in the history
  • Loading branch information
morenol committed May 31, 2020
2 parents dc78e78 + b00dcf0 commit 08b73c0
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 45 deletions.
52 changes: 39 additions & 13 deletions src/expression_evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,41 @@ pub enum UnaryOperation {
Minus,
LogicalNot,
}

#[derive(Debug)]
pub enum Expression {
pub struct SubscriptExpression<'a> {
expression: Box<Expression<'a>>,
subscript_expression: Vec<Box<dyn Evaluate + 'a>>,
}
pub enum Expression<'a> {
Constant(Value),
BinaryExpression(BinaryOperation, Box<Expression>, Box<Expression>),
UnaryExpression(UnaryOperation, Box<Expression>),
BinaryExpression(BinaryOperation, Box<Expression<'a>>, Box<Expression<'a>>),
UnaryExpression(UnaryOperation, Box<Expression<'a>>),
SubscriptExpression(SubscriptExpression<'a>),
}

impl Evaluate for Expression {
impl<'a> SubscriptExpression<'a> {
pub fn new(expression: Box<Expression<'a>>) -> Self {
let subscript_expression = vec![];
Self {
expression,
subscript_expression,
}
}
pub fn add_index(&mut self, subscript: Box<dyn Evaluate + 'a>) {
self.subscript_expression.push(subscript);
}
}
impl<'a> Evaluate for SubscriptExpression<'a> {
fn evaluate(&self) -> Value {
let mut cur = self.expression.evaluate();
for idx in &self.subscript_expression {
let subscript = idx.evaluate();
cur = visitors::Subscription::apply(cur, subscript);
}

cur
}
}
impl<'a> Evaluate for Expression<'a> {
fn evaluate(&self) -> Value {
match &self {
Expression::Constant(value) => value.clone(),
Expand All @@ -57,32 +83,32 @@ impl Evaluate for Expression {
UnaryOperation::LogicalNot => !expression,
}
}
Expression::SubscriptExpression(sub) => sub.evaluate(),
}
}
}
#[derive(Debug)]
pub struct FullExpressionEvaluator {
expression: Option<Expression>,
pub struct FullExpressionEvaluator<'a> {
expression: Option<Expression<'a>>,
}

impl Render for FullExpressionEvaluator {
impl<'a> Render for FullExpressionEvaluator<'a> {
fn render(&self, out: &mut dyn Write) {
let value = self.evaluate();
out.write(value.to_string().as_bytes());
}
}

impl FullExpressionEvaluator {
impl<'a> FullExpressionEvaluator<'a> {
pub fn new() -> Self {
Self { expression: None }
}

pub fn set_expression(&mut self, expression: Expression) {
pub fn set_expression(&mut self, expression: Expression<'a>) {
self.expression = Some(expression)
}
}

impl Evaluate for FullExpressionEvaluator {
impl<'a> Evaluate for FullExpressionEvaluator<'a> {
fn evaluate(&self) -> Value {
match &self.expression {
Some(expression) => expression.evaluate(),
Expand Down
103 changes: 79 additions & 24 deletions src/expression_parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::error::{Error, ErrorKind, Result, SourceLocation};
use crate::expression_evaluator::{
BinaryOperation, Expression, FullExpressionEvaluator, UnaryOperation,
BinaryOperation, Expression, FullExpressionEvaluator, SubscriptExpression, UnaryOperation,
};
use crate::lexer::Token;
use crate::value::Value;
Expand All @@ -26,7 +26,7 @@ impl ExpressionParser {

pub fn full_expresion_parser<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<FullExpressionEvaluator> {
) -> Result<FullExpressionEvaluator<'a>> {
let mut evaluator = FullExpressionEvaluator::new();

let value = ExpressionParser::parse_logical_or(&mut lexer);
Expand All @@ -38,7 +38,9 @@ impl ExpressionParser {
Ok(evaluator)
}

fn parse_logical_or<'a>(mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>) -> Result<Expression> {
fn parse_logical_or<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_logical_and(&mut lexer)?;
if let Some(Token::LogicalOr) = lexer.peek() {
lexer.next();
Expand All @@ -52,7 +54,9 @@ impl ExpressionParser {
Ok(left)
}

fn parse_logical_and<'a>(mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>) -> Result<Expression> {
fn parse_logical_and<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_logical_compare(&mut lexer)?;
if let Some(Token::LogicalAnd) = lexer.peek() {
lexer.next();
Expand All @@ -68,7 +72,7 @@ impl ExpressionParser {

fn parse_logical_compare<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_string_concat(&mut lexer)?;

let binary_op = match lexer.peek() {
Expand All @@ -93,7 +97,7 @@ impl ExpressionParser {

fn parse_string_concat<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_math_pow(&mut lexer)?;
if let Some(Token::Tilde) = lexer.peek() {
lexer.next();
Expand All @@ -107,7 +111,9 @@ impl ExpressionParser {
Ok(left)
}

fn parse_math_pow<'a>(mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>) -> Result<Expression> {
fn parse_math_pow<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_math_plus_minus(&mut lexer)?;
if let Some(Token::MulMul) = lexer.peek() {
lexer.next();
Expand All @@ -123,7 +129,7 @@ impl ExpressionParser {

fn parse_math_plus_minus<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_math_mul_div(&mut lexer)?;
let binary_op = match lexer.peek() {
Some(Token::Plus) => BinaryOperation::Plus,
Expand All @@ -141,7 +147,7 @@ impl ExpressionParser {

fn parse_math_mul_div<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let left = ExpressionParser::parse_unary_plus_min(&mut lexer)?;
let binary_op = match lexer.peek() {
Some(Token::Mul) => BinaryOperation::Mul,
Expand All @@ -160,7 +166,9 @@ impl ExpressionParser {
));
}

fn parse_unary_plus_min<'a>(lexer: &mut Peekable<Lexer<'a, Token<'a>>>) -> Result<Expression> {
fn parse_unary_plus_min<'a>(
lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression<'a>> {
let unary_op = match lexer.peek() {
Some(Token::Plus) => Some(UnaryOperation::Plus),
Some(Token::Minus) => Some(UnaryOperation::Minus),
Expand All @@ -186,34 +194,41 @@ impl ExpressionParser {

fn parse_value_expression<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let token = lexer.next();

let value = if let Some(tok) = token {
match tok {
Token::IntegerNum(num) => return Ok(Expression::Constant(Value::from(num))),
Token::True => return Ok(Expression::Constant(Value::from(true))),
Token::False => return Ok(Expression::Constant(Value::from(false))),
Token::FloatNum(num) => return Ok(Expression::Constant(Value::from(num))),
Token::String(string) => {
return Ok(Expression::Constant(Value::from(string.to_string())))
}
Token::LBracket => ExpressionParser::parse_braced_expression_or_tuple(&mut lexer),
Token::IntegerNum(num) => Expression::Constant(Value::from(num)),
Token::True => Expression::Constant(Value::from(true)),
Token::False => Expression::Constant(Value::from(false)),
Token::FloatNum(num) => Expression::Constant(Value::from(num)),
Token::String(string) => Expression::Constant(Value::from(string.to_string())),
Token::LBracket => ExpressionParser::parse_braced_expression_or_tuple(&mut lexer)?,
_ => todo!(),
}
} else {
Err(Error::from(ErrorKind::ExpectedExpression(
return Err(Error::from(ErrorKind::ExpectedExpression(
SourceLocation::new(1, 2), // TODO: Use actual source locations
)))
)));
};

let token = lexer.peek();

let value = match token {
Some(Token::LSqBracket) | Some(Token::Point) => {
ExpressionParser::parse_subscript(&mut lexer, value)?
}
Some(Token::LBracket) => todo!(),
_ => value,
};

return value;
// TODO: implement accessors
return Ok(value);
}

fn parse_braced_expression_or_tuple<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
) -> Result<Expression> {
) -> Result<Expression<'a>> {
let mut is_tuple: bool = false;
let mut exprs = vec![];
loop {
Expand All @@ -234,4 +249,44 @@ impl ExpressionParser {
return Ok(exprs.remove(0));
}
}
fn parse_subscript<'a>(
mut lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
expression: Expression<'a>,
) -> Result<Expression<'a>> {
let mut subscript = SubscriptExpression::new(Box::new(expression));
loop {
if let Some(token) = lexer.peek() {
match token {
Token::LSqBracket => {
lexer.next();
let expr = ExpressionParser::full_expresion_parser(&mut lexer)?;
if let Some(Token::RSqBracket) = lexer.next() {
subscript.add_index(Box::new(expr));
} else {
return Err(Error::from(ErrorKind::ExpectedSquareBracket(
SourceLocation::new(1, 2),
)));
}
}
Token::Point => {
lexer.next();
let token = lexer.next();
if let Some(Token::Identifier(identifier)) = token {
subscript.add_index(Box::new(Expression::Constant(Value::String(
identifier.to_string(),
))));
} else {
return Err(Error::from(ErrorKind::ExpectedIdentifier(
SourceLocation::new(1, 2),
)));
}
}
_ => break,
};
} else {
break;
}
}
Ok(Expression::SubscriptExpression(subscript))
}
}
11 changes: 5 additions & 6 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,18 @@ impl<'a> Render for RawTextRenderer<'a> {
}
}

#[derive(Debug)]
pub struct ExpressionRenderer {
expression: FullExpressionEvaluator,
pub struct ExpressionRenderer<'a> {
expression: FullExpressionEvaluator<'a>,
}

impl Render for ExpressionRenderer {
impl<'a> Render for ExpressionRenderer<'a> {
fn render(&self, out: &mut dyn Write) {
self.expression.render(out);
}
}

impl ExpressionRenderer {
pub fn new(expression: FullExpressionEvaluator) -> Self {
impl<'a> ExpressionRenderer<'a> {
pub fn new(expression: FullExpressionEvaluator<'a>) -> Self {
Self { expression }
}
}
4 changes: 2 additions & 2 deletions src/statement/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl StatementParser {
}
fn parse_if<'a>(
lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
statementinfo_list: &mut StatementInfoList,
statementinfo_list: &mut StatementInfoList<'a>,
) -> Result<()> {
let value = ExpressionParser::full_expresion_parser(lexer)?;
let composed_renderer = Rc::new(ComposedRenderer::new());
Expand All @@ -45,7 +45,7 @@ impl StatementParser {
}
fn parse_elif<'a>(
lexer: &mut Peekable<Lexer<'a, Token<'a>>>,
statementinfo_list: &mut StatementInfoList,
statementinfo_list: &mut StatementInfoList<'a>,
) -> Result<()> {
let value = ExpressionParser::full_expresion_parser(lexer)?;
let composed_renderer = Rc::new(ComposedRenderer::new());
Expand Down
12 changes: 12 additions & 0 deletions src/value/visitors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,15 @@ impl BinaryMathOperation {
}
}
}

pub struct Subscription;
impl Subscription {
pub fn apply(value: Value, subscript: Value) -> Value {
match (value, subscript) {
(Value::String(st), Value::Integer(idx)) => {
Value::String(st.chars().nth(idx as usize).unwrap().to_string())
}
_ => todo!(),
}
}
}
5 changes: 5 additions & 0 deletions tests/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,8 @@ fn logical_operators() -> Result<()> {
assert_render_template_eq("{{ false or false }}", "false")?;
assert_render_template_eq("{{ false or true }}", "true")
}

#[test]
fn accessors() -> Result<()> {
assert_render_template_eq("{{ \"hola\"[2] }}", "l")
}

0 comments on commit 08b73c0

Please sign in to comment.