<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate phf_codegen;
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;

use std::ascii::AsciiExt;

/// Find a `#[cssparser__assert_ascii_lowercase__data(string = "…", string = "…")]` attribute,
/// and panic if any string contains ASCII uppercase letters.
#[proc_macro_derive(cssparser__assert_ascii_lowercase,
                    attributes(cssparser__assert_ascii_lowercase__data))]
pub fn assert_ascii_lowercase(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let data = list_attr(&input, "cssparser__assert_ascii_lowercase__data");

    for sub_attr in data {
        let string = sub_attr_value(sub_attr, "string");
        assert_eq!(*string, string.to_ascii_lowercase(),
                   "the expected strings must be given in ASCII lowercase");
    }

    "".parse().unwrap()
}

/// Find a `#[cssparser__max_len__data(string = "…", string = "…")]` attribute,
/// panic if any string contains ASCII uppercase letters,
/// emit a `MAX_LENGTH` constant with the length of the longest string.
#[proc_macro_derive(cssparser__max_len,
                    attributes(cssparser__max_len__data))]
pub fn max_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let data = list_attr(&input, "cssparser__max_len__data");

    let lengths = data.iter().map(|sub_attr| sub_attr_value(sub_attr, "string").len());
    let max_length = lengths.max().expect("expected at least one string");

    let tokens = quote! {
        const MAX_LENGTH: usize = #max_length;
    };

    tokens.as_str().parse().unwrap()
}

/// On `struct $Name($ValueType)`, add a new static method
/// `fn map() -> &'static ::phf::Map<&'static str, $ValueType>`.
/// The map’s content is given as:
/// `#[cssparser__phf_map__kv_pairs(key = "…", value = "…", key = "…", value = "…")]`.
/// Keys are ASCII-lowercased.
#[proc_macro_derive(cssparser__phf_map,
                    attributes(cssparser__phf_map__kv_pairs))]
pub fn phf_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let name = &input.ident;
    let value_type = match input.body {
        syn::Body::Struct(syn::VariantData::Tuple(ref fields)) if fields.len() == 1 => {
            &fields[0].ty
        }
        _ => panic!("expected tuple struct newtype, got {:?}", input.body)
    };

    let pairs: Vec<_> = list_attr(&input, "cssparser__phf_map__kv_pairs").chunks(2).map(|chunk| {
        let key = sub_attr_value(&chunk[0], "key");
        let value = sub_attr_value(&chunk[1], "value");
        (key.to_ascii_lowercase(), value)
    }).collect();

    let mut map = phf_codegen::Map::new();
    for &(ref key, value) in &pairs {
        map.entry(&**key, value);
    }

    let mut initializer_bytes = Vec::<u8>::new();
    let mut initializer_tokens = quote::Tokens::new();
    map.build(&mut initializer_bytes).unwrap();
    initializer_tokens.append(::std::str::from_utf8(&initializer_bytes).unwrap());

    let tokens = quote! {
        impl #name {
            #[inline]
            fn map() -> &'static ::phf::Map<&'static str, #value_type> {
                static MAP: ::phf::Map<&'static str, #value_type> = #initializer_tokens;
                &MAP
            }
        }
    };

    tokens.as_str().parse().unwrap()
}

/// Panic if the first attribute isn’t `#[foo(…)]` with the given name,
/// or return the parameters.
fn list_attr<'a>(input: &'a syn::DeriveInput, expected_name: &str) -> &'a [syn::NestedMetaItem] {
    match input.attrs[0].value {
        syn::MetaItem::List(ref name, ref nested) if name == expected_name => {
            nested
        }
        _ => {
            panic!("expected a {} attribute", expected_name)
        }
    }
}

/// Panic if `sub_attr` is not a name-value like `foo = "…"` with the given name,
/// or return the value.
fn sub_attr_value<'a>(sub_attr: &'a syn::NestedMetaItem, expected_name: &str) -> &'a str {
    match *sub_attr {
        syn::NestedMetaItem::MetaItem(
            syn::MetaItem::NameValue(ref name, syn::Lit::Str(ref value, _))
        )
        if name == expected_name => {
            value
        }
        _ => {
            panic!("expected a `{} = \"…\"` parameter to the attribute, got {:?}",
                   expected_name, sub_attr)
        }
    }
}
<commit_msg>Be more robust regarding attribute ordering in proc macros.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate phf_codegen;
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;

use std::ascii::AsciiExt;

/// Find a `#[cssparser__assert_ascii_lowercase__data(string = "…", string = "…")]` attribute,
/// and panic if any string contains ASCII uppercase letters.
#[proc_macro_derive(cssparser__assert_ascii_lowercase,
                    attributes(cssparser__assert_ascii_lowercase__data))]
pub fn assert_ascii_lowercase(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let data = list_attr(&input, "cssparser__assert_ascii_lowercase__data");

    for sub_attr in data {
        let string = sub_attr_value(sub_attr, "string");
        assert_eq!(*string, string.to_ascii_lowercase(),
                   "the expected strings must be given in ASCII lowercase");
    }

    "".parse().unwrap()
}

/// Find a `#[cssparser__max_len__data(string = "…", string = "…")]` attribute,
/// panic if any string contains ASCII uppercase letters,
/// emit a `MAX_LENGTH` constant with the length of the longest string.
#[proc_macro_derive(cssparser__max_len,
                    attributes(cssparser__max_len__data))]
pub fn max_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let data = list_attr(&input, "cssparser__max_len__data");

    let lengths = data.iter().map(|sub_attr| sub_attr_value(sub_attr, "string").len());
    let max_length = lengths.max().expect("expected at least one string");

    let tokens = quote! {
        const MAX_LENGTH: usize = #max_length;
    };

    tokens.as_str().parse().unwrap()
}

/// On `struct $Name($ValueType)`, add a new static method
/// `fn map() -> &'static ::phf::Map<&'static str, $ValueType>`.
/// The map’s content is given as:
/// `#[cssparser__phf_map__kv_pairs(key = "…", value = "…", key = "…", value = "…")]`.
/// Keys are ASCII-lowercased.
#[proc_macro_derive(cssparser__phf_map,
                    attributes(cssparser__phf_map__kv_pairs))]
pub fn phf_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    let name = &input.ident;
    let value_type = match input.body {
        syn::Body::Struct(syn::VariantData::Tuple(ref fields)) if fields.len() == 1 => {
            &fields[0].ty
        }
        _ => panic!("expected tuple struct newtype, got {:?}", input.body)
    };

    let pairs: Vec<_> = list_attr(&input, "cssparser__phf_map__kv_pairs").chunks(2).map(|chunk| {
        let key = sub_attr_value(&chunk[0], "key");
        let value = sub_attr_value(&chunk[1], "value");
        (key.to_ascii_lowercase(), value)
    }).collect();

    let mut map = phf_codegen::Map::new();
    for &(ref key, value) in &pairs {
        map.entry(&**key, value);
    }

    let mut initializer_bytes = Vec::<u8>::new();
    let mut initializer_tokens = quote::Tokens::new();
    map.build(&mut initializer_bytes).unwrap();
    initializer_tokens.append(::std::str::from_utf8(&initializer_bytes).unwrap());

    let tokens = quote! {
        impl #name {
            #[inline]
            fn map() -> &'static ::phf::Map<&'static str, #value_type> {
                static MAP: ::phf::Map<&'static str, #value_type> = #initializer_tokens;
                &MAP
            }
        }
    };

    tokens.as_str().parse().unwrap()
}

/// Panic if the first attribute isn’t `#[foo(…)]` with the given name,
/// or return the parameters.
fn list_attr<'a>(input: &'a syn::DeriveInput, expected_name: &str) -> &'a [syn::NestedMetaItem] {
    for attr in &input.attrs {
        match attr.value {
            syn::MetaItem::List(ref name, ref nested) if name == expected_name => {
                return nested
            }
            _ => {}
        }
    }
    panic!("expected a {} attribute", expected_name)
}

/// Panic if `sub_attr` is not a name-value like `foo = "…"` with the given name,
/// or return the value.
fn sub_attr_value<'a>(sub_attr: &'a syn::NestedMetaItem, expected_name: &str) -> &'a str {
    match *sub_attr {
        syn::NestedMetaItem::MetaItem(
            syn::MetaItem::NameValue(ref name, syn::Lit::Str(ref value, _))
        )
        if name == expected_name => {
            value
        }
        _ => {
            panic!("expected a `{} = \"…\"` parameter to the attribute, got {:?}",
                   expected_name, sub_attr)
        }
    }
}
<|endoftext|>


<commit_before>use libc;
use libc::{c_int, c_void, timespec};

use std::mem::transmute;
use std::ptr::null;
use std::result::Result;

pub enum Errors {
    /// No read access to futex memory
    FutexRead,
    /// Futex value does not equal given expected value (e.g. in race condition)
    FutexValue,
    /// Wait was interrupted by a signal
    Signal,
    /// Oops.
    InvalidArg,
    /// Too many open files
    TooManyFiles,
    /// Oops.
    InvalidOp,
    /// Futex hit wait timeout
    WaitTimeout
}

/// Wraps futex(2):
///
/// int futex(int *uaddr, int op, int val, const struct timespec *timeout,
///           int *uaddr2, int val3);
//#[link(name="libc")]
//extern {
unsafe fn futex(addr1:    *mut   c_int,
         op:              c_int,
         val:             c_int,
         timespec: *const timespec,
         addr2:    *mut   c_int,
         val3:            c_int)
         -> c_int {
syscall!(FUTEX, addr1, op, val, timespec, addr2, val3) as c_int
         }
//}

const OP_WAIT        : i32 = 0;
const OP_WAKE        : i32 = 1;
// deprecated: const OP_FD          : i32 = 2;
// deprecated: const OP_REQUEUE     : i32 = 3;
const OP_CMP_REQUEUE : i32 = 4;

#[inline(always)]
fn get_result(retval: i32) -> Result<i32, Errors> {
    use libc::{EACCES, EAGAIN, EINTR, EINVAL, ENOSYS, ETIMEDOUT};

    if retval >= 0 {
        return Ok(retval);
    }

    match retval {
        EACCES => Err(Errors::FutexRead),
        EINTR  => Err(Errors::Signal),
        EINVAL => Err(Errors::InvalidArg),
        ENOSYS => Err(Errors::InvalidOp),
        EAGAIN => Err(Errors::FutexValue),
        ETIMEDOUT => Err(Errors::WaitTimeout),
        _ => panic!("unexpected futex return value: {}", retval)
    }
}

/// Verifies that the futex in `addr` still contains the value `val`, and then
/// sleeps the thread awaiting a FUTEX_WAKE.
pub fn wait(addr: &mut i32, val: i32) -> Result<i32, Errors> {
    unsafe {
        get_result(
            futex(addr as (*mut i32),
                  OP_WAIT,
                  val,
                  null::<timespec>(),
                  transmute(null::<i32>()),
                  0))
    }
}

/// Same as `wait`, except only sleeps for the given number of seconds.
/// If the wait times out, Err(Errors::WaitTimeout) will be returned.
pub fn time_wait(addr: &mut i32, val: i32, wait_secs: u32) -> Result<i32, Errors> {
    let ts = timespec { tv_sec: wait_secs as i64, tv_nsec: 0 };

    let ret = unsafe {
        futex(addr as (*mut i32),
              OP_WAIT,
              val,
              &ts,
              transmute(null::<i32>()),
              0)
    };

    get_result(ret)
}

/// This operation wakes at most `nprocs` processes waiting on this
/// futex address (i.e., inside FUTEX_WAIT).
///
/// Results the number of processes woken up or error
pub fn wake(addr: &mut i32, nprocs: u32) -> Result<i32, Errors> {
    let ret = unsafe {
        futex(addr as (*mut i32),
              OP_WAKE,
              nprocs as i32,
              null::<timespec>(),
              transmute(null::<i32>()),
              0)
    };

    get_result(ret)
}

/// This operation was introduced in order to avoid a "thundering herd" effect
/// when `wake` is used and all processes woken up need to acquire another
/// futex. This call wakes up `nprocs` processes, and requeues all other
/// waiters on the futex at address `requeue_addr`.
///
/// TODO: explain val.
pub fn requeue(addr: &mut i32, requeue_addr: &mut i32, val: i32, nprocs: u32) -> Result<i32, Errors> {
    let ret = unsafe {
        futex(addr as (*mut i32),
              OP_CMP_REQUEUE,
              nprocs as i32,
              null::<timespec>(),
              transmute(requeue_addr),
              val)
    };

    get_result(ret)
}
<commit_msg>ptr::null_mut is better than transmute(ptr::null)<commit_after>use libc;
use libc::{c_int, c_void, timespec};

use std::mem::transmute;
use std::ptr::{null, null_mut};
use std::result::Result;

pub enum Errors {
    /// No read access to futex memory
    FutexRead,
    /// Futex value does not equal given expected value (e.g. in race condition)
    FutexValue,
    /// Wait was interrupted by a signal
    Signal,
    /// Oops.
    InvalidArg,
    /// Too many open files
    TooManyFiles,
    /// Oops.
    InvalidOp,
    /// Futex hit wait timeout
    WaitTimeout
}

/// Wraps futex(2):
///
/// int futex(int *uaddr, int op, int val, const struct timespec *timeout,
///           int *uaddr2, int val3);
//#[link(name="libc")]
//extern {
unsafe fn futex(addr1:    *mut   c_int,
         op:              c_int,
         val:             c_int,
         timespec: *const timespec,
         addr2:    *mut   c_int,
         val3:            c_int)
         -> c_int {
syscall!(FUTEX, addr1, op, val, timespec, addr2, val3) as c_int
         }
//}

const OP_WAIT        : i32 = 0;
const OP_WAKE        : i32 = 1;
// deprecated: const OP_FD          : i32 = 2;
// deprecated: const OP_REQUEUE     : i32 = 3;
const OP_CMP_REQUEUE : i32 = 4;

#[inline(always)]
fn get_result(retval: i32) -> Result<i32, Errors> {
    use libc::{EACCES, EAGAIN, EINTR, EINVAL, ENOSYS, ETIMEDOUT};

    if retval >= 0 {
        return Ok(retval);
    }

    match retval {
        EACCES => Err(Errors::FutexRead),
        EINTR  => Err(Errors::Signal),
        EINVAL => Err(Errors::InvalidArg),
        ENOSYS => Err(Errors::InvalidOp),
        EAGAIN => Err(Errors::FutexValue),
        ETIMEDOUT => Err(Errors::WaitTimeout),
        _ => panic!("unexpected futex return value: {}", retval)
    }
}

/// Verifies that the futex in `addr` still contains the value `val`, and then
/// sleeps the thread awaiting a FUTEX_WAKE.
pub fn wait(addr: &mut i32, val: i32) -> Result<i32, Errors> {
    unsafe {
        get_result(
            futex(addr as (*mut i32),
                  OP_WAIT,
                  val,
                  null::<timespec>(),
                  null_mut::<i32>(),
                  0))
    }
}

/// Same as `wait`, except only sleeps for the given number of seconds.
/// If the wait times out, Err(Errors::WaitTimeout) will be returned.
pub fn time_wait(addr: &mut i32, val: i32, wait_secs: u32) -> Result<i32, Errors> {
    let ts = timespec { tv_sec: wait_secs as i64, tv_nsec: 0 };

    let ret = unsafe {
        futex(addr as (*mut i32),
              OP_WAIT,
              val,
              &ts,
              transmute(null::<i32>()),
              0)
    };

    get_result(ret)
}

/// This operation wakes at most `nprocs` processes waiting on this
/// futex address (i.e., inside FUTEX_WAIT).
///
/// Results the number of processes woken up or error
pub fn wake(addr: &mut i32, nprocs: u32) -> Result<i32, Errors> {
    let ret = unsafe {
        futex(addr as (*mut i32),
              OP_WAKE,
              nprocs as i32,
              null::<timespec>(),
              null_mut::<i32>(),
              0)
    };

    get_result(ret)
}

/// This operation was introduced in order to avoid a "thundering herd" effect
/// when `wake` is used and all processes woken up need to acquire another
/// futex. This call wakes up `nprocs` processes, and requeues all other
/// waiters on the futex at address `requeue_addr`.
///
/// TODO: explain val.
pub fn requeue(addr: &mut i32, requeue_addr: &mut i32, val: i32, nprocs: u32) -> Result<i32, Errors> {
    let ret = unsafe {
        futex(addr as *mut i32,
              OP_CMP_REQUEUE,
              nprocs as i32,
              null::<timespec>(),
              requeue_addr as *mut i32,
              val)
    };

    get_result(ret)
}
<|endoftext|>


<commit_before>use token::Token;
use token_offset::TokenOffset;
use operator::Operator;
use operator_offset::OperatorOffset;
use operator_or_token::OperatorOrToken;
use context::Context;
use error::{Result, SassError, ErrorKind};

use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Value(OperatorOrToken),
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string()
                ).collect::<Vec<_>>().join(" ").fmt(f)
            },
            Expression::Value(ref v) => v.fmt(f),
        }
    }
}

impl Expression {
    pub fn parse<T>(tokenizer: &mut T) -> Result<Expression>
        where T: Iterator<Item = Result<OperatorOrToken>> {
        let mut list = vec![];
        while let Some(Ok(t)) = tokenizer.next() {
            match t {
                OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::Semicolon, ..
                }) => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                OperatorOrToken::Token(TokenOffset {
                    token: Token::Comment(_), ..
                }) => {},
                _ => list.push(Expression::Value(t)),
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::Value(v)) => v.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(exprs: Vec<Expression>, context: &Context, force_slash: bool) -> Expression {

        let mut last_was_an_operator = true;
        let mut paren_level = 0;

        // TODO: I'd love to have more types here, to ensure only values are
        // on the value stack and only operators are on the operator stack...
        let mut value_stack: Vec<Expression> = Vec::new();
        let mut op_stack: Vec<OperatorOffset> = Vec::new();

        // Split into value stacks and operator stacks

        let mut exprs = exprs.into_iter();
        while let Some(part) = exprs.next() {
            debug!("Processing list item {:#?}", part);
            match part {
                v @ Expression::Value(OperatorOrToken::Token(TokenOffset {
                    token: Token::Number { .. }, ..
                })) => {
                    if last_was_an_operator {
                        debug!("Push on value stack {:#?}", v);
                        value_stack.push(v);
                    } else {
                        while !op_stack.is_empty() &&
                              op_stack.last().unwrap().operator !=
                                  Operator::LeftParen {
                            Expression::math_machine(
                                &mut op_stack, &mut value_stack, context
                            );
                        }
                        let list = Expression::create_list(
                            value_stack.pop(),
                            v,
                        );
                        debug!("Push on list on value stack {:#?}", list);
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
                Expression::Value(OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::RightParen, ..
                })) => {
                    let mut last_operator = op_stack.pop();
                    while last_operator.is_some() &&
                          last_operator.unwrap().operator !=
                              Operator::LeftParen {
                        op_stack.push(last_operator.unwrap());
                        Expression::math_machine(
                            &mut op_stack, &mut value_stack, context
                        );
                        last_operator = op_stack.pop();
                    }

                    op_stack.pop();
                    last_was_an_operator = false;
                    paren_level -= 1;
                },
                Expression::Value(OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::LeftParen, offset
                })) => {
                    op_stack.push(OperatorOffset {
                        operator: Operator::LeftParen, offset: offset
                    });
                    last_was_an_operator = true;
                    paren_level += 1;
                },
                Expression::Value(OperatorOrToken::Operator(
                    oo @ OperatorOffset { .. }
                )) => {
                    if let Some(&last_operator) = op_stack.last() {
                        if last_operator.operator
                                .same_or_greater_precedence(oo.operator) {
                            Expression::math_machine(
                                &mut op_stack, &mut value_stack, context
                            );
                        }
                    }
                    debug!("Push on op stack {:#?}", oo);
                    op_stack.push(oo);
                    last_was_an_operator = true;
                },
                Expression::Value(OperatorOrToken::Token(t @ TokenOffset {
                    token: Token::String(_), ..
                })) => {
                    let var_eval = context.get_variable(&t)
                                    .unwrap_or(Expression::Value(
                                        OperatorOrToken::Token(t)
                                    ));

                    if last_was_an_operator {
                        value_stack.push(var_eval);
                    } else {
                        let list = Expression::create_list(
                            value_stack.pop(),
                            var_eval,
                        );
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
                Expression::List(list) => {
                    debug!("Push list on value stack {:#?}", list);
                    value_stack.push(Expression::List(list));
                    last_was_an_operator = false;
                },
                other => {
                    if last_was_an_operator {
                        value_stack.push(other);
                    } else {
                        let list = Expression::create_list(
                            value_stack.pop(),
                            other,
                        );
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
            }
        }

        // Process the stacks
        while !op_stack.is_empty() {
            Expression::math_machine(
                &mut op_stack, &mut value_stack, context
            );
        }

        value_stack.pop().unwrap()
    }

    fn math_machine(op_stack: &mut Vec<OperatorOffset>, value_stack: &mut Vec<Expression>, context: &Context) {
        let op = op_stack.pop().unwrap();
        let second = value_stack.pop()
                       .expect("Expected a second argument on the value stack");
        let first = value_stack.pop()
                       .expect("Expected a first argument on the value stack");

        let math_result = Expression::apply_math(
            op, first, second, context
        );
        debug!("Math result: {:#?}", math_result);

        value_stack.push(math_result);
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Value(OperatorOrToken::Token(t @ TokenOffset {
                token: Token::String(_), ..
            })) => {
                context.get_variable(&t)
                       .unwrap_or(Expression::Value(
                            OperatorOrToken::Token(t)
                       ))
            },
            Expression::List(exprs) => {
                Expression::evaluate_list(exprs, context, false)
            },
            other => other,
        }
    }

    fn apply_math(operator: OperatorOffset, first: Expression, second: Expression, context: &Context) -> Expression {
        debug!("Applying math to:\nfirst: {:#?}\nop: {:#?}\nsecond: {:#?}", first, operator, second);

        match (first, second) {
            (Expression::Value(f), Expression::Value(s)) => {
                let result = match operator.operator {
                    Operator::Plus => f + s,
                    Operator::Minus => f - s,
                    Operator::Star => f * s,
                    Operator::Slash => f / s,
                    Operator::Percent => f % s,
                    _ => unimplemented!(),
                };
                Expression::Value(result)
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::evaluate_list(f, context, true);
                let eval_second = Expression::evaluate_list(s, context, true);
                Expression::apply_math(
                    operator, eval_first, eval_second, context
                )
            },
            (Expression::List(f), Expression::Value(s)) => {
                let eval_first = Expression::evaluate_list(f, context, true);
                Expression::apply_math(
                    operator, eval_first, Expression::Value(s), context
                )
            },
            (Expression::Value(f), Expression::List(s)) => {
                if s.iter().any(|e|
                    match *e {
                        Expression::Value(
                            OperatorOrToken::Operator(OperatorOffset {
                                operator: Operator::Slash, ..
                            })
                        ) => true,
                        _ => false,
                    }) {
                    let evaled_list = Expression::evaluate_list(
                        s, context, true
                    );
                    Expression::apply_math(
                        operator, Expression::Value(f), evaled_list, context
                    )
                } else {
                    if let Some((ref first_in_list, rest_of_list)) =
                            s.split_first() {

                        // Adding a number to a list means we should do
                        // string concatenation.
                        let new_first = if operator.operator == Operator::Plus {
                            Expression::Value(
                                OperatorOrToken::Token(
                                    TokenOffset {
                                        token: Token::String(
                                            format!("{}{}", f, first_in_list)
                                        ),
                                        offset: f.offset(),
                                    }
                                )
                            )

                        } else {
                            Expression::apply_math(
                                operator,
                                Expression::Value(f),
                                (*first_in_list).clone(),
                                context
                            )
                        };

                        let mut new_list = vec![new_first];
                        new_list.extend_from_slice(rest_of_list);
                        Expression::List(new_list)

                    } else {
                        panic!("Trying to perform an operation on a number and a list; expected to get a list with something in it");
                    }
                }
            },
        }
    }

    fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
        let mut list = match head {
            Some(Expression::List(v)) => v,
            Some(e) => vec![e],
            None => vec![],
        };
        list.push(tail);
        Expression::List(list)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token_offset::TokenOffset;
    use operator_or_token::OperatorOrToken;
    use operator::Operator;
    use operator_offset::OperatorOffset;
    use context::Context;

    fn semicolon() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Semicolon, offset: None }
        )
    }

    fn blue() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset { token: Token::String("blue".into()), offset: None }
        )
    }

    fn plus() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Plus, offset: None }
        )
    }

    fn slash() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Slash, offset: None }
        )
    }

    fn one() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 1.0, units: None, computed: false
                },
                offset: None
            }
        )
    }

    fn two() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 2.0, units: None, computed: false
                },
                offset: None
            }
        )
    }

    fn one_px() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 1.0, units: Some("px".into()), computed: false
                },
                offset: None
            }
        )
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Value(one()),
                Expression::Value(plus()),
                Expression::Value(one()),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(one()))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![
            Ok(one_px()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(one_px()))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Value(one()),
            Expression::Value(slash()),
            Expression::Value(two()),
            Expression::Value(plus()),
            Expression::Value(one()),
            Expression::Value(slash()),
            Expression::Value(two()),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Value(OperatorOrToken::Token(
                TokenOffset {
                    token: Token::Number {
                        value: 1.0,
                        units: None,
                        computed: true,
                    },
                    offset: None,
                }
            ))
        );
    }
}
<commit_msg>Extract a function for special casing of slash<commit_after>use token::Token;
use token_offset::TokenOffset;
use operator::Operator;
use operator_offset::OperatorOffset;
use operator_or_token::OperatorOrToken;
use context::Context;
use error::{Result, SassError, ErrorKind};

use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Value(OperatorOrToken),
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string()
                ).collect::<Vec<_>>().join(" ").fmt(f)
            },
            Expression::Value(ref v) => v.fmt(f),
        }
    }
}

impl Expression {
    pub fn parse<T>(tokenizer: &mut T) -> Result<Expression>
        where T: Iterator<Item = Result<OperatorOrToken>> {
        let mut list = vec![];
        while let Some(Ok(t)) = tokenizer.next() {
            match t {
                OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::Semicolon, ..
                }) => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                OperatorOrToken::Token(TokenOffset {
                    token: Token::Comment(_), ..
                }) => {},
                _ => list.push(Expression::Value(t)),
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::Value(v)) => v.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(exprs: Vec<Expression>, context: &Context) -> Expression {

        let mut last_was_an_operator = true;
        let mut paren_level = 0;

        // TODO: I'd love to have more types here, to ensure only values are
        // on the value stack and only operators are on the operator stack...
        let mut value_stack: Vec<Expression> = Vec::new();
        let mut op_stack: Vec<OperatorOffset> = Vec::new();

        // Split into value stacks and operator stacks

        let mut exprs = exprs.into_iter();
        while let Some(part) = exprs.next() {
            debug!("Processing list item {:#?}", part);
            match part {
                v @ Expression::Value(OperatorOrToken::Token(TokenOffset {
                    token: Token::Number { .. }, ..
                })) => {
                    if last_was_an_operator {
                        debug!("Push on value stack {:#?}", v);
                        value_stack.push(v);
                    } else {
                        while !op_stack.is_empty() &&
                              op_stack.last().unwrap().operator !=
                                  Operator::LeftParen {
                            Expression::math_machine(
                                &mut op_stack, &mut value_stack,
                                context, paren_level
                            );
                        }
                        let list = Expression::create_list(
                            value_stack.pop(),
                            v,
                        );
                        debug!("Push on list on value stack {:#?}", list);
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
                Expression::Value(OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::RightParen, ..
                })) => {
                    let mut last_operator = op_stack.pop();
                    while last_operator.is_some() &&
                          last_operator.unwrap().operator !=
                              Operator::LeftParen {
                        op_stack.push(last_operator.unwrap());
                        Expression::math_machine(
                            &mut op_stack, &mut value_stack,
                            context, paren_level
                        );
                        last_operator = op_stack.pop();
                    }

                    op_stack.pop();
                    last_was_an_operator = false;
                    paren_level -= 1;
                },
                Expression::Value(OperatorOrToken::Operator(OperatorOffset {
                    operator: Operator::LeftParen, offset
                })) => {
                    op_stack.push(OperatorOffset {
                        operator: Operator::LeftParen, offset: offset
                    });
                    last_was_an_operator = true;
                    paren_level += 1;
                },
                Expression::Value(OperatorOrToken::Operator(
                    oo @ OperatorOffset { .. }
                )) => {
                    if let Some(&last_operator) = op_stack.last() {
                        if last_operator.operator
                                .same_or_greater_precedence(oo.operator) {
                            Expression::math_machine(
                                &mut op_stack, &mut value_stack,
                                context, paren_level
                            );
                        }
                    }
                    debug!("Push on op stack {:#?}", oo);
                    op_stack.push(oo);
                    last_was_an_operator = true;
                },
                Expression::Value(OperatorOrToken::Token(t @ TokenOffset {
                    token: Token::String(_), ..
                })) => {
                    let var_eval = context.get_variable(&t)
                                    .unwrap_or(Expression::Value(
                                        OperatorOrToken::Token(t)
                                    ));

                    if last_was_an_operator {
                        value_stack.push(var_eval);
                    } else {
                        let list = Expression::create_list(
                            value_stack.pop(),
                            var_eval,
                        );
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
                Expression::List(list) => {
                    debug!("Push list on value stack {:#?}", list);
                    value_stack.push(Expression::List(list));
                    last_was_an_operator = false;
                },
                other => {
                    if last_was_an_operator {
                        value_stack.push(other);
                    } else {
                        let list = Expression::create_list(
                            value_stack.pop(),
                            other,
                        );
                        value_stack.push(list);
                    }
                    last_was_an_operator = false;
                },
            }
        }

        // Process the stacks
        while !op_stack.is_empty() {
            Expression::math_machine(
                &mut op_stack, &mut value_stack, context, paren_level
            );
        }

        value_stack.pop().unwrap()
    }

    fn math_machine(op_stack: &mut Vec<OperatorOffset>, value_stack: &mut Vec<Expression>, context: &Context, paren_level: i32) {
        let op = op_stack.pop().unwrap();
        let second = value_stack.pop()
                       .expect("Expected a second argument on the value stack");
        let first = value_stack.pop()
                       .expect("Expected a first argument on the value stack");

        let math_result = Expression::apply_math(
            op, first, second, context, paren_level,
        );
        debug!("Math result: {:#?}", math_result);

        value_stack.push(math_result);
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Value(OperatorOrToken::Token(t @ TokenOffset {
                token: Token::String(_), ..
            })) => {
                context.get_variable(&t)
                       .unwrap_or(Expression::Value(
                            OperatorOrToken::Token(t)
                       ))
            },
            Expression::List(exprs) => {
                Expression::evaluate_list(exprs, context)
            },
            other => other,
        }
    }

    fn apply_slash(first: OperatorOrToken, second: OperatorOrToken, paren_level: i32) -> OperatorOrToken {
        first / second
    }

    fn apply_math(operator: OperatorOffset, first: Expression, second: Expression, context: &Context, paren_level: i32) -> Expression {
        debug!("Applying math to:\nfirst: {:#?}\nop: {:#?}\nsecond: {:#?}", first, operator, second);

        match (first, second) {
            (Expression::Value(f), Expression::Value(s)) => {
                let result = match operator.operator {
                    Operator::Plus => f + s,
                    Operator::Minus => f - s,
                    Operator::Star => f * s,
                    Operator::Percent => f % s,
                    Operator::Slash => Expression::apply_slash(
                        f, s, paren_level
                    ),
                    _ => unimplemented!(),
                };
                Expression::Value(result)
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::evaluate_list(f, context);
                let eval_second = Expression::evaluate_list(s, context);
                Expression::apply_math(
                    operator, eval_first, eval_second,
                    context, paren_level
                )
            },
            (Expression::List(f), Expression::Value(s)) => {
                let eval_first = Expression::evaluate_list(f, context);
                Expression::apply_math(
                    operator, eval_first, Expression::Value(s),
                    context, paren_level
                )
            },
            (Expression::Value(f), Expression::List(s)) => {
                if s.iter().any(|e|
                    match *e {
                        Expression::Value(
                            OperatorOrToken::Operator(OperatorOffset {
                                operator: Operator::Slash, ..
                            })
                        ) => true,
                        _ => false,
                    }) {
                    let evaled_list = Expression::evaluate_list(
                        s, context
                    );
                    Expression::apply_math(
                        operator, Expression::Value(f), evaled_list,
                        context, paren_level
                    )
                } else {
                    if let Some((ref first_in_list, rest_of_list)) =
                            s.split_first() {

                        // Adding a number to a list means we should do
                        // string concatenation.
                        let new_first = if operator.operator == Operator::Plus {
                            Expression::Value(
                                OperatorOrToken::Token(
                                    TokenOffset {
                                        token: Token::String(
                                            format!("{}{}", f, first_in_list)
                                        ),
                                        offset: f.offset(),
                                    }
                                )
                            )

                        } else {
                            Expression::apply_math(
                                operator,
                                Expression::Value(f),
                                (*first_in_list).clone(),
                                context,
                                paren_level
                            )
                        };

                        let mut new_list = vec![new_first];
                        new_list.extend_from_slice(rest_of_list);
                        Expression::List(new_list)

                    } else {
                        panic!("Trying to perform an operation on a number and a list; expected to get a list with something in it");
                    }
                }
            },
        }
    }

    fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
        let mut list = match head {
            Some(Expression::List(v)) => v,
            Some(e) => vec![e],
            None => vec![],
        };
        list.push(tail);
        Expression::List(list)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token_offset::TokenOffset;
    use operator_or_token::OperatorOrToken;
    use operator::Operator;
    use operator_offset::OperatorOffset;
    use context::Context;

    fn semicolon() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Semicolon, offset: None }
        )
    }

    fn blue() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset { token: Token::String("blue".into()), offset: None }
        )
    }

    fn plus() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Plus, offset: None }
        )
    }

    fn slash() -> OperatorOrToken {
        OperatorOrToken::Operator(
            OperatorOffset { operator: Operator::Slash, offset: None }
        )
    }

    fn one() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 1.0, units: None, computed: false
                },
                offset: None
            }
        )
    }

    fn two() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 2.0, units: None, computed: false
                },
                offset: None
            }
        )
    }

    fn one_px() -> OperatorOrToken {
        OperatorOrToken::Token(
            TokenOffset {
                token: Token::Number {
                    value: 1.0, units: Some("px".into()), computed: false
                },
                offset: None
            }
        )
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Value(one()),
                Expression::Value(plus()),
                Expression::Value(one()),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(one()))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![
            Ok(one_px()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Value(one_px()))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Value(one()),
            Expression::Value(slash()),
            Expression::Value(two()),
            Expression::Value(plus()),
            Expression::Value(one()),
            Expression::Value(slash()),
            Expression::Value(two()),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Value(OperatorOrToken::Token(
                TokenOffset {
                    token: Token::Number {
                        value: 1.0,
                        units: None,
                        computed: true,
                    },
                    offset: None,
                }
            ))
        );
    }
}
<|endoftext|>


<commit_before>use std::result::Result;
use std::process::Command;
use std::str;

use backend;
use backend::Backend;
use provider::error::Error;
use provider::HandleFunc;
use provider::Output;
use platform::platform::Platform;
use platform::platforms::Platforms;

pub struct Direct;

impl Direct {
    pub fn new() -> Direct {
        Direct
    }
}

impl Backend for Direct {
    fn detect_platform(&self) -> Option<Box<Platform>> {
        let mut platforms = Platforms::new();
        while let Some(p) = platforms.next() {
            match p.inline_detector() {
                Some(m) => return Some(m),
                None => (),
            };

            match p.shell_detector(self) {
                Some(m) => return Some(m),
                None => (),
            }
        }
        None
    }

    fn handle(&self, handle_func: Box<HandleFunc>) -> Result<Output, Error> {
        (handle_func.inline)().or_else(|_| (handle_func.shell)(self))
    }

    fn run_command(&self, c: &str) -> Result<String, backend::error::Error> {
        let out = try!(Command::new("sh").args(&["-c", c]).output());
        let res = try!(String::from_utf8(out.stdout));
        Ok(res.trim().to_string())
    }
}

// Wrapper functions for FFI

use backend::BackendWrapper;

#[no_mangle]
pub extern "C" fn backend_direct_new() -> *mut BackendWrapper {
    let b = BackendWrapper { backend: Box::new(Direct::new()) };
    Box::into_raw(Box::new(b))
}

#[no_mangle]
pub extern "C" fn backend_direct_free(ptr: *mut BackendWrapper) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}
<commit_msg>Fix error handling to return appropreate error<commit_after>use std::result::Result;
use std::process::Command;
use std::str;

use backend;
use backend::Backend;
use provider::error::Error;
use provider::HandleFunc;
use provider::Output;
use platform::platform::Platform;
use platform::platforms::Platforms;

pub struct Direct;

impl Direct {
    pub fn new() -> Direct {
        Direct
    }
}

impl Backend for Direct {
    fn detect_platform(&self) -> Option<Box<Platform>> {
        let mut platforms = Platforms::new();
        while let Some(p) = platforms.next() {
            match p.inline_detector() {
                Some(m) => return Some(m),
                None => (),
            };

            match p.shell_detector(self) {
                Some(m) => return Some(m),
                None => (),
            }
        }
        None
    }

    fn handle(&self, handle_func: Box<HandleFunc>) -> Result<Output, Error> {
        match (handle_func.inline)() {
            Ok(r) => return Ok(r),
            Err(Error::HandleFuncNotDefined(_)) => (),
            Err(e) => return Err(e),
        };

        (handle_func.shell)(self)
    }

    fn run_command(&self, c: &str) -> Result<String, backend::error::Error> {
        let out = try!(Command::new("sh").args(&["-c", c]).output());
        let res = try!(String::from_utf8(out.stdout));
        Ok(res.trim().to_string())
    }
}

// Wrapper functions for FFI

use backend::BackendWrapper;

#[no_mangle]
pub extern "C" fn backend_direct_new() -> *mut BackendWrapper {
    let b = BackendWrapper { backend: Box::new(Direct::new()) };
    Box::into_raw(Box::new(b))
}

#[no_mangle]
pub extern "C" fn backend_direct_free(ptr: *mut BackendWrapper) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;

use tokio_core::reactor::Interval;
use tokio_core::reactor::Handle;
use futures::stream::{Stream};

use std::time::{Instant, Duration};
use futures::Future;
use futures::IntoFuture;
use futures::Then;
use futures::Map;
use futures::Async;
use futures::future::Ok;
use futures::Poll;
use std::thread;
use std::cell::Cell;

use tokio_core::reactor::{Core, Timeout};

struct Error {
    code: i32
}

impl Error {
    fn new(c: i32) -> Error {
        Error { code: c }
    }
}

// A future as return type of getAsynch() method below.
//struct After {
//    d: Duration,
//    s: State
//}
//
//impl Future for After {
//    type Item = State;
//    type Error = Error;
//
//    fn poll(&mut self) -> Poll<State, Error> {
//        Ok(Async::Ready(self.s))
//    }
//}

enum Cmd<S: Clone> {
    Start(S),
    //    Immediately(Duration, S),
    After(Duration, S)
}

// A struct that holds some state and a handle on
// which to run its worker function.
struct Actor<S: Clone> {
    dur: Duration,
    state: S,
    //fu: fn(S) -> Future<Item = S, Error = Error>,
    fu: fn(S) -> Cmd<S>,
}

impl<S: 'static + Clone> Actor<S> {
    // Create a new S and schedule its worker function
    //    fn new(handle: Handle, start: S, f: fn(S) -> Future<Item = S, Error = Error>) -> Actor<S> {
    fn new(handle: Handle, start: S, f: fn(S) -> Cmd<S>) -> Actor<S> {
        let d = Duration::from_millis(5000);
        let a: Actor<S> = Actor { dur: d, state: start.clone(), fu: f };
        let cmd = Cmd::Start(start.clone());
        Actor::nextf2(handle, cmd, f);
        //handle.spawn(fut);
        a
    }

    fn nextf2(handle: Handle, cmd: Cmd<S>, f: fn(S) -> Cmd<S>) {
        let futu = match cmd {
            Cmd::Start(s) => {
                let timeout = Timeout::new(Duration::from_millis(5000), &handle).unwrap();
                let x = handle.clone();
                let s2 = s.clone();
                let f2 = f.clone();
                let futu = timeout.then(move |r| {
                    println!("Worker says start");
                    match r {
                        Ok(_) => {
                            let cmd2 = f2(s2);
                            Actor::nextf2(x, cmd2, f);
                            futures::future::ok::<(), ()>(())
                        },
                        Err(_) => futures::future::ok::<(), ()>(()),
                    }
                });
                handle.spawn(futu);
            },
            Cmd::After(d, s) => {
                let timeout = Timeout::new(d, &handle).unwrap();
                let x = handle.clone();
                let s2 = s.clone();
                let f2 = f.clone();
                let futu = timeout.then(move |r| {
                    println!("Worker says after");
                    match r {
                        Ok(_) => {
                            let cmd2 = f2(s2);
                            Actor::nextf2(x, cmd2, f);
                            futures::future::ok::<(), ()>(())
                        },
                        Err(_) => futures::future::ok::<(), ()>(()),
                    }
                });
                handle.spawn(futu);
            },
            //            Cmd::Run(rf) => {
            //                let timeout = Timeout::new(d, &handle).unwrap();
            //                let x = handle.clone();
            //
            //                let s2 = s.clone();
            //                let f2 = f.clone();
            //                let futu = rf.then(move |r| {
            //                    println!("Worker says run");
            //                    match r {
            //                        Ok(_) => {
            //                            let cmd2 = f2(s2);
            //                            Actor::nextf2(x, cmd2, f);
            //                            futures::future::ok::<(), ()>(())
            //                        },
            //                        Err(_) => futures::future::ok::<(), ()>(()),
            //                    }
            //                });
            //                handle.spawn(futu);
            //            }
        };
    }

    // Will later on be used to access state from other threads in a reactive way.
    //    fn getAsync(&self) -> MyFuture {
    //        MyFuture { v: self.state }
    //    }
}

#[derive(Copy, Clone)]
enum State {
    Start(i32),
    Foo,
    End
}

//fn testGetFromUpstream<R, F>(handle: &Handle, d: Duration, v: R) -> Map<Timeout, F>
//    where R: Clone, F: FnOnce(()) -> R,
//{
//    let timeout = Timeout::new(d, handle).unwrap();
//    let futu = timeout.map(|r| { v });
//    futu
//}

fn testSimulateRemoteGetValue<R, F>(handle: &Handle, d: Duration, v: R) -> Map<Timeout, F>
    where R: Clone, F: FnOnce(()) -> R,
{
    let timeout = Timeout::new(d, handle).unwrap();
    let fut: Map<Timeout, F> = timeout.map(|r| -> R { v });
    fut
}

//fn map<F, U>( self , f: F) -> Map < Self, F>
//where F: FnOnce( Self::Item) -> U,
//Self: Sized,
//{
//assert_future::< U, Self::Error, _> (map::new( self, f))
//}

//type FOO = fn(()) -> i32;
//
//fn testGetFromUpstream(handle: &Handle, d: Duration, v: i32) -> Map<Timeout, fn(()) -> i32> {
//    let timeout = Timeout::new(d, handle).unwrap();
//    let c: fn(()) -> i32 = |r| { v };
//    timeout.map(c)
//}

fn main() {
    // A thread on which background workers will be run.
    let worker_thread = thread::spawn(move || {
        let mut core = Core::new().unwrap();

        //        fn add_10<F>(f: F) -> Map<F, fn(i32) -> i32>
        //            where F: Future<Item = i32>,
        //        {
        //            fn do_map(i: i32) -> i32 { i + 10 }
        //            f.map(do_map)
        //        }
        //
        //        fn doIt<S>(s:S) -> Map<F, fn(i32) -> i32>
        //            where F: Future<Item = S>,
        //        {
        //
        //        }

        //        fn update(state: State) -> Future<Item = State, Error = Error> {
        fn update(state: State) -> Cmd<State> {
            match state {
                State::Start(s) => {
                    println!("start");
                    Cmd::After(Duration::new(1, 0), State::Foo)
                },
                //                State::Foo => {
                //                    println!("foo");
                //                    Cmd::Run(|| {
                //
                //                    })
                //                },
                State::End => {
                    println!("end");
                    Cmd::After(Duration::new(1, 0), State::End)
                },
            }
        }

        // Create a background worker
        let a: Actor<State> = Actor::new(core.handle(), State::Start(10), update);

        // An interval stream to drive the background worker futures.
        let interval_stream = Interval::new(Duration::new(1, 0), &(core.handle())).unwrap();
        let stream_future = interval_stream.for_each(|_| {
            println!("Worker driver says hello");
            Ok(())
        });

        core.run(stream_future).unwrap();
    });

    // Request handler threads to be started here (e.g. HTTP server)
    // These threads will eventually use the state the workers work on.

    worker_thread.join().unwrap();
}
<commit_msg>Learning<commit_after>extern crate futures;
extern crate tokio_core;

use tokio_core::reactor::Interval;
use tokio_core::reactor::Handle;
use futures::stream::{Stream};

use std::time::{Instant, Duration};
use futures::Future;
use futures::IntoFuture;
use futures::Then;
use futures::Map;
use futures::Async;
use futures::future::Ok;
use futures::Poll;
use std::thread;
use std::cell::Cell;

use tokio_core::reactor::{Core, Timeout};

struct Error {
    code: i32
}

impl Error {
    fn new(c: i32) -> Error {
        Error { code: c }
    }
}

// A future as return type of getAsynch() method below.
//struct After {
//    d: Duration,
//    s: State
//}
//
//impl Future for After {
//    type Item = State;
//    type Error = Error;
//
//    fn poll(&mut self) -> Poll<State, Error> {
//        Ok(Async::Ready(self.s))
//    }
//}

enum Cmd<S: Clone> {
    Start(S),
    //    Immediately(Duration, S),
    After(Duration, S)
}

// A struct that holds some state and a handle on
// which to run its worker function.
struct Actor<S: Clone> {
    dur: Duration,
    state: S,
    //fu: fn(S) -> Future<Item = S, Error = Error>,
    fu: fn(S) -> Cmd<S>,
}

impl<S: 'static + Clone> Actor<S> {
    // Create a new S and schedule its worker function
    //    fn new(handle: Handle, start: S, f: fn(S) -> Future<Item = S, Error = Error>) -> Actor<S> {
    fn new(handle: Handle, start: S, f: fn(S) -> Cmd<S>) -> Actor<S> {
        let d = Duration::from_millis(5000);
        let a: Actor<S> = Actor { dur: d, state: start.clone(), fu: f };
        let cmd = Cmd::Start(start.clone());
        Actor::nextf2(handle, cmd, f);
        //handle.spawn(fut);
        a
    }

    fn nextf2(handle: Handle, cmd: Cmd<S>, f: fn(S) -> Cmd<S>) {
        let futu = match cmd {
            Cmd::Start(s) => {
                let timeout = Timeout::new(Duration::from_millis(5000), &handle).unwrap();
                let x = handle.clone();
                let s2 = s.clone();
                let f2 = f.clone();
                let futu = timeout.then(move |r| {
                    println!("Worker says start");
                    match r {
                        Ok(_) => {
                            let cmd2 = f2(s2);
                            Actor::nextf2(x, cmd2, f);
                            futures::future::ok::<(), ()>(())
                        },
                        Err(_) => futures::future::ok::<(), ()>(()),
                    }
                });
                handle.spawn(futu);
            },
            Cmd::After(d, s) => {
                let timeout = Timeout::new(d, &handle).unwrap();
                let x = handle.clone();
                let s2 = s.clone();
                let f2 = f.clone();
                let futu = timeout.then(move |r| {
                    println!("Worker says after");
                    match r {
                        Ok(_) => {
                            let cmd2 = f2(s2);
                            Actor::nextf2(x, cmd2, f);
                            futures::future::ok::<(), ()>(())
                        },
                        Err(_) => futures::future::ok::<(), ()>(()),
                    }
                });
                handle.spawn(futu);
            },
            //            Cmd::Run(rf) => {
            //                let timeout = Timeout::new(d, &handle).unwrap();
            //                let x = handle.clone();
            //
            //                let s2 = s.clone();
            //                let f2 = f.clone();
            //                let futu = rf.then(move |r| {
            //                    println!("Worker says run");
            //                    match r {
            //                        Ok(_) => {
            //                            let cmd2 = f2(s2);
            //                            Actor::nextf2(x, cmd2, f);
            //                            futures::future::ok::<(), ()>(())
            //                        },
            //                        Err(_) => futures::future::ok::<(), ()>(()),
            //                    }
            //                });
            //                handle.spawn(futu);
            //            }
        };
    }

    // Will later on be used to access state from other threads in a reactive way.
    //    fn getAsync(&self) -> MyFuture {
    //        MyFuture { v: self.state }
    //    }
}

#[derive(Copy, Clone)]
enum State {
    Start(i32),
    Foo,
    End
}

//fn testGetFromUpstream<R, F>(handle: &Handle, d: Duration, v: R) -> Map<Timeout, F>
//    where R: Clone, F: FnOnce(()) -> R,
//{
//    let timeout = Timeout::new(d, handle).unwrap();
//    let futu = timeout.map(|r| { v });
//    futu
//}

fn testSimulateRemoteGetValue<R, F>(handle: &Handle, d: Duration, f: F) -> Map<Timeout, F>
    where R: Clone, F: FnOnce(()) -> R,
{
    let timeout = Timeout::new(d, handle).unwrap();
    let fut: Map<Timeout, F> = timeout.map(f);
    fut
}

//fn map<F, U>( self , f: F) -> Map < Self, F>
//where F: FnOnce( Self::Item) -> U,
//Self: Sized,
//{
//assert_future::< U, Self::Error, _> (map::new( self, f))
//}

//type FOO = fn(()) -> i32;
//
//fn testGetFromUpstream(handle: &Handle, d: Duration, v: i32) -> Map<Timeout, fn(()) -> i32> {
//    let timeout = Timeout::new(d, handle).unwrap();
//    let c: fn(()) -> i32 = |r| { v };
//    timeout.map(c)
//}

fn main() {
    // A thread on which background workers will be run.
    let worker_thread = thread::spawn(move || {
        let mut core = Core::new().unwrap();

        //        fn add_10<F>(f: F) -> Map<F, fn(i32) -> i32>
        //            where F: Future<Item = i32>,
        //        {
        //            fn do_map(i: i32) -> i32 { i + 10 }
        //            f.map(do_map)
        //        }
        //
        //        fn doIt<S>(s:S) -> Map<F, fn(i32) -> i32>
        //            where F: Future<Item = S>,
        //        {
        //
        //        }

        //        fn update(state: State) -> Future<Item = State, Error = Error> {
        fn update(state: State) -> Cmd<State> {
            match state {
                State::Start(s) => {
                    println!("start");
                    Cmd::After(Duration::new(1, 0), State::Foo)
                },
                //                State::Foo => {
                //                    println!("foo");
                //                    Cmd::Run(|| {
                //
                //                    })
                //                },
                State::End => {
                    println!("end");
                    Cmd::After(Duration::new(1, 0), State::End)
                },
            }
        }

        // Create a background worker
        let a: Actor<State> = Actor::new(core.handle(), State::Start(10), update);

        // An interval stream to drive the background worker futures.
        let interval_stream = Interval::new(Duration::new(1, 0), &(core.handle())).unwrap();
        let stream_future = interval_stream.for_each(|_| {
            println!("Worker driver says hello");
            Ok(())
        });

        core.run(stream_future).unwrap();
    });

    // Request handler threads to be started here (e.g. HTTP server)
    // These threads will eventually use the state the workers work on.

    worker_thread.join().unwrap();
}
<|endoftext|>


<commit_before>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
use rustc::lib::llvm;
use rustc::lib::llvm::*;

use std::ffi::CString;
use std::mem::transmute;

use libc::{c_char, c_uint};

use ::errors::{ExpectICE, UnwrapICE};

// pub struct Context(llvm::ContextRef);
//
// pub struct Builder(llvm::BuilderRef);

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

trait LLVMWrapper {
    type Ref;
    fn to_ref(&self) -> Self::Ref;
    fn from_ref(r: Self::Ref) -> Self;
}

macro_rules! llvm_wrapper {
    ( $($name:ident wrapping $wrapped:path),*) => {$(
        pub struct $name ($wrapped);

        impl LLVMWrapper for $name {
            type Ref = $wrapped;

            fn to_ref(&self) -> Self::Ref {
                not_null!(self.0)
            }

            fn from_ref(r: $wrapped) -> Self {
                $name( not_null!(r) )
            }
        }
    )*};
    ( $($name:ident wrapping $wrapped:path, dropped by $drop:path),*) => {$(
        llvm_wrapper!{ $name wrapping $wrapped }

        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { $drop(self.0) }
            }
        }
    )*}
}

llvm_wrapper! {
    Context wrapping llvm::ContextRef,
        dropped by llvm::LLVMContextDispose,
    Builder wrapping llvm::BuilderRef,
        dropped by llvm::LLVMDisposeBuilder,
    OperandBundle wrapping llvm::OperandBundleDefRef,
        dropped by llvm::LLVMRustFreeOperandBundleDef
}

llvm_wrapper! {
    BasicBlock wrapping llvm::BasicBlockRef,
    Value wrapping llvm::ValueRef
}

impl Context {
    /// Construct a new `Builder` within this `Context`.
    pub fn create_builder(&self) -> Builder {
        unsafe {
            Builder::from_ref(LLVMCreateBuilderInContext(self.to_ref()))
        }
    }
}

impl OperandBundle {
    /// Construct a new `OperandBundle`
    pub fn new(name: &str, vals: &mut [Value]) -> Self {
        let cname = CString::new(name).unwrap_ice();
        unsafe {
            let vals_ref = transmute::<&mut [Value], &mut [ValueRef]>(vals);
            let def = LLVMRustBuildOperandBundleDef( cname.as_ptr()
                                                   , vals_ref.as_ptr()
                                                   , vals_ref.len() as c_uint);
            OperandBundle(def)
        }
    }
}

impl Builder {
    //---- positioning --------------------------------------------------------
    /// Wrapper for `LLVMPositionBuilder`.
    pub fn position(&mut self, block: &mut BasicBlock, inst: &Value)
                   -> &mut Self {
        unsafe {
            LLVMPositionBuilder(self.to_ref(), block.to_ref(), inst.to_ref());
        }
        self
    }

    /// Wrapper for `LLVMPositionBuilderBefore`.
    pub fn position_before(&mut self, inst: &Value) -> &mut Self {
        unsafe { LLVMPositionBuilderBefore(self.to_ref(), inst.to_ref()) }
        self
    }

    /// Wrapper for `LLVMPositionBuilderAtEnd`.
    pub fn position_at_end(&mut self, block: &mut BasicBlock) -> &mut Self {
        unsafe { LLVMPositionBuilderAtEnd(self.to_ref(), block.to_ref()) }
        self
    }

    //---- insertion ----------------------------------------------------------
    pub fn get_insert_block(&mut self) -> BasicBlock {
        unsafe { BasicBlock::from_ref(LLVMGetInsertBlock(self.to_ref())) }
    }

    pub fn clear_insertion_position(&mut self) -> &mut Self {
        unsafe { LLVMClearInsertionPosition(self.to_ref()) }
        self
    }

    pub fn insert(&mut self, inst: &mut Value) -> &mut Self {
        unsafe { LLVMInsertIntoBuilder(self.to_ref(), inst.to_ref()) }
        self
    }

    pub fn insert_with_name(&mut self, inst: &mut Value, name: &str)
                            -> &mut Self {
        let cname = CString::new(name).expect_ice(
                    format!("Couldn't create CString for {}", name).as_ref());
        unsafe {
            LLVMInsertIntoBuilderWithName( self.to_ref()
                                         , inst.to_ref()
                                         , cname.as_ptr() as *const c_char)
        }
        self
    }
    //---- building ----------------------------------------------------------
    /// Create a `ret void` return instruction.
    pub fn build_ret_void(&mut self) -> Value {
        unsafe { Value::from_ref( LLVMBuildRetVoid(self.to_ref()) ) }
    }

    /// Create a `ret <value>` instruction.
    ///
    /// # Arguments
    ///
    ///  + `v`: the `Value` to return
    pub fn build_ret(&mut self, v: &Value) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildRet(self.to_ref(), v.to_ref()) )
        }
    }

    /// Create an unconditional branch `br label X` instruction.
    ///
    /// # Arguments
    ///
    ///  + `dest` the `BasicBlock` to branch to.
    ///
    /// # Return Value
    ///  An unconditional branch `br` instruction.
    pub fn build_br(&mut self, dest: &BasicBlock) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildBr(self.to_ref(), dest.to_ref()) )
        }
    }

    /// Create a conditional branch instruction.
    ///
    /// # Arguments
    ///
    ///  + `condition`: the condition to test
    ///  + `then_block`: the block to branch to if the condition is true
    ///  + `else_block`: the block to branch to if the condition is false
    ///
    ///  # Returns Value
    ///
    /// A conditional branch instruction of the form
    /// `br $condition, $then_block, $else_block`.
    pub fn build_cond_br( &mut self
                        , condition: Value
                        , then_block: &BasicBlock
                        , else_block: &BasicBlock )
                        -> Value {
        unsafe {
            let val = LLVMBuildCondBr( self.to_ref()
                                     , condition.to_ref()
                                     , then_block.to_ref()
                                     , else_block.to_ref() );
            Value::from_ref(val)
        }
    }

    /// Create a switch instruction.
    ///
    /// # Arguments
    ///
    ///  + `on`: the `Value` to switch on
    ///  + `else_block`: a `BasicBlock` representing the default destination
    ///  + `num_cases`: a hint towards the number of cases in the switch
    ///                 expression (for more efficient allocation)
    ///
    /// # Return Value
    ///
    /// A switch instruction with the specified value and default destination.
    pub fn build_switch_br( &mut self
                          , on: Value
                          , else_block: &BasicBlock
                          , num_cases: u32 )
                          -> Value {
        unsafe {
            Value::from_ref(LLVMBuildSwitch( self.to_ref()
                                            , on.to_ref()
                                            , else_block.to_ref()
                                            , num_cases))
        }
    }

    /// Create a function invocation instruction.
    ///
    /// # Arguments
    ///
    ///  + `function`: the function to invoke
    ///  + `args': the arguments to `function`
    ///  + `then_block`:
    ///  + `catch_block`:
    ///  + `name`: the name of the instruction.
    ///
    /// # Return Value
    ///
    /// A function invocation instruction.
    pub fn build_invoke( &mut self
                       , function: Value
                       , args: &mut [Value]
                       , then_block: &BasicBlock
                       , catch_block: &BasicBlock
                       , bundle: &OperandBundle
                       , name: &str )
                       -> Value {
        let cname = CString::new(name).unwrap_ice().as_ptr();
        unsafe {
            let args_ref = transmute::<&mut [Value], &mut [ValueRef]>(args)
                            .as_ptr();
            let val = LLVMRustBuildInvoke( self.to_ref()
                                         , function.to_ref()
                                         , args_ref, args.len() as c_uint
                                         , then_block.to_ref()
                                         , catch_block.to_ref()
                                         , bundle.to_ref()
                                         , cname as *const c_char);
            Value::from_ref(val)
        }
    }

    pub fn build_resume(&mut self, ex: Value) -> Value {
        unsafe { Value::from_ref(LLVMBuildResume(self.to_ref(), ex.to_ref())) }
    }

    pub fn build_unreachable(&mut self) -> Value {
        unsafe { Value::from_ref(LLVMBuildUnreachable(self.to_ref())) }
    }

}
<commit_msg>[core] Add builders for exception handlign stuff<commit_after>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
use rustc::lib::llvm;
use rustc::lib::llvm::*;

use std::ffi::CString;
use std::mem::transmute;

use libc::{c_char, c_uint};

use ::errors::{ExpectICE, UnwrapICE};

// pub struct Context(llvm::ContextRef);
//
// pub struct Builder(llvm::BuilderRef);

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

trait LLVMWrapper {
    type Ref;
    fn to_ref(&self) -> Self::Ref;
    fn from_ref(r: Self::Ref) -> Self;
}

macro_rules! llvm_wrapper {
    ( $($name:ident wrapping $wrapped:path),*) => {$(
        pub struct $name ($wrapped);

        impl LLVMWrapper for $name {
            type Ref = $wrapped;

            fn to_ref(&self) -> Self::Ref {
                not_null!(self.0)
            }

            fn from_ref(r: $wrapped) -> Self {
                $name( not_null!(r) )
            }
        }
    )*};
    ( $($name:ident wrapping $wrapped:path, dropped by $drop:path),*) => {$(
        llvm_wrapper!{ $name wrapping $wrapped }

        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { $drop(self.0) }
            }
        }
    )*}
}

llvm_wrapper! {
    Context wrapping llvm::ContextRef,
        dropped by llvm::LLVMContextDispose,
    Builder wrapping llvm::BuilderRef,
        dropped by llvm::LLVMDisposeBuilder,
    OperandBundle wrapping llvm::OperandBundleDefRef,
        dropped by llvm::LLVMRustFreeOperandBundleDef
}

llvm_wrapper! {
    BasicBlock wrapping llvm::BasicBlockRef,
    Value wrapping llvm::ValueRef
}

impl Context {
    /// Construct a new `Builder` within this `Context`.
    pub fn create_builder(&self) -> Builder {
        unsafe {
            Builder::from_ref(LLVMCreateBuilderInContext(self.to_ref()))
        }
    }
}

impl OperandBundle {
    /// Construct a new `OperandBundle`
    pub fn new(name: &str, vals: &mut [Value]) -> Self {
        let cname = CString::new(name).unwrap_ice();
        unsafe {
            let vals_ref = transmute::<&mut [Value], &mut [ValueRef]>(vals);
            let def = LLVMRustBuildOperandBundleDef( cname.as_ptr()
                                                   , vals_ref.as_ptr()
                                                   , vals_ref.len() as c_uint);
            OperandBundle(def)
        }
    }
}

impl Builder {
    //---- positioning --------------------------------------------------------
    /// Wrapper for `LLVMPositionBuilder`.
    pub fn position(&mut self, block: &mut BasicBlock, inst: &Value)
                   -> &mut Self {
        unsafe {
            LLVMPositionBuilder(self.to_ref(), block.to_ref(), inst.to_ref());
        }
        self
    }

    /// Wrapper for `LLVMPositionBuilderBefore`.
    pub fn position_before(&mut self, inst: &Value) -> &mut Self {
        unsafe { LLVMPositionBuilderBefore(self.to_ref(), inst.to_ref()) }
        self
    }

    /// Wrapper for `LLVMPositionBuilderAtEnd`.
    pub fn position_at_end(&mut self, block: &mut BasicBlock) -> &mut Self {
        unsafe { LLVMPositionBuilderAtEnd(self.to_ref(), block.to_ref()) }
        self
    }

    //---- insertion ----------------------------------------------------------
    pub fn get_insert_block(&mut self) -> BasicBlock {
        unsafe { BasicBlock::from_ref(LLVMGetInsertBlock(self.to_ref())) }
    }

    pub fn clear_insertion_position(&mut self) -> &mut Self {
        unsafe { LLVMClearInsertionPosition(self.to_ref()) }
        self
    }

    pub fn insert(&mut self, inst: &mut Value) -> &mut Self {
        unsafe { LLVMInsertIntoBuilder(self.to_ref(), inst.to_ref()) }
        self
    }

    pub fn insert_with_name(&mut self, inst: &mut Value, name: &str)
                            -> &mut Self {
        let cname = CString::new(name).expect_ice(
                    format!("Couldn't create CString for {}", name).as_ref());
        unsafe {
            LLVMInsertIntoBuilderWithName( self.to_ref()
                                         , inst.to_ref()
                                         , cname.as_ptr() as *const c_char)
        }
        self
    }
    //---- building ----------------------------------------------------------
    /// Create a `ret void` return instruction.
    pub fn build_ret_void(&mut self) -> Value {
        unsafe { Value::from_ref( LLVMBuildRetVoid(self.to_ref()) ) }
    }

    /// Create a `ret <value>` instruction.
    ///
    /// # Arguments
    ///
    ///  + `v`: the `Value` to return
    pub fn build_ret(&mut self, v: &Value) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildRet(self.to_ref(), v.to_ref()) )
        }
    }

    /// Create an unconditional branch `br label X` instruction.
    ///
    /// # Arguments
    ///
    ///  + `dest` the `BasicBlock` to branch to.
    ///
    /// # Return Value
    ///  An unconditional branch `br` instruction.
    pub fn build_br(&mut self, dest: &BasicBlock) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildBr(self.to_ref(), dest.to_ref()) )
        }
    }

    /// Create a conditional branch instruction.
    ///
    /// # Arguments
    ///
    ///  + `condition`: the condition to test
    ///  + `then_block`: the block to branch to if the condition is true
    ///  + `else_block`: the block to branch to if the condition is false
    ///
    ///  # Returns Value
    ///
    /// A conditional branch instruction of the form
    /// `br $condition, $then_block, $else_block`.
    pub fn build_cond_br( &mut self
                        , condition: Value
                        , then_block: &BasicBlock
                        , else_block: &BasicBlock )
                        -> Value {
        unsafe {
            let val = LLVMBuildCondBr( self.to_ref()
                                     , condition.to_ref()
                                     , then_block.to_ref()
                                     , else_block.to_ref() );
            Value::from_ref(val)
        }
    }

    /// Create a switch instruction.
    ///
    /// # Arguments
    ///
    ///  + `on`: the `Value` to switch on
    ///  + `else_block`: a `BasicBlock` representing the default destination
    ///  + `num_cases`: a hint towards the number of cases in the switch
    ///                 expression (for more efficient allocation)
    ///
    /// # Return Value
    ///
    /// A switch instruction with the specified value and default destination.
    pub fn build_switch_br( &mut self
                          , on: Value
                          , else_block: &BasicBlock
                          , num_cases: u32 )
                          -> Value {
        unsafe {
            Value::from_ref(LLVMBuildSwitch( self.to_ref()
                                            , on.to_ref()
                                            , else_block.to_ref()
                                            , num_cases))
        }
    }

    /// Create a function invocation instruction.
    ///
    /// # Arguments
    ///
    ///  + `function`: the function to invoke
    ///  + `args': the arguments to `function`
    ///  + `then_block`:
    ///  + `catch_block`:
    ///  + `name`: the name of the instruction.
    ///  + `bundle`:
    ///
    /// # Return Value
    ///
    /// A function invocation instruction.
    pub fn build_invoke( &mut self
                       , function: Value
                       , args: &mut [Value]
                       , then_block: &BasicBlock
                       , catch_block: &BasicBlock
                       , bundle: &OperandBundle
                       , name: &str )
                       -> Value {
        let cname = CString::new(name).unwrap_ice().as_ptr();
        unsafe {
            let args_ref = transmute::<&mut [Value], &mut [ValueRef]>(args)
                            .as_ptr();
            let val = LLVMRustBuildInvoke( self.to_ref()
                                         , function.to_ref()
                                         , args_ref, args.len() as c_uint
                                         , then_block.to_ref()
                                         , catch_block.to_ref()
                                         , bundle.to_ref()
                                         , cname as *const c_char);
            Value::from_ref(val)
        }
    }

    /// Create landing pad
    ///
    // TODO: do we even want to support this? We don't have checked exns
    pub fn build_landing_pad( &mut self
                            , ty: TypeRef
                            , pers_fn: Value
                            , num_clauses: usize
                            , name: &str
                            , f: Value)
                            -> Value {
        let cname = CString::new(name).unwrap_ice().as_ptr();
        unsafe {
            Value::from_ref(
                LLVMRustBuildLandingPad( self.to_ref()
                                       , ty
                                       , pers_fn.to_ref()
                                       , num_clauses as c_uint
                                       , cname as *const c_char
                                       , f.to_ref() )
            )
        }
    }

    pub fn build_cleanup_pad( &mut self
                            , parent_pad: Value
                            , args: &mut [Value]
                            , name: &str )
                            -> Value {
        let cname = CString::new(name).unwrap_ice().as_ptr();
        unsafe {
            let args_ref = transmute::<&mut [Value], &mut [ValueRef]>(args);
            Value::from_ref(
                LLVMRustBuildCleanupPad( self.to_ref()
                                       , parent_pad.to_ref()
                                       , args_ref.len() as c_uint
                                       , args_ref.as_ptr()
                                       , cname as *const c_char ))
        }
    }

    pub fn build_cleanup_ret( &mut self
                            , cleanup_pad: Value
                            , unwind_blk: BasicBlock )
                            -> Value {
        unsafe {
            Value::from_ref(LLVMRustBuildCleanupRet( self.to_ref()
                                                   , cleanup_pad.to_ref()
                                                   , unwind_blk.to_ref() ))
        }
    }

    pub fn build_resume(&mut self, ex: Value) -> Value {
        unsafe { Value::from_ref(LLVMBuildResume(self.to_ref(), ex.to_ref())) }
    }

    pub fn build_unreachable(&mut self) -> Value {
        unsafe { Value::from_ref(LLVMBuildUnreachable(self.to_ref())) }
    }

}
<|endoftext|>