FEATURE: Add the %% modulo operator.

This commit is contained in:
Jeremy Wall 2019-02-18 21:09:42 -06:00
parent de97109681
commit c7a87894ba
5 changed files with 54 additions and 3 deletions

View File

@ -61,4 +61,14 @@ assert {
assert { assert {
ok = (1 == 1) || (1 != 1) == true, ok = (1 == 1) || (1 != 1) == true,
desc = "(1 == 1) && (1 != 1) == true", desc = "(1 == 1) && (1 != 1) == true",
};
assert {
ok = 4 %% 2 == 0,
desc = "4 %% 2 is 0",
};
assert {
ok = 4 %% 3 == 1,
desc = "4 %% 3 is 1",
}; };

View File

@ -392,6 +392,7 @@ pub enum BinaryExprType {
Sub, Sub,
Mul, Mul,
Div, Div,
Mod,
// Boolean // Boolean
AND, AND,
OR, OR,
@ -433,6 +434,7 @@ impl BinaryExprType {
// Product operators are next tightly bound // Product operators are next tightly bound
BinaryExprType::Mul => 4, BinaryExprType::Mul => 4,
BinaryExprType::Div => 4, BinaryExprType::Div => 4,
BinaryExprType::Mod => 4,
// Boolean operators bind tighter than math // Boolean operators bind tighter than math
BinaryExprType::AND => 5, BinaryExprType::AND => 5,
BinaryExprType::OR => 5, BinaryExprType::OR => 5,

View File

@ -613,6 +613,33 @@ impl<'a> FileBuilder<'a> {
} }
} }
fn mod_vals(
&self,
lpos: &Position,
rpos: &Position,
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<dyn Error>> {
match *left {
Val::Int(i) => {
eval_binary_expr!(&Val::Int(ii), rpos, right, Val::Int(i % ii), "Integer")
}
Val::Float(f) => {
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f % ff), "Float")
}
ref expr => {
return Err(Box::new(error::BuildError::new(
format!(
"{} does not support the 'modulus' operation",
expr.type_name()
),
error::ErrorType::Unsupported,
lpos.clone(),
)));
}
}
}
fn divide_vals( fn divide_vals(
&self, &self,
lpos: &Position, lpos: &Position,
@ -964,6 +991,7 @@ impl<'a> FileBuilder<'a> {
&BinaryExprType::Sub => self.subtract_vals(&def.pos, def.right.pos(), left, right), &BinaryExprType::Sub => self.subtract_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Mul => self.multiply_vals(&def.pos, def.right.pos(), left, right), &BinaryExprType::Mul => self.multiply_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Div => self.divide_vals(&def.pos, def.right.pos(), left, right), &BinaryExprType::Div => self.divide_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Mod => self.mod_vals(&def.pos, def.right.pos(), left, right),
// Handle Comparison operators here // Handle Comparison operators here
&BinaryExprType::Equal => self.do_deep_equal(def.right.pos(), left, right), &BinaryExprType::Equal => self.do_deep_equal(def.right.pos(), left, right),
&BinaryExprType::GT => self.do_gt(&def.right.pos(), left, right), &BinaryExprType::GT => self.do_gt(&def.right.pos(), left, right),

View File

@ -59,7 +59,10 @@ make_fn!(
(Element::Op(BinaryExprType::Mul))), (Element::Op(BinaryExprType::Mul))),
do_each!( do_each!(
_ => punct!("/"), _ => punct!("/"),
(Element::Op(BinaryExprType::Div))) (Element::Op(BinaryExprType::Div))),
do_each!(
_ => punct!("%%"),
(Element::Op(BinaryExprType::Mod)))
) )
); );
@ -175,6 +178,9 @@ fn parse_product_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
&BinaryExprType::Div => { &BinaryExprType::Div => {
return Result::Complete(i_.clone(), op.clone()); return Result::Complete(i_.clone(), op.clone());
} }
&BinaryExprType::Mod => {
return Result::Complete(i_.clone(), op.clone());
}
_other => { _other => {
// noop // noop
} }
@ -423,9 +429,9 @@ pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Ex
); );
Result::Fail(err) Result::Fail(err)
} }
Result::Abort(_e) => { Result::Abort(e) => {
let err = Error::new( let err = Error::new(
"Abort while parsing operator expression", format!("Abort while parsing operator expression\n{}", e),
Box::new(rest.clone()), Box::new(rest.clone()),
); );
Result::Abort(err) Result::Abort(err)

View File

@ -198,6 +198,10 @@ make_fn!(slashtok<OffsetStrIter, Token>,
do_text_token_tok!(TokenType::PUNCT, "/") do_text_token_tok!(TokenType::PUNCT, "/")
); );
make_fn!(modulustok<OffsetStrIter, Token>,
do_text_token_tok!(TokenType::PUNCT, "%%")
);
make_fn!(pcttok<OffsetStrIter, Token>, make_fn!(pcttok<OffsetStrIter, Token>,
do_text_token_tok!(TokenType::PUNCT, "%") do_text_token_tok!(TokenType::PUNCT, "%")
); );
@ -403,6 +407,7 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
startok, startok,
comment, // Note comment must come before slashtok comment, // Note comment must come before slashtok
slashtok, slashtok,
modulustok,
pcttok, pcttok,
eqeqtok, eqeqtok,
notequaltok, notequaltok,