Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bools #2

Merged
merged 2 commits into from Feb 9, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -1,8 +1,8 @@
use token::{Token, Opcode};
use token::{Token, Opcode, Type};
use runtime_error::RuntimeError;


pub fn eval(tokens: Vec<Token>) -> Result<isize, RuntimeError> {
pub fn eval(tokens: Vec<Token>) -> Result<Type, RuntimeError> {

// shift reduce parsing
// two operations
@@ -79,10 +79,10 @@ fn reduce<'a>(stack: &mut Vec<Token>) {
fn reduce_addition(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {
let operands = unwrap_operand_tokens(stack);
match operands {
Ok(operand_vec) => Ok(Token::Operand(
Ok(operand_vec) => Ok(Token::Operand(Type::Integer(
operand_vec
.iter()
.fold(0, |sum, value| sum + value))),
.fold(0, |sum, value| sum + value)))),
Err(_) => Err(RuntimeError{})
}
}
@@ -93,10 +93,10 @@ fn reduce_subtraction(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {
Ok(mut operand_vec) =>{
let initial_positive_option = operand_vec.pop();
if let Some(initial_positive) = initial_positive_option {
Ok(Token::Operand(
Ok(Token::Operand(Type::Integer(
operand_vec
.iter()
.fold(initial_positive, |sum, value| sum - value)))
.fold(initial_positive, |sum, value| sum - value))))
} else {
Err(RuntimeError{})
}
@@ -108,10 +108,10 @@ fn reduce_subtraction(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {
fn reduce_multiplication(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {
let operands = unwrap_operand_tokens(stack);
match operands {
Ok(operand_vec) => Ok(Token::Operand(
Ok(operand_vec) => Ok(Token::Operand(Type::Integer(
operand_vec
.iter()
.fold(1, |prod, value| prod * value))),
.fold(1, |prod, value| prod * value)))),
Err(_) => Err(RuntimeError{})
}
}
@@ -122,10 +122,10 @@ fn reduce_division(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {
Ok(mut operand_vec) =>{
let initial_numerator_option = operand_vec.pop();
if let Some(initial_numerator) = initial_numerator_option {
Ok(Token::Operand(
Ok(Token::Operand(Type::Integer(
operand_vec
.iter()
.fold(initial_numerator, |numerator, value| numerator / value)))
.fold(initial_numerator, |numerator, value| numerator / value))))
} else {
Err(RuntimeError{})
}
@@ -136,7 +136,7 @@ fn reduce_division(stack: &mut Vec<Token>) -> Result<Token, RuntimeError> {

fn unwrap_operand_tokens(tokens: &Vec<Token>) -> Result<Vec<isize>, RuntimeError> {
let result : Vec<isize> = tokens.iter().filter_map(|t| match *t {
Token::Operand(val) => Some(val),
Token::Operand(Type::Integer(val)) => Some(val),
_ => None,
})
.collect();
@@ -150,11 +150,11 @@ fn unwrap_operand_tokens(tokens: &Vec<Token>) -> Result<Vec<isize>, RuntimeError
#[test]
fn it_adds_arrays() {
let mut array = vec![
Token::Operand(1),
Token::Operand(2),
Token::Operand(3)
Token::Operand(Type::Integer(1)),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3))
];
let expected = Token::Operand(6);
let expected = Token::Operand(Type::Integer(6));
let actual = reduce_addition(&mut array).expect("Unexpected addition failure");
assert!(expected == actual);
}
@@ -164,11 +164,11 @@ fn it_evals_simple_stacks() {
let tokens = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(2),
Token::Operand(3),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3)),
Token::RightParen
];
let expected = 5;
let expected = Type::Integer(5);
let actual = eval(tokens).expect("Failed to eval valid simple addition");
assert!(expected == actual, "Eval failed on simple addition");
}
@@ -178,11 +178,11 @@ fn it_evals_simple_stacks_with_subtract() {
let tokens = vec![
Token::LeftParen,
Token::Operator(Opcode::Subtract),
Token::Operand(2),
Token::Operand(3),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3)),
Token::RightParen
];
let expected = -1;
let expected = Type::Integer(-1);
let actual = eval(tokens).expect("Failed to eval valid simple addition");
assert!(expected == actual, "Eval failed on simple addition");
}
@@ -192,16 +192,16 @@ fn it_handles_nested_addition() {
let tokens = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(2),
Token::Operand(3),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3)),
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(1),
Token::Operand(2),
Token::Operand(Type::Integer(1)),
Token::Operand(Type::Integer(2)),
Token::RightParen,
Token::RightParen
];
let expected = 8;
let expected = Type::Integer(8);
let actual = eval(tokens).expect("Failed to eval nested addition");
assert!(expected == actual, "Eval incorrect on nested addition");
}
@@ -211,16 +211,16 @@ fn it_handles_nested_addition_with_subrtraction() {
let tokens = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(2),
Token::Operand(3),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3)),
Token::LeftParen,
Token::Operator(Opcode::Subtract),
Token::Operand(1),
Token::Operand(2),
Token::Operand(Type::Integer(1)),
Token::Operand(Type::Integer(2)),
Token::RightParen,
Token::RightParen
];
let expected = 4;
let expected = Type::Integer(4);
let actual = eval(tokens).expect("Failed to eval nested addition");
assert!(expected == actual, "Eval incorrect on nested addition with subraction");
}
@@ -230,27 +230,27 @@ fn it_handles_nested_nonses_with_all_ops() {
let tokens = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(2),
Token::Operand(3),
Token::Operand(Type::Integer(2)),
Token::Operand(Type::Integer(3)),
Token::LeftParen,
Token::Operator(Opcode::Subtract),
Token::Operand(1),
Token::Operand(2),
Token::Operand(Type::Integer(1)),
Token::Operand(Type::Integer(2)),
Token::RightParen,
Token::LeftParen,
Token::Operator(Opcode::Multiply),
Token::LeftParen,
Token::Operator(Opcode::Divide),
Token::Operand(4),
Token::Operand(2),
Token::Operand(Type::Integer(4)),
Token::Operand(Type::Integer(2)),
Token::RightParen,
Token::Operand(3),
Token::Operand(Type::Integer(3)),
Token::RightParen,
Token::RightParen
];

// (+ 2 3 (- 1 2)(* (/ 4 2) 3)) == 10
let expected = 10;
let expected = Type::Integer(10);
let actual = eval(tokens).expect("Failed to eval complex expression");
assert!(expected == actual, "failed to get correct result for complex expression");
}
@@ -1,6 +1,6 @@

use nom;
use token::{Token,Opcode};
use token::{Token,Opcode,Type};
use tokenization_error::TokenizationError;
use std::str;

@@ -32,15 +32,31 @@ named!(division_sign<&[u8], Token>,
do_parse!(tag!("/") >> (Token::Operator(Opcode::Divide)))
);

named!(operand<&[u8], Token>,
named!(bool_literal_true<&[u8], Token>,
do_parse!(alt!(tag!("#t") | tag!("true")) >> (Token::Operand(Type::Bool(true))))
);

named!(bool_literal_false<&[u8], Token>,
do_parse!(alt!(tag!("#f") | tag!("false")) >> (Token::Operand(Type::Bool(false))))
);

named!(integer_literal<&[u8], Token>,
map!(nom::digit, parse_string_to_operand)
);

named!(operand<&[u8], Token>,
alt!(
bool_literal_true |
bool_literal_false |
integer_literal
)
);

fn parse_string_to_operand(slice: &[u8]) -> Token {
// I believe `unwrap()` is OK because the nom macro digit! shouldn't match anything
// that doesn't parse as an int.
let string = str::from_utf8(slice).unwrap();
Token::Operand(string.parse::<isize>().unwrap())
Token::Operand(Type::Integer(string.parse::<isize>().unwrap()))
}

named!(single_token<&[u8], Token>,
@@ -73,8 +89,8 @@ fn test_several_tokens() {
let expected = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(3),
Token::Operand(4),
Token::Operand(Type::Integer(3)),
Token::Operand(Type::Integer(4)),
Token::RightParen
];

@@ -88,8 +104,8 @@ fn test_several_tokens_with_long_numeric_token() {
let expected = vec![
Token::LeftParen,
Token::Operator(Opcode::Add),
Token::Operand(3),
Token::Operand(40_424),
Token::Operand(Type::Integer(3)),
Token::Operand(Type::Integer(40_424)),
Token::RightParen
];

@@ -104,7 +120,7 @@ fn test_single_token() {

#[test]
fn test_single_numeric_token() {
assert!(single_token(&b"4"[..]).to_result().expect("failed to parse token (") == Token::Operand(4isize));
assert!(single_token(&b"4"[..]).to_result().expect("failed to parse token (") == Token::Operand(Type::Integer(4isize)));
}

#[test]
@@ -139,5 +155,5 @@ fn division_sign_parser() {

#[test]
fn operand_parser() {
assert!(operand(&b"123"[..]).to_result().expect("failed to parse numeric operand") == Token::Operand(123isize));
assert!(operand(&b"123"[..]).to_result().expect("failed to parse numeric operand") == Token::Operand(Type::Integer(123isize)));
}
@@ -5,14 +5,19 @@ pub enum Token {
LeftParen,
RightParen,
Operator(Opcode),
Operand(isize)
Operand(Type),
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Opcode {
Add, Subtract, Multiply, Divide,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Type {
Bool(bool), Integer(isize)
}

impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@@ -30,7 +35,16 @@ impl fmt::Display for Token {
Token::LeftParen => write!(f, "Token:LeftParen"),
Token::RightParen => write!(f, "Token:RightParen"),
Token::Operator(code) => write!(f, "Token:Operator:{}", code),
Token::Operand(value) => write!(f, "Token:Operand:{}", value),
Token::Operand(operand) => write!(f, "Token:Operand:{}", operand),
}
}
}

impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Bool(b) => write!(f, "Bool:{}",b),
Type::Integer(int) => write!(f, "Integer:{}",int),
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.