<commit_before>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape, ShapeType};
use std::borrow::Cow;
use super::GenerateProtocol;
use super::generate_field_name;

pub struct Ec2Generator;

impl GenerateProtocol for Ec2Generator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            format!(
                "{documentation}
                {method_signature} {{
                    let mut request = SignedRequest::new(\"{http_method}\", \"{endpoint_prefix}\", self.region, \"{request_uri}\");
                    let mut params = Params::new();

                    params.put(\"Action\", \"{operation_name}\");
                    params.put(\"Version\", \"{api_version}\");

                    {serialize_input}

                    request.set_params(params);
                    request.sign(&try!(self.credentials_provider.credentials()));

                    let result = try!(self.dispatcher.dispatch(&request));

                    match result.status {{
                        200 => {{
                            let mut reader = EventReader::from_str(&result.body);
                            let mut stack = XmlResponse::new(reader.events().peekable());
                            stack.next();
                            {method_return_value}
                        }},
                        _ => Err({error_type}::from_body(&result.body))
                    }}
                }}
                ",
                documentation = generate_documentation(operation),
                http_method = &operation.http.method,
                endpoint_prefix = &service.metadata.endpoint_prefix,
                method_return_value = generate_method_return_value(operation),
                method_signature = generate_method_signature(operation),
                operation_name = &operation.name,
                error_type = operation.error_type_name(),
                api_version = service.metadata.api_version,
                request_uri = &operation.http.request_uri,
                serialize_input = generate_method_input_serialization(operation),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, _service: &Service) -> String {
        "use std::str::{FromStr, from_utf8};

        use xml::EventReader;

        use param::{Params, ServiceParams};

        use signature::SignedRequest;
        use xml::reader::events::XmlEvent;
        use xmlutil::{Next, Peek, XmlParseError, XmlResponse};
        use xmlutil::{characters, end_element, start_element, skip_tree};
        use xmlerror::*;

        enum DeserializerNext {
            Close,
            Skip,
            Element(String),
        }
        ".to_owned()
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Clone)]".to_owned()
    }

    fn generate_support_types(&self, name: &str, shape: &Shape, _service: &Service) -> Option<String> {
        Some(format!(
            "/// Deserializes `{name}` from XML.
            struct {name}Deserializer;
            impl {name}Deserializer {{
                #[allow(unused_variables)]
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}

            /// Serialize `{name}` contents to a `SignedRequest`.
            struct {name}Serializer;
            impl {name}Serializer {{
                {serializer_signature} {{
                    {serializer_body}
                }}
            }}
            ",
            deserializer_body = generate_deserializer_body(name, shape),
            name = name,
            serializer_body = generate_serializer_body(shape),
            serializer_signature = generate_serializer_signature(name, shape),
        ))
    }

    fn timestamp_type(&self) -> &'static str {
        "String"
    }
}

fn generate_documentation(operation: &Operation) -> String {
    match operation.documentation {
        Some(ref docs) => format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"").replace("C:\\", "C:\\\\")),
        None => "".to_owned(),
    }
}

fn generate_method_input_serialization(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "{input_type}Serializer::serialize(&mut params, \"\", &input);",
            input_type = operation.input.as_ref().unwrap().shape,
        )
    } else {
        String::new()
    }
}

fn generate_response_tag_name<'a>(member_name: &'a str) -> Cow<'a, str> {
    if member_name.ends_with("Result") {
        format!("{}Response", &member_name[..member_name.len()-6]).into()
    } else {
        member_name.into()
    }
}

fn generate_method_return_value(operation: &Operation) -> String {
    if operation.output.is_some() {
        let output_type = &operation.output.as_ref().unwrap().shape;
        let tag_name = generate_response_tag_name(output_type);
        format!(
            "Ok(try!({output_type}Deserializer::deserialize(\"{tag_name}\", &mut stack)))",
            output_type = output_type,
            tag_name = tag_name
        )
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {operation_name}(&self, input: &{input_type}) -> Result<{output_type}, {error_type}>",
            input_type = operation.input.as_ref().unwrap().shape,
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
            error_type = operation.error_type_name(),
        )
    } else {
        format!(
            "pub fn {operation_name}(&self) -> Result<{output_type}, {error_type}>",
            operation_name = operation.name.to_snake_case(),
            error_type = operation.error_type_name(),
            output_type = &operation.output_shape_or("()"),
        )
    }
}

fn generate_deserializer_body(name: &str, shape: &Shape) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_deserializer(shape),
        ShapeType::Structure => generate_struct_deserializer(name, shape),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {

    let location_name = shape.member.as_ref().and_then(|m| m.location_name.as_ref()).map(|name| &name[..]).unwrap_or(shape.member());

    format!(
        "
        let mut obj = vec![];
        try!(start_element(tag_name, stack));

        loop {{
            let next_event = match stack.peek() {{
                Some(&XmlEvent::EndElement {{ .. }}) => DeserializerNext::Close,
                Some(&XmlEvent::StartElement {{ ref name, .. }}) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    if name == \"{location_name}\" {{
                        obj.push(try!({member_name}Deserializer::deserialize(\"{location_name}\", stack)));
                    }} else {{
                        skip_tree(stack);
                    }}
                }},
                DeserializerNext::Close => {{
                    try!(end_element(tag_name, stack));
                    break;
                }}
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        Ok(obj)
        ",
        location_name = location_name,
        member_name = shape.member()
    )
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement =  match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "try!(characters(stack))",
        ShapeType::Integer => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Long => "i64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Double => "f64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Float => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Blob => "try!(characters(stack)).into_bytes()",
        ShapeType::Boolean => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {:?}", shape_type),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, shape: &Shape) -> String {
    if shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));
            stack.next();

            let obj = {name}::default();

            try!(end_element(tag_name, stack));
            stack.next();

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            let next_event = match stack.peek() {{
                Some(&XmlEvent::EndElement {{ .. }}) => DeserializerNext::Close,   // TODO verify that we received the expected tag?
                Some(&XmlEvent::StartElement {{ ref name, .. }}) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    match &name[..] {{
                        {struct_field_deserializers}
                        _ => skip_tree(stack),
                    }}
                }},
                DeserializerNext::Close => break,
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(shape),
    )
}

fn generate_struct_field_deserializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        // look up member.shape in all_shapes.  use that shape.member.location_name
        let location_name = member.location_name.as_ref().unwrap_or(member_name);

        let parse_expression = generate_struct_field_parse_expression(shape, member_name, member, member.location_name.as_ref());
        format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
            }}",
            field_name = generate_field_name(member_name),
            parse_expression = parse_expression,
            location_name = location_name,
        )

    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct_field_parse_expression(
    shape: &Shape,
    member_name: &str,
    member: &Member,
    location_name: Option<&String>,
) -> String {

    let location_to_use = match location_name {
        Some(loc) => loc.to_string(),
        None => member_name.to_string(),
    };
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location}\", stack))",
        name = member.shape,
        location = location_to_use,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}

fn generate_serializer_body(shape: &Shape) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_serializer(shape),
        ShapeType::Map => generate_map_serializer(shape),
        ShapeType::Structure => generate_struct_serializer(shape),
        _ => generate_primitive_serializer(shape),
    }
}

fn generate_serializer_signature(name: &str, shape: &Shape) -> String {
    if shape.shape_type == ShapeType::Structure && shape.members.as_ref().unwrap().is_empty() {
        format!("fn serialize(_params: &mut Params, name: &str, _obj: &{})", name)
    } else {
        format!("fn serialize(params: &mut Params, name: &str, obj: &{})", name)
    }
}

fn generate_list_serializer(shape: &Shape) -> String {
    format!(
        "for (index, element) in obj.iter().enumerate() {{
    let key = format!(\"{{}}.{{}}\", name, index);
    {name}Serializer::serialize(params, &key, element);
}}
        ",
        name = shape.member(),
    )
}

fn generate_map_serializer(shape: &Shape) -> String {
    format!(
        "for (index, (key, value)) in obj.iter().enumerate() {{
    let prefix = format!(\"{{}}.{{}}\", name, index);
    {key_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{key_name}\"),
        key,
    );
    {value_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{value_name}\"),
        value,
    );
}}
        ",
        key_name = shape.key(),
        value_name = shape.value(),
    )
}

fn generate_struct_serializer(shape: &Shape) -> String {
    format!(
        "let mut prefix = name.to_string();
if prefix != \"\" {{
    prefix.push_str(\".\");
}}

{struct_field_serializers}
        ",
        struct_field_serializers = generate_struct_field_serializers(shape),
    )
}

fn generate_struct_field_serializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        if shape.required(member_name) {
            format!(
                "{member_shape_name}Serializer::serialize(
    params,
    &format!(\"{{}}{tag_name}\", prefix),
    &obj.{field_name},
);
                ",
                field_name = generate_field_name(member_name),
                member_shape_name = member.shape,
                tag_name = member_name,
            )
        } else {
            format!(
                "if let Some(ref field_value) = obj.{field_name} {{
    {member_shape_name}Serializer::serialize(
        params,
        &format!(\"{{}}{tag_name}\", prefix),
        field_value,
    );
}}
                ",
                field_name = generate_field_name(member_name),
                member_shape_name = member.shape,
                tag_name = member.tag_name(),
            )
        }
    }).collect::<Vec<String>>().join("\n")
}

fn generate_primitive_serializer(shape: &Shape) -> String {
    let expression = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "obj",
        ShapeType::Integer | ShapeType::Long | ShapeType::Float | ShapeType::Double | ShapeType::Boolean => "&obj.to_string()",
        ShapeType::Blob => "from_utf8(obj).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {:?}", shape_type),
    };

    format!("params.put(name, {});", expression)
}
<commit_msg>fix incorrect struct field name<commit_after>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape, ShapeType};
use std::borrow::Cow;
use super::GenerateProtocol;
use super::generate_field_name;

pub struct Ec2Generator;

impl GenerateProtocol for Ec2Generator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            format!(
                "{documentation}
                {method_signature} {{
                    let mut request = SignedRequest::new(\"{http_method}\", \"{endpoint_prefix}\", self.region, \"{request_uri}\");
                    let mut params = Params::new();

                    params.put(\"Action\", \"{operation_name}\");
                    params.put(\"Version\", \"{api_version}\");

                    {serialize_input}

                    request.set_params(params);
                    request.sign(&try!(self.credentials_provider.credentials()));

                    let result = try!(self.dispatcher.dispatch(&request));

                    match result.status {{
                        200 => {{
                            let mut reader = EventReader::from_str(&result.body);
                            let mut stack = XmlResponse::new(reader.events().peekable());
                            stack.next();
                            {method_return_value}
                        }},
                        _ => Err({error_type}::from_body(&result.body))
                    }}
                }}
                ",
                documentation = generate_documentation(operation),
                http_method = &operation.http.method,
                endpoint_prefix = &service.metadata.endpoint_prefix,
                method_return_value = generate_method_return_value(operation),
                method_signature = generate_method_signature(operation),
                operation_name = &operation.name,
                error_type = operation.error_type_name(),
                api_version = service.metadata.api_version,
                request_uri = &operation.http.request_uri,
                serialize_input = generate_method_input_serialization(operation),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, _service: &Service) -> String {
        "use std::str::{FromStr, from_utf8};

        use xml::EventReader;

        use param::{Params, ServiceParams};

        use signature::SignedRequest;
        use xml::reader::events::XmlEvent;
        use xmlutil::{Next, Peek, XmlParseError, XmlResponse};
        use xmlutil::{characters, end_element, start_element, skip_tree};
        use xmlerror::*;

        enum DeserializerNext {
            Close,
            Skip,
            Element(String),
        }
        ".to_owned()
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Clone)]".to_owned()
    }

    fn generate_support_types(&self, name: &str, shape: &Shape, _service: &Service) -> Option<String> {
        Some(format!(
            "/// Deserializes `{name}` from XML.
            struct {name}Deserializer;
            impl {name}Deserializer {{
                #[allow(unused_variables)]
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}

            /// Serialize `{name}` contents to a `SignedRequest`.
            struct {name}Serializer;
            impl {name}Serializer {{
                {serializer_signature} {{
                    {serializer_body}
                }}
            }}
            ",
            deserializer_body = generate_deserializer_body(name, shape),
            name = name,
            serializer_body = generate_serializer_body(shape),
            serializer_signature = generate_serializer_signature(name, shape),
        ))
    }

    fn timestamp_type(&self) -> &'static str {
        "String"
    }
}

fn generate_documentation(operation: &Operation) -> String {
    match operation.documentation {
        Some(ref docs) => format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"").replace("C:\\", "C:\\\\")),
        None => "".to_owned(),
    }
}

fn generate_method_input_serialization(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "{input_type}Serializer::serialize(&mut params, \"\", &input);",
            input_type = operation.input.as_ref().unwrap().shape,
        )
    } else {
        String::new()
    }
}

fn generate_response_tag_name<'a>(member_name: &'a str) -> Cow<'a, str> {
    if member_name.ends_with("Result") {
        format!("{}Response", &member_name[..member_name.len()-6]).into()
    } else {
        member_name.into()
    }
}

fn generate_method_return_value(operation: &Operation) -> String {
    if operation.output.is_some() {
        let output_type = &operation.output.as_ref().unwrap().shape;
        let tag_name = generate_response_tag_name(output_type);
        format!(
            "Ok(try!({output_type}Deserializer::deserialize(\"{tag_name}\", &mut stack)))",
            output_type = output_type,
            tag_name = tag_name
        )
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {operation_name}(&self, input: &{input_type}) -> Result<{output_type}, {error_type}>",
            input_type = operation.input.as_ref().unwrap().shape,
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
            error_type = operation.error_type_name(),
        )
    } else {
        format!(
            "pub fn {operation_name}(&self) -> Result<{output_type}, {error_type}>",
            operation_name = operation.name.to_snake_case(),
            error_type = operation.error_type_name(),
            output_type = &operation.output_shape_or("()"),
        )
    }
}

fn generate_deserializer_body(name: &str, shape: &Shape) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_deserializer(shape),
        ShapeType::Structure => generate_struct_deserializer(name, shape),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {

    let location_name = shape.member.as_ref().and_then(|m| m.location_name.as_ref()).map(|name| &name[..]).unwrap_or(shape.member());

    format!(
        "
        let mut obj = vec![];
        try!(start_element(tag_name, stack));

        loop {{
            let next_event = match stack.peek() {{
                Some(&XmlEvent::EndElement {{ .. }}) => DeserializerNext::Close,
                Some(&XmlEvent::StartElement {{ ref name, .. }}) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    if name == \"{location_name}\" {{
                        obj.push(try!({member_name}Deserializer::deserialize(\"{location_name}\", stack)));
                    }} else {{
                        skip_tree(stack);
                    }}
                }},
                DeserializerNext::Close => {{
                    try!(end_element(tag_name, stack));
                    break;
                }}
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        Ok(obj)
        ",
        location_name = location_name,
        member_name = shape.member()
    )
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement =  match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "try!(characters(stack))",
        ShapeType::Integer => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Long => "i64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Double => "f64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Float => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Blob => "try!(characters(stack)).into_bytes()",
        ShapeType::Boolean => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {:?}", shape_type),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, shape: &Shape) -> String {
    if shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));
            stack.next();

            let obj = {name}::default();

            try!(end_element(tag_name, stack));
            stack.next();

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            let next_event = match stack.peek() {{
                Some(&XmlEvent::EndElement {{ .. }}) => DeserializerNext::Close,   // TODO verify that we received the expected tag?
                Some(&XmlEvent::StartElement {{ ref name, .. }}) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    match &name[..] {{
                        {struct_field_deserializers}
                        _ => skip_tree(stack),
                    }}
                }},
                DeserializerNext::Close => break,
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(shape),
    )
}

fn generate_struct_field_deserializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        // look up member.shape in all_shapes.  use that shape.member.location_name
        let location_name = member.location_name.as_ref().unwrap_or(member_name);

        let parse_expression = generate_struct_field_parse_expression(shape, member_name, member, member.location_name.as_ref());
        format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
            }}",
            field_name = generate_field_name(member_name),
            parse_expression = parse_expression,
            location_name = location_name,
        )

    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct_field_parse_expression(
    shape: &Shape,
    member_name: &str,
    member: &Member,
    location_name: Option<&String>,
) -> String {

    let location_to_use = match location_name {
        Some(loc) => loc.to_string(),
        None => member_name.to_string(),
    };
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location}\", stack))",
        name = member.shape,
        location = location_to_use,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}

fn generate_serializer_body(shape: &Shape) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_serializer(shape),
        ShapeType::Map => generate_map_serializer(shape),
        ShapeType::Structure => generate_struct_serializer(shape),
        _ => generate_primitive_serializer(shape),
    }
}

fn generate_serializer_signature(name: &str, shape: &Shape) -> String {
    if shape.shape_type == ShapeType::Structure && shape.members.as_ref().unwrap().is_empty() {
        format!("fn serialize(_params: &mut Params, name: &str, _obj: &{})", name)
    } else {
        format!("fn serialize(params: &mut Params, name: &str, obj: &{})", name)
    }
}

fn generate_list_serializer(shape: &Shape) -> String {
    format!(
        "for (index, element) in obj.iter().enumerate() {{
    let key = format!(\"{{}}.{{}}\", name, index);
    {name}Serializer::serialize(params, &key, element);
}}
        ",
        name = shape.member(),
    )
}

fn generate_map_serializer(shape: &Shape) -> String {
    format!(
        "for (index, (key, value)) in obj.iter().enumerate() {{
    let prefix = format!(\"{{}}.{{}}\", name, index);
    {key_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{key_name}\"),
        key,
    );
    {value_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{value_name}\"),
        value,
    );
}}
        ",
        key_name = shape.key(),
        value_name = shape.value(),
    )
}

fn generate_struct_serializer(shape: &Shape) -> String {
    format!(
        "let mut prefix = name.to_string();
if prefix != \"\" {{
    prefix.push_str(\".\");
}}

{struct_field_serializers}
        ",
        struct_field_serializers = generate_struct_field_serializers(shape),
    )
}

fn generate_struct_field_serializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        if shape.required(member_name) {
            format!(
                "{member_shape_name}Serializer::serialize(
    params,
    &format!(\"{{}}{tag_name}\", prefix),
    &obj.{field_name},
);
                ",
                field_name = generate_field_name(member_name),
                member_shape_name = member.shape,
                tag_name = member_name,
            )
        } else {
            format!(
                "if let Some(ref field_value) = obj.{field_name} {{
    {member_shape_name}Serializer::serialize(
        params,
        &format!(\"{{}}{tag_name}\", prefix),
        field_value,
    );
}}
                ",
                field_name = generate_field_name(member_name),
                member_shape_name = member.shape,
                tag_name = member.location_name.as_ref().unwrap_or(member_name),
            )
        }
    }).collect::<Vec<String>>().join("\n")
}

fn generate_primitive_serializer(shape: &Shape) -> String {
    let expression = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "obj",
        ShapeType::Integer | ShapeType::Long | ShapeType::Float | ShapeType::Double | ShapeType::Boolean => "&obj.to_string()",
        ShapeType::Blob => "from_utf8(obj).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {:?}", shape_type),
    };

    format!("params.put(name, {});", expression)
}
<|endoftext|>


<commit_before>use inflector::Inflector;

use botocore::{Service, Shape};

use self::json::JsonGenerator;
use self::query::QueryGenerator;

mod json;
mod query;

pub trait GenerateProtocol {
    fn generate_methods(&self, service: &Service) -> String;

    fn generate_prelude(&self, service: &Service) -> String;

    fn generate_struct_attributes(&self) -> String;

    fn generate_support_types(&self, _name: &str, _shape: &Shape) -> Option<String> {
        None
    }
}

pub fn generate_source(service: &Service) -> String {
    match &service.metadata.protocol[..] {
        "json" => generate(service, JsonGenerator),
        "query" => generate(service, QueryGenerator),
        protocol => panic!("Unknown protocol {}", protocol),
    }
}

fn generate<P>(service: &Service, protocol_generator: P) -> String where P: GenerateProtocol {
    format!(
        "{prelude}

        {types}

        {client}",
        client = generate_client(service, &protocol_generator),
        prelude = &protocol_generator.generate_prelude(service),
        types = generate_types(service, &protocol_generator),
    )
}

fn generate_client<P>(service: &Service, protocol_generator: &P) -> String
where P: GenerateProtocol {
    format!(
        "/// A client for the {service_name} API.
        pub struct {type_name}<'a> {{
            credentials_provider: Box<ProvideAWSCredentials + 'a>,
            region: &'a Region,
        }}

        impl<'a> {type_name}<'a> {{
            pub fn new<P>(
                credentials_provider: P,
                region: &'a Region,
            ) -> Self where P: ProvideAWSCredentials + 'a {{
                {type_name} {{
                    credentials_provider: Box::new(credentials_provider),
                    region: region,
                }}
            }}

            {methods}
        }}
        ",
        methods = protocol_generator.generate_methods(service),
        service_name = &service.metadata.service_abbreviation,
        type_name = service.client_type_name(),
    )
}

fn generate_list(name: &str, shape: &Shape) -> String {
    format!("pub type {} = Vec<{}>;", name, shape.member())
}

fn generate_map(name: &str, shape: &Shape) -> String {
    format!(
        "pub type {} = ::std::collections::HashMap<{}, {}>;",
        name,
        shape.key(),
        shape.value(),
    )
}

fn generate_primitive_type(name: &str, shape_type: &str) -> String {
    let primitive_type = match shape_type {
        "blob" => "Vec<u8>",
        "boolean" => "bool",
        "double" => "f64",
        "float" => "f32",
        "integer" => "i32",
        "long" => "i64",
        "string" => "String",
        "timestamp" => "f64",
        primitive_type => panic!("Unknown primitive type: {}", primitive_type),
    };

    format!("pub type {} = {};", name, primitive_type)
}

fn generate_types<P>(service: &Service, protocol_generator: &P) -> String
where P: GenerateProtocol {
    service.shapes.iter().filter_map(|(name, shape)| {
        if name == "String" {
            return protocol_generator.generate_support_types(name, shape);
        }

        let mut parts = Vec::with_capacity(3);

        if let Some(ref docs) = shape.documentation {
            parts.push(format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")));
        }

        match &shape.shape_type[..] {
            "structure" => parts.push(generate_struct(name, shape, protocol_generator)),
            "map" => parts.push(generate_map(name, shape)),
            "list" => parts.push(generate_list(name, shape)),
            shape_type => parts.push(generate_primitive_type(name, shape_type)),
        }

        if let Some(support_types) = protocol_generator.generate_support_types(name, shape) {
            parts.push(support_types);
        }

        Some(parts.join("\n"))
    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct<P>(name: &String, shape: &Shape, protocol_generator: &P) -> String
where P: GenerateProtocol {
    if shape.members.is_none() || shape.members.as_ref().unwrap().is_empty() {
        format!(
            "{attributes}
            pub struct {name};
            ",
            attributes = protocol_generator.generate_struct_attributes(),
            name = name,
        )
    } else {
        format!(
            "{attributes}
            pub struct {name} {{
                {struct_fields}
            }}
            ",
            attributes = protocol_generator.generate_struct_attributes(),
            name = name,
            struct_fields = generate_struct_fields(shape),
        )
    }

}

fn generate_struct_fields(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        let mut lines = Vec::with_capacity(2);
        let name = member_name.to_snake_case();

        if let Some(ref docs) = member.documentation {
            lines.push(format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")));
        }

        if shape.required(member_name) {
            lines.push(format!("pub {}: {},",  name, member.shape));
        } else if name == "type" {
            lines.push(format!("pub aws_{}: Option<{}>,",  name, member.shape));
        } else {
            lines.push(format!("pub {}: Option<{}>,",  name, member.shape));
        }

        lines.join("\n")
    }).collect::<Vec<String>>().join("\n")
}
<commit_msg>Serialize struct fields to original camel case.<commit_after>use inflector::Inflector;

use botocore::{Service, Shape};

use self::json::JsonGenerator;
use self::query::QueryGenerator;

mod json;
mod query;

pub trait GenerateProtocol {
    fn generate_methods(&self, service: &Service) -> String;

    fn generate_prelude(&self, service: &Service) -> String;

    fn generate_struct_attributes(&self) -> String;

    fn generate_support_types(&self, _name: &str, _shape: &Shape) -> Option<String> {
        None
    }
}

pub fn generate_source(service: &Service) -> String {
    match &service.metadata.protocol[..] {
        "json" => generate(service, JsonGenerator),
        "query" => generate(service, QueryGenerator),
        protocol => panic!("Unknown protocol {}", protocol),
    }
}

fn generate<P>(service: &Service, protocol_generator: P) -> String where P: GenerateProtocol {
    format!(
        "{prelude}

        {types}

        {client}",
        client = generate_client(service, &protocol_generator),
        prelude = &protocol_generator.generate_prelude(service),
        types = generate_types(service, &protocol_generator),
    )
}

fn generate_client<P>(service: &Service, protocol_generator: &P) -> String
where P: GenerateProtocol {
    format!(
        "/// A client for the {service_name} API.
        pub struct {type_name}<'a> {{
            credentials_provider: Box<ProvideAWSCredentials + 'a>,
            region: &'a Region,
        }}

        impl<'a> {type_name}<'a> {{
            pub fn new<P>(
                credentials_provider: P,
                region: &'a Region,
            ) -> Self where P: ProvideAWSCredentials + 'a {{
                {type_name} {{
                    credentials_provider: Box::new(credentials_provider),
                    region: region,
                }}
            }}

            {methods}
        }}
        ",
        methods = protocol_generator.generate_methods(service),
        service_name = &service.metadata.service_abbreviation,
        type_name = service.client_type_name(),
    )
}

fn generate_list(name: &str, shape: &Shape) -> String {
    format!("pub type {} = Vec<{}>;", name, shape.member())
}

fn generate_map(name: &str, shape: &Shape) -> String {
    format!(
        "pub type {} = ::std::collections::HashMap<{}, {}>;",
        name,
        shape.key(),
        shape.value(),
    )
}

fn generate_primitive_type(name: &str, shape_type: &str) -> String {
    let primitive_type = match shape_type {
        "blob" => "Vec<u8>",
        "boolean" => "bool",
        "double" => "f64",
        "float" => "f32",
        "integer" => "i32",
        "long" => "i64",
        "string" => "String",
        "timestamp" => "f64",
        primitive_type => panic!("Unknown primitive type: {}", primitive_type),
    };

    format!("pub type {} = {};", name, primitive_type)
}

fn generate_types<P>(service: &Service, protocol_generator: &P) -> String
where P: GenerateProtocol {
    service.shapes.iter().filter_map(|(name, shape)| {
        if name == "String" {
            return protocol_generator.generate_support_types(name, shape);
        }

        let mut parts = Vec::with_capacity(3);

        if let Some(ref docs) = shape.documentation {
            parts.push(format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")));
        }

        match &shape.shape_type[..] {
            "structure" => parts.push(generate_struct(name, shape, protocol_generator)),
            "map" => parts.push(generate_map(name, shape)),
            "list" => parts.push(generate_list(name, shape)),
            shape_type => parts.push(generate_primitive_type(name, shape_type)),
        }

        if let Some(support_types) = protocol_generator.generate_support_types(name, shape) {
            parts.push(support_types);
        }

        Some(parts.join("\n"))
    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct<P>(name: &String, shape: &Shape, protocol_generator: &P) -> String
where P: GenerateProtocol {
    if shape.members.is_none() || shape.members.as_ref().unwrap().is_empty() {
        format!(
            "{attributes}
            pub struct {name};
            ",
            attributes = protocol_generator.generate_struct_attributes(),
            name = name,
        )
    } else {
        format!(
            "{attributes}
            pub struct {name} {{
                {struct_fields}
            }}
            ",
            attributes = protocol_generator.generate_struct_attributes(),
            name = name,
            struct_fields = generate_struct_fields(shape),
        )
    }

}

fn generate_struct_fields(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        let mut lines = Vec::with_capacity(3);
        let name = member_name.to_snake_case();

        if let Some(ref docs) = member.documentation {
            lines.push(format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")));
        }

        lines.push(format!("#[serde(rename=\"{}\")]", member_name));

        if shape.required(member_name) {
            lines.push(format!("pub {}: {},",  name, member.shape));
        } else if name == "type" {
            lines.push(format!("pub aws_{}: Option<{}>,",  name, member.shape));
        } else {
            lines.push(format!("pub {}: Option<{}>,",  name, member.shape));
        }

        lines.join("\n")
    }).collect::<Vec<String>>().join("\n")
}
<|endoftext|>


<commit_before>// Used internally for evalulating expressions

use super::lexer::Token;
use super::lexer;
use super::{CompileError, SourcePos, from_bool, is_truthy};
use super::scope::Scope;
use std::num;

#[deriving(Show, Clone)]
enum ExprToken {
	Op(Operator),
	Value(f32),
	Var(uint),
	LParen,
	RParen,
}

#[deriving(Show, Clone)]
enum Operator {
	Add,
	Sub,
	Mul,
	Div,
	Exp,
	Mod,
	Neg,
	Less,
	Greater,
	Equ,
	NotEqu,
	ApproxEqu,
	Not,
	And,
	Or,
	Xor,
	GreaterEqual,
	LessEqual,
}

#[deriving(PartialEq)]
enum Associativity {
	Left,
	Right,
}

impl Operator {
	fn precedence(self) -> int {
		match self {
			And | Or | Xor => 0,
			Equ | NotEqu | ApproxEqu => 1,
			Less | Greater | GreaterEqual | LessEqual => 2,
			Add | Sub => 3,
			Mul | Div | Mod => 4,
			Neg | Not | Exp => 6,
		}
	}

	fn num_args(self) -> uint {
		match self {
			Neg | Not => 1,
			_ => 2,
		}
	}

	fn associativity(self) -> Associativity {
		match self {
			Exp => Right,
			_ => Left,
		}
	}
}

// An expression is a mathematical statement containing a number of operators, constants and
// variables. It evaluates to a single number.
#[deriving(Show, Clone)]
pub struct Expression<'a> {
	rpn: Vec<ExprToken>, // reverse polish notation
	pos: SourcePos,
}

impl<'a> Expression<'a> {
	// converts a token slice from the lexer into an expression that can be evaluated
	pub fn new<'s>(tok: &'a [Token<'a>], scope: &'s Scope<'a>) -> Result<Expression<'a>, CompileError> {
		let out = try!(to_expr_tokens(tok, scope));
		let out = match shunting_yard(out.as_slice()) {
			Ok(out) => out,
			Err(e) => return Err(CompileError { msg: e.to_string(), pos: Some(tok[0].pos) })
		};

		Ok(Expression {
			rpn: out,
			pos: tok[0].pos, // Point to the location in the source that the expression started at.
		})
	}

	// Replaces variables with their values in the given scope
	pub fn fold_scope(&mut self, scope: &'a Scope<'a>) {
		for tok in self.rpn.iter_mut() {
			match tok {
				&Var(id) => {
					match scope.get_var(id) {
						Some(id) => *tok = Value(id),
						None => { }
					}
				},
				_ => { }
			}
		}
	}

	// Evaluates the value of the expression
	pub fn eval(&self, scope: &'a Scope<'a>) -> Result<f32, CompileError> {
		match eval_rpn(self.rpn.as_slice(), scope) {
			Ok(val) => Ok(val),
			Err(e) => Err(CompileError { msg: e, pos: Some(self.pos) }),
		}
	}
}

// Converts tokens from the lexer into ExprTokens, which are simplified to drop any strings and
// contain only information understandable by the expression parser. Any variables encountered are
// defined in the scope.
fn to_expr_tokens(tok: &[Token], scope: &Scope) -> Result<Vec<ExprToken>, CompileError> {
	if tok.is_empty() {
		return Err(CompileError { msg: "empty expression in file".to_string(), pos: None });
	}
	let mut out = Vec::new();

	for &t in tok.iter() {
		match t.t {
			// Try to parse constants as f32. subject to maybe change but probably not.
			lexer::Const(v) => {
				out.push(Value(v))
			},
			lexer::Operator(v) => {
				out.push(Op(match v {
					"+" => Add,
					"-" => Sub,
					"*" => Mul,
					"/" => Div,
					"^" => Exp,
					"%" => Mod,
					"==" => Equ,
					"!=" => NotEqu,
					"~=" => ApproxEqu,
					"<" => Less,
					">" => Greater,
					"<=" => LessEqual,
					">=" => GreaterEqual,
					"!" => Not,
					"&&" => And,
					"||" => Or,
					"^^" => Xor,
					x => {
						return Err(CompileError { msg: format!("unexpected operator in expression: `{}`", x), pos: Some(t.pos) });
					}
				}))
			},
			lexer::Paren(v) => {
				out.push(match v {
					'(' => LParen,
					')' => RParen,
					x => {
						return Err(CompileError { msg: format!("unexpected paren type in expression: `{}`", x), pos: Some(t.pos) });
					}
				})
			},
			// An identifier in the context of an expression is always a variable
			lexer::Ident(v) => {
				match scope.var_id(v) {
					Some(id) => out.push(Var(id)),
					None => {
						return Err(CompileError { msg: format!("variable `{}` appears in expression but is not defined in scope", v), pos: Some(t.pos) })
					}
				}
			},
			// Discard whitesapce
			lexer::Newline => { },

			x => {
				return Err(CompileError { msg: format!("unexpected token in expression `{}`", x), pos: Some(t.pos) });
			}
		}
	}

	// Handle special case with unary minus
	// If an subtraction operator is preceded by another operator, left paren, or the start of the
	// expression, make it a negation operator.
	// would be nice if you could use map_in_place here, but can't because of enumerate.
	let out: Vec<ExprToken> = out.iter().enumerate().map(|(i, &v)| {
		match v {
			Op(Sub) => {
				if i == 0 || match out[i-1] { Op(_) | LParen => true, _ => false } {
					Op(Neg)
				} else {
					v
				}
			},
			_ => v
		}
	}).collect();

	Ok(out)
}

// http://en.wikipedia.org/wiki/Shunting-yard_algorithm
fn shunting_yard(tok: &[ExprToken]) -> Result<Vec<ExprToken>, &'static str> {
	let mut out = Vec::new();
	let mut stack: Vec<ExprToken> = Vec::new();

	for &t in tok.iter() {
		match t {
			Value(_) | Var(_) => {
				out.push(t);
			}

			Op(op1) => {
				while stack.len() > 0 {
					let top = *stack.last().unwrap(); // unwrap() can't fail, see condition on while loop
					match top {
						Op(op2) => {
							if op1.associativity() == Left && op1.precedence() <= op2.precedence()
								|| op1.precedence() < op2.precedence() {
								stack.pop();
								out.push(top);
							} else {
								break;
							}
						},
						_ => break
					}
				}
				stack.push(t);
			},

			LParen => {
				stack.push(t);
			},

			RParen => {
				let mut foundleft = false;
				while stack.len() > 0 {
					let op = stack.pop().unwrap();
					match op {
						Op(_) => {
							out.push(op);
						},
						LParen => {
							foundleft = true;
							break;
						},
						x => panic!("internal error: unexpected value on stack: `{}`", x)
					}
				}
				if !foundleft {
					return Err("mismatched parens: skewed right");
				}
			}
		};
	}

	while stack.len() > 0 {
		let top = stack[stack.len()-1];
		match top {
			Op(_) => {
				stack.pop();
				out.push(top);
			},
			LParen | RParen => return Err("mismatched parens: skewed left"),
			x => panic!("internal error: non operator on stack: `{}`", x)
		}
	}

	Ok(out)
}

// http://en.wikipedia.org/wiki/Reverse_Polish_notation
fn eval_rpn(rpn: &[ExprToken], scope: &Scope) -> Result<f32, String> {
	let mut stack = Vec::new();

	for &t in rpn.iter() {
		match t {
			Value(v) => {
				stack.push(v);
			},

			Var(id) => {
				match scope.get_var(id) {
					Some(val) => stack.push(val),
					None => return Err(format!("Attempted to access a nonexistent variable (id={})", id))
				}
			},

			Op(op) => {
				// Pop args off stack
				let n = op.num_args();
				if stack.len() < n {
					return Err(format!("invalid expression: not enough args for operator {}", op));
				}
				// unwrap() can't fail because of the size check above.
				let args: Vec<f32> = range(0, n).map(|_| stack.pop().unwrap()).collect();

				// Do calculation and push result
				stack.push(match op {
					Add => {
						args[1] + args[0]
					},
					Sub => {
						args[1] - args[0]
					},
					Mul => {
						args[1] * args[0]
					},
					Div => {
						args[1] / args[0]
					},
					Exp => {
						args[1].powf(args[0])
					},
					Mod => {
						let c = num::abs(args[1]/args[0]).fract()*num::abs(args[0]);
						if is_truthy(args[1]) { c } else { -c }
					},
					Neg => {
						-args[0]
					},
					Not => {
						from_bool(is_truthy(-args[0]))
					},
					Less => {
						from_bool(args[1] < args[0])
					},
					Greater => {
						from_bool(args[1] > args[0])
					},
					LessEqual => {
						from_bool(args[1] <= args[0])
					},
					GreaterEqual => {
						from_bool(args[1] >= args[0])
					},
					Equ => {
						from_bool(args[1] == args[0])
					},
					NotEqu => {
						from_bool(args[1] != args[0])
					},
					ApproxEqu => {
						from_bool(num::abs(args[1] - args[0]) < 0.0001)
					},
					And => {
						from_bool(is_truthy(args[1]) && is_truthy(args[0]))
					},
					Or => {
						from_bool(is_truthy(args[1]) || is_truthy(args[0]))
					},
					Xor => {
						from_bool(is_truthy(args[1]) ^ is_truthy(args[0]))
					},
				});
			},

			x => return Err(format!("unexpected token in expression: `{}`", x))
		}
	}
	match stack.len() {
		1 => {
			let val = stack.pop().unwrap();
			Ok(val)
		},
		0 => {
			Err("zero values in expression".to_string())
		},
		_ => {
			Err("too many values in expression".to_string())
		}
	}
}
<commit_msg>revert of the boolean related changes that didn't actually make sense<commit_after>// Used internally for evalulating expressions

use super::lexer::Token;
use super::lexer;
use super::{CompileError, SourcePos, from_bool, is_truthy};
use super::scope::Scope;
use std::num;

#[deriving(Show, Clone)]
enum ExprToken {
	Op(Operator),
	Value(f32),
	Var(uint),
	LParen,
	RParen,
}

#[deriving(Show, Clone)]
enum Operator {
	Add,
	Sub,
	Mul,
	Div,
	Exp,
	Mod,
	Neg,
	Less,
	Greater,
	Equ,
	NotEqu,
	ApproxEqu,
	Not,
	And,
	Or,
	Xor,
	GreaterEqual,
	LessEqual,
}

#[deriving(PartialEq)]
enum Associativity {
	Left,
	Right,
}

impl Operator {
	fn precedence(self) -> int {
		match self {
			And | Or | Xor => 0,
			Equ | NotEqu | ApproxEqu => 1,
			Less | Greater | GreaterEqual | LessEqual => 2,
			Add | Sub => 3,
			Mul | Div | Mod => 4,
			Neg | Not | Exp => 6,
		}
	}

	fn num_args(self) -> uint {
		match self {
			Neg | Not => 1,
			_ => 2,
		}
	}

	fn associativity(self) -> Associativity {
		match self {
			Exp => Right,
			_ => Left,
		}
	}
}

// An expression is a mathematical statement containing a number of operators, constants and
// variables. It evaluates to a single number.
#[deriving(Show, Clone)]
pub struct Expression<'a> {
	rpn: Vec<ExprToken>, // reverse polish notation
	pos: SourcePos,
}

impl<'a> Expression<'a> {
	// converts a token slice from the lexer into an expression that can be evaluated
	pub fn new<'s>(tok: &'a [Token<'a>], scope: &'s Scope<'a>) -> Result<Expression<'a>, CompileError> {
		let out = try!(to_expr_tokens(tok, scope));
		let out = match shunting_yard(out.as_slice()) {
			Ok(out) => out,
			Err(e) => return Err(CompileError { msg: e.to_string(), pos: Some(tok[0].pos) })
		};

		Ok(Expression {
			rpn: out,
			pos: tok[0].pos, // Point to the location in the source that the expression started at.
		})
	}

	// Replaces variables with their values in the given scope
	pub fn fold_scope(&mut self, scope: &'a Scope<'a>) {
		for tok in self.rpn.iter_mut() {
			match tok {
				&Var(id) => {
					match scope.get_var(id) {
						Some(id) => *tok = Value(id),
						None => { }
					}
				},
				_ => { }
			}
		}
	}

	// Evaluates the value of the expression
	pub fn eval(&self, scope: &'a Scope<'a>) -> Result<f32, CompileError> {
		match eval_rpn(self.rpn.as_slice(), scope) {
			Ok(val) => Ok(val),
			Err(e) => Err(CompileError { msg: e, pos: Some(self.pos) }),
		}
	}
}

// Converts tokens from the lexer into ExprTokens, which are simplified to drop any strings and
// contain only information understandable by the expression parser. Any variables encountered are
// defined in the scope.
fn to_expr_tokens(tok: &[Token], scope: &Scope) -> Result<Vec<ExprToken>, CompileError> {
	if tok.is_empty() {
		return Err(CompileError { msg: "empty expression in file".to_string(), pos: None });
	}
	let mut out = Vec::new();

	for &t in tok.iter() {
		match t.t {
			// Try to parse constants as f32. subject to maybe change but probably not.
			lexer::Const(v) => {
				out.push(Value(v))
			},
			lexer::Operator(v) => {
				out.push(Op(match v {
					"+" => Add,
					"-" => Sub,
					"*" => Mul,
					"/" => Div,
					"^" => Exp,
					"%" => Mod,
					"==" => Equ,
					"!=" => NotEqu,
					"~=" => ApproxEqu,
					"<" => Less,
					">" => Greater,
					"<=" => LessEqual,
					">=" => GreaterEqual,
					"!" => Not,
					"&&" => And,
					"||" => Or,
					"^^" => Xor,
					x => {
						return Err(CompileError { msg: format!("unexpected operator in expression: `{}`", x), pos: Some(t.pos) });
					}
				}))
			},
			lexer::Paren(v) => {
				out.push(match v {
					'(' => LParen,
					')' => RParen,
					x => {
						return Err(CompileError { msg: format!("unexpected paren type in expression: `{}`", x), pos: Some(t.pos) });
					}
				})
			},
			// An identifier in the context of an expression is always a variable
			lexer::Ident(v) => {
				match scope.var_id(v) {
					Some(id) => out.push(Var(id)),
					None => {
						return Err(CompileError { msg: format!("variable `{}` appears in expression but is not defined in scope", v), pos: Some(t.pos) })
					}
				}
			},
			// Discard whitesapce
			lexer::Newline => { },

			x => {
				return Err(CompileError { msg: format!("unexpected token in expression `{}`", x), pos: Some(t.pos) });
			}
		}
	}

	// Handle special case with unary minus
	// If an subtraction operator is preceded by another operator, left paren, or the start of the
	// expression, make it a negation operator.
	// would be nice if you could use map_in_place here, but can't because of enumerate.
	let out: Vec<ExprToken> = out.iter().enumerate().map(|(i, &v)| {
		match v {
			Op(Sub) => {
				if i == 0 || match out[i-1] { Op(_) | LParen => true, _ => false } {
					Op(Neg)
				} else {
					v
				}
			},
			_ => v
		}
	}).collect();

	Ok(out)
}

// http://en.wikipedia.org/wiki/Shunting-yard_algorithm
fn shunting_yard(tok: &[ExprToken]) -> Result<Vec<ExprToken>, &'static str> {
	let mut out = Vec::new();
	let mut stack: Vec<ExprToken> = Vec::new();

	for &t in tok.iter() {
		match t {
			Value(_) | Var(_) => {
				out.push(t);
			}

			Op(op1) => {
				while stack.len() > 0 {
					let top = *stack.last().unwrap(); // unwrap() can't fail, see condition on while loop
					match top {
						Op(op2) => {
							if op1.associativity() == Left && op1.precedence() <= op2.precedence()
								|| op1.precedence() < op2.precedence() {
								stack.pop();
								out.push(top);
							} else {
								break;
							}
						},
						_ => break
					}
				}
				stack.push(t);
			},

			LParen => {
				stack.push(t);
			},

			RParen => {
				let mut foundleft = false;
				while stack.len() > 0 {
					let op = stack.pop().unwrap();
					match op {
						Op(_) => {
							out.push(op);
						},
						LParen => {
							foundleft = true;
							break;
						},
						x => panic!("internal error: unexpected value on stack: `{}`", x)
					}
				}
				if !foundleft {
					return Err("mismatched parens: skewed right");
				}
			}
		};
	}

	while stack.len() > 0 {
		let top = stack[stack.len()-1];
		match top {
			Op(_) => {
				stack.pop();
				out.push(top);
			},
			LParen | RParen => return Err("mismatched parens: skewed left"),
			x => panic!("internal error: non operator on stack: `{}`", x)
		}
	}

	Ok(out)
}

// http://en.wikipedia.org/wiki/Reverse_Polish_notation
fn eval_rpn(rpn: &[ExprToken], scope: &Scope) -> Result<f32, String> {
	let mut stack = Vec::new();

	for &t in rpn.iter() {
		match t {
			Value(v) => {
				stack.push(v);
			},

			Var(id) => {
				match scope.get_var(id) {
					Some(val) => stack.push(val),
					None => return Err(format!("Attempted to access a nonexistent variable (id={})", id))
				}
			},

			Op(op) => {
				// Pop args off stack
				let n = op.num_args();
				if stack.len() < n {
					return Err(format!("invalid expression: not enough args for operator {}", op));
				}
				// unwrap() can't fail because of the size check above.
				let args: Vec<f32> = range(0, n).map(|_| stack.pop().unwrap()).collect();

				// Do calculation and push result
				stack.push(match op {
					Add => {
						args[1] + args[0]
					},
					Sub => {
						args[1] - args[0]
					},
					Mul => {
						args[1] * args[0]
					},
					Div => {
						args[1] / args[0]
					},
					Exp => {
						args[1].powf(args[0])
					},
					Mod => {
						let c = num::abs(args[1]/args[0]).fract()*num::abs(args[0]);
						if args[1] > 0_f32 { c } else { -c }
					},
					Neg => {
						-args[0]
					},
					Not => {
						from_bool(is_truthy(-args[0]))
					},
					Less => {
						from_bool(args[1] < args[0])
					},
					Greater => {
						from_bool(args[1] > args[0])
					},
					LessEqual => {
						from_bool(args[1] <= args[0])
					},
					GreaterEqual => {
						from_bool(args[1] >= args[0])
					},
					Equ => {
						from_bool(args[1] == args[0])
					},
					NotEqu => {
						from_bool(args[1] != args[0])
					},
					ApproxEqu => {
						from_bool(num::abs(args[1] - args[0]) < 0.0001)
					},
					And => {
						from_bool(is_truthy(args[1]) && is_truthy(args[0]))
					},
					Or => {
						from_bool(is_truthy(args[1]) || is_truthy(args[0]))
					},
					Xor => {
						from_bool(is_truthy(args[1]) ^ is_truthy(args[0]))
					},
				});
			},

			x => return Err(format!("unexpected token in expression: `{}`", x))
		}
	}
	match stack.len() {
		1 => {
			let val = stack.pop().unwrap();
			Ok(val)
		},
		0 => {
			Err("zero values in expression".to_string())
		},
		_ => {
			Err("too many values in expression".to_string())
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>tile type field for Tile made public<commit_after><|endoftext|>


<commit_before><commit_msg>Added operation composition example<commit_after>extern crate gpuarray as ga;

use ga::Context;
use ga::tensor::{Tensor, TensorMode};
use ga::array::Array;

fn main() {
    let ref ctx = Context::new();

    let a = Array::from_vec(vec![5, 15], (0..5*15).map(|x| x as f32).collect());
    let b = Array::from_vec(vec![15, 10], (0..15*10).map(|x| (x as f32)*2.0).collect());
    let c = Array::from_vec(vec![5, 10], vec![1.0; 5*10]);

    let a_gpu = Tensor::from_array(ctx, &a, TensorMode::In);
    let b_gpu = Tensor::from_array(ctx, &b, TensorMode::In);
    let c_gpu = Tensor::from_array(ctx, &c, TensorMode::In);
    // Our intermediate result must be TensorMode::Mut
    let d_gpu: Tensor<f32> = Tensor::new(ctx, vec![5, 10], TensorMode::Mut);
    let e_gpu: Tensor<f32> = Tensor::new(ctx, vec![5, 10], TensorMode::Out);

    ga::matmul(ctx, &a_gpu, &b_gpu, &d_gpu);
    ga::add(ctx, &d_gpu, -1, &c_gpu, &e_gpu);

    let d = d_gpu.get(ctx);
    let e = e_gpu.get(ctx);

    println!("A = \n{:?}", a);
    println!("B = \n{:?}", b);
    println!("C = \n{:?}", c);
    println!("D = A * B  = \n{:?}", d);
    println!("D + C = \n{:?}", e);
}
<|endoftext|>


<commit_before><commit_msg>debuginfo: Add test case for destructured for-loop variable.<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android: FIXME(#10381)
// min-lldb-version: 310

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run

// DESTRUCTURED STRUCT
// gdb-command:print x
// gdb-check:$1 = 400
// gdb-command:print y
// gdb-check:$2 = 401.5
// gdb-command:print z
// gdb-check:$3 = true
// gdb-command:continue

// DESTRUCTURED TUPLE
// gdb-command:print/x _i8
// gdb-check:$4 = 0x6f
// gdb-command:print/x _u8
// gdb-check:$5 = 0x70
// gdb-command:print _i16
// gdb-check:$6 = -113
// gdb-command:print _u16
// gdb-check:$7 = 114
// gdb-command:print _i32
// gdb-check:$8 = -115
// gdb-command:print _u32
// gdb-check:$9 = 116
// gdb-command:print _i64
// gdb-check:$10 = -117
// gdb-command:print _u64
// gdb-check:$11 = 118
// gdb-command:print _f32
// gdb-check:$12 = 119.5
// gdb-command:print _f64
// gdb-check:$13 = 120.5
// gdb-command:continue

// MORE COMPLEX CASE
// gdb-command:print v1
// gdb-check:$14 = 80000
// gdb-command:print x1
// gdb-check:$15 = 8000
// gdb-command:print *y1
// gdb-check:$16 = 80001.5
// gdb-command:print z1
// gdb-check:$17 = false
// gdb-command:print *x2
// gdb-check:$18 = -30000
// gdb-command:print y2
// gdb-check:$19 = -300001.5
// gdb-command:print *z2
// gdb-check:$20 = true
// gdb-command:print v2
// gdb-check:$21 = 854237.5
// gdb-command:continue

// SIMPLE IDENTIFIER
// gdb-command:print i
// gdb-check:$22 = 1234
// gdb-command:continue

// gdb-command:print simple_struct_ident
// gdb-check:$23 = {x = 3537, y = 35437.5, z = true}
// gdb-command:continue

// gdb-command:print simple_tuple_ident
// gdb-check:$24 = {34903493, 232323}
// gdb-command:continue

// === LLDB TESTS ==================================================================================

// lldb-command:type format add --format hex char
// lldb-command:type format add --format hex 'unsigned char'

// lldb-command:run

// DESTRUCTURED STRUCT
// lldb-command:print x
// lldb-check:[...]$0 = 400
// lldb-command:print y
// lldb-check:[...]$1 = 401.5
// lldb-command:print z
// lldb-check:[...]$2 = true
// lldb-command:continue

// DESTRUCTURED TUPLE
// lldb-command:print _i8
// lldb-check:[...]$3 = 0x6f
// lldb-command:print _u8
// lldb-check:[...]$4 = 0x70
// lldb-command:print _i16
// lldb-check:[...]$5 = -113
// lldb-command:print _u16
// lldb-check:[...]$6 = 114
// lldb-command:print _i32
// lldb-check:[...]$7 = -115
// lldb-command:print _u32
// lldb-check:[...]$8 = 116
// lldb-command:print _i64
// lldb-check:[...]$9 = -117
// lldb-command:print _u64
// lldb-check:[...]$10 = 118
// lldb-command:print _f32
// lldb-check:[...]$11 = 119.5
// lldb-command:print _f64
// lldb-check:[...]$12 = 120.5
// lldb-command:continue

// MORE COMPLEX CASE
// lldb-command:print v1
// lldb-check:[...]$13 = 80000
// lldb-command:print x1
// lldb-check:[...]$14 = 8000
// lldb-command:print *y1
// lldb-check:[...]$15 = 80001.5
// lldb-command:print z1
// lldb-check:[...]$16 = false
// lldb-command:print *x2
// lldb-check:[...]$17 = -30000
// lldb-command:print y2
// lldb-check:[...]$18 = -300001.5
// lldb-command:print *z2
// lldb-check:[...]$19 = true
// lldb-command:print v2
// lldb-check:[...]$20 = 854237.5
// lldb-command:continue

// SIMPLE IDENTIFIER
// lldb-command:print i
// lldb-check:[...]$21 = 1234
// lldb-command:continue

// lldb-command:print simple_struct_ident
// lldb-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
// lldb-command:continue

// lldb-command:print simple_tuple_ident
// lldb-check:[...]$23 = (34903493, 232323)
// lldb-command:continue

struct Struct {
    x: i16,
    y: f32,
    z: bool
}

fn main() {

    let s = Struct {
        x: 400,
        y: 401.5,
        z: true
    };

    for &Struct { x, y, z } in [s].iter() {
        zzz(); // #break
    }

    let tuple: (i8, u8, i16, u16, i32, u32, i64, u64, f32, f64) =
        (0x6f, 0x70, -113, 114, -115, 116, -117, 118, 119.5, 120.5);

    for &(_i8, _u8, _i16, _u16, _i32, _u32, _i64, _u64, _f32, _f64) in [tuple].iter() {
        zzz(); // #break
    }

    let more_complex: (i32, &Struct, Struct, Box<f64>) =
        (80000,
         &Struct {
            x: 8000,
            y: 80001.5,
            z: false
         },
         Struct {
            x: -30000,
            y: -300001.5,
            z: true
         },
         box 854237.5);

    for &(v1,
          &Struct { x: x1, y: ref y1, z: z1 },
          Struct { x: ref x2, y: y2, z: ref z2 },
          box v2) in [more_complex].iter() {
        zzz(); // #break
    }

    for i in range(1234, 1235i) {
        zzz(); // #break
    }

    for simple_struct_ident in
      vec![Struct {
            x: 3537,
            y: 35437.5,
            z: true
           }].into_iter() {
      zzz(); // #break
    }

    for simple_tuple_ident in vec![(34903493u32, 232323i64)].into_iter() {
      zzz(); // #break
    }
}

fn zzz() {()}
<|endoftext|>


<commit_before>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

use std::ascii::OwnedStrAsciiExt; // for `into_ascii_lower`
use std::from_str::FromStr;
use std::num::FromStrRadix;

// Data structures:

#[deriving(Show)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[deriving(Show)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[deriving(Show)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[deriving(Show)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[deriving(Show)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[deriving(Show, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    Color(u8, u8, u8, u8), // RGBA
}

#[deriving(Show, Clone, PartialEq)]
pub enum Unit {
    Px,
}

pub type Specificity = (uint, uint, uint);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Simple(ref simple) = *self;
        let a = simple.id.iter().len();
        let b = simple.class.len();
        let c = simple.tag_name.iter().len();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Length(f, Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0u, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        rules
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); }
                '{' => break,
                c   => fail!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        selectors
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut result = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    result.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    result.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    result.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        result
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert!(self.consume_char() == '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        declarations
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert!(self.consume_char() == ':')
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert!(self.consume_char() == ';')

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'..'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'..'9' | '.' => true,
            _ => false
        });
        let f: Option<f32> = FromStr::from_str(s.as_slice());
        f.unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match self.parse_identifier().into_ascii_lower().as_slice() {
            "px" => Px,
            _ => fail!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert!(self.consume_char() == '#');
        Color(self.parse_hex_pair(), self.parse_hex_pair(), self.parse_hex_pair(), 255)
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = self.input.as_slice().slice(self.pos, self.pos + 2);
        self.pos = self.pos + 2;
        FromStrRadix::from_str_radix(s, 0x10).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<commit_msg>Allow whitespace after comma in selector list<commit_after>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

use std::ascii::OwnedStrAsciiExt; // for `into_ascii_lower`
use std::from_str::FromStr;
use std::num::FromStrRadix;

// Data structures:

#[deriving(Show)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[deriving(Show)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[deriving(Show)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[deriving(Show)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[deriving(Show)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[deriving(Show, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    Color(u8, u8, u8, u8), // RGBA
}

#[deriving(Show, Clone, PartialEq)]
pub enum Unit {
    Px,
}

pub type Specificity = (uint, uint, uint);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Simple(ref simple) = *self;
        let a = simple.id.iter().len();
        let b = simple.class.len();
        let c = simple.tag_name.iter().len();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Length(f, Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0u, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        rules
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); self.consume_whitespace(); }
                '{' => break,
                c   => fail!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        selectors
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut result = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    result.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    result.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    result.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        result
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert!(self.consume_char() == '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        declarations
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert!(self.consume_char() == ':')
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert!(self.consume_char() == ';')

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'..'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'..'9' | '.' => true,
            _ => false
        });
        let f: Option<f32> = FromStr::from_str(s.as_slice());
        f.unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match self.parse_identifier().into_ascii_lower().as_slice() {
            "px" => Px,
            _ => fail!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert!(self.consume_char() == '#');
        Color(self.parse_hex_pair(), self.parse_hex_pair(), self.parse_hex_pair(), 255)
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = self.input.as_slice().slice(self.pos, self.pos + 2);
        self.pos = self.pos + 2;
        FromStrRadix::from_str_radix(s, 0x10).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<|endoftext|>


<commit_before><commit_msg>follow clippys orders<commit_after><|endoftext|>