feat: ordering operators
This commit is contained in:
parent
519fa4ee99
commit
c2b95dfee4
4 changed files with 98 additions and 0 deletions
|
@ -155,6 +155,66 @@ pub fn core_environment() -> Rc<Environment> {
|
|||
Ok(Expression::Boolean(false).into())
|
||||
}),
|
||||
),
|
||||
(
|
||||
"<",
|
||||
Expression::NativeFunc(|args| {
|
||||
if args.len() != 2 {
|
||||
Err(Error::MismatchedArgCount(2, args.len()))?
|
||||
}
|
||||
|
||||
let less_than = match (args[0].borrow(), args[1].borrow()) {
|
||||
(Expression::Int(lhs), Expression::Int(rhs)) => lhs < rhs,
|
||||
_ => Err(Error::ExpectedNumber)?,
|
||||
};
|
||||
|
||||
Ok(Expression::Boolean(less_than).into())
|
||||
}),
|
||||
),
|
||||
(
|
||||
">",
|
||||
Expression::NativeFunc(|args| {
|
||||
if args.len() != 2 {
|
||||
Err(Error::MismatchedArgCount(2, args.len()))?
|
||||
}
|
||||
|
||||
let greater_than = match (args[0].borrow(), args[1].borrow()) {
|
||||
(Expression::Int(lhs), Expression::Int(rhs)) => lhs > rhs,
|
||||
_ => Err(Error::ExpectedNumber)?,
|
||||
};
|
||||
|
||||
Ok(Expression::Boolean(greater_than).into())
|
||||
}),
|
||||
),
|
||||
(
|
||||
"<=",
|
||||
Expression::NativeFunc(|args| {
|
||||
if args.len() != 2 {
|
||||
Err(Error::MismatchedArgCount(2, args.len()))?
|
||||
}
|
||||
|
||||
let less_than_equal = match (args[0].borrow(), args[1].borrow()) {
|
||||
(Expression::Int(lhs), Expression::Int(rhs)) => lhs <= rhs,
|
||||
_ => Err(Error::ExpectedNumber)?,
|
||||
};
|
||||
|
||||
Ok(Expression::Boolean(less_than_equal).into())
|
||||
}),
|
||||
),
|
||||
(
|
||||
">=",
|
||||
Expression::NativeFunc(|args| {
|
||||
if args.len() != 2 {
|
||||
Err(Error::MismatchedArgCount(2, args.len()))?
|
||||
}
|
||||
|
||||
let greater_than_equal = match (args[0].borrow(), args[1].borrow()) {
|
||||
(Expression::Int(lhs), Expression::Int(rhs)) => lhs >= rhs,
|
||||
_ => Err(Error::ExpectedNumber)?,
|
||||
};
|
||||
|
||||
Ok(Expression::Boolean(greater_than_equal).into())
|
||||
}),
|
||||
),
|
||||
// Branching
|
||||
(
|
||||
"if",
|
||||
|
|
|
@ -85,6 +85,8 @@ pub enum Error {
|
|||
ExpectedSymbol,
|
||||
#[error("expected list")]
|
||||
ExpectedList,
|
||||
#[error("expected number")]
|
||||
ExpectedNumber,
|
||||
#[error("expected {0} arguments, got {1}")]
|
||||
MismatchedArgCount(usize, usize),
|
||||
}
|
||||
|
@ -222,6 +224,17 @@ mod test {
|
|||
#[case("(not true)", "false")]
|
||||
#[case("(not nil)", "false")]
|
||||
#[case("(not 1)", "false")]
|
||||
// Ordering
|
||||
#[case("(< 1 2)", "true")]
|
||||
#[case("(< 2 1)", "false")]
|
||||
#[case("(> 1 2)", "false")]
|
||||
#[case("(> 2 1)", "true")]
|
||||
#[case("(<= 1 2)", "true")]
|
||||
#[case("(<= 1 1)", "true")]
|
||||
#[case("(<= 2 1)", "false")]
|
||||
#[case("(>= 2 1)", "true")]
|
||||
#[case("(>= 1 1)", "true")]
|
||||
#[case("(>= 1 2)", "false")]
|
||||
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||
let env = core_environment();
|
||||
let tokens = lexer::read(input).unwrap();
|
||||
|
|
20
src/lexer.rs
20
src/lexer.rs
|
@ -26,6 +26,11 @@ pub enum Token {
|
|||
Asterisk,
|
||||
Slash,
|
||||
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
LessThanEqual,
|
||||
GreaterThanEqual,
|
||||
|
||||
// Values
|
||||
Keyword(String),
|
||||
Int(i64),
|
||||
|
@ -97,6 +102,21 @@ fn next_token(input: &mut Peekable<Chars>) -> Result<Option<Token>> {
|
|||
'*' => Token::Asterisk,
|
||||
'/' => Token::Slash,
|
||||
|
||||
'<' => match input.peek() {
|
||||
Some('=') => {
|
||||
input.next();
|
||||
Token::LessThanEqual
|
||||
}
|
||||
_ => Token::LessThan,
|
||||
},
|
||||
'>' => match input.peek() {
|
||||
Some('=') => {
|
||||
input.next();
|
||||
Token::GreaterThanEqual
|
||||
}
|
||||
_ => Token::GreaterThan,
|
||||
},
|
||||
|
||||
'"' => read_string(input)?,
|
||||
':' => read_keyword(input),
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@ fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>
|
|||
Token::Asterisk => Node::Symbol("*".into()),
|
||||
Token::Slash => Node::Symbol("/".into()),
|
||||
|
||||
Token::LessThan => Node::Symbol("<".into()),
|
||||
Token::GreaterThan => Node::Symbol(">".into()),
|
||||
Token::LessThanEqual => Node::Symbol("<=".into()),
|
||||
Token::GreaterThanEqual => Node::Symbol(">=".into()),
|
||||
|
||||
Token::Keyword(val) => Node::Keyword(val),
|
||||
Token::Ident(val) => Node::Symbol(val),
|
||||
Token::String(val) => Node::String(val),
|
||||
|
|
Loading…
Reference in a new issue