<commit_before>use actor::Actor;
use actor::ActorView;
use actor;

static PI : f32 = 3.14159265359;

#[deriving(Show, Clone, PartialEq)]
pub struct Spaceship{
    id: i32,
    x: f32,
    y: f32,
    accX: f32,
    accY: f32,
    rotation: f32,
    is_accelerating: bool,
    is_decelerating: bool,
    is_rotating_right: bool,
    is_rotating_left: bool,
    shape: Vec<f32>,
    acc: f32,
    is_alive:bool,
    color: Vec<f32>,
    shield: bool,
    normal_color : Vec<f32>,
    normal_shape : Vec<f32>,
    fire_countdown: i32,
    shield_timer: uint,
    shield_max_time: uint,
    secondary_shape: Vec<f32>,
    secondary_color: Vec<f32>
}

impl Spaceship{
    pub fn new(id: i32, x: i32, y: i32, rotation: f32) -> Spaceship {
        let shape = vec!(
            0.0, 0.05,
            0.025, -0.05,
            0.0, -0.025,

            0.0, -0.025,
            -0.025, -0.05,
            0.0, 0.05
        );

        let secondary_shape = vec!(
            0.0, -0.025,
            0.015, -0.04,
            0.0,  -0.07,

            0.0, -0.07,
            -0.015, -0.04,
            0.0, -0.025
        );

        let secondary_color = vec!(1.0, 1.0, 0.7);

        let acc = 1.05;

        let color = vec!(0.5, 0.2, 0.2);

        Spaceship{
            id: id, x: x as f32, y: y as f32,
            rotation: rotation, accX: 0.0, accY: 0.0,
            is_accelerating: false, is_decelerating: false,
            is_rotating_right: false, is_rotating_left: false,
            shape: shape.clone(),
            normal_shape: shape.clone(),
            acc: acc,
            is_alive: true,
            color: color.clone(),
            normal_color: color.clone(),
            shield: false,
            fire_countdown: 0,
            shield_timer: 100,
            shield_max_time: 100,
            secondary_color: secondary_color,
            secondary_shape: secondary_shape
        }
    }

    pub fn set_color(&mut self, c: Vec<f32>){
        self.normal_color = c.clone();
        self.color = c;
    }

    fn begin_increase_throttle(&mut self){
        self.is_accelerating = true;
    }
    fn stop_increase_throttle(&mut self){
        self.is_accelerating = false;
    }

    fn begin_decrease_throttle(&mut self){
        self.is_decelerating = true;
    }
    fn stop_decrease_throttle(&mut self){
        self.is_decelerating = false;
    }

    fn begin_rotate_right(&mut self){
        self.is_rotating_right = true;
    }

    fn stop_rotate_right(&mut self){
        self.is_rotating_right = false;
    }

    fn begin_rotate_left(&mut self){
        self.is_rotating_left = true;
    }
    fn stop_rotate_left(&mut self){
        self.is_rotating_left = false;
    }

    fn accelerate(&mut self){
        let acc = self.acc;

        let (dirx, diry) = self.get_rotate_vec();
        self.accX += acc * dirx;
        self.accY += acc * diry;
        self.is_decelerating = false;
    }
    fn decelerate(&mut self){
        let acc = 0.8;

        let (dirx, diry) = self.get_rotate_vec();

        self.accX -= acc * dirx;
        self.accY -= acc * diry;
    }

    fn slow_down(&mut self){

        self.accX *= 0.992;
        self.accY *= 0.992;

        if self.accX < 0.005 && self.accX > -0.005 {
            self.accX = 0.0;
        }

        if self.accY < 0.005 && self.accY > -0.005 {
            self.accY = 0.0;
        }
    }

    fn rotate(&mut self, direction : i32){
        self.rotation += (direction * 5) as f32;
    }

    fn get_rotate_vec(&mut self) -> (f32, f32){
        let r = (self.rotation * PI) / 180.0;
        (r.sin(), r.cos())
    }

    fn shield_up(&mut self){

        if self.shield_timer < 1 {
            return;
        }

        self.shield = true;
        self.color = vec!(0.75, 0.85, 0.5);
        self.shape = vec!(
            0.0, 0.05,
            0.04, -0.05,
            0.0, -0.03,

            0.0, -0.03,
            -0.04, -0.05,
            0.0, 0.05
        );
    }

    fn shield_down(&mut self){
        self.shield = false;
        self.color = self.normal_color.clone();
        self.shape = self.normal_shape.clone();
    }
}

impl Actor for Spaceship{

    fn update(&mut self){
        if self.is_accelerating {
            self.accelerate();
        }

        if self.is_decelerating{
            self.decelerate();
        }

        if self.is_rotating_left {
            self.rotate(-1);
        }

        if self.is_rotating_right {
            self.rotate(1);
        }

        self.y += self.accY;
        self.x += self.accX;

        self.slow_down();

        if self.fire_countdown > 0 {
            self.fire_countdown -= 1;
        }

        if self.shield {
            if self.shield_timer > 0 {
                self.shield_timer -= 1;
            } else {
                self.shield_down();
            }
        } else if self.shield_timer < self.shield_max_time {
            self.shield_timer += 1;
        }

    }

    fn get_view(&self) -> ActorView {
        ActorView {
            id: self.id,
            parent: 0,
            x: self.x,
            y: self.y,
            width: 50.0,
            height: 100.0,
            rotation: (self.rotation * PI) / 180.0,
            shape: self.shape.clone(),
            color: self.color.clone(),
            collision_type: actor::Collide,
            show_secondary: self.is_accelerating,
            secondary_shape: Some(self.secondary_shape.clone()),
            secondary_color: Some(self.secondary_color.clone())
        }
    }

    fn execute(&mut self, message: &str, output_messages:&mut Vec<(&str, ActorView)>){
        match message {
            "begin_increase_throttle"   => self.begin_increase_throttle(),
            "begin_decrease_throttle"   => self.begin_decrease_throttle(),
            "stop_increase_throttle"    => self.stop_increase_throttle(),
            "stop_decrease_throttle"    => self.stop_decrease_throttle(),
            "begin_rotate_right"        => self.begin_rotate_right(),
            "begin_rotate_left"         => self.begin_rotate_left(),
            "stop_rotate_right"         => self.stop_rotate_right(),
            "stop_rotate_left"          => self.stop_rotate_left(),
            "fire"                      => {
                                            if self.fire_countdown == 0{
                                                output_messages.push(("fire", self.get_view().clone()));
                                                self.fire_countdown = 20;
                                            }
                                        },
            "collide"                   => {
                                            if !self.shield {
                                                self.is_alive = false;
                                                output_messages.push(("explode", self.get_view().clone()));
                                            }
                                        },
            "collect"                   => output_messages.push(("collect", self.get_view().clone())),
            "shield_up"                 => self.shield_up(),
            "shield_down"               => self.shield_down(),
            _                           => ()
        };
    }

    fn kill(&mut self){
        self.is_alive = false;
    }

    fn get_id(&self) -> i32{
        self.id
    }

    fn is_alive(&self) -> bool{
        self.is_alive
    }

}<commit_msg>playing with thrust colours<commit_after>use actor::Actor;
use actor::ActorView;
use actor;
use std::rand;
use std::rand::Rng;

static PI : f32 = 3.14159265359;

#[deriving(Show, Clone, PartialEq)]
pub struct Spaceship{
    id: i32,
    x: f32,
    y: f32,
    accX: f32,
    accY: f32,
    rotation: f32,
    is_accelerating: bool,
    is_decelerating: bool,
    is_rotating_right: bool,
    is_rotating_left: bool,
    shape: Vec<f32>,
    acc: f32,
    is_alive:bool,
    color: Vec<f32>,
    shield: bool,
    normal_color : Vec<f32>,
    normal_shape : Vec<f32>,
    fire_countdown: i32,
    shield_timer: uint,
    shield_max_time: uint,
    secondary_shape: Vec<f32>,
    secondary_shape_1: Vec<f32>,
    secondary_shape_2: Vec<f32>,
    secondary_color: Vec<f32>,
    thrust_timer: uint
}

impl Spaceship{
    pub fn new(id: i32, x: i32, y: i32, rotation: f32) -> Spaceship {
        let shape = vec!(
            0.0, 0.05,
            0.025, -0.05,
            0.0, -0.025,

            0.0, -0.025,
            -0.025, -0.05,
            0.0, 0.05
        );

        let secondary_shape = vec!(
            0.0, -0.025,
            0.015, -0.04,
            0.0,  -0.07,

            0.0, -0.07,
            -0.015, -0.04,
            0.0, -0.025
        );

        let secondary_shape2 = vec!(
            0.0, -0.025,
            0.012, -0.03,
            0.0,  -0.04,

            0.0, -0.04,
            -0.012, -0.03,
            0.0, -0.025
        );

        let secondary_color = vec!(1.0, 1.0, 0.7);

        let acc = 1.05;

        let color = vec!(0.5, 0.2, 0.2);

        Spaceship{
            id: id, x: x as f32, y: y as f32,
            rotation: rotation, accX: 0.0, accY: 0.0,
            is_accelerating: false, is_decelerating: false,
            is_rotating_right: false, is_rotating_left: false,
            shape: shape.clone(),
            normal_shape: shape.clone(),
            acc: acc,
            is_alive: true,
            color: color.clone(),
            normal_color: color.clone(),
            shield: false,
            fire_countdown: 0,
            shield_timer: 100,
            shield_max_time: 100,
            secondary_color: secondary_color,
            secondary_shape: secondary_shape.clone(),
            secondary_shape_1: secondary_shape.clone(),
            secondary_shape_2: secondary_shape2,
            thrust_timer: 0
        }
    }

    pub fn set_color(&mut self, c: Vec<f32>){
        self.normal_color = c.clone();
        self.color = c;
    }

    fn begin_increase_throttle(&mut self){
        self.is_accelerating = true;
        self.secondary_shape = self.secondary_shape_1.clone();
        self.thrust_timer = 0;
    }
    fn stop_increase_throttle(&mut self){
        self.is_accelerating = false;
        self.secondary_shape = self.secondary_shape_2.clone();
    }

    fn begin_decrease_throttle(&mut self){
        self.is_decelerating = true;
    }
    fn stop_decrease_throttle(&mut self){
        self.is_decelerating = false;
    }

    fn begin_rotate_right(&mut self){
        self.is_rotating_right = true;
    }

    fn stop_rotate_right(&mut self){
        self.is_rotating_right = false;
    }

    fn begin_rotate_left(&mut self){
        self.is_rotating_left = true;
    }
    fn stop_rotate_left(&mut self){
        self.is_rotating_left = false;
    }

    fn accelerate(&mut self){
        let acc = self.acc;

        let (dirx, diry) = self.get_rotate_vec();
        self.accX += acc * dirx;
        self.accY += acc * diry;
        self.is_decelerating = false;
    }
    fn decelerate(&mut self){
        let acc = 0.8;

        let (dirx, diry) = self.get_rotate_vec();

        self.accX -= acc * dirx;
        self.accY -= acc * diry;
    }

    fn slow_down(&mut self){

        self.accX *= 0.992;
        self.accY *= 0.992;

        if self.accX < 0.005 && self.accX > -0.005 {
            self.accX = 0.0;
        }

        if self.accY < 0.005 && self.accY > -0.005 {
            self.accY = 0.0;
        }
    }

    fn rotate(&mut self, direction : i32){
        self.rotation += (direction * 5) as f32;
    }

    fn get_rotate_vec(&mut self) -> (f32, f32){
        let r = (self.rotation * PI) / 180.0;
        (r.sin(), r.cos())
    }

    fn shield_up(&mut self){

        if self.shield_timer < 1 {
            return;
        }

        self.shield = true;
        self.color = vec!(0.75, 0.85, 0.5);
        self.shape = vec!(
            0.0, 0.05,
            0.04, -0.05,
            0.0, -0.03,

            0.0, -0.03,
            -0.04, -0.05,
            0.0, 0.05
        );
    }

    fn shield_down(&mut self){
        self.shield = false;
        self.color = self.normal_color.clone();
        self.shape = self.normal_shape.clone();
    }
}

impl Actor for Spaceship{

    fn update(&mut self){
        if self.is_accelerating {
            self.accelerate();
            let r1 = rand::task_rng().gen_range(0.8f32, 1.0);
            let r2 = rand::task_rng().gen_range(0.0f32, 1.0);
            self.secondary_color = vec!(r1, r1, r2);
        }else {
            self.thrust_timer += 1;
        }

        if self.is_decelerating{
            self.decelerate();
        }

        if self.is_rotating_left {
            self.rotate(-1);
        }

        if self.is_rotating_right {
            self.rotate(1);
        }

        self.y += self.accY;
        self.x += self.accX;

        self.slow_down();

        if self.fire_countdown > 0 {
            self.fire_countdown -= 1;
        }

        if self.shield {
            if self.shield_timer > 0 {
                self.shield_timer -= 1;
            } else {
                self.shield_down();
            }
        } else if self.shield_timer < self.shield_max_time {
            self.shield_timer += 1;
        }

    }

    fn get_view(&self) -> ActorView {
        ActorView {
            id: self.id,
            parent: 0,
            x: self.x,
            y: self.y,
            width: 50.0,
            height: 100.0,
            rotation: (self.rotation * PI) / 180.0,
            shape: self.shape.clone(),
            color: self.color.clone(),
            collision_type: actor::Collide,
            show_secondary: self.is_accelerating || self.thrust_timer < 5,
            secondary_shape: Some(self.secondary_shape.clone()),
            secondary_color: Some(self.secondary_color.clone())
        }
    }

    fn execute(&mut self, message: &str, output_messages:&mut Vec<(&str, ActorView)>){
        match message {
            "begin_increase_throttle"   => self.begin_increase_throttle(),
            "begin_decrease_throttle"   => self.begin_decrease_throttle(),
            "stop_increase_throttle"    => self.stop_increase_throttle(),
            "stop_decrease_throttle"    => self.stop_decrease_throttle(),
            "begin_rotate_right"        => self.begin_rotate_right(),
            "begin_rotate_left"         => self.begin_rotate_left(),
            "stop_rotate_right"         => self.stop_rotate_right(),
            "stop_rotate_left"          => self.stop_rotate_left(),
            "fire"                      => {
                                            if self.fire_countdown == 0{
                                                output_messages.push(("fire", self.get_view().clone()));
                                                self.fire_countdown = 20;
                                            }
                                        },
            "collide"                   => {
                                            if !self.shield {
                                                self.is_alive = false;
                                                output_messages.push(("explode", self.get_view().clone()));
                                            }
                                        },
            "collect"                   => output_messages.push(("collect", self.get_view().clone())),
            "shield_up"                 => self.shield_up(),
            "shield_down"               => self.shield_down(),
            _                           => ()
        };
    }

    fn kill(&mut self){
        self.is_alive = false;
    }

    fn get_id(&self) -> i32{
        self.id
    }

    fn is_alive(&self) -> bool{
        self.is_alive
    }

}<|endoftext|>


<commit_before>use regex::Regex;
use std::collections::BTreeMap;
use serialize::json::{Json, ToJson};
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

lazy_static! {
    static ref PARENT_REGEX: Regex = Regex::new(r"^([^][]+)").unwrap();
    static ref CHILD_REGEX: Regex = Regex::new(r"(\[[^][]*\])").unwrap();
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split("&") {
        let separator = part.find("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = &part[..pos];
                let val = &part[(pos + 1)..];
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1).unwrap()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.at(1).unwrap()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

trait StrExt {
    fn _slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str;
}

impl StrExt for str {
    fn _slice_chars(&self, begin: usize, end: usize) -> &str {
        assert!(begin <= end);
        let mut count = 0;
        let mut begin_byte = None;
        let mut end_byte = None;

        // This could be even more efficient by not decoding,
        // only finding the char boundaries
        for (idx, _) in self.char_indices() {
            if count == begin { begin_byte = Some(idx); }
            if count == end { end_byte = Some(idx); break; }
            count += 1;
        }
        if begin_byte.is_none() && count == begin { begin_byte = Some(self.len()) }
        if end_byte.is_none() && count == end { end_byte = Some(self.len()) }

        match (begin_byte, end_byte) {
            (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
            (_, None) => panic!("slice_chars: `end` is beyond end of string"),
            (Some(a), Some(b)) => unsafe { self.slice_unchecked(a, b) }
        }
    }
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        key._slice_chars(1, key.len()-1)
    } else {
        key
    }
}

fn create_idx_merger(idx: usize, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return Json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert(key, obj);
    return Json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key == "[]" {
            let mut new_array = create_array();
            let item = apply_object(&keys[1..], val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key);
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(&keys[1..], val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(&keys[1..], val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: BTreeMap<String,Json> = BTreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").ok().unwrap().to_string(), r#"{"0":"foo"}"#.to_string());
    assert_eq!(parse("a[<=>]==23").ok().unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string());
    assert_eq!(parse(" foo = bar = baz ").ok().unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string());
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").ok().unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c&a=d&a=e").ok().unwrap().to_string(),
        r#"{"a":["b","c","d","e"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").ok().unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").ok().unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").ok().unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").ok().unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").ok().unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").ok().unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").ok().unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}
<commit_msg>refactor(parser): remove StrExt from the library, use [x..y] instead<commit_after>use regex::Regex;
use std::collections::BTreeMap;
use serialize::json::{Json, ToJson};
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

lazy_static! {
    static ref PARENT_REGEX: Regex = Regex::new(r"^([^][]+)").unwrap();
    static ref CHILD_REGEX: Regex = Regex::new(r"(\[[^][]*\])").unwrap();
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split("&") {
        let separator = part.find("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = &part[..pos];
                let val = &part[(pos + 1)..];
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1).unwrap()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.at(1).unwrap()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        &key[1..(key.len()-1)]
    } else {
        key
    }
}

fn create_idx_merger(idx: usize, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return Json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert(key, obj);
    return Json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key == "[]" {
            let mut new_array = create_array();
            let item = apply_object(&keys[1..], val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key);
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(&keys[1..], val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(&keys[1..], val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: BTreeMap<String,Json> = BTreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").ok().unwrap().to_string(), r#"{"0":"foo"}"#.to_string());
    assert_eq!(parse("a[<=>]==23").ok().unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string());
    assert_eq!(parse(" foo = bar = baz ").ok().unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string());
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").ok().unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c&a=d&a=e").ok().unwrap().to_string(),
        r#"{"a":["b","c","d","e"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").ok().unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").ok().unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").ok().unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").ok().unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").ok().unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").ok().unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").ok().unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}
<|endoftext|>


<commit_before>//! The parser is based on the following grammar
//!
//! Expression ==> Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function OpenDelim Equation CloseDelim
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  OpenDelim Equation CloseDelim
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "π" | "e" | "phi" | "ϕ" | "ans"
//!
//! OpenDelim  ==> "(" | "[" | "{"
//!
//! CloseDelim ==> ")" | "]" | "}"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::OpKind as AstOp;
//use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use token::Token;
use token::OpKind as TokOp;
use token::TokVal;
use token::TokVal::*;
use token::DelimKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        let eq = try!(self.parse_equation());
        if self.toks_empty() {
            Ok(eq)
        } else if self.next_tok_is(Op(TokOp::Assign)) {
            self.consume_tok();
            if let AstVal::Name(_) = eq.val {
                let rhs = try!(self.parse_equation());
                Ok(Ast {
                    val: AstVal::Op(AstOp::Assign),
                    span: (eq.span.0, rhs.span.1),
                    branches: vec!(eq, rhs)
                })
            } else {
                let assign_target = match eq {
                    Ast { val: AstVal::Func(_), span: _, branches: _ } => "function",
                    Ast { val: AstVal::Const(_), span: _, branches: _ } => "constant",
                    Ast { val: AstVal::Num(_), span: _, branches: _ } => "number",
                    Ast { val: AstVal::LastResult, span: _, branches: _ } => "constant",
                    _ => "equtation", // TODO: Make this case more nuanced
                };
                Err(CalcrError {
                    desc: format!("Cannot assign to {}", assign_target),
                    span: Some(eq.get_total_span()),
                })
            }
        } else {
            let tok = self.consume_tok();
            Err(CalcrError {
                desc: "Expected operator".to_string(),
                span: Some(tok.span),
            })
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(TokOp::Plus) || *val == Op(TokOp::Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap().into()),
                span: tok_span,
                branches: vec!(lhs, rhs),
            }
        }
        if self.next_tok_matches(|val| val.is_close_delim()) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(TokOp::Mult) || *val == Op(TokOp::Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap().into()),
                span: tok_span,
                branches: vec!(lhs, rhs),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(TokOp::Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(AstOp::Neg),
                span: tok_span,
                branches: vec!(rhs),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(TokOp::Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(AstOp::Pow),
                    span: tok_span,
                    branches: vec!(lhs, rhs),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(TokOp::Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(AstOp::Fact),
                span: tok_span,
                branches: vec!(out),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_matches(|val| val.is_open_delim()) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_number());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: vec!(arg) ,
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening delimiter after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: vec!(),
                        })
                    }
                },
                OpenDelim(kind) => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(CloseDelim(kind)) {
                        Err(CalcrError {
                            desc: "Missing matching closing delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: vec!(eq),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: vec!(eq),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: vec!(),
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_tokens(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_tokens(toks);
        assert!(err.is_err());
    }
}<commit_msg>Fix mistake in error output<commit_after>//! The parser is based on the following grammar
//!
//! Expression ==> Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function OpenDelim Equation CloseDelim
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  OpenDelim Equation CloseDelim
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "π" | "e" | "phi" | "ϕ" | "ans"
//!
//! OpenDelim  ==> "(" | "[" | "{"
//!
//! CloseDelim ==> ")" | "]" | "}"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::OpKind as AstOp;
//use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use token::Token;
use token::OpKind as TokOp;
use token::TokVal;
use token::TokVal::*;
use token::DelimKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        let eq = try!(self.parse_equation());
        if self.toks_empty() {
            Ok(eq)
        } else if self.next_tok_is(Op(TokOp::Assign)) {
            self.consume_tok();
            if let AstVal::Name(_) = eq.val {
                let rhs = try!(self.parse_equation());
                Ok(Ast {
                    val: AstVal::Op(AstOp::Assign),
                    span: (eq.span.0, rhs.span.1),
                    branches: vec!(eq, rhs)
                })
            } else {
                let assign_target = match eq {
                    Ast { val: AstVal::Func(_), span: _, branches: _ } => "function",
                    Ast { val: AstVal::Const(_), span: _, branches: _ } => "constant",
                    Ast { val: AstVal::Num(_), span: _, branches: _ } => "number",
                    Ast { val: AstVal::LastResult, span: _, branches: _ } => "constant",
                    _ => "equtation", // TODO: Make this case more nuanced
                };
                Err(CalcrError {
                    desc: format!("Cannot assign to {}", assign_target),
                    span: Some(eq.get_total_span()),
                })
            }
        } else {
            let tok = self.consume_tok();
            Err(CalcrError {
                desc: "Expected operator".to_string(),
                span: Some(tok.span),
            })
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(TokOp::Plus) || *val == Op(TokOp::Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap().into()),
                span: tok_span,
                branches: vec!(lhs, rhs),
            }
        }
        if self.next_tok_matches(|val| val.is_close_delim()) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing matching opening delimiter"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(TokOp::Mult) || *val == Op(TokOp::Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap().into()),
                span: tok_span,
                branches: vec!(lhs, rhs),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(TokOp::Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(AstOp::Neg),
                span: tok_span,
                branches: vec!(rhs),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(TokOp::Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(AstOp::Pow),
                    span: tok_span,
                    branches: vec!(lhs, rhs),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(TokOp::Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(AstOp::Fact),
                span: tok_span,
                branches: vec!(out),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_matches(|val| val.is_open_delim()) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_number());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: vec!(arg) ,
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening delimiter after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: vec!(),
                        })
                    }
                },
                OpenDelim(kind) => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(CloseDelim(kind)) {
                        Err(CalcrError {
                            desc: "Missing matching closing delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: vec!(eq),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: vec!(eq),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: vec!(),
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_tokens(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_tokens(toks);
        assert!(err.is_err());
    }
}<|endoftext|>


<commit_before>use std::fmt;
use parser_combinators::*;
use parser_combinators::primitives::{State, Stream};

// Main entry point for the parser
pub fn parse(input: &str) -> Result<(Expr, &str), ParseError<char>> {
    return parser(term).parse(input);
}

// The type which defines our expression primitives (numbers and operators basically)
#[derive(Debug, PartialEq)]
pub enum Expr {
    Number(f64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Pow(Box<Expr>, Box<Expr>)
}
// For pretty printing, we implement the Display trait for Expr,
// currently we're not pretty printing the parsed expression tree,
// but we could easily if we wanted to thanks to this
impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Number(ref i)       => write!(f, "{}", i),
            Expr::Plus(ref l, ref r)  => write!(f, "{} + {}", l, r),
            Expr::Minus(ref l, ref r) => write!(f, "{} - {}", l, r),
            Expr::Mul(ref l, ref r)   => write!(f, "{} * {}", l, r),
            Expr::Div(ref l, ref r)   => write!(f, "{} / {}", l, r),
            Expr::Pow(ref l, ref r)   => write!(f, "{}^{}", l, r)
        }
    }
}

// Parser which extracts a signed integer value from the input string
fn number<'a, I>(input: State<I>) -> ParseResult<f64, I>
    where I: Stream<Item=char> {
    let (((negation, whole), fractional), input) = try!(optional(char('-'))
                            .and(many1::<String, _>(digit()))
                            .and(optional(char('.').and(many1::<String, _>(digit()))))
                            .expected("number")
                            .parse_state(input));

    // Build whole number
    let mut n = 0;
    for c in whole.chars() {
        n = n * 10 + (c as i64 - '0' as i64)
    }
    // Build fractional part
    let mut m = 0;
    let mut precision = 0;
    match fractional {
        Some((_, f)) => {
            for c in f.chars() {
                precision = precision + 1u32;
                m = m * 10 + (c as i64 - '0' as i64);
            }
        }
        None => ()
    }
    // Add fractional part to whole if present
    let mut number = n as f64;
    if precision > 0 {
        number = number + (m as f64 / (10i64.pow(precision) as f64));
    }
    number = match negation {
        Some(_) => number * -1f64,
        None    => number
    };
    Ok((number, input))
}

// Parser which extracts an expression from the input string, where an expression
// is any signed integer or parenthized sub-expression, with whitespace ignored.
#[allow(unconditional_recursion)]
fn expr(input: State<&str>) -> ParseResult<Expr, &str> {
    let spaces     = spaces();
    let number     = parser(number);
    let paren_expr = between(char('('), char(')'), parser(term)).expected("(");

    spaces.clone()
          .with(number.map(Expr::Number).or(paren_expr))
          .skip(spaces)
          .parse_state(input)
}

// Parser which extracts terms, where a term is an operator surrounded by two operands.
fn term(input: State<&str>) -> ParseResult<Expr, &str> {
    fn pow(l: Expr, r: Expr)   -> Expr { Expr::Pow(Box::new(l), Box::new(r)) }
    fn mul(l: Expr, r: Expr)   -> Expr { Expr::Mul(Box::new(l), Box::new(r)) }
    fn div(l: Expr, r: Expr)   -> Expr { Expr::Div(Box::new(l), Box::new(r)) }
    fn plus(l: Expr, r: Expr)  -> Expr { Expr::Plus(Box::new(l), Box::new(r)) }
    fn minus(l: Expr, r: Expr) -> Expr { Expr::Minus(Box::new(l), Box::new(r)) }

    let exp      = char('^').map(|_| pow);
    let multiply = char('*').map(|_| mul);
    let divide   = char('/').map(|_| div);
    let add      = char('+').map(|_| plus);
    let subtract = char('-').map(|_| minus);
    return chainl1(chainl1(chainl1(chainl1(chainl1(parser(expr), exp), multiply), divide), add), subtract)
        .parse_state(input);
}
<commit_msg>Update comment on number parser<commit_after>use std::fmt;
use parser_combinators::*;
use parser_combinators::primitives::{State, Stream};

// Main entry point for the parser
pub fn parse(input: &str) -> Result<(Expr, &str), ParseError<char>> {
    return parser(term).parse(input);
}

// The type which defines our expression primitives (numbers and operators basically)
#[derive(Debug, PartialEq)]
pub enum Expr {
    Number(f64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Pow(Box<Expr>, Box<Expr>)
}
// For pretty printing, we implement the Display trait for Expr,
// currently we're not pretty printing the parsed expression tree,
// but we could easily if we wanted to thanks to this
impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Number(ref i)       => write!(f, "{}", i),
            Expr::Plus(ref l, ref r)  => write!(f, "{} + {}", l, r),
            Expr::Minus(ref l, ref r) => write!(f, "{} - {}", l, r),
            Expr::Mul(ref l, ref r)   => write!(f, "{} * {}", l, r),
            Expr::Div(ref l, ref r)   => write!(f, "{} / {}", l, r),
            Expr::Pow(ref l, ref r)   => write!(f, "{}^{}", l, r)
        }
    }
}

// Parser which extracts a signed integer or floating point value from the input string
fn number<'a, I>(input: State<I>) -> ParseResult<f64, I>
    where I: Stream<Item=char> {
    let (((negation, whole), fractional), input) = try!(optional(char('-'))
                            .and(many1::<String, _>(digit()))
                            .and(optional(char('.').and(many1::<String, _>(digit()))))
                            .expected("number")
                            .parse_state(input));

    // Build whole number
    let mut n = 0;
    for c in whole.chars() {
        n = n * 10 + (c as i64 - '0' as i64)
    }
    // Build fractional part
    let mut m = 0;
    let mut precision = 0;
    match fractional {
        Some((_, f)) => {
            for c in f.chars() {
                precision = precision + 1u32;
                m = m * 10 + (c as i64 - '0' as i64);
            }
        }
        None => ()
    }
    // Add fractional part to whole if present
    let mut number = n as f64;
    if precision > 0 {
        number = number + (m as f64 / (10i64.pow(precision) as f64));
    }
    number = match negation {
        Some(_) => number * -1f64,
        None    => number
    };
    Ok((number, input))
}

// Parser which extracts an expression from the input string, where an expression
// is any signed integer or parenthized sub-expression, with whitespace ignored.
#[allow(unconditional_recursion)]
fn expr(input: State<&str>) -> ParseResult<Expr, &str> {
    let spaces     = spaces();
    let number     = parser(number);
    let paren_expr = between(char('('), char(')'), parser(term)).expected("(");

    spaces.clone()
          .with(number.map(Expr::Number).or(paren_expr))
          .skip(spaces)
          .parse_state(input)
}

// Parser which extracts terms, where a term is an operator surrounded by two operands.
fn term(input: State<&str>) -> ParseResult<Expr, &str> {
    fn pow(l: Expr, r: Expr)   -> Expr { Expr::Pow(Box::new(l), Box::new(r)) }
    fn mul(l: Expr, r: Expr)   -> Expr { Expr::Mul(Box::new(l), Box::new(r)) }
    fn div(l: Expr, r: Expr)   -> Expr { Expr::Div(Box::new(l), Box::new(r)) }
    fn plus(l: Expr, r: Expr)  -> Expr { Expr::Plus(Box::new(l), Box::new(r)) }
    fn minus(l: Expr, r: Expr) -> Expr { Expr::Minus(Box::new(l), Box::new(r)) }

    let exp      = char('^').map(|_| pow);
    let multiply = char('*').map(|_| mul);
    let divide   = char('/').map(|_| div);
    let add      = char('+').map(|_| plus);
    let subtract = char('-').map(|_| minus);
    return chainl1(chainl1(chainl1(chainl1(chainl1(parser(expr), exp), multiply), divide), add), subtract)
        .parse_state(input);
}
<|endoftext|>


<commit_before>use nom::{  IResult,
            be_u8,be_u16,
            be_i32,be_f32,
            ErrorKind,Err};

pub enum ConstEntry {
    Utf8(Utf8Constant),
    Integer(IntegerConstant),
    Float(FloatConstant),
//    Long(LongConstant),
//    Double(DoubleConstant),
    Class(ClassConstant),
    String(StringConstant),
    FieldRef(FieldRefConstant),
    MethodRef(MethodRefConstant),
    InterfaceMethodRef(InterfaceMethodRefConstant),
    NameAndType(NameAndTypeConstant),
//    MethodHandle(MethodHandleConstant),
//    MethodType(MethodTypeConstant),
//    InvokeDynamic(InvokeDynamicConstant),
}

impl ConstEntry {
    pub fn to_string(&self) -> String {
        match *self {
            /*
             * For all of the below matches, a reference to
             * the underlying struct must be used; this is because we have
             * borrowed self, and thus cannot take
             * ownership of anything owned by self.
             */
            ConstEntry::Utf8(ref s) => format!(
                "Utf8Constant[utf8_string=\"{}\"]", s.utf8_string),
            ConstEntry::Integer(ref s) => format!(
                "IntegerConstant[value=\"{}\"]", s.value),
            ConstEntry::Float(ref s) => format!(
                "FloatConstant[value=\"{}\"]", s.value),
            ConstEntry::Class(ref s) => format!(
                "ClassConstant[name_index={}]", s.name_index),
            ConstEntry::String(ref s) => format!(
                "StringConstant[string_index={}]", s.string_index),
            ConstEntry::FieldRef(ref s) => format!(
                "FieldRefConstant[class_index={}, name_and_type_index={}]",
                    s.class_index, s.name_and_type_index),
            ConstEntry::MethodRef(ref s) => format!(
                "MethodRefConstant[class_index={}, name_and_type_index={}]",
                    s.class_index, s.name_and_type_index),
            ConstEntry::InterfaceMethodRef(ref s) => format!(
                "InterfaceMethodRefConstant[class_index={}, name_and_type_index={}]",
                    s.class_index, s.name_and_type_index),
            ConstEntry::NameAndType(ref s) => format!(
                "NameAndTypeConstant[name_index={}, descriptor_index={}]",
                    s.name_index, s.descriptor_index),
        }
    }
}

pub struct Utf8Constant {
    pub utf8_string: String,
}

pub struct IntegerConstant {
    pub value: i32,
}
pub struct FloatConstant {
    pub value: f32,
}

pub struct ClassConstant {
    pub name_index: u16,
}

pub struct StringConstant {
    pub string_index: u16,
}

pub struct FieldRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct MethodRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct InterfaceMethodRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct NameAndTypeConstant {
    pub name_index: u16,
    pub descriptor_index: u16,
}

pub struct ClassFile {
    pub minor_version: u16,
    pub major_version: u16,
    pub const_pool_size: u16,
    pub const_pool: Vec<ConstEntry>,
    pub access_flags: u16,
    pub this_class: u16,
    pub super_class: u16,
    pub interfaces_count: u16,
//     pub interfaces[interfaces_count]: u16,
//     pub fields_count: u16,
//     pub fields[fields_count]: u16,
//     pub methods_count: u16,
//     pub methods[methods_count]: u16,
//     pub attributes_count: u16,
//     pub attributes[attributes_count]: u16,
}

named!(magic_ident, tag!(&[0xCA, 0xFE, 0xBA, 0xBE]));

named!(const_utf8<&[u8], ConstEntry>, chain!(
    // tag!([0x01]) ~
    length: be_u16 ~
    utf8_str: take_str!(length),
    || {
        ConstEntry::Utf8(
            Utf8Constant {
                utf8_string: utf8_str.to_owned(),
            }
        )
    }
));

named!(const_integer<&[u8], ConstEntry>, chain!(
    // tag!([0x03]) ~
    value: be_i32,
    || {
        ConstEntry::Integer(
            IntegerConstant {
                value: value,
            }
        )
    }
));

named!(const_float<&[u8], ConstEntry>, chain!(
    // tag!([0x04]) ~
    value: be_f32,
    || {
        ConstEntry::Float(
            FloatConstant {
                value: value,
            }
        )
    }
));

named!(const_class<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x07]) ~
    name_index: be_u16,
    || {
        ConstEntry::Class(
            ClassConstant {
                name_index: name_index,
            }
        )
    }
));

named!(const_string<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x08]) ~
    string_index: be_u16,
    || {
        ConstEntry::String(
            StringConstant {
                string_index: string_index,
            }
        )
    }
));

named!(const_field_ref<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x09]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        ConstEntry::FieldRef(
            FieldRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_method_ref<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x0A]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        ConstEntry::MethodRef(
            MethodRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_interface_method_ref<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x0B]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        ConstEntry::InterfaceMethodRef(
            InterfaceMethodRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_name_and_type<&[u8], ConstEntry>, chain!(
    // tag: tag!([0x0C]) ~
    name_index: be_u16 ~
    descriptor_index: be_u16,
    || {
        ConstEntry::NameAndType(
            NameAndTypeConstant {
                name_index: name_index,
                descriptor_index: descriptor_index,
            }
        )
    }
));

pub fn parse_const(input: &[u8]) -> IResult<&[u8], ConstEntry> {
    chain!(input,
        const_type: be_u8 ~
        const_block: apply!(const_block, const_type),
        || {
            const_block
        }
    )
}
pub fn const_block(input: &[u8], const_type: u8) -> IResult<&[u8], ConstEntry> {
    match const_type {
        1 => const_utf8(input),
        3 => const_integer(input),
        4 => const_float(input),
        // // 5 => //CONSTANT_Long,
        // // 6 => //CONSTANT_Double,
        7 => const_class(input),
        8 => const_string(input),
        9 => const_field_ref(input),
        10 => const_method_ref(input),
        11 => const_interface_method_ref(input),
        12 => const_name_and_type(input),
        // // 15 => //CONSTANT_MethodHandle,
        // // 16 => //CONSTANT_MethodType,
        // // 18 => //CONSTANT_InvokeDynamic,
        _ => IResult::Error(Err::Position(ErrorKind::Alt, input)),
    }
}

// TODO - This is a bitmask op, flag u16 matches multiple of these, how to stoe in class spec?
pub enum AccessFlags {
    Public,     // 	0x0001 	Declared public; may be accessed from outside its package.
    Final,      // 	0x0010 	Declared final; no subclasses allowed.
    Super,      // 	0x0020 	Treat superclass methods specially when invoked by the invokespecial instruction.
    Interface,  // 	0x0200 	Is an interface, not a class.
    Abstract,   // 	0x0400 	Declared abstract; must not be instantiated.
    Synthetic,  // 	0x1000 	Declared synthetic; not present in the source code.
    Annotation, // 	0x2000 	Declared as an annotation type.
    Enum,       // 	0x4000 	Declared as an enum type
}

pub fn parse_classfile(input: &[u8]) -> IResult<&[u8], ClassFile> {
  chain!(input,
    magic_ident ~
    minor_version: be_u16 ~
    major_version: be_u16 ~
    const_pool_size: be_u16 ~
    const_pool: count!(parse_const, (const_pool_size - 1) as usize) ~
    access_flags: be_u16 ~
    this_class: be_u16 ~
    super_class: be_u16 ~
    interfaces_count: be_u16,
    || {
        ClassFile {
            minor_version: minor_version,
            major_version: major_version,
            const_pool_size: const_pool_size,
            const_pool: const_pool,
            access_flags: access_flags,
            this_class: this_class,
            super_class: super_class,
            interfaces_count: interfaces_count,
        }
    }
  )
}

#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../assets/SimpleMath.class");
    let res = parse_classfile(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count);
            println!("Constant pool:");
            let mut const_index = 1;
            for f in &c.const_pool {
                println!("\t[{}] = {}", const_index, f.to_string());
                const_index += 1;
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../assets/malformed.class");
    let res = parse_classfile(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

#[test]
fn test_constant_utf8() {
    let hello_world_data = &[
        // 0x01, // tag = 1
        0x00, 0x0C, // length = 12
        0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
    ];
    let res = const_utf8(hello_world_data);

    match res {
        IResult::Done(_, c) =>
        match c {
            ConstEntry::Utf8(ref s) =>
                 println!("Valid UTF8 const: {}", s.utf8_string),
            _ => panic!("It's a const, but of what type?")
        },
        _ => panic!("Not a UTF type const?"),
    };
}
<commit_msg>Stubbed field implementation and general refactoring<commit_after>use nom::{  IResult,
            be_u8,be_u16,
            be_i32,be_f32,
            ErrorKind,Err};

pub struct ClassFile {
    pub minor_version: u16,
    pub major_version: u16,
    pub const_pool_size: u16,
    pub const_pool: Vec<Constant>,
    pub access_flags: u16,
    pub this_class: u16,
    pub super_class: u16,
    pub interfaces_count: u16,
    pub interfaces: Vec<u16>,
    pub fields_count: u16,
    pub fields: Vec<FieldInfo>,
//     pub methods_count: u16,
//     pub methods[methods_count]: u16,
//     pub attributes_count: u16,
//     pub attributes[attributes_count]: u16,
}

named!(magic_ident, tag!(&[0xCA, 0xFE, 0xBA, 0xBE]));

// TODO - NP - Move this lot to a constants mod
pub enum Constant {
    Utf8(Utf8Constant),
    Integer(IntegerConstant),
    Float(FloatConstant),
//    Long(LongConstant),
//    Double(DoubleConstant),
    Class(ClassConstant),
    String(StringConstant),
    FieldRef(FieldRefConstant),
    MethodRef(MethodRefConstant),
    InterfaceMethodRef(InterfaceMethodRefConstant),
    NameAndType(NameAndTypeConstant),
//    MethodHandle(MethodHandleConstant),
//    MethodType(MethodTypeConstant),
//    InvokeDynamic(InvokeDynamicConstant),
}

impl Constant {
    pub fn to_string(&self) -> String {
        match *self {
            Constant::Utf8(ref s) => format!("Utf8Constant[utf8_string=\"{}\"]", s.utf8_string),
            Constant::Integer(ref s) => format!("IntegerConstant[value=\"{}\"]", s.value),
            Constant::Float(ref s) => format!("FloatConstant[value=\"{}\"]", s.value),
            Constant::Class(ref s) => format!("ClassConstant[name_index={}]", s.name_index),
            Constant::String(ref s) => format!("StringConstant[string_index={}]", s.string_index),
            Constant::FieldRef(ref s) => format!("FieldRefConstant[class_index={}, name_and_type_index={}]", s.class_index, s.name_and_type_index),
            Constant::MethodRef(ref s) => format!("MethodRefConstant[class_index={}, name_and_type_index={}]", s.class_index, s.name_and_type_index),
            Constant::InterfaceMethodRef(ref s) => format!("InterfaceMethodRefConstant[class_index={}, name_and_type_index={}]", s.class_index, s.name_and_type_index),
            Constant::NameAndType(ref s) => format!("NameAndTypeConstant[name_index={}, descriptor_index={}]", s.name_index, s.descriptor_index),
        }
    }
}

pub struct Utf8Constant {
    pub utf8_string: String,
}

pub struct IntegerConstant {
    pub value: i32,
}
pub struct FloatConstant {
    pub value: f32,
}

pub struct ClassConstant {
    pub name_index: u16,
}

pub struct StringConstant {
    pub string_index: u16,
}

pub struct FieldRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct MethodRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct InterfaceMethodRefConstant {
    pub class_index: u16,
    pub name_and_type_index: u16,
}

pub struct NameAndTypeConstant {
    pub name_index: u16,
    pub descriptor_index: u16,
}

named!(const_utf8<&[u8], Constant>, chain!(
    // tag!([0x01]) ~
    length: be_u16 ~
    utf8_str: take_str!(length),
    || {
        Constant::Utf8(
            Utf8Constant {
                utf8_string: utf8_str.to_owned(),
            }
        )
    }
));

named!(const_integer<&[u8], Constant>, chain!(
    // tag!([0x03]) ~
    value: be_i32,
    || {
        Constant::Integer(
            IntegerConstant {
                value: value,
            }
        )
    }
));

named!(const_float<&[u8], Constant>, chain!(
    // tag!([0x04]) ~
    value: be_f32,
    || {
        Constant::Float(
            FloatConstant {
                value: value,
            }
        )
    }
));

named!(const_class<&[u8], Constant>, chain!(
    // tag: tag!([0x07]) ~
    name_index: be_u16,
    || {
        Constant::Class(
            ClassConstant {
                name_index: name_index,
            }
        )
    }
));

named!(const_string<&[u8], Constant>, chain!(
    // tag: tag!([0x08]) ~
    string_index: be_u16,
    || {
        Constant::String(
            StringConstant {
                string_index: string_index,
            }
        )
    }
));

named!(const_field_ref<&[u8], Constant>, chain!(
    // tag: tag!([0x09]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        Constant::FieldRef(
            FieldRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_method_ref<&[u8], Constant>, chain!(
    // tag: tag!([0x0A]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        Constant::MethodRef(
            MethodRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_interface_method_ref<&[u8], Constant>, chain!(
    // tag: tag!([0x0B]) ~
    class_index: be_u16 ~
    name_and_type_index: be_u16,
    || {
        Constant::InterfaceMethodRef(
            InterfaceMethodRefConstant {
                class_index: class_index,
                name_and_type_index: name_and_type_index,
            }
        )
    }
));

named!(const_name_and_type<&[u8], Constant>, chain!(
    // tag: tag!([0x0C]) ~
    name_index: be_u16 ~
    descriptor_index: be_u16,
    || {
        Constant::NameAndType(
            NameAndTypeConstant {
                name_index: name_index,
                descriptor_index: descriptor_index,
            }
        )
    }
));

pub fn parse_const(input: &[u8]) -> IResult<&[u8], Constant> {
    chain!(input,
        const_type: be_u8 ~
        const_block: apply!(const_block, const_type),
        || {
            const_block
        }
    )
}
pub fn const_block(input: &[u8], const_type: u8) -> IResult<&[u8], Constant> {
    match const_type {
        1 => const_utf8(input),
        3 => const_integer(input),
        4 => const_float(input),
        // // 5 => //CONSTANT_Long,
        // // 6 => //CONSTANT_Double,
        7 => const_class(input),
        8 => const_string(input),
        9 => const_field_ref(input),
        10 => const_method_ref(input),
        11 => const_interface_method_ref(input),
        12 => const_name_and_type(input),
        // // 15 => //CONSTANT_MethodHandle,
        // // 16 => //CONSTANT_MethodType,
        // // 18 => //CONSTANT_InvokeDynamic,
        _ => IResult::Error(Err::Position(ErrorKind::Alt, input)),
    }
}

// TODO - This is a bitmask op, flag u16 matches multiple of these, how to stoe in class spec?
pub enum AccessFlags {
    Public,     // 	0x0001 	Declared public; may be accessed from outside its package.
    Final,      // 	0x0010 	Declared final; no subclasses allowed.
    Super,      // 	0x0020 	Treat superclass methods specially when invoked by the invokespecial instruction.
    Interface,  // 	0x0200 	Is an interface, not a class.
    Abstract,   // 	0x0400 	Declared abstract; must not be instantiated.
    Synthetic,  // 	0x1000 	Declared synthetic; not present in the source code.
    Annotation, // 	0x2000 	Declared as an annotation type.
    Enum,       // 	0x4000 	Declared as an enum type
}

pub struct FieldInfo {
    access_flags: u16,
    name_index: u16,
    descriptor_index: u16,
    attributes_count: u16,
    // attributes: Vec<attribute_info>,
}
pub fn parse_field(input: &[u8]) -> IResult<&[u8], FieldInfo> {
    chain!(input,
        access_flags: be_u16 ~
        name_index: be_u16 ~
        descriptor_index: be_u16 ~
        attributes_count: be_u16,
        || {
            if attributes_count > 0 {
                panic!("Attr count > 0  on field but attrs not implemented yet!");
                /*
The attributes defined by this specification as appearing in the attributes table of a field_info structure are ConstantValue (§4.7.2), Synthetic (§4.7.8), Signature (§4.7.9), Deprecated (§4.7.15), RuntimeVisibleAnnotations (§4.7.16) and RuntimeInvisibleAnnotations (§4.7.17).

A Java Virtual Machine implementation must recognize and correctly read ConstantValue (§4.7.2) attributes found in the attributes table of a field_info structure. If a Java Virtual Machine implementation recognizes class files whose version number is 49.0 or above, it must recognize and correctly read Signature (§4.7.9), RuntimeVisibleAnnotations (§4.7.16) and RuntimeInvisibleAnnotations (§4.7.17) attributes found in the attributes table of a field_info structure of a class file whose version number is 49.0 or above.

A Java Virtual Machine implementation is required to silently ignore any or all attributes that it does not recognize in the attributes table of a field_info structure. Attributes not defined in this specification are not allowed to affect the semantics of the class file, but only to provide additional descriptive information (§4.7.1).
                */
            }
            FieldInfo {
                access_flags: access_flags,
                name_index: name_index,
                descriptor_index: descriptor_index,
                attributes_count: attributes_count,
            }
        }
    )
}

pub fn parse_classfile(input: &[u8]) -> IResult<&[u8], ClassFile> {
  chain!(input,
    magic_ident ~
    minor_version: be_u16 ~
    major_version: be_u16 ~
    const_pool_size: be_u16 ~
    const_pool: count!(parse_const, (const_pool_size - 1) as usize) ~
    access_flags: be_u16 ~
    this_class: be_u16 ~
    super_class: be_u16 ~
    interfaces_count: be_u16 ~
    interfaces: count!(be_u16, interfaces_count as usize) ~
    fields_count: be_u16 ~
    fields: count!(parse_field, fields_count as usize),
    || {
        ClassFile {
            minor_version: minor_version,
            major_version: major_version,
            const_pool_size: const_pool_size,
            const_pool: const_pool,
            access_flags: access_flags,
            this_class: this_class,
            super_class: super_class,
            interfaces_count: interfaces_count,
            interfaces: interfaces,
            fields_count: fields_count,
            fields: fields,
        }
    }
  )
}

#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../assets/BasicClass.class");
    let res = parse_classfile(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({}), fields({})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count, c.fields_count);
            println!("Constant pool:");
            let mut const_index = 1;
            for f in &c.const_pool {
                println!("\t[{}] = {}", const_index, f.to_string());
                const_index += 1;
            }
            println!("Interfaces:");
            let mut interface_index = 0;
            for i in &c.interfaces {
                println!("\t[{}] = const[{}] = {}", interface_index, i, c.const_pool[(i-1) as usize].to_string());
                interface_index += 1;
            }
            println!("Fields:");
            let mut field_index = 0;
            for f in &c.fields {
                println!("\t[{}] Name(const[{}] = {})", field_index, f.name_index, c.const_pool[(f.name_index - 1) as usize].to_string());
                field_index += 1;
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../assets/malformed.class");
    let res = parse_classfile(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

#[test]
fn test_constant_utf8() {
    let hello_world_data = &[
        // 0x01, // tag = 1
        0x00, 0x0C, // length = 12
        0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
    ];
    let res = const_utf8(hello_world_data);

    match res {
        IResult::Done(_, c) =>
        match c {
            Constant::Utf8(ref s) =>
                 println!("Valid UTF8 const: {}", s.utf8_string),
            _ => panic!("It's a const, but of what type?")
        },
        _ => panic!("Not a UTF type const?"),
    };
}
<|endoftext|>


<commit_before>//! This crate provides the `#[quickcheck]` attribute. Its use is
//! documented in the `quickcheck` crate.

#![crate_name = "quickcheck_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/quickcheck")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, Modifier};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

use rustc::plugin::Registry;

/// For the `#[quickcheck]` attribute. Do not use.
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("quickcheck"),
                                  Modifier(box expand_meta_quickcheck));
}

/// Expands the `#[quickcheck]` attribute.
///
/// Expands:
/// ```
/// #[quickcheck]
/// fn check_something(_: uint) -> bool {
///     true
/// }
/// ```
/// to:
/// ```
/// #[test]
/// fn check_something() {
///     fn check_something(_: uint) -> bool {
///         true
///     }
///     ::quickcheck::quickcheck(check_something)
/// }
/// ```
fn expand_meta_quickcheck(cx: &mut ExtCtxt,
                          span: codemap::Span,
                          _: &ast::MetaItem,
                          item: P<ast::Item>) -> P<ast::Item> {
    match item.node {
        ast::ItemFn(..) | ast::ItemStatic(..) => {
            // Copy original function without attributes
            let prop = P(ast::Item {attrs: Vec::new(), ..(*item).clone()});
            // ::quickcheck::quickcheck
            let check_ident = token::str_to_ident("quickcheck");
            let check_path = vec!(check_ident, check_ident);
            // Wrap original function in new outer function, calling ::quickcheck::quickcheck()
            let fn_decl = P(codemap::respan(span, ast::DeclItem(prop.clone())));
            let inner_fn = P(codemap::respan(span, ast::StmtDecl(fn_decl, ast::DUMMY_NODE_ID)));
            let inner_ident = cx.expr_ident(span, prop.ident);
            let check_call = cx.expr_call_global(span, check_path, vec![inner_ident]);
            let body = cx.block(span, vec![inner_fn], Some(check_call));
            let test = cx.item_fn(span, item.ident, Vec::new(), cx.ty_nil(), body);

            // Copy attributes from original function
            let mut attrs = item.attrs.clone();
            // Add #[test] attribute
            attrs.push(cx.attribute(span, cx.meta_word(span, token::intern_and_get_ident("test"))));
            // Attach the attributes to the outer function
            P(ast::Item {attrs: attrs, ..(*test).clone()})
        },
        _ => {
            cx.span_err(span, "#[quickcheck] only supported on statics and functions");
            item
        }
    }
}
<commit_msg>fix macro: `TyNil` has been removed, use zero-length `TyTup`<commit_after>//! This crate provides the `#[quickcheck]` attribute. Its use is
//! documented in the `quickcheck` crate.

#![crate_name = "quickcheck_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/quickcheck")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, Modifier};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

use rustc::plugin::Registry;

/// For the `#[quickcheck]` attribute. Do not use.
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("quickcheck"),
                                  Modifier(box expand_meta_quickcheck));
}

/// Expands the `#[quickcheck]` attribute.
///
/// Expands:
/// ```
/// #[quickcheck]
/// fn check_something(_: uint) -> bool {
///     true
/// }
/// ```
/// to:
/// ```
/// #[test]
/// fn check_something() {
///     fn check_something(_: uint) -> bool {
///         true
///     }
///     ::quickcheck::quickcheck(check_something)
/// }
/// ```
fn expand_meta_quickcheck(cx: &mut ExtCtxt,
                          span: codemap::Span,
                          _: &ast::MetaItem,
                          item: P<ast::Item>) -> P<ast::Item> {
    match item.node {
        ast::ItemFn(..) | ast::ItemStatic(..) => {
            // Copy original function without attributes
            let prop = P(ast::Item {attrs: Vec::new(), ..(*item).clone()});
            // ::quickcheck::quickcheck
            let check_ident = token::str_to_ident("quickcheck");
            let check_path = vec!(check_ident, check_ident);
            // Wrap original function in new outer function, calling ::quickcheck::quickcheck()
            let fn_decl = P(codemap::respan(span, ast::DeclItem(prop.clone())));
            let inner_fn = P(codemap::respan(span, ast::StmtDecl(fn_decl, ast::DUMMY_NODE_ID)));
            let inner_ident = cx.expr_ident(span, prop.ident);
            let check_call = cx.expr_call_global(span, check_path, vec![inner_ident]);
            let body = cx.block(span, vec![inner_fn], Some(check_call));
            let nil = P(ast::Ty {
                id: ast::DUMMY_NODE_ID,
                node: ast::TyTup(vec![]),
                span: codemap::DUMMY_SP,
            });
            let test = cx.item_fn(span, item.ident, Vec::new(), nil, body);

            // Copy attributes from original function
            let mut attrs = item.attrs.clone();
            // Add #[test] attribute
            attrs.push(cx.attribute(span, cx.meta_word(span, token::intern_and_get_ident("test"))));
            // Attach the attributes to the outer function
            P(ast::Item {attrs: attrs, ..(*test).clone()})
        },
        _ => {
            cx.span_err(span, "#[quickcheck] only supported on statics and functions");
            item
        }
    }
}
<|endoftext|>