<commit_before>use std::default::Default;
use ::internal::prelude::*;

macro_rules! colour {
    ($(#[$attr:meta] $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub fn $name() -> Colour {
                    Colour::new($val)
                }
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivilant to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`get_g`]:
///
/// ```rust,ignore
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let colour = Colour::new(role.colour);
/// let green = colour.get_g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`dark_teal`] presets:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::dark_teal();
///
/// assert_eq!(colour.get_tuple(), (17, 128, 106));
/// ```
///
/// [`Role`]: ../model/struct.Role.html
/// [`dark_teal`]: #method.dark_teal
/// [`get_g`]: #method.get_g
#[derive(Clone, Copy, Debug)]
pub struct Colour {
    /// The raw inner 32-bit unsigned integer value of this Colour. This is
    /// worked with to generate values such as the red component value.
    pub value: u32,
}

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivilant
    /// to a specific RGB value, retrieved via [`get_tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_tuple`]: #method.get_tuple
    pub fn new(value: u32) -> Colour {
        Colour {
            value: value,
        }
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).value == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).value == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.get_r(), 217);
    /// assert_eq!(colour.get_g(), 45);
    /// assert_eq!(colour.get_b(), 215);
    /// assert_eq!(colour.get_tuple(), (217, 45, 215));
    /// ```
    pub fn from_rgb(r: u8, g: u8, b: u8) -> Colour {
        let mut uint = r as u32;
        uint = (uint << 8) | (g as u32);
        uint = (uint << 8) | (b as u32);

        Colour::new(uint)
    }

    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Colour> {
        match value {
            Value::U64(v) => Ok(Colour::new(v as u32)),
            Value::I64(v) => Ok(Colour::new(v as u32)),
            other => Err(Error::Decode("Expected valid colour", other)),
        }
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_r(), 100);
    /// ```
    pub fn get_r(&self) -> u8 {
        ((self.value >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_g(), 76);
    /// ```
    pub fn get_g(&self) -> u8 {
        ((self.value >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_b(), 67);
    pub fn get_b(&self) -> u8 {
        (self.value & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivilant to creating a tuple with the return values of
    /// [`get_r`], [`get_g`], and [`get_b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_r`]: #method.get_r
    /// [`get_g`]: #method.get_g
    /// [`get_b`]: #method.get_b
    pub fn get_tuple(&self) -> (u8, u8, u8) {
        (self.get_r(), self.get_g(), self.get_b())
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).get_tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour::new(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).get_r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour::new(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).get_r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour::new(value as u32)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    /// This is equivilant to setting the RGB value to `(0, 0, 0)`.
    fn default() -> Colour {
        Colour {
            value: 0,
        }
    }
}
<commit_msg>Add fabled_pink to Colour struct<commit_after>use std::default::Default;
use ::internal::prelude::*;

macro_rules! colour {
    ($(#[$attr:meta] $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub fn $name() -> Colour {
                    Colour::new($val)
                }
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivilant to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`get_g`]:
///
/// ```rust,ignore
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let colour = Colour::new(role.colour);
/// let green = colour.get_g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`dark_teal`] presets:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::dark_teal();
///
/// assert_eq!(colour.get_tuple(), (17, 128, 106));
/// ```
///
/// [`Role`]: ../model/struct.Role.html
/// [`dark_teal`]: #method.dark_teal
/// [`get_g`]: #method.get_g
#[derive(Clone, Copy, Debug)]
pub struct Colour {
    /// The raw inner 32-bit unsigned integer value of this Colour. This is
    /// worked with to generate values such as the red component value.
    pub value: u32,
}

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivilant
    /// to a specific RGB value, retrieved via [`get_tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_tuple`]: #method.get_tuple
    pub fn new(value: u32) -> Colour {
        Colour {
            value: value,
        }
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).value == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).value == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.get_r(), 217);
    /// assert_eq!(colour.get_g(), 45);
    /// assert_eq!(colour.get_b(), 215);
    /// assert_eq!(colour.get_tuple(), (217, 45, 215));
    /// ```
    pub fn from_rgb(r: u8, g: u8, b: u8) -> Colour {
        let mut uint = r as u32;
        uint = (uint << 8) | (g as u32);
        uint = (uint << 8) | (b as u32);

        Colour::new(uint)
    }

    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Colour> {
        match value {
            Value::U64(v) => Ok(Colour::new(v as u32)),
            Value::I64(v) => Ok(Colour::new(v as u32)),
            other => Err(Error::Decode("Expected valid colour", other)),
        }
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_r(), 100);
    /// ```
    pub fn get_r(&self) -> u8 {
        ((self.value >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_g(), 76);
    /// ```
    pub fn get_g(&self) -> u8 {
        ((self.value >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_b(), 67);
    pub fn get_b(&self) -> u8 {
        (self.value & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivilant to creating a tuple with the return values of
    /// [`get_r`], [`get_g`], and [`get_b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_r`]: #method.get_r
    /// [`get_g`]: #method.get_g
    /// [`get_b`]: #method.get_b
    pub fn get_tuple(&self) -> (u8, u8, u8) {
        (self.get_r(), self.get_g(), self.get_b())
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).get_tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour::new(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).get_r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour::new(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).get_r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour::new(value as u32)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(250, 177, 237)`.
    fabled_pink, 0xFAB1ED
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    /// This is equivilant to setting the RGB value to `(0, 0, 0)`.
    fn default() -> Colour {
        Colour {
            value: 0,
        }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use tokens::*;
use lexer::*;
use parser::*;
use symbol_table::*;
use support::*;
use plp::PLPWriter;

pub fn compile_class(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    if tokens[current_index].value != "{" { panic!("Expected '{{' received: {}", tokens[current_index].value); }
    else { current_index += 1; }

    for (index, token) in tokens.iter().enumerate()
    {
        // Handle forward skipping
        if index < current_index { continue; }
        else { current_index = index; }

        // TODO: encapsulate into token_rules.validate(token)
        // Panic! if token type is invalid
        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        // Panic! if token value is invalid
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (end_index, compiled_class) = compile_class(&tokens, index + 1);
            plp_string.push_str(&*compiled_class);

            current_index = end_index;
        }
        else if token.name == "type" // || token.name == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }

    (current_index + 1, plp_string)
}

/// Write PLP code to evaluate the given symbol sequence, and load the result into a specific register
/// A sequence can be:
/// * a  simple variable reference,
/// * a method call,
/// * a variable accessed from another symbol (e.g. foo.bar or Foo.staticBar),
/// * a method accessed from another symbol (e.g. foo.bar() or Foo.staticBar()), or
/// * a complex chain of the above (e.g. foo.method().valueInReturnValue.value.method())
///
/// The start index should be the first symbol in the sequence
/// @return (plp_code, the first index AFTER this symbol sequence)
pub fn compile_symbol_sequence( tokens: &Vec<Token>,
                            start: usize,
                            current_namespace: &str,
                            temp_register: &str, // indirect
                            load_registers: (&str, &str),
                            target_register: &str,
                            symbols: &StaticSymbolTable)
                            -> (String, usize)
{
    // TODO: handle array access

    let mut plp = PLPWriter::new();
    let mut index = start;
    while index < (tokens.len() - 1)
    {
        let token = &tokens[index];

        if token.name == "identifier"
        {
            let lookahead_token = &tokens[index + 1];

            // Method call
            if lookahead_token.value == "("
            {
                // compile the method and append it directly to the compiled plp code
                let (method_code, return_type) = compile_method_call(tokens, index, current_namespace, temp_register, load_registers, symbols);
                plp.code.push_str(&*method_code);
            }
            // Variable read
            else
            {
                let symbol = symbols.lookup_variable(current_namespace, &*token.value).unwrap();
                match symbol.location
                {
                    SymbolLocation::Register(name) => {
                            plp.mov(target_register, name);
                        },
                    SymbolLocation::Memory(address) => {
                            plp.li(load_registers.0, address.label_name);
                            plp.lw(target_register, address.offset, load_registers.0);
                        },
                    SymbolLocation::InstancedMemory(offset) => {
                            plp.lw(target_register, offset, target_register);
                        },
                    SymbolLocation::Structured => {
                            // TODO: append to namespace
                        },
                };
            }
        }
        else if token.value == "."
        {
            // Access references are handled when it's children are parsed (in the if block above)
            // so skip this token
            index += 1;
            continue;
        }
        else
        {
            break;
        }

        index += 1;
    }
    // first index AFTER the sequence
    index += 1;

    // TODO: compile

    (plp.code, index)
}

/// The range should start at the method identifier and end on the token AFTER the closing parenthesis
/// @return (code, return_type)
pub fn compile_method_call( tokens: &Vec<Token>,
                            start: usize,
                            current_namespace: &str,
                            arg_register: &str,
                            load_registers: (&str, &str),
                            symbols: &StaticSymbolTable)
                            -> (String, String)
{
    let mut plp = PLPWriter::new();

    // start at the token AFTER the open parenthesis
    let mut index = start + 2;

    // Index OF the closing parenthesis
    let end_index = identify_body_bounds(&tokens, index, ("(", ")")).unwrap();

    // TODO: Keep track of argument types, in order, to determine the method signature
    let mut argument_types: Vec<String> = Vec::new();

    while index < end_index
    {
        let token = &tokens[index];
        if token.value == "("
        {
            panic!("Parenthesis surrounding expression currently unsupported");
        }
        else if token.value == ","
        {
            // Skip commas, arguments are separated by the stack divisors
            index += 1;
            continue;
        }
        else
        {
            // Load argument into arg_register
            let (code, argument_type, new_index) = compile_arithmetic_statement(tokens, index, current_namespace, "$t9", load_registers, arg_register, symbols);
            plp.code.push_str(&*code);
            index = new_index;

            // Push argument_type to argument_types
            argument_types.push(argument_type.clone());

            // Push argument to the stack
            plp.push(arg_register);
        }
    }

    // Find nested method calls
    // Handle each argument one at a time, and push each to the stack

    // TODO: determine namespace from caller and current_namespace
    let namespace = "";

    let id_token = &tokens[start];
    let method_name = &*id_token.value;
    // TODO: determine if method is static
    // TODO: if function is non-static, push $this to stack

    let method_symbol = symbols.lookup_function(namespace, method_name, &argument_types).unwrap();
    let return_type = match method_symbol.symbol_class
    {
        SymbolClass::Variable(variable_type) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(return_type, argument_types) => return_type,
        SymbolClass::Structure(subtype) => {
                panic!("Expected Function found Structure");
            }
    };
    match method_symbol.location
    {
        SymbolLocation::Register(name) => {
                panic!("Found method at a Register instead of a constant Memory address");
            },
        SymbolLocation::Memory(address) => {
                plp.call(address.label_name);
            },
        SymbolLocation::InstancedMemory(offset) => {
                panic!("Found method at InstancedMemory instead of a constant Memory address");
            },
        SymbolLocation::Structured => {
                // TODO: call constructor
                panic!("Constructors currently unsupported");
            },
    };

    return (plp.code, return_type.to_string());
}

/// @return (code, result_type, end_index)
pub fn compile_arithmetic_statement(tokens: &Vec<Token>,            // used
	                                start: usize,                   // used
	                                current_namespace: &str,        // indirect
	                                temp_register: &str,   			// used
	                                load_registers: (&str, &str),	// indirect
	                                target_register: &str,			// used
	                                symbols: &StaticSymbolTable)	// indirect
	                                -> (String, String, usize)
{
    // TODO: handle parenthesis
    // TODO: handle order of operations
    let mut plp = PLPWriter::new();

    // Evaluate first symbol and store it in target_register, then push the result to the stack
    let mut index = compile_evaluation(tokens, start, current_namespace, temp_register, load_registers, target_register, symbols, &mut plp);
	plp.push(target_register);

    // loop until arithmetic sequence ends
	let operator_token = &tokens[index];
    if operator_token.name.starts_with("operator")
    {
        // PRESUMPTION: The first operand is at the top of the stack

        // Evaluate the second operand and store the result in temp_register
        let (code, operand_type, new_index) = compile_arithmetic_statement(tokens, index + 1, current_namespace, temp_register, load_registers, temp_register, symbols);
		index = new_index;
		plp.code.push_str(&*code);

		// Retreive the first operand from the stack and store it in target_register
		plp.pop(target_register);

        // Perform the operation on the first (target_register) and second operand (temp_register) and store the result in target_register
        let code = compile_arithmetic_operation(&operator_token, (target_register, temp_register), target_register);
		plp.code.push_str(&*code);
    }

    // TODO: determine real type instead of "Number"
    (plp.code, "Number".to_string(),index)
}

/// Evaluates either a literal, or a sequence of symbols (variables, accessors, method calls, etc)
///
/// Writes to the specified PLPWriter code to evaluate a value triggered by the start token
/// If the token is a literal, the literal value will be loaded into the target_register
/// If the token is an identifier, it will be evaluated based on what the symbol represents
/// * If the symbol represents a method, the method will be called and the result stored in target_register
/// * If the symbol represents a variable, or a chain of accessors, the sequence will be evaluated and the result stored in target_register
///
/// This method will compile plp code directly to a PLPWriter as specified
///
/// @return
pub fn compile_evaluation(  tokens: &Vec<Token>,            // used
                            start: usize,                   // used
                            current_namespace: &str,        // indirect-------------
                            temp_register: &str,            // used
                            load_registers: (&str, &str),   // indirect-------------
                            target_register: &str,          // used
                            symbols: &StaticSymbolTable,    // indirect-------------
                            plp: &mut PLPWriter)            // used
                            -> usize
{
    let mut token = &tokens[start];
    let mut end_index = start;

    if token.name.starts_with("literal")
    {
        let value = &*token.value;
        plp.li(target_register, value);

        end_index += 1;
    }
    else if token.name == "identifier"
    {
        // handle identifier
        let (access_code, new_index) = compile_symbol_sequence(tokens, start, current_namespace, temp_register, load_registers, target_register, symbols);
        plp.code.push_str(&*access_code);

        end_index = new_index;
    }
    else if token.value == "("
    {
        // TODO: find end bounds and evaluate parenthetical expression
        panic!("Unexpected token: {}\t{}", token.name, token.value);
    }
    else
    {
        panic!("Unexpected token: {}\t{}", token.name, token.value);
    }

    end_index
}

/// Writes plp code to perform a binary operation on two registers, and store the result in a third register
/// The specified registers need not be unique, and may all be the same if desired
/// This method performs only a single operation, and does not check for register validity
/// The register arguments are assumed to be prefaced with '$'
pub fn compile_arithmetic_operation(operator: &Token, operand_registers: (&str, &str), result_register: &str) -> String
{
    let mut plp = PLPWriter::new();

    match &*operator.value
    {
        "+" => plp.addu(result_register, operand_registers.0, operand_registers.1),
        "-" => plp.subu(result_register, operand_registers.0, operand_registers.1),
        "*" => plp.mullo(result_register, operand_registers.0, operand_registers.1),
         _  => panic!("Unsupported operator: {}: {}", operator.name, operator.value)
    };

    return plp.code;
}
<commit_msg>Fix indexing defect<commit_after>use std::vec::Vec;
use tokens::*;
use lexer::*;
use symbol_table::*;
use support::*;
use plp::PLPWriter;

pub fn compile_class(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    if tokens[current_index].value != "{" { panic!("Expected '{{' received: {}", tokens[current_index].value); }
    else { current_index += 1; }

    for (index, token) in tokens.iter().enumerate()
    {
        // Handle forward skipping
        if index < current_index { continue; }
        else { current_index = index; }

        // TODO: encapsulate into token_rules.validate(token)
        // Panic! if token type is invalid
        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        // Panic! if token value is invalid
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (end_index, compiled_class) = compile_class(&tokens, index + 1);
            plp_string.push_str(&*compiled_class);

            current_index = end_index;
        }
        else if token.name == "type" // || token.name == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }

    (current_index + 1, plp_string)
}

/// Write PLP code to evaluate the given symbol sequence, and load the result into a specific register
/// A sequence can be:
/// * a  simple variable reference,
/// * a method call,
/// * a variable accessed from another symbol (e.g. foo.bar or Foo.staticBar),
/// * a method accessed from another symbol (e.g. foo.bar() or Foo.staticBar()), or
/// * a complex chain of the above (e.g. foo.method().valueInReturnValue.value.method())
///
/// The start index should be the first symbol in the sequence
/// @return (plp_code, the first index AFTER this symbol sequence)
pub fn compile_symbol_sequence( tokens: &Vec<Token>,
                            start: usize,
                            current_namespace: &str,
                            temp_register: &str, // indirect
                            load_registers: (&str, &str),
                            target_register: &str,
                            symbols: &StaticSymbolTable)
                            -> (String, usize)
{
    // TODO: handle array access

    let mut plp = PLPWriter::new();
    let mut index = start;
    while index < (tokens.len() - 1)
    {
        let token = &tokens[index];

        if token.name == "identifier"
        {
            let lookahead_token = &tokens[index + 1];

            // Method call
            if lookahead_token.value == "("
            {
                // compile the method and append it directly to the compiled plp code
                let (method_code, return_type, new_index) = compile_method_call(tokens, index, current_namespace, temp_register, load_registers, symbols);
                plp.code.push_str(&*method_code);
                index = new_index;
            }
            // Variable read
            else
            {
                let symbol = symbols.lookup_variable(current_namespace, &*token.value).unwrap();
                match symbol.location
                {
                    SymbolLocation::Register(name) => {
                            plp.mov(target_register, name);
                        },
                    SymbolLocation::Memory(address) => {
                            plp.li(load_registers.0, address.label_name);
                            plp.lw(target_register, address.offset, load_registers.0);
                        },
                    SymbolLocation::InstancedMemory(offset) => {
                            plp.lw(target_register, offset, target_register);
                        },
                    SymbolLocation::Structured => {
                            // TODO: append to namespace
                        },
                };

                index += 1;
            }
        }
        else if token.value == "."
        {
            // Access references are handled when it's children are parsed (in the if block above)
            // so skip this token
            index += 1;
            continue;
        }
        else
        {
            break;
        }
    }
    // first index AFTER the sequence
    index += 1;

    // TODO: compile

    (plp.code, index)
}

/// The range should start at the method identifier
/// The returned end_index will be the index AFTER the closing parenthesis
/// @return (code, return_type, end_index)
pub fn compile_method_call( tokens: &Vec<Token>,
                            start: usize,
                            current_namespace: &str,
                            arg_register: &str,
                            load_registers: (&str, &str),
                            symbols: &StaticSymbolTable)
                            -> (String, String, usize)
{
    let mut plp = PLPWriter::new();

    // start at the token AFTER the open parenthesis
    let mut index = start + 2;

    // Index OF the closing parenthesis
    let end_index = identify_body_bounds(&tokens, index, ("(", ")")).unwrap();

    // TODO: Keep track of argument types, in order, to determine the method signature
    let mut argument_types: Vec<String> = Vec::new();

    while index < end_index
    {
        let token = &tokens[index];
        if token.value == "("
        {
            panic!("Parenthesis surrounding expression currently unsupported");
        }
        else if token.value == ","
        {
            // Skip commas, arguments are separated by the stack divisors
            index += 1;
            continue;
        }
        else
        {
            // Load argument into arg_register
            let (code, argument_type, new_index) = compile_arithmetic_statement(tokens, index, current_namespace, "$t9", load_registers, arg_register, symbols);
            plp.code.push_str(&*code);
            index = new_index;

            // Push argument_type to argument_types
            argument_types.push(argument_type.clone());

            // Push argument to the stack
            plp.push(arg_register);
        }
    }

    // Find nested method calls
    // Handle each argument one at a time, and push each to the stack

    // TODO: determine namespace from caller and current_namespace
    let namespace = "";

    let id_token = &tokens[start];
    let method_name = &*id_token.value;
    // TODO: determine if method is static
    // TODO: if function is non-static, push $this to stack

    let method_symbol = symbols.lookup_function(namespace, method_name, &argument_types).unwrap();
    let return_type = match method_symbol.symbol_class
    {
        SymbolClass::Variable(variable_type) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(return_type, argument_types) => return_type,
        SymbolClass::Structure(subtype) => {
                panic!("Expected Function found Structure");
            }
    };
    match method_symbol.location
    {
        SymbolLocation::Register(name) => {
                panic!("Found method at a Register instead of a constant Memory address");
            },
        SymbolLocation::Memory(address) => {
                plp.call(address.label_name);
            },
        SymbolLocation::InstancedMemory(offset) => {
                panic!("Found method at InstancedMemory instead of a constant Memory address");
            },
        SymbolLocation::Structured => {
                // TODO: call constructor
                panic!("Constructors currently unsupported");
            },
    };

    //Return index AFTER the closing parenthesis
    return (plp.code, return_type.to_string(), end_index + 1);
}

/// @return (code, result_type, end_index)
pub fn compile_arithmetic_statement(tokens: &Vec<Token>,            // used
	                                start: usize,                   // used
	                                current_namespace: &str,        // indirect
	                                temp_register: &str,   			// used
	                                load_registers: (&str, &str),	// indirect
	                                target_register: &str,			// used
	                                symbols: &StaticSymbolTable)	// indirect
	                                -> (String, String, usize)
{
    // TODO: handle parenthesis
    // TODO: handle order of operations
    let mut plp = PLPWriter::new();

    // Evaluate first symbol and store it in target_register, then push the result to the stack
    let mut index = compile_evaluation(tokens, start, current_namespace, temp_register, load_registers, target_register, symbols, &mut plp);
	plp.push(target_register);

    // loop until arithmetic sequence ends
	let operator_token = &tokens[index];
    if operator_token.name.starts_with("operator")
    {
        // PRESUMPTION: The first operand is at the top of the stack

        // Evaluate the second operand and store the result in temp_register
        let (code, operand_type, new_index) = compile_arithmetic_statement(tokens, index + 1, current_namespace, temp_register, load_registers, temp_register, symbols);
		index = new_index;
		plp.code.push_str(&*code);

		// Retreive the first operand from the stack and store it in target_register
		plp.pop(target_register);

        // Perform the operation on the first (target_register) and second operand (temp_register) and store the result in target_register
        let code = compile_arithmetic_operation(&operator_token, (target_register, temp_register), target_register);
		plp.code.push_str(&*code);
    }

    // TODO: determine real type instead of "Number"
    (plp.code, "Number".to_string(),index)
}

/// Evaluates either a literal, or a sequence of symbols (variables, accessors, method calls, etc)
///
/// Writes to the specified PLPWriter code to evaluate a value triggered by the start token
/// If the token is a literal, the literal value will be loaded into the target_register
/// If the token is an identifier, it will be evaluated based on what the symbol represents
/// * If the symbol represents a method, the method will be called and the result stored in target_register
/// * If the symbol represents a variable, or a chain of accessors, the sequence will be evaluated and the result stored in target_register
///
/// This method will compile plp code directly to a PLPWriter as specified
///
/// @return
pub fn compile_evaluation(  tokens: &Vec<Token>,            // used
                            start: usize,                   // used
                            current_namespace: &str,        // indirect-------------
                            temp_register: &str,            // used
                            load_registers: (&str, &str),   // indirect-------------
                            target_register: &str,          // used
                            symbols: &StaticSymbolTable,    // indirect-------------
                            plp: &mut PLPWriter)            // used
                            -> usize
{
    let mut token = &tokens[start];
    let mut end_index = start;

    if token.name.starts_with("literal")
    {
        let value = &*token.value;
        plp.li(target_register, value);

        end_index += 1;
    }
    else if token.name == "identifier"
    {
        // handle identifier
        let (access_code, new_index) = compile_symbol_sequence(tokens, start, current_namespace, temp_register, load_registers, target_register, symbols);
        plp.code.push_str(&*access_code);

        end_index = new_index;
    }
    else if token.value == "("
    {
        // TODO: find end bounds and evaluate parenthetical expression
        panic!("Unexpected token: {}\t{}", token.name, token.value);
    }
    else
    {
        panic!("Unexpected token: {}\t{}", token.name, token.value);
    }

    end_index
}

/// Writes plp code to perform a binary operation on two registers, and store the result in a third register
/// The specified registers need not be unique, and may all be the same if desired
/// This method performs only a single operation, and does not check for register validity
/// The register arguments are assumed to be prefaced with '$'
pub fn compile_arithmetic_operation(operator: &Token, operand_registers: (&str, &str), result_register: &str) -> String
{
    let mut plp = PLPWriter::new();

    match &*operator.value
    {
        "+" => plp.addu(result_register, operand_registers.0, operand_registers.1),
        "-" => plp.subu(result_register, operand_registers.0, operand_registers.1),
        "*" => plp.mullo(result_register, operand_registers.0, operand_registers.1),
         _  => panic!("Unsupported operator: {}: {}", operator.name, operator.value)
    };

    return plp.code;
}
<|endoftext|>


<commit_before>use rsfml::graphics::{RectangleShape, RenderWindow, Color, Vertex, VertexArray, LinesStrip};
use rsfml::system::Vector2f;

pub struct HUD<'self> {
    priv window_size : Vector2f,
    priv background : RectangleShape<'self>,
    priv face : i32,
    priv hud_vertex_array : VertexArray
}

impl<'self> HUD<'self> {
    pub fn new(window_size : &Vector2f) -> HUD<'self> {
        let mut array = VertexArray::new().unwrap();
        array.set_primitive_type(LinesStrip);
        HUD {
            window_size : window_size.clone(),
            background : RectangleShape::new().unwrap(),
            face : 0,
            hud_vertex_array : array
        }
    }

    pub fn update(&mut self) -> () {
        self.background.set_size2f(self.window_size.x - 20., 60.);
        self.background.set_fill_color(~Color::new_RGB(6, 1, 162));
        self.background.set_position2f(10., self.window_size.y - 70.);
    }

    fn draw_line(&mut self, x1 : f32, x2 : f32, y1 : f32, y2 : f32, color : &Color, render_window : &mut RenderWindow) -> () {
        self.hud_vertex_array.clear();
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x1, y : y1}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x2, y : y2}, color));
        render_window.draw(&self.hud_vertex_array);
    }

    fn draw_2line(&mut self, x1 : f32, x2 : f32, x3 : f32, y1 : f32, y2 : f32, y3 : f32, color : &Color, render_window : &mut RenderWindow) -> () {
        self.hud_vertex_array.clear();
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x1, y : y1}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x2, y : y2}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x3, y : y3}, color));
        render_window.draw(&self.hud_vertex_array);
    }

    pub fn draw(&mut self, render_window : &mut RenderWindow) -> () {
        // render_window.draw(&self.background);
        // let mut border = VertexArray::new().unwrap();
        // border.set_primitive_type(LinesStrip);
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 9., y : self.window_size.y - 70.}, &Color::new_RGBA(255, 255, 255, 75)));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 9., y : self.window_size.y - 10.}, &Color::new_RGBA(255, 255, 255, 75)));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 9., y : self.window_size.y - 10.}, &Color::new_RGBA(255, 255, 255, 75)));
        // render_window.draw(&border);
        // border.clear();
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 11., y : self.window_size.y - 70.}, &Color::black()));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 11., y : self.window_size.y - 12.}, &Color::black()));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 11., y : self.window_size.y - 12.}, &Color::black()));
        // render_window.draw(&border);
        // border.clear();
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 9., y : self.window_size.y - 12.}, &Color::black()));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 9., y : self.window_size.y - 71.}, &Color::black()));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 9., y : self.window_size.y - 71.}, &Color::black()));
        // render_window.draw(&border);
        // border.clear();
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 11., y : self.window_size.y - 11.}, &Color::new_RGBA(255, 255, 255, 75)));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : 11., y : self.window_size.y - 69.}, &Color::new_RGBA(255, 255, 255, 75)));
        // border.append(&Vertex::new_with_pos_color(~Vector2f {x : self.window_size.x - 11., y : self.window_size.y - 69.}, &Color::new_RGBA(255, 255, 255, 75)));
        // render_window.draw(&border);
        self.draw_2line(self.window_size.x - 9., self.window_size.x - 9., 9., self.window_size.y - 70., self.window_size.y - 10., self.window_size.y - 10., &Color::new_RGBA(255, 255, 255, 75), render_window);
        self.draw_2line(self.window_size.x - 11., self.window_size.x - 11., 11., self.window_size.y - 70., self.window_size.y - 12., self.window_size.y - 12., &Color::black(), render_window);
        self.draw_2line(9., 9., self.window_size.x - 9., self.window_size.y - 12., self.window_size.y - 71., self.window_size.y - 71., &Color::black(), render_window);
        self.draw_2line(11., 11., self.window_size.x - 11., self.window_size.y - 11., self.window_size.y - 69., self.window_size.y - 69., &Color::new_RGBA(255, 255, 255, 75), render_window);
        self.draw_line(self.window_size.x, 0., self.window_size.y - 80., self.window_size.y - 80., &Color::new_RGBA(255, 255, 255, 50), render_window);
        self.draw_line(self.window_size.x, 0., self.window_size.y - 79., self.window_size.y - 79., &Color::new_RGBA(255, 255, 255, 75), render_window);
    }
}<commit_msg>remove comment...<commit_after>use rsfml::graphics::{RectangleShape, RenderWindow, Color, Vertex, VertexArray, LinesStrip};
use rsfml::system::Vector2f;

pub struct HUD<'self> {
    priv window_size : Vector2f,
    priv background : RectangleShape<'self>,
    priv face : i32,
    priv hud_vertex_array : VertexArray
}

impl<'self> HUD<'self> {
    pub fn new(window_size : &Vector2f) -> HUD<'self> {
        let mut array = VertexArray::new().unwrap();
        array.set_primitive_type(LinesStrip);
        HUD {
            window_size : window_size.clone(),
            background : RectangleShape::new().unwrap(),
            face : 0,
            hud_vertex_array : array
        }
    }

    pub fn update(&mut self) -> () {
        self.background.set_size2f(self.window_size.x - 20., 60.);
        self.background.set_fill_color(~Color::new_RGB(6, 1, 162));
        self.background.set_position2f(10., self.window_size.y - 70.);
    }

    fn draw_line(&mut self, x1 : f32, x2 : f32, y1 : f32, y2 : f32, color : &Color, render_window : &mut RenderWindow) -> () {
        self.hud_vertex_array.clear();
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x1, y : y1}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x2, y : y2}, color));
        render_window.draw(&self.hud_vertex_array);
    }

    fn draw_2line(&mut self, x1 : f32, x2 : f32, x3 : f32, y1 : f32, y2 : f32, y3 : f32, color : &Color, render_window : &mut RenderWindow) -> () {
        self.hud_vertex_array.clear();
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x1, y : y1}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x2, y : y2}, color));
        self.hud_vertex_array.append(&Vertex::new_with_pos_color(~Vector2f {x : x3, y : y3}, color));
        render_window.draw(&self.hud_vertex_array);
    }

    pub fn draw(&mut self, render_window : &mut RenderWindow) -> () {
        self.draw_2line(self.window_size.x - 9., self.window_size.x - 9., 9., self.window_size.y - 70., self.window_size.y - 10., self.window_size.y - 10., &Color::new_RGBA(255, 255, 255, 75), render_window);
        self.draw_2line(self.window_size.x - 11., self.window_size.x - 11., 11., self.window_size.y - 70., self.window_size.y - 12., self.window_size.y - 12., &Color::black(), render_window);
        self.draw_2line(9., 9., self.window_size.x - 9., self.window_size.y - 12., self.window_size.y - 71., self.window_size.y - 71., &Color::black(), render_window);
        self.draw_2line(11., 11., self.window_size.x - 11., self.window_size.y - 11., self.window_size.y - 69., self.window_size.y - 69., &Color::new_RGBA(255, 255, 255, 75), render_window);
        self.draw_line(self.window_size.x, 0., self.window_size.y - 80., self.window_size.y - 80., &Color::new_RGBA(255, 255, 255, 50), render_window);
        self.draw_line(self.window_size.x, 0., self.window_size.y - 79., self.window_size.y - 79., &Color::new_RGBA(255, 255, 255, 75), render_window);
    }
}<|endoftext|>


<commit_before>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;
use url::Url;

use error::{Error, NotAcceptable};
use schema::{Schema, BoxedSchema};
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(PartialEq, Debug)]
pub struct Definition {
  /// The default driver when one is not specified for a specific type.
  driver: Option<DriverConfig>,
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      driver: None,
      types: BTreeMap::new()
    }
  }

  /// Set the driver config.
  pub fn set_driver(&mut self, driver: DriverConfig) {
    self.driver = Some(driver);
  }

  /// Get the driver config.
  pub fn driver(&self) -> Option<&DriverConfig> {
    self.driver.as_ref()
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type<'a, K>(&self, name: K) -> Option<&Type> where K: Into<&'a Key> {
    self.types.get(name.into())
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(
          Error
          ::new(NotAcceptable, format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()))
          .set_hint("Use a recognizable file extension like '.json' or '.yml'.")
        )
      }
    })
  }
}

/// Represents a high-level database type.
#[derive(PartialEq, Debug)]
pub struct Type {
  /// A type may optionally have its own driver.
  driver: Option<DriverConfig>,
  /// The schema used to validate data which claims to be of this type.
  schema: Option<BoxedSchema>
}

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      driver: None,
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: BoxedSchema) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}

/// Configuration for what driver to use and what URL to use to connect that
/// driver.
// TODO: can't finalize this until dynamic loading of drivers is implemented.
#[derive(PartialEq, Debug)]
pub struct DriverConfig {
  /// The name of the driver to use.
  name: String,
  /// The URL to pass into the driver when connecting.
  url: Url
}

impl DriverConfig {
  /// Create a new driver config. Is only passed a URL and the scheme of the
  /// URL will be used for the name.
  pub fn new(url: Url) -> Self {
    DriverConfig {
      name: url.scheme.clone(),
      url: url
    }
  }

  /// Returns the name of the driver.
  pub fn name(&self) -> &str {
    &self.name
  }

  /// Returns the URL to the driver.
  pub fn url(&self) -> &Url {
    &self.url
  }
}
<commit_msg>refactor(schema): remove name from driver config<commit_after>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;
use url::Url;

use error::{Error, NotAcceptable};
use schema::{Schema, BoxedSchema};
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(PartialEq, Debug)]
pub struct Definition {
  /// The default driver when one is not specified for a specific type.
  driver: Option<DriverConfig>,
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      driver: None,
      types: BTreeMap::new()
    }
  }

  /// Set the driver config.
  pub fn set_driver(&mut self, driver: DriverConfig) {
    self.driver = Some(driver);
  }

  /// Get the driver config.
  pub fn driver(&self) -> Option<&DriverConfig> {
    self.driver.as_ref()
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type<'a, K>(&self, name: K) -> Option<&Type> where K: Into<&'a Key> {
    self.types.get(name.into())
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(
          Error
          ::new(NotAcceptable, format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()))
          .set_hint("Use a recognizable file extension like '.json' or '.yml'.")
        )
      }
    })
  }
}

/// Represents a high-level database type.
#[derive(PartialEq, Debug)]
pub struct Type {
  /// A type may optionally have its own driver.
  driver: Option<DriverConfig>,
  /// The schema used to validate data which claims to be of this type.
  schema: Option<BoxedSchema>
}

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      driver: None,
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: BoxedSchema) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}

/// Configuration for what driver to use and what URL to use to connect that
/// driver.
// TODO: can't finalize this until dynamic loading of drivers is implemented.
#[derive(PartialEq, Debug)]
pub struct DriverConfig {
  /// The URL to pass into the driver when connecting.
  url: Url
}

impl DriverConfig {
  /// Create a new driver config. Is only passed a URL and the scheme of the
  /// URL will be used for the name.
  pub fn new(url: Url) -> Self {
    DriverConfig {
      url: url
    }
  }

  /// Returns the URL to the driver.
  pub fn url(&self) -> &Url {
    &self.url
  }
}
<|endoftext|>


<commit_before>#[doc = "
A graphics sink that renders to PNG format buffers

Each time the renderer renders a frame the bufsink will output a
`~[u8]` containing the frame in PNG format.
"];

export PngSink, Msg, Exit;

import libc::{c_int, c_uint, c_void, c_uchar};
import azure::AzDrawTargetRef;
import azure_bg = azure::bindgen;
import azure_bg::{AzCreateDrawTargetForCairoSurface, AzReleaseDrawTarget};
import azure::cairo;
import cairo::{CAIRO_FORMAT_ARGB32, cairo_surface_t, cairo_status_t,
               CAIRO_STATUS_SUCCESS};
import cairo_bg = cairo::bindgen;
import cairo_bg::{cairo_image_surface_create, cairo_surface_destroy,
                  cairo_surface_write_to_png_stream};
import renderer::{Renderer, Sink, RenderMsg};
import task::spawn_listener;
import comm::chan;
import unsafe::reinterpret_cast;
import vec_from_buf = vec::unsafe::from_buf;
import ptr::addr_of;
import dom::event::Event;
import dvec::dvec;
import layout::display_list::display_list;

type PngSink = chan<Msg>;

enum Msg {
    BeginDrawing(pipes::chan<AzDrawTargetRef>),
    Draw(pipes::chan<AzDrawTargetRef>, AzDrawTargetRef),
    Exit
}

impl chan<Msg> : Sink {
    fn begin_drawing(+next_dt: pipes::chan<AzDrawTargetRef>) {
        self.send(BeginDrawing(next_dt))
    }
    fn draw(+next_dt: pipes::chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef) {
        self.send(Draw(next_dt, draw_me))
    }
    fn add_event_listener(_listener: chan<Event>) {
        // No events in this sink.
    }
}

fn PngSink(output: chan<~[u8]>) -> PngSink {
    spawn_listener::<Msg>(|po| {
        let cairo_surf = cairo_image_surface_create(
            CAIRO_FORMAT_ARGB32, 800 as c_int, 600 as c_int
            );
        assert cairo_surf.is_not_null();

        let draw_target = AzCreateDrawTargetForCairoSurface(cairo_surf);
        assert draw_target.is_not_null();

        loop {
            match po.recv() {
              BeginDrawing(sender) => {
                #debug("pngsink: begin_drawing");
                sender.send(draw_target);
              }
              Draw(sender, dt) => {
                #debug("pngsink: draw");
                do_draw(sender, dt, output, cairo_surf);
              }
              Exit => { break }
            }
        }

        AzReleaseDrawTarget(draw_target);
        cairo_surface_destroy(cairo_surf);
    })
}

fn do_draw(sender: pipes::chan<AzDrawTargetRef>,
           dt: AzDrawTargetRef,
           output: chan<~[u8]>,
           cairo_surf: *cairo_surface_t) {

    listen(|data_ch: chan<~[u8]>| {

        extern fn write_fn(closure: *c_void,
                           data: *c_uchar,
                           len: c_uint)

            -> cairo_status_t unsafe {

            let p: *chan<~[u8]> = reinterpret_cast(closure);
            let data_ch = *p;

            // Convert from *c_uchar to *u8
            let data = reinterpret_cast(data);
            let len = len as uint;
            // Copy to a vector
            let data = vec_from_buf(data, len);
            data_ch.send(data);

            return CAIRO_STATUS_SUCCESS;
        }

        let closure = addr_of(data_ch);

        unsafe {
            cairo_surface_write_to_png_stream(
                cairo_surf, write_fn, reinterpret_cast(closure));
        }

        // Collect the entire image into a single vector
        let mut result = ~[];
        while data_ch.peek() {
            result += data_ch.recv();
        }

        // Send the PNG image away
        output.send(result);
    });
    // Send the next draw target to the renderer
    sender.send(dt);
}

#[test]
fn sanity_check() {
    listen(|self_channel| {

        let sink = PngSink(self_channel);
        let renderer = Renderer(sink);

        let dlist : display_list = dvec();
        renderer.send(RenderMsg(dlist));
        let (exit_chan, exit_response_from_engine) = pipes::stream();
        renderer.send(renderer::ExitMsg(exit_chan));
        exit_response_from_engine.recv();

        sink.send(Exit)
    })
}
<commit_msg>Use the high-level, safe Azure API in the PNG sink instead of the low-level, unsafe one<commit_after>#[doc = "
A graphics sink that renders to PNG format buffers

Each time the renderer renders a frame the bufsink will output a
`~[u8]` containing the frame in PNG format.
"];

export PngSink, Msg, Exit;

import libc::{c_int, c_uint, c_void, c_uchar};
import azure::AzDrawTargetRef;
import azure_bg = azure::bindgen;
import azure_bg::{AzCreateDrawTargetForCairoSurface, AzReleaseDrawTarget};
import azure::cairo;
import azure::azure_hl::DrawTarget;
import azure::cairo_hl::ImageSurface;
import cairo::{CAIRO_FORMAT_ARGB32, cairo_surface_t, cairo_status_t, CAIRO_STATUS_SUCCESS};
import cairo_bg = cairo::bindgen;
import cairo_bg::{cairo_image_surface_create, cairo_surface_destroy,
                  cairo_surface_write_to_png_stream};
import renderer::{Renderer, Sink, RenderMsg};
import task::spawn_listener;
import comm::{chan, port};
import unsafe::reinterpret_cast;
import vec_from_buf = vec::unsafe::from_buf;
import ptr::addr_of;
import dom::event::Event;
import dvec::dvec;
import layout::display_list::display_list;

type PngSink = chan<Msg>;

enum Msg {
    BeginDrawing(pipes::chan<AzDrawTargetRef>),
    Draw(pipes::chan<AzDrawTargetRef>, AzDrawTargetRef),
    Exit
}

impl chan<Msg> : Sink {
    fn begin_drawing(+next_dt: pipes::chan<AzDrawTargetRef>) {
        self.send(BeginDrawing(next_dt))
    }
    fn draw(+next_dt: pipes::chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef) {
        self.send(Draw(next_dt, draw_me))
    }
    fn add_event_listener(_listener: chan<Event>) {
        // No events in this sink.
    }
}

fn PngSink(output: chan<~[u8]>) -> PngSink {
    do spawn_listener |po: port<Msg>| {
        let cairo_surface = ImageSurface(CAIRO_FORMAT_ARGB32, 800, 600);
        let draw_target = DrawTarget(cairo_surface);

        loop {
            match po.recv() {
                BeginDrawing(sender) => {
                    debug!("pngsink: begin_drawing");
                    sender.send(draw_target.azure_draw_target);
                }
                Draw(sender, dt) => {
                    debug!("pngsink: draw");
                    do_draw(sender, dt, output, cairo_surface);
                }
                Exit => break
            }
        }
    }
}

fn do_draw(sender: pipes::chan<AzDrawTargetRef>, dt: AzDrawTargetRef, output: chan<~[u8]>,
           cairo_surface: ImageSurface) {
    let buffer = io::mem_buffer();
    cairo_surface.write_to_png_stream(&buffer);
    let @{ buf: buffer, pos: _ } <- buffer;
    output.send(vec::from_mut(dvec::unwrap(move buffer)));

    // Send the next draw target to the renderer
    sender.send(dt);
}

#[test]
fn sanity_check() {
    do listen |self_channel| {
        let sink = PngSink(self_channel);
        let renderer = Renderer(sink);

        let dlist : display_list = dvec();
        renderer.send(RenderMsg(dlist));
        let (exit_chan, exit_response_from_engine) = pipes::stream();
        renderer.send(renderer::ExitMsg(exit_chan));
        exit_response_from_engine.recv();

        sink.send(Exit)
    }
}
<|endoftext|>


<commit_before>mod analysis_stats;
mod analysis_bench;
mod help;

use std::{error::Error, fmt::Write, io::Read};

use flexi_logger::Logger;
use pico_args::Arguments;
use ra_ide_api::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

#[derive(Clone, Copy)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

impl Verbosity {
    fn is_verbose(&self) -> bool {
        match self {
            Verbosity::Verbose => true,
            _ => false,
        }
    }
}

fn main() -> Result<()> {
    Logger::with_env().start()?;

    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());

    match &*subcommand.to_string_lossy() {
        "parse" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::PARSE_HELP);
                return Ok(());
            }
            let no_dump = matches.contains("--no-dump");
            matches.finish().or_else(handle_extra_flags)?;

            let _p = profile("parsing");
            let file = file()?;
            if !no_dump {
                println!("{:#?}", file.syntax());
            }
            std::mem::forget(file);
        }
        "symbols" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::SYMBOLS_HELP);
                return Ok(());
            }
            matches.finish().or_else(handle_extra_flags)?;
            let file = file()?;
            for s in file_structure(&file) {
                println!("{:?}", s);
            }
        }
        "highlight" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::HIGHLIGHT_HELP);
                return Ok(());
            }
            let rainbow_opt = matches.contains(["-r", "--rainbow"]);
            matches.finish().or_else(handle_extra_flags)?;
            let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
            let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
            println!("{}", html);
        }
        "analysis-stats" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_STATS_HELP);
                return Ok(());
            }
            let verbosity = match (
                matches.contains(["-v", "--verbose"]),
                matches.contains(["-q", "--quiet"]),
            ) {
                (false, false) => Verbosity::Normal,
                (false, true) => Verbosity::Quiet,
                (true, false) => Verbosity::Verbose,
                (true, true) => Err("Invalid flags: -q conflicts with -v")?,
            };
            let memory_usage = matches.contains("--memory-usage");
            let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
            let path = {
                let mut trailing = matches.free()?;
                if trailing.len() != 1 {
                    eprintln!("{}", help::ANALYSIS_STATS_HELP);
                    Err("Invalid flags")?;
                }
                trailing.pop().unwrap()
            };
            analysis_stats::run(
                verbosity,
                memory_usage,
                path.as_ref(),
                only.as_ref().map(String::as_ref),
            )?;
        }
        "analysis-bench" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_BENCH_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let path: String = matches.value_from_str("--path")?.unwrap_or_default();
            let highlight_path = matches.value_from_str("--highlight")?;
            let complete_path = matches.value_from_str("--complete")?;
            if highlight_path.is_some() && complete_path.is_some() {
                panic!("either --highlight or --complete must be set, not both")
            }
            let op = if let Some(path) = highlight_path {
                let path: String = path;
                analysis_bench::Op::Highlight { path: path.into() }
            } else if let Some(path_line_col) = complete_path {
                let path_line_col: String = path_line_col;
                let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
                let (path, line) = rsplit_at_char(path_line, ':')?;
                analysis_bench::Op::Complete {
                    path: path.into(),
                    line: line.parse()?,
                    column: column.parse()?,
                }
            } else {
                panic!("either --highlight or --complete must be set")
            };
            matches.finish().or_else(handle_extra_flags)?;
            analysis_bench::run(verbose, path.as_ref(), op)?;
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}
<commit_msg>show error log by default<commit_after>mod analysis_stats;
mod analysis_bench;
mod help;

use std::{error::Error, fmt::Write, io::Read};

use flexi_logger::Logger;
use pico_args::Arguments;
use ra_ide_api::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

#[derive(Clone, Copy)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

impl Verbosity {
    fn is_verbose(&self) -> bool {
        match self {
            Verbosity::Verbose => true,
            _ => false,
        }
    }
}

fn main() -> Result<()> {
    Logger::with_env_or_str("error").start()?;

    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());

    match &*subcommand.to_string_lossy() {
        "parse" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::PARSE_HELP);
                return Ok(());
            }
            let no_dump = matches.contains("--no-dump");
            matches.finish().or_else(handle_extra_flags)?;

            let _p = profile("parsing");
            let file = file()?;
            if !no_dump {
                println!("{:#?}", file.syntax());
            }
            std::mem::forget(file);
        }
        "symbols" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::SYMBOLS_HELP);
                return Ok(());
            }
            matches.finish().or_else(handle_extra_flags)?;
            let file = file()?;
            for s in file_structure(&file) {
                println!("{:?}", s);
            }
        }
        "highlight" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::HIGHLIGHT_HELP);
                return Ok(());
            }
            let rainbow_opt = matches.contains(["-r", "--rainbow"]);
            matches.finish().or_else(handle_extra_flags)?;
            let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
            let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
            println!("{}", html);
        }
        "analysis-stats" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_STATS_HELP);
                return Ok(());
            }
            let verbosity = match (
                matches.contains(["-v", "--verbose"]),
                matches.contains(["-q", "--quiet"]),
            ) {
                (false, false) => Verbosity::Normal,
                (false, true) => Verbosity::Quiet,
                (true, false) => Verbosity::Verbose,
                (true, true) => Err("Invalid flags: -q conflicts with -v")?,
            };
            let memory_usage = matches.contains("--memory-usage");
            let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
            let path = {
                let mut trailing = matches.free()?;
                if trailing.len() != 1 {
                    eprintln!("{}", help::ANALYSIS_STATS_HELP);
                    Err("Invalid flags")?;
                }
                trailing.pop().unwrap()
            };
            analysis_stats::run(
                verbosity,
                memory_usage,
                path.as_ref(),
                only.as_ref().map(String::as_ref),
            )?;
        }
        "analysis-bench" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_BENCH_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let path: String = matches.value_from_str("--path")?.unwrap_or_default();
            let highlight_path = matches.value_from_str("--highlight")?;
            let complete_path = matches.value_from_str("--complete")?;
            if highlight_path.is_some() && complete_path.is_some() {
                panic!("either --highlight or --complete must be set, not both")
            }
            let op = if let Some(path) = highlight_path {
                let path: String = path;
                analysis_bench::Op::Highlight { path: path.into() }
            } else if let Some(path_line_col) = complete_path {
                let path_line_col: String = path_line_col;
                let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
                let (path, line) = rsplit_at_char(path_line, ':')?;
                analysis_bench::Op::Complete {
                    path: path.into(),
                    line: line.parse()?,
                    column: column.parse()?,
                }
            } else {
                panic!("either --highlight or --complete must be set")
            };
            matches.finish().or_else(handle_extra_flags)?;
            analysis_bench::run(verbose, path.as_ref(), op)?;
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}
<|endoftext|>


<commit_before>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;

use atom::*;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::*;
use std::thread;

#[test]
fn swap() {
    let a = Atom::empty();
    assert_eq!(a.swap(Box::new(1u8), Ordering::AcqRel), None);
    assert_eq!(a.swap(Box::new(2u8), Ordering::AcqRel), Some(Box::new(1u8)));
    assert_eq!(a.swap(Box::new(3u8), Ordering::AcqRel), Some(Box::new(2u8)));
}

#[test]
fn take() {
    let a = Atom::new(Box::new(7u8));
    assert_eq!(a.take(Ordering::Acquire), Some(Box::new(7)));
    assert_eq!(a.take(Ordering::Acquire), None);
}

#[test]
fn set_if_none() {
    let a = Atom::empty();
    assert_eq!(a.set_if_none(Box::new(7u8), Ordering::Release), None);
    assert_eq!(
        a.set_if_none(Box::new(8u8), Ordering::Release),
        Some(Box::new(8u8))
    );
}

#[derive(Clone)]
struct Canary(Arc<AtomicUsize>);

impl Drop for Canary {
    fn drop(&mut self) {
        self.0.fetch_add(1, Ordering::SeqCst);
    }
}

#[test]
fn ensure_drop() {
    let v = Arc::new(AtomicUsize::new(0));
    let a = Box::new(Canary(v.clone()));
    let a = Atom::new(a);
    assert_eq!(v.load(Ordering::SeqCst), 0);
    drop(a);
    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[test]
fn ensure_drop_arc() {
    let v = Arc::new(AtomicUsize::new(0));
    let a = Arc::new(Canary(v.clone()));
    let a = Atom::new(a);
    assert_eq!(v.load(Ordering::SeqCst), 0);
    drop(a);
    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[test]
fn ensure_send() {
    let atom = Arc::new(Atom::empty());
    let wait = Arc::new(Barrier::new(2));

    let w = wait.clone();
    let a = atom.clone();
    thread::spawn(move || {
        a.swap(Box::new(7u8), Ordering::AcqRel);
        w.wait();
    });

    wait.wait();
    assert_eq!(atom.take(Ordering::Acquire), Some(Box::new(7u8)));
}

#[test]
fn get() {
    let atom = Arc::new(AtomSetOnce::empty());
    assert_eq!(atom.get(Ordering::Acquire), None);
    assert_eq!(atom.set_if_none(Box::new(8u8), Ordering::Release), None);
    assert_eq!(atom.get(Ordering::Acquire), Some(&8u8));
}

#[test]
fn get_arc() {
    let atom = Arc::new(AtomSetOnce::empty());
    assert_eq!(atom.get(Ordering::Acquire), None);
    assert_eq!(atom.set_if_none(Arc::new(8u8), Ordering::Release), None);
    assert_eq!(atom.get(Ordering::Acquire), Some(&8u8));

    let v = Arc::new(AtomicUsize::new(0));
    let atom = Arc::new(AtomSetOnce::empty());
    atom.get(Ordering::Acquire);
    atom.set_if_none(Arc::new(Canary(v.clone())), Ordering::Release);
    atom.get(Ordering::Acquire);
    drop(atom);

    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[derive(Debug)]
struct Link {
    next: Option<Box<Link>>,
    value: u32,
}

impl Link {
    fn new(v: u32) -> Box<Link> {
        Box::new(Link {
            next: None,
            value: v,
        })
    }
}

impl GetNextMut for Box<Link> {
    type NextPtr = Option<Box<Link>>;
    fn get_next(&mut self) -> &mut Option<Box<Link>> {
        &mut self.next
    }
}

#[test]
fn lifo() {
    let atom = Atom::empty();
    for i in 0..100 {
        let x = atom.replace_and_set_next(Link::new(99 - i), Ordering::Relaxed, Ordering::AcqRel);
        assert_eq!(x, i == 0);
    }

    let expected: Vec<u32> = (0..100).collect();
    let mut found = Vec::new();
    let mut chain = atom.take(Ordering::Acquire);
    while let Some(v) = chain {
        found.push(v.value);
        chain = v.next;
    }
    assert_eq!(expected, found);
}

#[allow(dead_code)]
struct LinkCanary {
    next: Option<Box<LinkCanary>>,
    value: Canary,
}

impl LinkCanary {
    fn new(v: Canary) -> Box<LinkCanary> {
        Box::new(LinkCanary {
            next: None,
            value: v,
        })
    }
}

impl GetNextMut for Box<LinkCanary> {
    type NextPtr = Option<Box<LinkCanary>>;
    fn get_next(&mut self) -> &mut Option<Box<LinkCanary>> {
        &mut self.next
    }
}

#[test]
fn lifo_drop() {
    let v = Arc::new(AtomicUsize::new(0));
    let canary = Canary(v.clone());
    let mut link = LinkCanary::new(canary.clone());
    link.next = Some(LinkCanary::new(canary.clone()));

    let atom = Atom::empty();
    atom.replace_and_set_next(link, Ordering::Relaxed, Ordering::AcqRel);
    assert_eq!(1, v.load(Ordering::SeqCst));
    drop(atom);
    assert_eq!(2, v.load(Ordering::SeqCst));
}
<commit_msg>Add smoke test for borrow usage<commit_after>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;

use atom::*;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::*;
use std::thread;

#[test]
fn swap() {
    let a = Atom::empty();
    assert_eq!(a.swap(Box::new(1u8), Ordering::AcqRel), None);
    assert_eq!(a.swap(Box::new(2u8), Ordering::AcqRel), Some(Box::new(1u8)));
    assert_eq!(a.swap(Box::new(3u8), Ordering::AcqRel), Some(Box::new(2u8)));
}

#[test]
fn take() {
    let a = Atom::new(Box::new(7u8));
    assert_eq!(a.take(Ordering::Acquire), Some(Box::new(7)));
    assert_eq!(a.take(Ordering::Acquire), None);
}

#[test]
fn set_if_none() {
    let a = Atom::empty();
    assert_eq!(a.set_if_none(Box::new(7u8), Ordering::Release), None);
    assert_eq!(
        a.set_if_none(Box::new(8u8), Ordering::Release),
        Some(Box::new(8u8))
    );
}

#[derive(Clone)]
struct Canary(Arc<AtomicUsize>);

impl Drop for Canary {
    fn drop(&mut self) {
        self.0.fetch_add(1, Ordering::SeqCst);
    }
}

#[test]
fn ensure_drop() {
    let v = Arc::new(AtomicUsize::new(0));
    let a = Box::new(Canary(v.clone()));
    let a = Atom::new(a);
    assert_eq!(v.load(Ordering::SeqCst), 0);
    drop(a);
    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[test]
fn ensure_drop_arc() {
    let v = Arc::new(AtomicUsize::new(0));
    let a = Arc::new(Canary(v.clone()));
    let a = Atom::new(a);
    assert_eq!(v.load(Ordering::SeqCst), 0);
    drop(a);
    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[test]
fn ensure_send() {
    let atom = Arc::new(Atom::empty());
    let wait = Arc::new(Barrier::new(2));

    let w = wait.clone();
    let a = atom.clone();
    thread::spawn(move || {
        a.swap(Box::new(7u8), Ordering::AcqRel);
        w.wait();
    });

    wait.wait();
    assert_eq!(atom.take(Ordering::Acquire), Some(Box::new(7u8)));
}

#[test]
fn get() {
    let atom = Arc::new(AtomSetOnce::empty());
    assert_eq!(atom.get(Ordering::Acquire), None);
    assert_eq!(atom.set_if_none(Box::new(8u8), Ordering::Release), None);
    assert_eq!(atom.get(Ordering::Acquire), Some(&8u8));
}

#[test]
fn get_arc() {
    let atom = Arc::new(AtomSetOnce::empty());
    assert_eq!(atom.get(Ordering::Acquire), None);
    assert_eq!(atom.set_if_none(Arc::new(8u8), Ordering::Release), None);
    assert_eq!(atom.get(Ordering::Acquire), Some(&8u8));

    let v = Arc::new(AtomicUsize::new(0));
    let atom = Arc::new(AtomSetOnce::empty());
    atom.get(Ordering::Acquire);
    atom.set_if_none(Arc::new(Canary(v.clone())), Ordering::Release);
    atom.get(Ordering::Acquire);
    drop(atom);

    assert_eq!(v.load(Ordering::SeqCst), 1);
}

#[derive(Debug)]
struct Link {
    next: Option<Box<Link>>,
    value: u32,
}

impl Link {
    fn new(v: u32) -> Box<Link> {
        Box::new(Link {
            next: None,
            value: v,
        })
    }
}

impl GetNextMut for Box<Link> {
    type NextPtr = Option<Box<Link>>;
    fn get_next(&mut self) -> &mut Option<Box<Link>> {
        &mut self.next
    }
}

#[test]
fn lifo() {
    let atom = Atom::empty();
    for i in 0..100 {
        let x = atom.replace_and_set_next(Link::new(99 - i), Ordering::Relaxed, Ordering::AcqRel);
        assert_eq!(x, i == 0);
    }

    let expected: Vec<u32> = (0..100).collect();
    let mut found = Vec::new();
    let mut chain = atom.take(Ordering::Acquire);
    while let Some(v) = chain {
        found.push(v.value);
        chain = v.next;
    }
    assert_eq!(expected, found);
}

#[allow(dead_code)]
struct LinkCanary {
    next: Option<Box<LinkCanary>>,
    value: Canary,
}

impl LinkCanary {
    fn new(v: Canary) -> Box<LinkCanary> {
        Box::new(LinkCanary {
            next: None,
            value: v,
        })
    }
}

impl GetNextMut for Box<LinkCanary> {
    type NextPtr = Option<Box<LinkCanary>>;
    fn get_next(&mut self) -> &mut Option<Box<LinkCanary>> {
        &mut self.next
    }
}

#[test]
fn lifo_drop() {
    let v = Arc::new(AtomicUsize::new(0));
    let canary = Canary(v.clone());
    let mut link = LinkCanary::new(canary.clone());
    link.next = Some(LinkCanary::new(canary.clone()));

    let atom = Atom::empty();
    atom.replace_and_set_next(link, Ordering::Relaxed, Ordering::AcqRel);
    assert_eq!(1, v.load(Ordering::SeqCst));
    drop(atom);
    assert_eq!(2, v.load(Ordering::SeqCst));
}

#[test]
fn borrow() {
    let a = Atom::new(&5);
    assert_eq!(a.swap(&7, Ordering::Relaxed), Some(&5));
    assert_eq!(a.take(Ordering::Relaxed), Some(&7));
}
<|endoftext|>