Skip to content

Commit

Permalink
Operator Add implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
tailhook committed Aug 16, 2017
1 parent f575ed1 commit 307e3b6
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
/// Only numbers and strings can be compared for now.
///
/// Use `into()` conversion to make the value.
#[derive(Debug)] // TODO(tailhook) make normal debug
pub struct Comparable<'a>(ComparableInner<'a>);

#[derive(Debug)] // TODO(tailhook) make normal debug
enum ComparableInner<'a> {
I64(i64),
U64(u64),
Expand Down
35 changes: 33 additions & 2 deletions src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,47 @@ fn unary<'a>(input: TokenStream<'a>)
.parse_stream(input)
}

fn bool_and<'a>(input: TokenStream<'a>)
fn addition<'a>(input: TokenStream<'a>)
-> ParseResult<Expr, TokenStream<'a>>
{
use helpers::*;

enum Op {
Add,
Sub,
}

parser(unary)
.and(many(
operator("+").map(|_| Op::Add).or(operator("-").map(|_| Op::Sub))
.skip(ws())
.and(parser(unary))
.and(position())))
.map(|(expr, vec): (_, Vec<_>)| {
vec.into_iter().fold(expr,
|a: Expr, ((op, b), e): ((_, Expr), _)| {
Expr {
position: (a.position.0, e),
code: match op {
Op::Add => ExprCode::Add(Box::new(a), Box::new(b)),
Op::Sub => ExprCode::Sub(Box::new(a), Box::new(b)),
},
}
})
})
.parse_stream(input)
}

fn bool_and<'a>(input: TokenStream<'a>)
-> ParseResult<Expr, TokenStream<'a>>
{
use helpers::*;

parser(addition)
.and(many(
operator("and")
.skip(ws())
.with(parser(unary))
.with(parser(addition))
.and(position())))
.map(|(expr, vec): (_, Vec<_>)| {
vec.into_iter().fold(expr,
Expand Down
45 changes: 45 additions & 0 deletions src/number.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
use std::rc::Rc;
use std::i64;

use owning_ref::OwningRef;

use vars::{VarRef, Variable};

/// An internal representation of a number that may be integer of real
///
/// Use `into()` conversion to make the value.
#[derive(Debug)] // TODO(tailhook) make normal debug
pub struct Number(NumberInner);

#[derive(Clone, Copy, Debug)]
enum NumberInner {
I64(i64),
U64(u64),
Expand Down Expand Up @@ -68,3 +77,39 @@ impl From<f64> for Number {
Number(NumberInner::F64(x))
}
}

fn val<'x, T: Variable<'x>+'x>(v: T) -> VarRef<'x> {
OwningRef::new(Rc::new(v)).map(|x| x as &Variable).erase_owner()
}

fn norm(n: NumberInner) -> NumberInner {
use self::NumberInner::*;
match n {
I64(a) if a > 0 => U64(a as u64),
n => n,
}
}

pub fn add<'x>(a: Number, b: Number) -> VarRef<'x> {
use self::NumberInner::*;
match (norm(a.0), norm(b.0)) {
(I64(a), I64(b)) => {
a.checked_add(b).map(val)
.unwrap_or_else(|| val((a as f64) + (b as f64)))
}
(U64(a), U64(b)) => {
a.checked_add(b).map(val)
.unwrap_or_else(|| val((a as f64) + (b as f64)))
}
(F64(a), F64(b)) => val(a + b),
(I64(a), F64(b)) => val(a as f64 + b),
(F64(a), I64(b)) => val(a + b as f64),
(U64(a), F64(b)) => val(a as f64 + b),
(F64(a), U64(b)) => val(a + b as f64),
(I64(a), U64(b)) | (U64(b), I64(a)) => {
b.checked_sub((-a as u64)).map(val)
.or_else(|| (-a as u64).checked_sub(b).map(|x| val(-(x as i64))))
.unwrap_or_else(|| val((a as f64) + (b as f64)))
}
}
}
15 changes: 8 additions & 7 deletions src/owning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub trait Own {
type Owned<T> = OwningRef<Rc<Arc<Tpl>>, T>;

#[allow(dead_code)] // TODO(tailhook)
#[derive(Debug)]
pub enum ExprCode {
Str(Owned<String>),
Int(Owned<i64>),
Expand Down Expand Up @@ -126,28 +127,28 @@ impl Own for OwningRef<Rc<Arc<Tpl>>, grammar::ExprCode> {
I::Less(_, _) => O::Less(
omap!(self, I::Less(ref a, _) => &**a),
omap!(self, I::Less(_, ref b) => &**b)),
I::GreaterEq(_, _) => O::LessEq(
I::GreaterEq(_, _) => O::GreaterEq(
omap!(self, I::GreaterEq(ref a, _) => &**a),
omap!(self, I::GreaterEq(_, ref b) => &**b)),
I::Greater(_, _) => O::Less(
I::Greater(_, _) => O::Greater(
omap!(self, I::Greater(ref a, _) => &**a),
omap!(self, I::Greater(_, ref b) => &**b)),
I::List(_) => unimplemented!(),
I::Dict(_) => unimplemented!(),
I::Range(_, _) => unimplemented!(),
I::Add(_, _) => O::Less(
I::Add(_, _) => O::Add(
omap!(self, I::Add(ref a, _) => &**a),
omap!(self, I::Add(_, ref b) => &**b)),
I::Sub(_, _) => O::Less(
I::Sub(_, _) => O::Sub(
omap!(self, I::Sub(ref a, _) => &**a),
omap!(self, I::Sub(_, ref b) => &**b)),
I::Mul(_, _) => O::Less(
I::Mul(_, _) => O::Mul(
omap!(self, I::Mul(ref a, _) => &**a),
omap!(self, I::Mul(_, ref b) => &**b)),
I::Div(_, _) => O::Less(
I::Div(_, _) => O::Div(
omap!(self, I::Div(ref a, _) => &**a),
omap!(self, I::Div(_, ref b) => &**b)),
I::Mod(_, _) => O::Less(
I::Mod(_, _) => O::Mod(
omap!(self, I::Mod(ref a, _) => &**a),
omap!(self, I::Mod(_, ref b) => &**b)),
}
Expand Down
40 changes: 36 additions & 4 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ use std::sync::Arc;

use owning_ref::{OwningRef, Erased};

use grammar::{self, Statement, Expr, AssignTarget, Template as Tpl};
use grammar::OutputMode::{self, Preserve, Strip, Space};
use preparser::Syntax::Oneline;
use grammar::{self, Statement, Expr, AssignTarget, Template as Tpl};
use number::{self, Number};
use owning::{Own, ExprCode};
use preparser::Syntax::Oneline;
use render_error::{RenderError, DataError};
use vars::{UNDEFINED, TRUE, FALSE, Val, VarRef};
use varmap::{Context, SubContext, set, get};
use vars::{UNDEFINED, TRUE, FALSE, Val, VarRef};
use {Pos, Variable, Var};


Expand Down Expand Up @@ -65,6 +66,34 @@ fn nothing<'x, 'y, 'render: 'x>(n: &'x Rc<()>, _: &SubContext<'y, 'render>)
n.clone()
}

fn operator<'x, 'render: 'x>(op: fn(Number, Number) -> VarRef<'render>,
a: &OwningRef<Rc<Arc<Tpl>>, Expr>, b: &OwningRef<Rc<Arc<Tpl>>, Expr>,
r: &mut Renderer, root: &SubContext<'x, 'render>)
-> VarRef<'render>
{
let left = eval_expr(r, root, a);
let right = eval_expr(r, root, b);
match (left.as_number(), right.as_number()) {
(Ok(a), Ok(b)) => {
op(a, b)
}
(Ok(_), Err(eb)) => {
r.errors.push((b.position.0, eb));
left
}
(Err(ea), Ok(_)) => {
r.errors.push((a.position.0, ea));
right
}
(Err(ea), Err(eb)) => {
r.errors.push((a.position.0, ea));
r.errors.push((b.position.0, eb));
OwningRef::new(nothing(&r.nothing, root))
.map(|_| UNDEFINED as &Variable)
}
}
}

fn eval_expr<'x, 'render: 'x>(r: &mut Renderer, root: &SubContext<'x, 'render>,
expr: &OwningRef<Rc<Arc<Tpl>>, Expr>)
-> VarRef<'render>
Expand Down Expand Up @@ -102,6 +131,9 @@ fn eval_expr<'x, 'render: 'x>(r: &mut Renderer, root: &SubContext<'x, 'render>,
Err(v) => v,
}
}
ExprCode::Add(ref a, ref b) => {
operator(number::add, a, b, r, root)
}
ExprCode::And(ref a, ref b) => {
let left = eval_expr(r, root, a);
match left.as_bool() {
Expand Down Expand Up @@ -179,7 +211,7 @@ fn eval_expr<'x, 'render: 'x>(r: &mut Renderer, root: &SubContext<'x, 'render>,
}
}
},
_ => unimplemented!(),
x => panic!("Unimplemented oper {:?}", x),
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/tests/math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use {Variable, Parser, Context};

fn render_x_y<A, B>(template: &str, x: A, y: B) -> String
where A: for<'x> Variable<'x>, B: for<'x> Variable<'x>
{
let tpl = Parser::new().parse(template).unwrap();
let mut vars: Context = Context::new();
vars.set("x", &x);
vars.set("y", &y);
tpl.render(&vars).unwrap()
}

#[test]
fn render_plus_same_types() {
assert_eq!(render_x_y("{{ x + y }}", 1u32, 1u32), "2");
assert_eq!(render_x_y("{{ x + y }}", 10u64, 7u64), "17");
assert_eq!(render_x_y("{{ x + y }}", 10i64, -1i64), "9");
assert_eq!(render_x_y("{{ x + y }}", 1.5f64, -1f64), "0.5");
}

#[test]
fn render_plus_different_types() {
assert_eq!(render_x_y("{{ x + y }}", 1u32, 1f64), "2");
assert_eq!(render_x_y("{{ x + y }}", 10u64, 7u64), "17");
assert_eq!(render_x_y("{{ x + y }}", 10u64, -1i64), "9");
assert_eq!(render_x_y("{{ x + y }}", 1.5f64, -1i64), "0.5");
assert_eq!(render_x_y("{{ x + y }}", 10u64, -100i64), "-90");
assert_eq!(render_x_y("{{ x + y }}", -100i64, 10i64), "-90");
}
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ mod parse;
mod oneline;
mod vars;
mod boolean;
mod math;

pub use self::diff::assert_eq;

0 comments on commit 307e3b6

Please sign in to comment.