<commit_before>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use rparser::*;

use ipsec_parser::*;
use num_traits::cast::FromPrimitive;

use nom::IResult;

#[derive(Debug,PartialEq)]
pub struct SimpleProposal {
    pub enc: u16,
    pub prf: u16,
    pub int: u16,
    pub dhg: u16,
    pub esn: u16,
}

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    pub client_proposals: Vec<SimpleProposal>,

    pub dh_group: Option<IkeTransformDHType>,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            IResult::Done(rem,ref hdr) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    IResult::Done(_,Ok(ref p)) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_client_proposals(prop);
                                    }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    self.dh_group = IkeTransformDHType::from_u16(kex.dh_group);
                                    // XXX if self.dh_group == None, raise decoder event
                                    debug!("KEX {}/{:?}", kex.dh_group, self.dh_group);
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e @ _ => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e @ _ => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            dh_group: None,
        }
    }

    fn add_client_proposals(&mut self, prop: &Vec<IkeV2Proposal>) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}",xform);
                let xty = IkeTransformType::from_u8(xform.transform_type);
                debug!("\ttype: {:?} / {}",xty,xform.transform_type);
                match xty {
                    Some(IkeTransformType::EncryptionAlgorithm) => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::PseudoRandomFunction) => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::IntegrityAlgorithm) => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::DiffieHellmanGroup) => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::ExtendedSequenceNumbers) => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType::from_u16(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {}",xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            // "uncompress" the IPsec ciphersuites proposals
            // Despite the apparent complexity, the number of transforms should be small.
            let mut prop_enc : Vec<u16> = Vec::new();
            let mut prop_prf : Vec<u16> = Vec::new();
            let mut prop_int : Vec<u16> = Vec::new();
            let mut prop_dhg : Vec<u16> = Vec::new();
            let mut prop_esn : Vec<u16> = Vec::new();
            for ref xform in &p.transforms {
                let xty = IkeTransformType::from_u8(xform.transform_type);
                match xty {
                    Some(IkeTransformType::EncryptionAlgorithm)     => prop_enc.push(xform.transform_id),
                    Some(IkeTransformType::PseudoRandomFunction)    => prop_prf.push(xform.transform_id),
                    Some(IkeTransformType::IntegrityAlgorithm)      => prop_int.push(xform.transform_id),
                    Some(IkeTransformType::DiffieHellmanGroup)      => prop_dhg.push(xform.transform_id),
                    Some(IkeTransformType::ExtendedSequenceNumbers) => prop_esn.push(xform.transform_id),
                    _ => (),
                }
            }
            if prop_int.len() == 0 { prop_int.push(IkeTransformAuthType::None as u16); }
            if prop_dhg.len() == 0 { prop_int.push(IkeTransformDHType::None as u16); }
            if prop_esn.len() == 0 { prop_esn.push(IkeTransformESNType::NoESN as u16); }
            for enc in &prop_enc {
                for prf in &prop_prf {
                    for int in &prop_int {
                        for dhg in &prop_dhg {
                            for esn in &prop_esn {
                                let item = SimpleProposal{
                                    enc:*enc,
                                    prf:*prf,
                                    int:*int,
                                    dhg:*dhg,
                                    esn:*esn,
                                };
                                if ! self.client_proposals.contains(&item) {
                                    self.client_proposals.push(item);
                                }
                            };
                        };
                    };
                };
            };
            debug!("Proposals: {:?}",self.client_proposals);
        }
    }
}

fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 2 { return false; }
    true
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);

<commit_msg>IKEv2: convert transforms without uncompressing them. Warn on weak or unknown transform<commit_after>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use rparser::*;

use ipsec_parser::*;
use num_traits::cast::FromPrimitive;

use nom::IResult;

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    pub client_proposals : Vec<IkeV2Transform>,

    pub dh_group: Option<IkeTransformDHType>,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            IResult::Done(rem,ref hdr) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    IResult::Done(_,Ok(ref p)) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_client_proposals(prop);
                                    }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    self.dh_group = IkeTransformDHType::from_u16(kex.dh_group);
                                    // XXX if self.dh_group == None, raise decoder event
                                    debug!("KEX {}/{:?}", kex.dh_group, self.dh_group);
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e @ _ => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e @ _ => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            dh_group: None,
        }
    }

    fn add_client_proposals(&mut self, prop: &Vec<IkeV2Proposal>) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}",xform);
                let xty = IkeTransformType::from_u8(xform.transform_type);
                debug!("\ttype: {:?} / {}",xty,xform.transform_type);
                match xty {
                    Some(IkeTransformType::EncryptionAlgorithm) => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::PseudoRandomFunction) => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::IntegrityAlgorithm) => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::DiffieHellmanGroup) => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::ExtendedSequenceNumbers) => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType::from_u16(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {}",xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            let client_proposals : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
            debug!("Client proposals\n{:?}",client_proposals);
            for prop in &client_proposals {
                match prop {
                    &IkeV2Transform::DH(ref dh) => {
                        match dh {
                            &IkeTransformDHType::Modp768 |
                            &IkeTransformDHType::Modp1024 |
                            &IkeTransformDHType::Modp1024s160 => {
                                warn!("Weak DH: {:?}", dh);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Unknown(tx_type,tx_id) => {
                        warn!("Unknown proposal: type={}, id={}", tx_type, tx_id);
                    },
                    _ => (),
                }
            }
            self.client_proposals = client_proposals;
        }
    }
}

fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 2 { return false; }
    true
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);

<|endoftext|>


<commit_before>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::CommonState;

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(reader: &mut R, pos: &mut u64) -> Result<Self> {
        let end_offset = try_read_le_u32!(*pos, reader);
        let num_properties = try_read_le_u32!(*pos, reader);
        let property_list_len = try_read_le_u32!(*pos, reader);
        let name_len = try_read_le_u8!(*pos, reader);
        Ok(NodeRecordHeader {
            end_offset: end_offset,
            num_properties: num_properties,
            property_list_len: property_list_len,
            name_len: name_len,
        })
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<commit_msg>Implement Binary FBX Parser a little<commit_after>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::CommonState;

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
    end_offset_stack: Vec<u32>,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
            end_offset_stack: vec![],
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        // Read a node record header.
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        self.end_offset_stack.push(node_record_header.end_offset);

        // Read properties.
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(reader: &mut R, pos: &mut u64) -> Result<Self> {
        let end_offset = try_read_le_u32!(*pos, reader);
        let num_properties = try_read_le_u32!(*pos, reader);
        let property_list_len = try_read_le_u32!(*pos, reader);
        let name_len = try_read_le_u8!(*pos, reader);
        Ok(NodeRecordHeader {
            end_offset: end_offset,
            num_properties: num_properties,
            property_list_len: property_list_len,
            name_len: name_len,
        })
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::slice::Iter;

use memory::Size;

use super::scope::{ScopeStack, TypeId, ArraySize};

/// Possible types for function arguments
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FuncArgType {
    /// A single value of the specified type
    Arg(TypeId),

    /// A single value that is an array containing the specified item type
    Array {
        item: TypeId,
        /// The exact, required size of the array argument
        /// If size is None, the function can dynamically handle any size, otherwise only this size
        /// will be accepted
        ///TODO: Remove the ability for this to be optional when slices and references are
        /// implemented since our dynamic handling any length of array will not work for most things
        size: Option<ArraySize>,
    },

    /// Zero or more values of the specified type
    /// If the type is None, that means that there is no specific type being required
    /// so any type can be passed as an argument
    /// No arguments are allowed in a Function type after a variadic argument. This is mostly
    /// unenforced at the moment. If a function breaks this rule, it will never match during call()
    ///TODO: This is mostly a hack to allow for generics before we support them. It would be nice
    /// to eventually implement this properly when #45 comes along
    Variadic(Option<TypeId>),
}

impl FuncArgType {
    /// Returns true if this function argument is an array with the given item type
    pub fn is_array_of(&self, target: TypeId) -> bool {
        match *self {
            FuncArgType::Array {item, ..} => item == target,
            _ => false,
        }
    }
}

/// An item is anything that can be declared
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ItemType {
    /// Unit type
    /// The unit type is a type with a single zero-size value.
    /// Both the type and the value are specified: ()
    Unit,

    /// A primitive type is a raw interpretation of some memory cells
    /// These primitive types are built-in and cannot be declared
    /// within the language itself
    Primitive(Size),

    /// A struct has a single definition with any number of
    /// fields and generics
    /// Structs can have impls which contain methods for that
    /// struct
    Struct {
        //TODO: fields, generics, etc.
    },

    /// A declaration of an array type, optionally specialized for the given item type
    Array {
        /// The type of the items stored in this array
        /// If this is None, this is the base, generic array type
        item: Option<TypeId>,
        /// The exact, required size of the array argument
        /// If size is None, this represents any size of array (i.e. the wildcard size `_`)
        ///TODO: Remove the ability for this to be optional when slices and references are
        /// implemented since our dynamic handling any length of array will not work for most things
        size: Option<ArraySize>,
    },

    /// Definition of a function's type
    Function {
        args: Vec<FuncArgType>,
        return_type: TypeId,
    },
}

impl ItemType {
    /// Computes the required size in cells of an *instance* of this type
    pub fn required_size(&self, scope: &ScopeStack) -> Size {
        match *self {
            ItemType::Unit => Size::default(),
            ItemType::Primitive(size) => size,
            ItemType::Struct { .. } => Size::default(), //TODO: Update this when fields are supported
            _ => unimplemented!(),
        }
    }

    /// Returns true if this item type matches the given function signature (args, return type)
    /// Returns false if this item type is not a function
    /// Note: Variadic matching is only done one-way
    ///
    /// That means that this will return false:
    ///     self = Function {args: [Arg(1)], return_type: 0}
    ///     expected_args = [Variadic(1)]
    ///     return_type = 0
    ///
    /// However, this will return true (as expected):
    ///     self = Function {args: [Variadic(1)], return_type: 0}
    ///     expected_args = [Arg(1)]
    ///     return_type = 0
    pub fn matches_signature(&self, expected_args: &Vec<FuncArgType>, expected_return_type: TypeId) -> bool {
        let mut expected_args = expected_args.iter().peekable();
        match *self {
            ItemType::Function {ref args, return_type} => (
                return_type == expected_return_type &&
                // All the args must match an argument in expected_args
                args.iter().all(|arg| match *arg {
                    FuncArgType::Arg(type_id) => match expected_args.peek() {
                        Some(&&FuncArgType::Arg(arg_id)) if type_id == arg_id => {
                            expected_args.next();
                            true
                        },
                        _ => false,
                    },
                    FuncArgType::Array {item, size} => match expected_args.peek() {
                        Some(&&FuncArgType::Array {item: arg_item, size: arg_size}) if item == arg_item && size == arg_size => {
                            expected_args.next();
                            true
                        },
                        _ => false,
                    },
                    FuncArgType::Variadic(None) => {
                        // Exhaust the entire iterator
                        while let Some(_) = expected_args.next() {}
                        true
                    },
                    FuncArgType::Variadic(Some(type_id)) => match expected_args.peek() {
                        Some(&&FuncArgType::Variadic(Some(arg_id))) if type_id == arg_id => {
                            expected_args.next();
                            true
                        },
                        Some(&&FuncArgType::Arg(_)) => matches_variadic(type_id, &mut expected_args),
                        _ => false,
                    },
                })
            ),
            _ => false,
        }
    }
}

/// Tries to match as many of the expected_args as possible based on the given type_id
/// Returns false if this does not exhaust the iterator
fn matches_variadic(type_id: TypeId, expected_args: &mut Peekable<Iter<FuncArgType>>) -> bool {
    while let Some(&&FuncArgType::Arg(arg_id)) = expected_args.peek() {
        if arg_id == type_id {
            expected_args.next();
        }
        else {
            return false;
        }
    }

    // If the iterator is not exhausted, it means we hit something we did not expect
    expected_args.peek().is_none()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn matches_signature() {
        // Should never match non-function (and should not panic either)
        assert_eq!(test_matches_signature(
            ItemType::Unit,
            &Vec::new(),
            0
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            // Does not match!!
            &Vec::new(),
            22,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            // Does not match!!
            23,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            22,
        ), true);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(None),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            22,
        ), true);

        // To test that variadic arguments with a specified type does not match anything
        // other than its specified type
        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(Some(2)),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Arg(2),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
            ],
            22,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(None),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
            ],
            22,
        ), true);
    }

    fn test_matches_signature(
        typ: ItemType,
        expected_args: &Vec<FuncArgType>,
        expected_return_type: TypeId,
    ) -> bool {
        typ.matches_signature(expected_args, expected_return_type)
    }
}
<commit_msg>Implemented ItemType::required_size for remaining variants<commit_after>use std::iter::Peekable;
use std::slice::Iter;

use memory::Size;

use super::scope::{ScopeStack, TypeId, ArraySize};

/// Possible types for function arguments
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FuncArgType {
    /// A single value of the specified type
    Arg(TypeId),

    /// A single value that is an array containing the specified item type
    Array {
        item: TypeId,
        /// The exact, required size of the array argument
        /// If size is None, the function can dynamically handle any size, otherwise only this size
        /// will be accepted
        ///TODO: Remove the ability for this to be optional when slices and references are
        /// implemented since our dynamic handling any length of array will not work for most things
        size: Option<ArraySize>,
    },

    /// Zero or more values of the specified type
    /// If the type is None, that means that there is no specific type being required
    /// so any type can be passed as an argument
    /// No arguments are allowed in a Function type after a variadic argument. This is mostly
    /// unenforced at the moment. If a function breaks this rule, it will never match during call()
    ///TODO: This is mostly a hack to allow for generics before we support them. It would be nice
    /// to eventually implement this properly when #45 comes along
    Variadic(Option<TypeId>),
}

impl FuncArgType {
    /// Returns true if this function argument is an array with the given item type
    pub fn is_array_of(&self, target: TypeId) -> bool {
        match *self {
            FuncArgType::Array {item, ..} => item == target,
            _ => false,
        }
    }
}

/// An item is anything that can be declared
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ItemType {
    /// Unit type
    /// The unit type is a type with a single zero-size value.
    /// Both the type and the value are specified: ()
    Unit,

    /// A primitive type is a raw interpretation of some memory cells
    /// These primitive types are built-in and cannot be declared
    /// within the language itself
    Primitive(Size),

    /// A struct has a single definition with any number of
    /// fields and generics
    /// Structs can have impls which contain methods for that
    /// struct
    Struct {
        //TODO: fields, generics, etc.
    },

    /// A declaration of an array type, optionally specialized for the given item type
    Array {
        /// The type of the items stored in this array
        /// If this is None, this is the base, generic array type
        item: Option<TypeId>,
        /// The exact, required size of the array argument
        /// If size is None, this represents any size of array (i.e. the wildcard size `_`)
        ///TODO: Remove the ability for this to be optional when slices and references are
        /// implemented since our dynamic handling any length of array will not work for most things
        size: Option<ArraySize>,
    },

    /// Definition of a function's type
    Function {
        args: Vec<FuncArgType>,
        return_type: TypeId,
    },
}

impl ItemType {
    /// Computes the required size in cells of an *instance* of this type
    pub fn required_size(&self, scope: &ScopeStack) -> Size {
        match *self {
            ItemType::Unit => Size::default(),
            ItemType::Primitive(size) => size,
            ItemType::Struct { .. } => Size::default(), //TODO: Update this when fields are supported
            ItemType::Array {item: Some(item), size: Some(size)} => {
                scope.get_type(item).required_size(scope) * size
            },
            ItemType::Function { .. } => Size::default(),
            _ => unreachable!(),
        }
    }

    /// Returns true if this item type matches the given function signature (args, return type)
    /// Returns false if this item type is not a function
    /// Note: Variadic matching is only done one-way
    ///
    /// That means that this will return false:
    ///     self = Function {args: [Arg(1)], return_type: 0}
    ///     expected_args = [Variadic(1)]
    ///     return_type = 0
    ///
    /// However, this will return true (as expected):
    ///     self = Function {args: [Variadic(1)], return_type: 0}
    ///     expected_args = [Arg(1)]
    ///     return_type = 0
    pub fn matches_signature(&self, expected_args: &Vec<FuncArgType>, expected_return_type: TypeId) -> bool {
        let mut expected_args = expected_args.iter().peekable();
        match *self {
            ItemType::Function {ref args, return_type} => (
                return_type == expected_return_type &&
                // All the args must match an argument in expected_args
                args.iter().all(|arg| match *arg {
                    FuncArgType::Arg(type_id) => match expected_args.peek() {
                        Some(&&FuncArgType::Arg(arg_id)) if type_id == arg_id => {
                            expected_args.next();
                            true
                        },
                        _ => false,
                    },
                    FuncArgType::Array {item, size} => match expected_args.peek() {
                        Some(&&FuncArgType::Array {item: arg_item, size: arg_size}) if item == arg_item && size == arg_size => {
                            expected_args.next();
                            true
                        },
                        _ => false,
                    },
                    FuncArgType::Variadic(None) => {
                        // Exhaust the entire iterator
                        while let Some(_) = expected_args.next() {}
                        true
                    },
                    FuncArgType::Variadic(Some(type_id)) => match expected_args.peek() {
                        Some(&&FuncArgType::Variadic(Some(arg_id))) if type_id == arg_id => {
                            expected_args.next();
                            true
                        },
                        Some(&&FuncArgType::Arg(_)) => matches_variadic(type_id, &mut expected_args),
                        _ => false,
                    },
                })
            ),
            _ => false,
        }
    }
}

/// Tries to match as many of the expected_args as possible based on the given type_id
/// Returns false if this does not exhaust the iterator
fn matches_variadic(type_id: TypeId, expected_args: &mut Peekable<Iter<FuncArgType>>) -> bool {
    while let Some(&&FuncArgType::Arg(arg_id)) = expected_args.peek() {
        if arg_id == type_id {
            expected_args.next();
        }
        else {
            return false;
        }
    }

    // If the iterator is not exhausted, it means we hit something we did not expect
    expected_args.peek().is_none()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn matches_signature() {
        // Should never match non-function (and should not panic either)
        assert_eq!(test_matches_signature(
            ItemType::Unit,
            &Vec::new(),
            0
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            // Does not match!!
            &Vec::new(),
            22,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            // Does not match!!
            23,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Arg(2),
                    FuncArgType::Array {item: 0, size: None},
                    FuncArgType::Arg(0),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            22,
        ), true);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(None),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
                FuncArgType::Arg(0),
            ],
            22,
        ), true);

        // To test that variadic arguments with a specified type does not match anything
        // other than its specified type
        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(Some(2)),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
                FuncArgType::Arg(2),
                FuncArgType::Arg(2),
                FuncArgType::Arg(2),
                FuncArgType::Array {item: 0, size: None},
            ],
            22,
        ), false);

        assert_eq!(test_matches_signature(
            ItemType::Function {
                args: vec![
                    FuncArgType::Arg(0),
                    FuncArgType::Variadic(None),
                ],
                return_type: 22,
            },
            &vec![
                FuncArgType::Arg(0),
            ],
            22,
        ), true);
    }

    fn test_matches_signature(
        typ: ItemType,
        expected_args: &Vec<FuncArgType>,
        expected_return_type: TypeId,
    ) -> bool {
        typ.matches_signature(expected_args, expected_return_type)
    }
}
<|endoftext|>


<commit_before>

use chrono::*;
use std::fmt;
use timeclock::timeentry::TimeEntry;

#[derive(Clone,Debug)]
pub struct DateRecord {
    date: Date<FixedOffset>,
    duration: f64,
    memo: String,
}

impl DateRecord {
    pub fn from_time_entries(start: &TimeEntry, end: &TimeEntry) -> DateRecord {
        let mut dr = DateRecord {
            date: start.time.date(),
            duration: (end.time - start.time).num_seconds() as f64,
            memo: String::new(),
        };
        dr.append_memo(&start.memo);
        dr.append_memo(&end.memo);
        return dr;
    }

    #[allow(dead_code)]
    /// Construct a DateRecord from it's constituent parts
    pub fn from_parts(date: Date<FixedOffset>, dur: f64, memo: &str) -> Self {
        DateRecord {
            date: date,
            duration: dur,
            memo: memo.to_owned(),
        }
    }

    /// Get the duration, expressed in seconds
    pub fn seconds(&self) -> f64 {
        self.duration
    }

    #[allow(dead_code)]
    /// Get the duration, expressed in minutes
    pub fn minutes(&self) -> f64 {
        self.duration / 60.0
    }

    /// Get the duration, expressed in hours
    pub fn hours(&self) -> f64 {
        self.duration / 3600.0
    }

    pub fn date(&self) -> Date<FixedOffset> {
        self.date
    }

    pub fn add_seconds(&mut self, secs: f64) {
        self.duration += secs;
    }

    /// Returns the memo
    pub fn memo(&self) -> &str {
        &self.memo
    }

    /// Append &str to the memo
    pub fn append_memo(&mut self, memo: &str) {
        if !self.memo.is_empty() && !memo.is_empty() {
            self.memo.push_str(", ");
            self.memo.push_str(memo);
        } else if self.memo.is_empty() {
            self.memo.push_str(memo);
        }
    }
}

impl fmt::Display for DateRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {:.2} {}", self.date(), self.hours(), self.memo())
    }
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;

    fn daterecord_helper() -> DateRecord {
        let x = NaiveDate::parse_from_str("2017-01-07", "%F").unwrap();
        let y = FixedOffset::west(6 * 3600).from_local_date(&x).unwrap();
        DateRecord::from_parts(y, 4321.098765, "Test")
    }

    #[test]
    fn duration_methods_test() {
        let mut dr = daterecord_helper();
        // check math
        assert!(dr.seconds() == 4321.098765);
        assert!(dr.minutes() == 72.01831274999999);
        assert!(dr.hours() == 1.2003052125);
        // check that addition works
        dr.add_seconds(1357.246);
        assert!(dr.seconds() == 5678.344765);
    }

    #[test]
    fn memo_methods_test() {
        let mut dr = daterecord_helper();
        assert!(dr.memo() == "Test");
        // append empty str
        dr.append_memo("");
        assert!(dr.memo() == "Test");
        // append actual str
        dr.append_memo("success!");
        assert!(dr.memo() == "Test, success!");
    }

    #[test]
    fn fmt_debug_test() {
        let dr = daterecord_helper();
        let s = format!("{:?}", dr);
        println!("{:?}", dr);
        assert!(s ==
                "DateRecord { date: 2017-01-07-06:00, \
                duration: 4321.098765, memo: \"Test\" }")
    }

    #[test]
    fn fmt_display_test() {
        let dr = daterecord_helper();
        let s = format!("{}", dr);
        assert!(s == "2017-01-07-06:00 1.20 Test")
    }
}<commit_msg>Don't show TZ offset for Dates<commit_after>

use chrono::*;
use std::fmt;
use timeclock::timeentry::TimeEntry;

#[derive(Clone,Debug)]
pub struct DateRecord {
    date: Date<FixedOffset>,
    duration: f64,
    memo: String,
}

impl DateRecord {
    pub fn from_time_entries(start: &TimeEntry, end: &TimeEntry) -> DateRecord {
        let mut dr = DateRecord {
            date: start.time.date(),
            duration: (end.time - start.time).num_seconds() as f64,
            memo: String::new(),
        };
        dr.append_memo(&start.memo);
        dr.append_memo(&end.memo);
        return dr;
    }

    #[allow(dead_code)]
    /// Construct a DateRecord from it's constituent parts
    pub fn from_parts(date: Date<FixedOffset>, dur: f64, memo: &str) -> Self {
        DateRecord {
            date: date,
            duration: dur,
            memo: memo.to_owned(),
        }
    }

    /// Get the duration, expressed in seconds
    pub fn seconds(&self) -> f64 {
        self.duration
    }

    #[allow(dead_code)]
    /// Get the duration, expressed in minutes
    pub fn minutes(&self) -> f64 {
        self.duration / 60.0
    }

    /// Get the duration, expressed in hours
    pub fn hours(&self) -> f64 {
        self.duration / 3600.0
    }

    pub fn date(&self) -> Date<FixedOffset> {
        self.date
    }

    pub fn add_seconds(&mut self, secs: f64) {
        self.duration += secs;
    }

    /// Returns the memo
    pub fn memo(&self) -> &str {
        &self.memo
    }

    /// Append &str to the memo
    pub fn append_memo(&mut self, memo: &str) {
        if !self.memo.is_empty() && !memo.is_empty() {
            self.memo.push_str(", ");
            self.memo.push_str(memo);
        } else if self.memo.is_empty() {
            self.memo.push_str(memo);
        }
    }
}

impl fmt::Display for DateRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let date = self.date.format("%F");
        write!(f, "{} {:.2} {}", date, self.hours(), self.memo)
    }
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;

    fn daterecord_helper() -> DateRecord {
        let x = NaiveDate::parse_from_str("2017-01-07", "%F").unwrap();
        let y = FixedOffset::west(6 * 3600).from_local_date(&x).unwrap();
        DateRecord::from_parts(y, 4321.098765, "Test")
    }

    #[test]
    fn duration_methods_test() {
        let mut dr = daterecord_helper();
        // check math
        assert!(dr.seconds() == 4321.098765);
        assert!(dr.minutes() == 72.01831274999999);
        assert!(dr.hours() == 1.2003052125);
        // check that addition works
        dr.add_seconds(1357.246);
        assert!(dr.seconds() == 5678.344765);
    }

    #[test]
    fn memo_methods_test() {
        let mut dr = daterecord_helper();
        assert!(dr.memo() == "Test");
        // append empty str
        dr.append_memo("");
        assert!(dr.memo() == "Test");
        // append actual str
        dr.append_memo("success!");
        assert!(dr.memo() == "Test, success!");
    }

    #[test]
    fn fmt_debug_test() {
        let dr = daterecord_helper();
        let s = format!("{:?}", dr);
        println!("{:?}", dr);
        assert!(s ==
                "DateRecord { date: 2017-01-07-06:00, \
                duration: 4321.098765, memo: \"Test\" }")
    }

    #[test]
    fn fmt_display_test() {
        let dr = daterecord_helper();
        let s = format!("{}", dr);
        assert!(s == "2017-01-07 1.20 Test")
    }
}<|endoftext|>


<commit_before>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug)]
pub enum QuerySyntaxError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

#[derive(Debug)]
pub enum Query {
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

pub fn parse_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    let field = match json_object.get("field") {
        Some(val) => try!(val.as_string().ok_or(QuerySyntaxError::ExpectedString)).to_owned(),
        None => "_all".to_owned(),
    };

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QuerySyntaxError::ExpectedString)).to_owned();

    Ok(Query::Match {
        field: field,
        query: query,
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QuerySyntaxError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QuerySyntaxError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QuerySyntaxError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QuerySyntaxError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QuerySyntaxError::NoQuery));

    if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QuerySyntaxError::UnknownQueryType(first_key.clone()))
    }
}
<commit_msg>Corrected parsing of match query<commit_after>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug)]
pub enum QuerySyntaxError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

#[derive(Debug)]
pub enum Query {
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

pub fn parse_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QuerySyntaxError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QuerySyntaxError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QuerySyntaxError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QuerySyntaxError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QuerySyntaxError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QuerySyntaxError::NoQuery));

    if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QuerySyntaxError::UnknownQueryType(first_key.clone()))
    }
}
<|endoftext|>


<commit_before>/*!
 * Compiled representation of a grammar. Simplified, normalized
 * version of `parse_tree`. The normalization passes produce this
 * representation incrementally.
 */

use intern::{self, InternedString};
use grammar::pattern::{Pattern};
use message::Content;
use std::fmt::{Debug, Display, Formatter, Error};
use collections::{map, Map};
use util::Sep;

// These concepts we re-use wholesale
pub use grammar::parse_tree::{Annotation,
                              InternToken,
                              NonterminalString,
                              Path,
                              Span,
                              TerminalLiteral, TerminalString, TypeParameter};

#[derive(Clone, Debug)]
pub struct Grammar {
    // a unique prefix that can be appended to identifiers to ensure
    // that they do not conflict with any action strings
    pub prefix: String,

    // algorithm user requested for this parser
    pub algorithm: Algorithm,

    // these are the nonterminals that were declared to be public; the
    // key is the user's name for the symbol, the value is the
    // artificial symbol we introduce, which will always have a single
    // production like `Foo' = Foo`.
    pub start_nonterminals: Map<NonterminalString, NonterminalString>,

    // the "use foo;" statements that the user declared
    pub uses: Vec<String>,

    // type parameters declared on the grammar, like `grammar<T>;`
    pub type_parameters: Vec<TypeParameter>,

    // actual parameters declared on the grammar, like the `x: u32` in `grammar(x: u32);`
    pub parameters: Vec<Parameter>,

    // where clauses declared on the grammar, like `grammar<T> where T: Sized`
    pub where_clauses: Vec<String>,

    // optional tokenizer DFA; this is only needed if the user did not supply
    // an extern token declaration
    pub intern_token: Option<InternToken>,

    // the grammar proper:

    pub action_fn_defns: Vec<ActionFnDefn>,
    pub nonterminals: Map<NonterminalString, NonterminalData>,
    pub token_span: Span,
    pub conversions: Map<TerminalString, Pattern<TypeRepr>>,
    pub types: Types,

    // for each terminal, we map it to a small integer from 0 to N
    pub all_terminals: Vec<TerminalString>,
    pub terminal_bits: Map<TerminalString, usize>,
}

#[derive(Clone, Debug)]
pub struct NonterminalData {
    pub name: NonterminalString,
    pub span: Span,
    pub annotations: Vec<Annotation>,
    pub productions: Vec<Production>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Algorithm {
    LR1,
    LALR1,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Parameter {
    pub name: InternedString,
    pub ty: TypeRepr,
}

#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Production {
    // this overlaps with the key in the hashmap, obviously, but it's
    // handy to have it
    pub nonterminal: NonterminalString,
    pub symbols: Vec<Symbol>,
    pub action: ActionFn,
    pub span: Span,
}

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Symbol {
    Nonterminal(NonterminalString),
    Terminal(TerminalString),
}

#[derive(Clone, PartialEq, Eq)]
pub struct ActionFnDefn {
    pub fallible: bool,
    pub ret_type: TypeRepr,
    pub kind: ActionFnDefnKind,
}

#[derive(Clone, PartialEq, Eq)]
pub enum ActionFnDefnKind {
    User(UserActionFnDefn),
    Inline(InlineActionFnDefn),
    Lookaround(LookaroundActionFnDefn),
}

/// An action fn written by a user.
#[derive(Clone, PartialEq, Eq)]
pub struct UserActionFnDefn {
    pub arg_patterns: Vec<InternedString>,
    pub arg_types: Vec<TypeRepr>,
    pub code: String,
}

/// An action fn generated by the inlining pass.  If we were
/// inlining `A = B C D` (with action 44) into `X = Y A Z` (with
/// action 22), this would look something like:
///
/// ```
/// fn __action66(__0: Y, __1: B, __2: C, __3: D, __4: Z) {
///     __action22(__0, __action44(__1, __2, __3), __4)
/// }
/// ```
#[derive(Clone, PartialEq, Eq)]
pub struct InlineActionFnDefn {
    /// in the example above, this would be `action22`
    pub action: ActionFn,

    /// in the example above, this would be `Y, {action44: B, C, D}, Z`
    pub symbols: Vec<InlinedSymbol>
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LookaroundActionFnDefn {
    Lookahead,
    Lookbehind,
}

#[derive(Clone, PartialEq, Eq)]
pub enum InlinedSymbol {
    Original(Symbol),
    Inlined(ActionFn, Vec<Symbol>),
}

#[derive(Clone, PartialEq, Eq)]
pub enum TypeRepr {
    Tuple(Vec<TypeRepr>),
    Nominal(NominalTypeRepr),
    Lifetime(InternedString),
    Ref {
        lifetime: Option<InternedString>,
        mutable: bool,
        referent: Box<TypeRepr>,
    },
}

impl TypeRepr {
    pub fn usize() -> TypeRepr {
        TypeRepr::Nominal(NominalTypeRepr {
            path: Path::usize(),
            types: vec![]
        })
    }

    pub fn str() -> TypeRepr {
        TypeRepr::Nominal(NominalTypeRepr {
            path: Path::str(),
            types: vec![]
        })
    }

    /// Returns the type parameters (or potential type parameters)
    /// referenced by this type. e.g., for the type `&'x X`, would
    /// return `[TypeParameter::Lifetime('x), TypeParameter::Id(X)]`.
    /// This is later used to prune the type parameters list so that
    /// only those that are actually used are included.
    pub fn referenced(&self) -> Vec<TypeParameter> {
        match *self {
            TypeRepr::Tuple(ref tys) =>
                tys.iter().flat_map(|t| t.referenced()).collect(),
            TypeRepr::Nominal(ref data) =>
                data.types.iter()
                          .flat_map(|t| t.referenced())
                          .chain(match data.path.as_id() {
                              Some(id) => vec![TypeParameter::Id(id)],
                              None => vec![],
                          })
                          .collect(),
            TypeRepr::Lifetime(l) =>
                vec![TypeParameter::Lifetime(l)],
            TypeRepr::Ref { ref lifetime, mutable: _, ref referent } =>
                lifetime.iter()
                        .map(|&id| TypeParameter::Lifetime(id))
                        .chain(referent.referenced())
                        .collect(),
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct NominalTypeRepr {
    pub path: Path,
    pub types: Vec<TypeRepr>
}

#[derive(Clone, Debug)]
pub struct Types {
    terminal_token_type: TypeRepr,
    terminal_loc_type: Option<TypeRepr>,
    error_type: Option<TypeRepr>,
    terminal_types: Map<TerminalString, TypeRepr>,
    nonterminal_types: Map<NonterminalString, TypeRepr>
}

impl Types {
    pub fn new(terminal_loc_type: Option<TypeRepr>,
               error_type: Option<TypeRepr>,
               terminal_token_type: TypeRepr)
               -> Types {
        Types { terminal_loc_type: terminal_loc_type,
                error_type: error_type,
                terminal_token_type: terminal_token_type,
                terminal_types: map(),
                nonterminal_types: map() }
    }

    pub fn add_type(&mut self, nt_id: NonterminalString, ty: TypeRepr) {
        assert!(self.nonterminal_types.insert(nt_id, ty).is_none());
    }

    pub fn add_term_type(&mut self, term: TerminalString, ty: TypeRepr) {
        assert!(self.terminal_types.insert(term, ty).is_none());
    }

    pub fn terminal_token_type(&self) -> &TypeRepr {
        &self.terminal_token_type
    }

    pub fn opt_terminal_loc_type(&self) -> Option<&TypeRepr> {
        self.terminal_loc_type.as_ref()
    }

    pub fn terminal_loc_type(&self) -> TypeRepr {
        self.terminal_loc_type.clone()
                              .unwrap_or_else(|| TypeRepr::Tuple(vec![]))
    }

    pub fn error_type(&self) -> TypeRepr {
        self.error_type.clone()
                       .unwrap_or_else(|| TypeRepr::Tuple(vec![]))
    }

    pub fn terminal_type(&self, id: TerminalString) -> &TypeRepr {
        self.terminal_types.get(&id).unwrap_or(&self.terminal_token_type)
    }

    pub fn lookup_nonterminal_type(&self, id: NonterminalString) -> Option<&TypeRepr> {
        self.nonterminal_types.get(&id)
    }

    pub fn nonterminal_type(&self, id: NonterminalString) -> &TypeRepr {
        &self.nonterminal_types[&id]
    }

    pub fn nonterminal_types(&self) -> Vec<TypeRepr> {
        self.nonterminal_types.values()
                              .cloned()
                              .collect()
    }

    pub fn triple_type(&self) -> TypeRepr {
        let enum_type = self.terminal_token_type();
        let location_type = self.terminal_loc_type();
        TypeRepr::Tuple(vec![location_type.clone(),
                             enum_type.clone(),
                             location_type])
    }
}

impl Display for Parameter {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}: {}", self.name, self.ty)
    }
}

impl Display for TypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            TypeRepr::Tuple(ref types) =>
                write!(fmt, "({})", Sep(", ", types)),
            TypeRepr::Nominal(ref data) =>
                write!(fmt, "{}", data),
            TypeRepr::Lifetime(id) =>
                write!(fmt, "{}", id),
            TypeRepr::Ref { lifetime: None, mutable: false, ref referent } =>
                write!(fmt, "&{}", referent),
            TypeRepr::Ref { lifetime: Some(l), mutable: false, ref referent } =>
                write!(fmt, "&{} {}", l, referent),
            TypeRepr::Ref { lifetime: None, mutable: true, ref referent } =>
                write!(fmt, "&mut {}", referent),
            TypeRepr::Ref { lifetime: Some(l), mutable: true, ref referent } =>
                write!(fmt, "&{} mut {}", l, referent),
        }
    }
}

impl Debug for TypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

impl Display for NominalTypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        if self.types.len() == 0 {
            write!(fmt, "{}", self.path)
        } else {
            write!(fmt, "{}<{}>", self.path, Sep(", ", &self.types))
        }
    }
}

impl Debug for NominalTypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct ActionFn(u32);

impl ActionFn {
    pub fn new(x: usize) -> ActionFn {
        ActionFn(x as u32)
    }

    pub fn index(&self) -> usize {
        self.0 as usize
    }
}

impl Symbol {
    pub fn is_terminal(&self) -> bool {
        match *self {
            Symbol::Terminal(..) => true,
            Symbol::Nonterminal(..) => false,
        }
    }

    pub fn ty<'ty>(&self, t: &'ty Types) -> &'ty TypeRepr {
        match *self {
            Symbol::Terminal(id) => t.terminal_type(id),
            Symbol::Nonterminal(id) => t.nonterminal_type(id),
        }
    }
}

impl Display for Symbol {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Symbol::Nonterminal(id) => write!(fmt, "{}", id),
            Symbol::Terminal(id) => write!(fmt, "{}", id),
        }
    }
}

impl Debug for Symbol {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

impl Into<Box<Content>> for Symbol {
    fn into(self) -> Box<Content> {
        match self {
            Symbol::Nonterminal(nt) => nt.into(),
            Symbol::Terminal(term) => term.into(),
        }
    }
}

impl Debug for Production {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt,
               "{} = {} => {:?};",
               self.nonterminal, Sep(", ", &self.symbols), self.action)
    }
}

impl Debug for ActionFnDefn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self.to_fn_string("_"))
    }
}

impl ActionFnDefn {
    fn to_fn_string(&self, name: &str) -> String {
        match self.kind {
            ActionFnDefnKind::User(ref data) => data.to_fn_string(self, name),
            ActionFnDefnKind::Inline(ref data) => data.to_fn_string(name),
            ActionFnDefnKind::Lookaround(ref data) => format!("{:?}", data),
        }
    }
}

impl UserActionFnDefn {
    fn to_fn_string(&self, defn: &ActionFnDefn, name: &str) -> String {
        let arg_strings: Vec<String> =
               self.arg_patterns
                   .iter()
                   .zip(self.arg_types.iter())
                   .map(|(p, t)| format!("{}: {}", p, t))
                   .collect();

        format!("fn {}({}) -> {} {{ {} }}",
                name, Sep(", ", &arg_strings), defn.ret_type, self.code)
    }
}

impl InlineActionFnDefn {
    fn to_fn_string(&self, name: &str) -> String {
        let arg_strings: Vec<String> =
               self.symbols
                   .iter()
                   .map(|inline_sym| match *inline_sym {
                       InlinedSymbol::Original(s) =>
                           format!("{}", s),
                       InlinedSymbol::Inlined(a, ref s) =>
                           format!("{:?}({})", a, Sep(", ", s)),
                   })
                   .collect();

        format!("fn {}(..) {{ {:?}({}) }}", name, self.action, Sep(", ", &arg_strings))
    }
}

impl Grammar {
    pub fn pattern(&self, t: TerminalString) -> &Pattern<TypeRepr> {
        &self.conversions[&t]
    }

    pub fn productions_for(&self, nonterminal: NonterminalString) -> &[Production] {
        match self.nonterminals.get(&nonterminal) {
            Some(v) => &v.productions[..],
            None => &[], // this...probably shouldn't happen actually?
        }
    }

    pub fn user_parameter_refs(&self) -> String {
        let mut result = String::new();
        for parameter in &self.parameters {
            result.push_str(&format!("{}, ", parameter.name));
        }
        result
    }

    pub fn action_is_fallible(&self, f: ActionFn) -> bool {
        self.action_fn_defns[f.index()].fallible
    }
}

impl Algorithm {
    pub fn from_str(s: InternedString) -> Option<Algorithm> {
        intern::read(|r| match r.data(s) {
            "LR" | "LR(1)" => Some(Algorithm::LR1),
            "LALR" | "LALR(1)" => Some(Algorithm::LALR1),
            _ => None,
        })
    }
}
<commit_msg>add `spanned_type` helper<commit_after>/*!
 * Compiled representation of a grammar. Simplified, normalized
 * version of `parse_tree`. The normalization passes produce this
 * representation incrementally.
 */

use intern::{self, InternedString};
use grammar::pattern::{Pattern};
use message::Content;
use std::fmt::{Debug, Display, Formatter, Error};
use collections::{map, Map};
use util::Sep;

// These concepts we re-use wholesale
pub use grammar::parse_tree::{Annotation,
                              InternToken,
                              NonterminalString,
                              Path,
                              Span,
                              TerminalLiteral, TerminalString, TypeParameter};

#[derive(Clone, Debug)]
pub struct Grammar {
    // a unique prefix that can be appended to identifiers to ensure
    // that they do not conflict with any action strings
    pub prefix: String,

    // algorithm user requested for this parser
    pub algorithm: Algorithm,

    // these are the nonterminals that were declared to be public; the
    // key is the user's name for the symbol, the value is the
    // artificial symbol we introduce, which will always have a single
    // production like `Foo' = Foo`.
    pub start_nonterminals: Map<NonterminalString, NonterminalString>,

    // the "use foo;" statements that the user declared
    pub uses: Vec<String>,

    // type parameters declared on the grammar, like `grammar<T>;`
    pub type_parameters: Vec<TypeParameter>,

    // actual parameters declared on the grammar, like the `x: u32` in `grammar(x: u32);`
    pub parameters: Vec<Parameter>,

    // where clauses declared on the grammar, like `grammar<T> where T: Sized`
    pub where_clauses: Vec<String>,

    // optional tokenizer DFA; this is only needed if the user did not supply
    // an extern token declaration
    pub intern_token: Option<InternToken>,

    // the grammar proper:

    pub action_fn_defns: Vec<ActionFnDefn>,
    pub nonterminals: Map<NonterminalString, NonterminalData>,
    pub token_span: Span,
    pub conversions: Map<TerminalString, Pattern<TypeRepr>>,
    pub types: Types,

    // for each terminal, we map it to a small integer from 0 to N
    pub all_terminals: Vec<TerminalString>,
    pub terminal_bits: Map<TerminalString, usize>,
}

#[derive(Clone, Debug)]
pub struct NonterminalData {
    pub name: NonterminalString,
    pub span: Span,
    pub annotations: Vec<Annotation>,
    pub productions: Vec<Production>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Algorithm {
    LR1,
    LALR1,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Parameter {
    pub name: InternedString,
    pub ty: TypeRepr,
}

#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Production {
    // this overlaps with the key in the hashmap, obviously, but it's
    // handy to have it
    pub nonterminal: NonterminalString,
    pub symbols: Vec<Symbol>,
    pub action: ActionFn,
    pub span: Span,
}

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Symbol {
    Nonterminal(NonterminalString),
    Terminal(TerminalString),
}

#[derive(Clone, PartialEq, Eq)]
pub struct ActionFnDefn {
    pub fallible: bool,
    pub ret_type: TypeRepr,
    pub kind: ActionFnDefnKind,
}

#[derive(Clone, PartialEq, Eq)]
pub enum ActionFnDefnKind {
    User(UserActionFnDefn),
    Inline(InlineActionFnDefn),
    Lookaround(LookaroundActionFnDefn),
}

/// An action fn written by a user.
#[derive(Clone, PartialEq, Eq)]
pub struct UserActionFnDefn {
    pub arg_patterns: Vec<InternedString>,
    pub arg_types: Vec<TypeRepr>,
    pub code: String,
}

/// An action fn generated by the inlining pass.  If we were
/// inlining `A = B C D` (with action 44) into `X = Y A Z` (with
/// action 22), this would look something like:
///
/// ```
/// fn __action66(__0: Y, __1: B, __2: C, __3: D, __4: Z) {
///     __action22(__0, __action44(__1, __2, __3), __4)
/// }
/// ```
#[derive(Clone, PartialEq, Eq)]
pub struct InlineActionFnDefn {
    /// in the example above, this would be `action22`
    pub action: ActionFn,

    /// in the example above, this would be `Y, {action44: B, C, D}, Z`
    pub symbols: Vec<InlinedSymbol>
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LookaroundActionFnDefn {
    Lookahead,
    Lookbehind,
}

#[derive(Clone, PartialEq, Eq)]
pub enum InlinedSymbol {
    Original(Symbol),
    Inlined(ActionFn, Vec<Symbol>),
}

#[derive(Clone, PartialEq, Eq)]
pub enum TypeRepr {
    Tuple(Vec<TypeRepr>),
    Nominal(NominalTypeRepr),
    Lifetime(InternedString),
    Ref {
        lifetime: Option<InternedString>,
        mutable: bool,
        referent: Box<TypeRepr>,
    },
}

impl TypeRepr {
    pub fn usize() -> TypeRepr {
        TypeRepr::Nominal(NominalTypeRepr {
            path: Path::usize(),
            types: vec![]
        })
    }

    pub fn str() -> TypeRepr {
        TypeRepr::Nominal(NominalTypeRepr {
            path: Path::str(),
            types: vec![]
        })
    }

    /// Returns the type parameters (or potential type parameters)
    /// referenced by this type. e.g., for the type `&'x X`, would
    /// return `[TypeParameter::Lifetime('x), TypeParameter::Id(X)]`.
    /// This is later used to prune the type parameters list so that
    /// only those that are actually used are included.
    pub fn referenced(&self) -> Vec<TypeParameter> {
        match *self {
            TypeRepr::Tuple(ref tys) =>
                tys.iter().flat_map(|t| t.referenced()).collect(),
            TypeRepr::Nominal(ref data) =>
                data.types.iter()
                          .flat_map(|t| t.referenced())
                          .chain(match data.path.as_id() {
                              Some(id) => vec![TypeParameter::Id(id)],
                              None => vec![],
                          })
                          .collect(),
            TypeRepr::Lifetime(l) =>
                vec![TypeParameter::Lifetime(l)],
            TypeRepr::Ref { ref lifetime, mutable: _, ref referent } =>
                lifetime.iter()
                        .map(|&id| TypeParameter::Lifetime(id))
                        .chain(referent.referenced())
                        .collect(),
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct NominalTypeRepr {
    pub path: Path,
    pub types: Vec<TypeRepr>
}

#[derive(Clone, Debug)]
pub struct Types {
    terminal_token_type: TypeRepr,
    terminal_loc_type: Option<TypeRepr>,
    error_type: Option<TypeRepr>,
    terminal_types: Map<TerminalString, TypeRepr>,
    nonterminal_types: Map<NonterminalString, TypeRepr>
}

impl Types {
    pub fn new(terminal_loc_type: Option<TypeRepr>,
               error_type: Option<TypeRepr>,
               terminal_token_type: TypeRepr)
               -> Types {
        Types { terminal_loc_type: terminal_loc_type,
                error_type: error_type,
                terminal_token_type: terminal_token_type,
                terminal_types: map(),
                nonterminal_types: map() }
    }

    pub fn add_type(&mut self, nt_id: NonterminalString, ty: TypeRepr) {
        assert!(self.nonterminal_types.insert(nt_id, ty).is_none());
    }

    pub fn add_term_type(&mut self, term: TerminalString, ty: TypeRepr) {
        assert!(self.terminal_types.insert(term, ty).is_none());
    }

    pub fn terminal_token_type(&self) -> &TypeRepr {
        &self.terminal_token_type
    }

    pub fn opt_terminal_loc_type(&self) -> Option<&TypeRepr> {
        self.terminal_loc_type.as_ref()
    }

    pub fn terminal_loc_type(&self) -> TypeRepr {
        self.terminal_loc_type.clone()
                              .unwrap_or_else(|| TypeRepr::Tuple(vec![]))
    }

    pub fn error_type(&self) -> TypeRepr {
        self.error_type.clone()
                       .unwrap_or_else(|| TypeRepr::Tuple(vec![]))
    }

    pub fn terminal_type(&self, id: TerminalString) -> &TypeRepr {
        self.terminal_types.get(&id).unwrap_or(&self.terminal_token_type)
    }

    pub fn lookup_nonterminal_type(&self, id: NonterminalString) -> Option<&TypeRepr> {
        self.nonterminal_types.get(&id)
    }

    pub fn nonterminal_type(&self, id: NonterminalString) -> &TypeRepr {
        &self.nonterminal_types[&id]
    }

    pub fn nonterminal_types(&self) -> Vec<TypeRepr> {
        self.nonterminal_types.values()
                              .cloned()
                              .collect()
    }

    /// Returns a type `(L, T, L)` where L is the location type and T
    /// is the token type.
    pub fn triple_type(&self) -> TypeRepr {
        self.spanned_type(self.terminal_token_type().clone())
    }

    /// Returns a type `(L, T, L)` where L is the location type and T
    /// is the argument.
    pub fn spanned_type(&self, ty: TypeRepr) -> TypeRepr {
        let location_type = self.terminal_loc_type();
        TypeRepr::Tuple(vec![location_type.clone(),
                             ty,
                             location_type])
    }
}

impl Display for Parameter {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}: {}", self.name, self.ty)
    }
}

impl Display for TypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            TypeRepr::Tuple(ref types) =>
                write!(fmt, "({})", Sep(", ", types)),
            TypeRepr::Nominal(ref data) =>
                write!(fmt, "{}", data),
            TypeRepr::Lifetime(id) =>
                write!(fmt, "{}", id),
            TypeRepr::Ref { lifetime: None, mutable: false, ref referent } =>
                write!(fmt, "&{}", referent),
            TypeRepr::Ref { lifetime: Some(l), mutable: false, ref referent } =>
                write!(fmt, "&{} {}", l, referent),
            TypeRepr::Ref { lifetime: None, mutable: true, ref referent } =>
                write!(fmt, "&mut {}", referent),
            TypeRepr::Ref { lifetime: Some(l), mutable: true, ref referent } =>
                write!(fmt, "&{} mut {}", l, referent),
        }
    }
}

impl Debug for TypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

impl Display for NominalTypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        if self.types.len() == 0 {
            write!(fmt, "{}", self.path)
        } else {
            write!(fmt, "{}<{}>", self.path, Sep(", ", &self.types))
        }
    }
}

impl Debug for NominalTypeRepr {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct ActionFn(u32);

impl ActionFn {
    pub fn new(x: usize) -> ActionFn {
        ActionFn(x as u32)
    }

    pub fn index(&self) -> usize {
        self.0 as usize
    }
}

impl Symbol {
    pub fn is_terminal(&self) -> bool {
        match *self {
            Symbol::Terminal(..) => true,
            Symbol::Nonterminal(..) => false,
        }
    }

    pub fn ty<'ty>(&self, t: &'ty Types) -> &'ty TypeRepr {
        match *self {
            Symbol::Terminal(id) => t.terminal_type(id),
            Symbol::Nonterminal(id) => t.nonterminal_type(id),
        }
    }
}

impl Display for Symbol {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Symbol::Nonterminal(id) => write!(fmt, "{}", id),
            Symbol::Terminal(id) => write!(fmt, "{}", id),
        }
    }
}

impl Debug for Symbol {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        Display::fmt(self, fmt)
    }
}

impl Into<Box<Content>> for Symbol {
    fn into(self) -> Box<Content> {
        match self {
            Symbol::Nonterminal(nt) => nt.into(),
            Symbol::Terminal(term) => term.into(),
        }
    }
}

impl Debug for Production {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt,
               "{} = {} => {:?};",
               self.nonterminal, Sep(", ", &self.symbols), self.action)
    }
}

impl Debug for ActionFnDefn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self.to_fn_string("_"))
    }
}

impl ActionFnDefn {
    fn to_fn_string(&self, name: &str) -> String {
        match self.kind {
            ActionFnDefnKind::User(ref data) => data.to_fn_string(self, name),
            ActionFnDefnKind::Inline(ref data) => data.to_fn_string(name),
            ActionFnDefnKind::Lookaround(ref data) => format!("{:?}", data),
        }
    }
}

impl UserActionFnDefn {
    fn to_fn_string(&self, defn: &ActionFnDefn, name: &str) -> String {
        let arg_strings: Vec<String> =
               self.arg_patterns
                   .iter()
                   .zip(self.arg_types.iter())
                   .map(|(p, t)| format!("{}: {}", p, t))
                   .collect();

        format!("fn {}({}) -> {} {{ {} }}",
                name, Sep(", ", &arg_strings), defn.ret_type, self.code)
    }
}

impl InlineActionFnDefn {
    fn to_fn_string(&self, name: &str) -> String {
        let arg_strings: Vec<String> =
               self.symbols
                   .iter()
                   .map(|inline_sym| match *inline_sym {
                       InlinedSymbol::Original(s) =>
                           format!("{}", s),
                       InlinedSymbol::Inlined(a, ref s) =>
                           format!("{:?}({})", a, Sep(", ", s)),
                   })
                   .collect();

        format!("fn {}(..) {{ {:?}({}) }}", name, self.action, Sep(", ", &arg_strings))
    }
}

impl Grammar {
    pub fn pattern(&self, t: TerminalString) -> &Pattern<TypeRepr> {
        &self.conversions[&t]
    }

    pub fn productions_for(&self, nonterminal: NonterminalString) -> &[Production] {
        match self.nonterminals.get(&nonterminal) {
            Some(v) => &v.productions[..],
            None => &[], // this...probably shouldn't happen actually?
        }
    }

    pub fn user_parameter_refs(&self) -> String {
        let mut result = String::new();
        for parameter in &self.parameters {
            result.push_str(&format!("{}, ", parameter.name));
        }
        result
    }

    pub fn action_is_fallible(&self, f: ActionFn) -> bool {
        self.action_fn_defns[f.index()].fallible
    }
}

impl Algorithm {
    pub fn from_str(s: InternedString) -> Option<Algorithm> {
        intern::read(|r| match r.data(s) {
            "LR" | "LR(1)" => Some(Algorithm::LR1),
            "LALR" | "LALR(1)" => Some(Algorithm::LALR1),
            _ => None,
        })
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

// TODO use cfg(bench) to make pub functions not-pub depending on context
#[cfg(test)]
mod test {
    extern crate test;
    use bliss_rs::timbral::SpectralDesc;
    use test::Bencher;

    #[bench]
    fn bench_spectral_desc(b: &mut Bencher) {
        let mut spectral_desc = SpectralDesc::new(10);
        let chunk = vec![0.; 512];

        b.iter(|| {
            spectral_desc.do_(&chunk);
        });
    }
}
<commit_msg>Add bench for zcr desc<commit_after>#![feature(test)]

// TODO use cfg(bench) to make pub functions not-pub depending on context
#[cfg(test)]
mod test {
    extern crate test;
    use bliss_rs::timbral::SpectralDesc;
    use bliss_rs::timbral::ZeroCrossingRateDesc;
    use test::Bencher;

    #[bench]
    fn bench_spectral_desc(b: &mut Bencher) {
        let mut spectral_desc = SpectralDesc::new(10);
        let chunk = vec![0.; 512];

        b.iter(|| {
            spectral_desc.do_(&chunk);
        });
    }

    #[bench]
    fn bench_zcr_desc(b: &mut Bencher) {
        let mut zcr_desc = ZeroCrossingRateDesc::new(10);
        let chunk = vec![0.; 512];

        b.iter(|| {
            zcr_desc.do_(&chunk);
        });
    }
}
<|endoftext|>