<commit_before>
use npffi;
use pyffi;
use cpython::*;
use npffi::types::npy_intp;
use super::{NPY_TYPES, NPY_ORDER};

pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npffi::PyArrayObject {
        self.0.as_ptr() as *mut npffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npffi::PyArrayObject {
        self.0.steal_ptr() as *mut npffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    pub fn ndim(&self) -> usize {
        let ptr = self.as_ptr();
        unsafe { (*ptr).nd as usize }
    }

    pub fn dims(&self) -> Vec<usize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).dimensions;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as usize).collect()
    }

    pub fn strides(&self) -> Vec<isize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as isize).collect()
    }

    pub fn zeros(py: Python, dims: &[usize], typenum: NPY_TYPES, order: NPY_ORDER) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = npffi::PyArray_DescrFromType(typenum as i32);
            let ptr = npffi::PyArray_Zeros(dims.len() as i32,
                                           dims.as_ptr() as *mut npy_intp,
                                           descr,
                                           order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<commit_msg>Add shape (synonym of dims)<commit_after>
use npffi;
use pyffi;
use cpython::*;
use npffi::types::npy_intp;
use super::{NPY_TYPES, NPY_ORDER};

pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npffi::PyArrayObject {
        self.0.as_ptr() as *mut npffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npffi::PyArrayObject {
        self.0.steal_ptr() as *mut npffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    pub fn ndim(&self) -> usize {
        let ptr = self.as_ptr();
        unsafe { (*ptr).nd as usize }
    }

    pub fn dims(&self) -> Vec<usize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).dimensions;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as usize).collect()
    }

    pub fn shape(&self) -> Vec<usize> {
        self.dims()
    }

    pub fn strides(&self) -> Vec<isize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as isize).collect()
    }

    pub fn zeros(py: Python, dims: &[usize], typenum: NPY_TYPES, order: NPY_ORDER) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = npffi::PyArray_DescrFromType(typenum as i32);
            let ptr = npffi::PyArray_Zeros(dims.len() as i32,
                                           dims.as_ptr() as *mut npy_intp,
                                           descr,
                                           order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::UnscopedState;
use core::position::*;

type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
                            -> ParseResult<T, I>;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b LanguageEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl<'a, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition> {

}

fn def<'a, I>(env: &LanguageEnv<'a, I>,
              input: State<I>) -> ParseResult<ast::Form<'a, UnscopedState>, I>
where I: Stream<Item=char> {

    unimplemented!()
}

fn expr<'a, I>(env: &LanguageEnv<'a, I>, input: State<I>)
              -> ParseResult<ast::Expr<'a, UnscopedState>, I>
where I: Stream<Item=char> {
    // env.parens( choice([ form(
    //                     ])
    //           )
    //    .parse_state(input)
    unimplemented!()

}

pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Parser environment passing structs kinda work<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::UnscopedState;
use core::position::*;

type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
                            -> ParseResult<T, I>;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b LanguageEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

}

fn def<'a, I>(env: &LanguageEnv<'a, I>,
              input: State<I>) -> ParseResult<ast::Form<'a, UnscopedState>, I>
where I: Stream<Item=char> {

    unimplemented!()
}

fn expr<'a, I>(env: &LanguageEnv<'a, I>, input: State<I>)
              -> ParseResult<ast::Expr<'a, UnscopedState>, I>
where I: Stream<Item=char> {
    // env.parens( choice([ form(
    //                     ])
    //           )
    //    .parse_state(input)
    unimplemented!()

}

pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_type(&self, input: State<I>) -> ParseResult<types::Type, I> {
            let primitive =
                choice([ self.reserved("int")
                             .with(value(types::Primitive::Int))
                       , self.reserved("float")
                             .with(value(types::Primitive::Float))
                       , self.reserved("double")
                             .with(value(types::Primitive::Double))
                       , self.reserved("bool")
                             .with(value(types::Primitive::Bool))
                       ])
                       .map(|primitive| types::Type::Prim(primitive));

            choice([ primitive ])
                .parse_state(input)
        }

        fn parse_binding(&self, input: State<I>)
                        -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
            let pos = input.position.clone();
            self.parser(MnEnv::parse_name)
                .and(self.type_annotation())
                .and(self.expr())
                .map(|((name, typ), value)|
                    Annotated::new( Binding { name: name
                                            , typ: typ
                                            , value: Rc::new(value)
                                            }
                                   , Position::from(pos)
                               ))
                .parse_state(input)
        }

        fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

            let binding_form =
                self.reserved("let")
                    .with(many(self.parens(self.binding())))
                    .and(many(self.expr()))
                    .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                         , body: body });

            choice([ binding_form ])
                .map(Form::Let)
                .parse_state(input)
        }

        fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
            let position = input.position.clone();
            self.env.identifier::<'b>()
                .map(|name| Positional { pos: Position::from(position)
                                       , value: name })
                .parse_state(input)
        }

        fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            self.name()
                .and(many(self.expr()))
                .map(|(name, args)| Form::Call { fun: name, body: args })
                .parse_state(input)
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([ self.def()
                               , self.if_form()
                               , self.lambda()
                               , self.let_form()
                               , self.call()
                               ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_def)
        }

        fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_if)
        }

        fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_let)
        }

        fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_lambda)
        }

        fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_call)
        }

        fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
            self.parser(MnEnv::parse_name)
        }

        fn binding(&'b self)
                  -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
            self.parser(MnEnv::parse_binding)
        }

        fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
            self.parser(MnEnv::parse_type)
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      , "i8"                , "u8"
                      , "i16"               , "u16"
                      , "i32"               , "u32"         , "f32"
                      , "i64"               , "u64"         , "f64"
                      , "int"               , "uint"        , "float"
                      , "bool"                              , "double"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Add parsers for pointer types<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::types::*;
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_primitive_ty(&self, input: State<I>) -> ParseResult<Type, I> {
            choice([ self.reserved("int")
                         .with(value(Primitive::Int))
                   , self.reserved("float")
                         .with(value(Primitive::Float))
                   , self.reserved("double")
                         .with(value(Primitive::Double))
                   , self.reserved("bool")
                         .with(value(Primitive::Bool))
                   ])
                   .map(|primitive| Type::Prim(primitive))
                   .parse_state(input)
        }

        fn raw_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
            char('*').with(self.type_annotation())
                     .map(|t| Type::Ref(Reference::Raw(Rc::new(t))))
                     .parse_state(input)
        }

        fn unique_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
            char('@').with(self.type_annotation())
                     .map(|t| Type::Ref(Reference::Unique(Rc::new(t))))
                     .parse_state(input)
        }

        fn borrow_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
            char('&').with(self.type_annotation())
                     .map(|t| Type::Ref(Reference::Borrowed(Rc::new(t))))
                     .parse_state(input)
        }
        fn parse_type(&self, input: State<I>) -> ParseResult<Type, I> {
            choice([ self.parser(MnEnv::parse_primitive_ty)
                   , self.parser(MnEnv::raw_ptr_ty)
                   , self.parser(MnEnv::unique_ptr_ty)
                   , self.parser(MnEnv::borrow_ptr_ty)
                   ])
                .parse_state(input)
        }

        fn parse_binding(&self, input: State<I>)
                        -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
            let pos = input.position.clone();
            self.parser(MnEnv::parse_name)
                .and(self.type_annotation())
                .and(self.expr())
                .map(|((name, typ), value)|
                    Annotated::new( Binding { name: name
                                            , typ: typ
                                            , value: Rc::new(value)
                                            }
                                   , Position::from(pos)
                               ))
                .parse_state(input)
        }

        fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

            let binding_form =
                self.reserved("let")
                    .with(many(self.parens(self.binding())))
                    .and(many(self.expr()))
                    .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                         , body: body });

            choice([ binding_form ])
                .map(Form::Let)
                .parse_state(input)
        }

        fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
            let position = input.position.clone();
            self.env.identifier::<'b>()
                .map(|name| Positional { pos: Position::from(position)
                                       , value: name })
                .parse_state(input)
        }

        fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            self.name()
                .and(many(self.expr()))
                .map(|(name, args)| Form::Call { fun: name, body: args })
                .parse_state(input)
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([ self.def()
                               , self.if_form()
                               , self.lambda()
                               , self.let_form()
                               , self.call()
                               ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_def)
        }

        fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_if)
        }

        fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_let)
        }

        fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_lambda)
        }

        fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_call)
        }

        fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
            self.parser(MnEnv::parse_name)
        }

        fn binding(&'b self)
                  -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
            self.parser(MnEnv::parse_binding)
        }

        fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
            self.parser(MnEnv::parse_type)
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      , "i8"                , "u8"
                      , "i16"               , "u16"
                      , "i32"               , "u32"         , "f32"
                      , "i64"               , "u64"         , "f64"
                      , "int"               , "uint"        , "float"
                      , "bool"                              , "double"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>/// # Cartesian product of lists
///
/// Solution for the "cartesian product of two or more lists" entry in rosetta code
///

use std::collections::VecDeque;

/// Computes the cartesian product of two or more lists of clonable elements.
///
/// Uses a queue to iterate over the elements like a Breadth-First-Search
///
fn cartesian_product<T: Clone>(lists: &[&[T]]) -> Vec<Vec<T>> {
    // If there are no lists, jsut returns an empty list.
    if lists.is_empty() {
        return vec![];
    }
    // Fills the queue with the first list.
    let mut queue = lists[0]
        .iter()
        .map(|value| vec![value.clone()])
        .collect::<VecDeque<Vec<T>>>();

    let mut result = vec![];

    while let Some(next) = queue.pop_front() {

        // find the index of the next list to multiply with.
        let next_list = next.len();

        if lists.len() == next_list {
            // If there are no more lists to multiply with, save the result.
            result.push(next)
        } else {
            // Else add the products to the queue.
            for value_to_add in lists[next_list] {
                let mut nouv = next.clone();
                nouv.push(value_to_add.clone());
                queue.push_back(nouv);
            }
        }
    }
    result
}

fn main() {
    println!("\n{:?}", cartesian_product(&[&[1, 2], &[3, 4]]));
    println!("\n{:?}", cartesian_product(&[&[3, 4], &[1, 2]]));
    /*
        This will print :

        [[1, 3], [1, 4], [2, 3], [2, 4]]

        [[3, 1], [3, 2], [4, 1], [4, 2]]
    */

}

#[cfg(test)]
mod tests {
    use super::cartesian_product;
    #[test]
    fn basic_test() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[3, 4]]),
            vec![vec![1, 3], vec![1, 4], vec![2, 3], vec![2, 4]]
        );
    }

    #[test]
    fn empty_list() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[], &[3, 4]]),
            Vec::<Vec<i32>>::new()
        );
    }

    #[test]
    fn many_lists_different_length() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[4], &[3, 4, 7]]),
            vec![
                vec![1, 4, 3],
                vec![1, 4, 4],
                vec![1, 4, 7],
                vec![2, 4, 3],
                vec![2, 4, 4],
                vec![2, 4, 7],
            ]
        );
    }

    #[test]
    fn different_types() {
        assert_eq!(
            cartesian_product(&[&[true, false], &[true], &[false, true]]),
            vec![
                vec![true, true, false],
                vec![true, true, true],
                vec![false, true, false],
                vec![false, true, true],
            ]
        );
    }

    #[test]
    fn no_list() {
        assert_eq!(cartesian_product::<i32>(&[]), Vec::<Vec<i32>>::new());
    }
}
<commit_msg>Corrected typo<commit_after>/// # Cartesian product of lists
///
/// Solution for the "cartesian product of two or more lists" entry in rosetta code
///

use std::collections::VecDeque;

/// Computes the cartesian product of two or more lists of clonable elements.
///
/// Uses a queue to iterate over the elements (Breadth-First-Search).
///
fn cartesian_product<T: Clone>(lists: &[&[T]]) -> Vec<Vec<T>> {
    // If there are no lists, just returns an empty list.
    if lists.is_empty() {
        return vec![];
    }
    // Fills the queue with the first list.
    let mut queue = lists[0]
        .iter()
        .map(|value| vec![value.clone()])
        .collect::<VecDeque<Vec<T>>>();

    let mut result = vec![];

    while let Some(next) = queue.pop_front() {

        // find the index of the next list to multiply with.
        let next_list = next.len();

        if lists.len() == next_list {
            // If there are no more lists to multiply with, save the result.
            result.push(next)
        } else {
            // Else add the products to the queue.
            for value_to_add in lists[next_list] {
                let mut nouv = next.clone();
                nouv.push(value_to_add.clone());
                queue.push_back(nouv);
            }
        }
    }
    result
}

fn main() {
    println!("\n{:?}", cartesian_product(&[&[1, 2], &[3, 4]]));
    println!("\n{:?}", cartesian_product(&[&[3, 4], &[1, 2]]));
    /*
        This will print :

        [[1, 3], [1, 4], [2, 3], [2, 4]]

        [[3, 1], [3, 2], [4, 1], [4, 2]]
    */

}

#[cfg(test)]
mod tests {
    use super::cartesian_product;
    #[test]
    fn basic_test() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[3, 4]]),
            vec![vec![1, 3], vec![1, 4], vec![2, 3], vec![2, 4]]
        );
    }

    #[test]
    fn empty_list() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[], &[3, 4]]),
            Vec::<Vec<i32>>::new()
        );
    }

    #[test]
    fn many_lists_different_length() {
        assert_eq!(
            cartesian_product(&[&[1, 2], &[4], &[3, 4, 7]]),
            vec![
                vec![1, 4, 3],
                vec![1, 4, 4],
                vec![1, 4, 7],
                vec![2, 4, 3],
                vec![2, 4, 4],
                vec![2, 4, 7],
            ]
        );
    }

    #[test]
    fn different_types() {
        assert_eq!(
            cartesian_product(&[&[true, false], &[true], &[false, true]]),
            vec![
                vec![true, true, false],
                vec![true, true, true],
                vec![false, true, false],
                vec![false, true, true],
            ]
        );
    }

    #[test]
    fn no_list() {
        assert_eq!(cartesian_product::<i32>(&[]), Vec::<Vec<i32>>::new());
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]
#![feature(const_fn)]
#![feature(i128_type)]

extern crate syntax;
extern crate rustc_plugin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate owning_ref;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::codemap::{Span, Spanned};
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::parser::Parser;
use syntax::parse::PResult;
use syntax::symbol::Symbol;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
use syntax::ptr::P;

use std::sync::{RwLock, RwLockReadGuard, Mutex};
use std::collections::HashMap;

use owning_ref::{OwningRef, RwLockReadGuardRef};

pub mod arch;
mod directive;
mod serialize;

/// Welcome to the documentation of the dynasm plugin. This mostly exists to ease
/// development and to show a glimpse of what is under the hood of dynasm. Please
/// be aware that nothing in here should be counted on to be stable, the only
/// guarantees are in the syntax the `dynasm!` macro parses and in the code it
/// generates.

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        Symbol::intern("dynasm"),
        SyntaxExtension::NormalTT(
            Box::new(dynasm),
            None,
            false
        )
    );

    #[cfg(feature = "dynasm_opmap")]
    reg.register_syntax_extension(
        Symbol::intern("dynasm_opmap"),
        SyntaxExtension::NormalTT(
            Box::new(dynasm_opmap),
            None,
            false
        )
    );
}

/// dynasm! macro expansion result type
struct DynAsm<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    stmts: Vec<ast::Stmt>
}

impl<'cx, 'a> MacResult for DynAsm<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_block(self.ecx.block(self.ecx.call_site(), self.stmts)))
    }

    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(SmallVector::many(self.stmts))
    }

    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
        if self.stmts.is_empty() {
            Some(SmallVector::new())
        } else {
            None
        }
    }
}

/// The guts of the dynasm! macro start here.
fn dynasm<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm (whenever this actually gets implemented within rustc)
    let token_tree = ecx.expander().fold_tts(token_tree);

    let mut parser = ecx.new_parser_from_tts(&token_tree);

    // due to the structure of directives / assembly, we have to evaluate while parsing as
    // things like aliases, arch choices, affect the way in which parsing works.

    match compile(ecx, &mut parser) {
        Ok(stmts) => Box::new(DynAsm {
            ecx: ecx,
            stmts: stmts
        }),
        Err(mut e) => {
            e.emit();
            DummyResult::any(span)
        }
    }
}

// this is a macro internal to dynasm's documentation
#[cfg(feature = "dynasm_opmap")]
struct DynAsmDoc<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    data: String
}

#[cfg(feature = "dynasm_opmap")]
impl<'cx, 'a> MacResult for DynAsmDoc<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_str(self.ecx.call_site(), Symbol::intern(&self.data)))
    }
}

#[cfg(feature = "dynasm_opmap")]
fn dynasm_opmap<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    if token_tree.len() > 0 {
        ecx.span_err(span, "dynasm_opmap does not take any arguments");
    }

    let mut s = String::new();
    s.push_str("% Instruction Reference\n\n");

    let mut mnemnonics: Vec<_> = arch::x64::x64data::mnemnonics().cloned().collect();
    mnemnonics.sort();
    for mnemnonic in mnemnonics {
        // get the data for this mnemnonic
        let data = arch::x64::x64data::get_mnemnonic_data(mnemnonic).unwrap();
        // format the data for the opmap docs
        let mut formats = data.into_iter()
                              .map(|x| arch::x64::debug::format_opdata(mnemnonic, x))
                              .flat_map(|x| x)
                              .map(|x| x.replace(">>> ", ""))
                              .collect::<Vec<_>>();
        formats.sort();

        // push mnemnonic name as title
        s.push_str("### ");
        s.push_str(mnemnonic);
        s.push_str("\n```\n");

        // push the formats
        s.push_str(&formats.join("\n"));
        s.push_str("\n```\n");
    }

    Box::new(DynAsmDoc {
        ecx: ecx,
        data: s
    })
}

/// This struct contains all non-parsing state that dynasm! requires while parsing and compiling
pub struct State<'a> {
    pub stmts: &'a mut Vec<serialize::Stmt>,
    pub target: &'a P<ast::Expr>,
    pub crate_data: &'a DynasmData
}

/// top-level parsing. Handles common prefix symbols and diverts to the selected architecture
/// when an assembly instruction is encountered. When parsing fails an Err() is returned, when
/// non-parsing errors happen a local error message is generated but the function returns Ok().
fn compile<'a>(ecx: &mut ExtCtxt, parser: &mut Parser<'a>) -> PResult<'a, Vec<ast::Stmt>> {
    let target = parser.parse_expr()?;

    let crate_data = crate_local_data(ecx);
    let mut crate_data = crate_data.lock().unwrap();

    let mut stmts = Vec::new();

    while !parser.check(&token::Eof) {
        parser.expect(&token::Semi)?;

        // ;; stmt
        if parser.eat(&token::Semi) {
            if let Some(stmt) = parser.parse_stmt()? {
                stmts.push(serialize::Stmt::Stmt(stmt));
            }
            continue;
        }

        // ; . directive
        if parser.eat(&token::Dot) {
            crate_data.evaluate_directive(&mut stmts, ecx, parser)?;
            continue;
        }

        // ; -> label :
        if parser.eat(&token::RArrow) {
            let span = parser.span;
            let name = parser.parse_ident()?;
            parser.expect(&token::Colon)?;
            stmts.push(serialize::Stmt::GlobalLabel(Spanned {span: span, node: name} ));
            continue;
        }

        // ; => expr
        if parser.eat(&token::FatArrow) {
            let expr = parser.parse_expr()?;
            stmts.push(serialize::Stmt::DynamicLabel(expr));
            continue;
        }

        // ; label :
        if parser.token.is_ident() && parser.look_ahead(1, |t| t == &token::Colon) {
            let span = parser.span;
            let name = parser.parse_ident()?;
            parser.expect(&token::Colon)?;
            stmts.push(serialize::Stmt::LocalLabel(Spanned {span: span, node: name} ));
            continue;
        }

        // anything else is an assembly instruction which should be in current_arch
        let mut state = State {
            stmts: &mut stmts,
            target: &target,
            crate_data: &*crate_data
        };
        crate_data.current_arch.compile_instruction(&mut state, ecx, parser)?;
    }

    Ok(serialize::serialize(ecx, target, stmts))
}

// Crate local data implementation.

type DynasmStorage = HashMap<String, Mutex<DynasmData>>;

pub struct DynasmData {
    pub current_arch: Box<arch::Arch>,
    pub aliases: HashMap<String, String>
}

impl DynasmData {
    fn new() -> DynasmData {
        DynasmData {
            current_arch: arch::from_str(arch::CURRENT_ARCH).expect("Default architecture is invalid"),
            aliases: HashMap::new()
        }
    }
}

pub type CrateLocalData = OwningRef<
    RwLockReadGuard<'static, DynasmStorage>,
    Mutex<DynasmData>
>;

pub fn crate_local_data(ecx: &ExtCtxt) -> CrateLocalData {
    let id = &ecx.ecfg.crate_name;

    {
        let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

        if data.get(id).is_some() {
            return data.map(|x| x.get(id).unwrap())
        }
    }

    {
        let mut lock = DYNASM_STORAGE.write().unwrap();
        lock.insert(id.clone(), Mutex::new(DynasmData::new()));
    }
    RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap())
                       .map(|x| x.get(id).unwrap())
}

// this is where the actual storage resides.

lazy_static! {
    static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
}
<commit_msg>fixed build error with last syntax crate.<commit_after>#![feature(plugin_registrar, rustc_private)]
#![feature(const_fn)]
#![feature(i128_type)]

extern crate syntax;
extern crate rustc_plugin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate owning_ref;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::codemap::{Span, Spanned};
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::parser::Parser;
use syntax::parse::PResult;
use syntax::symbol::Symbol;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
use syntax::ptr::P;

use std::sync::{RwLock, RwLockReadGuard, Mutex};
use std::collections::HashMap;

use owning_ref::{OwningRef, RwLockReadGuardRef};

pub mod arch;
mod directive;
mod serialize;

/// Welcome to the documentation of the dynasm plugin. This mostly exists to ease
/// development and to show a glimpse of what is under the hood of dynasm. Please
/// be aware that nothing in here should be counted on to be stable, the only
/// guarantees are in the syntax the `dynasm!` macro parses and in the code it
/// generates.
#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(Symbol::intern("dynasm"),
                                  SyntaxExtension::NormalTT(Box::new(dynasm), None, false));

    #[cfg(feature = "dynasm_opmap")]
    reg.register_syntax_extension(Symbol::intern("dynasm_opmap"),
                                  SyntaxExtension::NormalTT(Box::new(dynasm_opmap), None, false));
}

/// dynasm! macro expansion result type
struct DynAsm<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    stmts: Vec<ast::Stmt>,
}

impl<'cx, 'a> MacResult for DynAsm<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_block(self.ecx.block(self.ecx.call_site(), self.stmts)))
    }

    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(SmallVector::many(self.stmts))
    }

    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
        if self.stmts.is_empty() {
            Some(SmallVector::new())
        } else {
            None
        }
    }
}

/// The guts of the dynasm! macro start here.
fn dynasm<'cx>(ecx: &'cx mut ExtCtxt,
               span: Span,
               token_tree: &[TokenTree])
               -> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm (whenever this actually gets implemented within rustc)
    let mut parser = ecx.new_parser_from_tts(token_tree);

    // due to the structure of directives / assembly, we have to evaluate while parsing as
    // things like aliases, arch choices, affect the way in which parsing works.

    match compile(ecx, &mut parser) {
        Ok(stmts) => {
            Box::new(DynAsm {
                         ecx: ecx,
                         stmts: stmts,
                     })
        }
        Err(mut e) => {
            e.emit();
            DummyResult::any(span)
        }
    }
}

// this is a macro internal to dynasm's documentation
#[cfg(feature = "dynasm_opmap")]
struct DynAsmDoc<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    data: String,
}

#[cfg(feature = "dynasm_opmap")]
impl<'cx, 'a> MacResult for DynAsmDoc<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_str(self.ecx.call_site(), Symbol::intern(&self.data)))
    }
}

#[cfg(feature = "dynasm_opmap")]
fn dynasm_opmap<'cx>(ecx: &'cx mut ExtCtxt,
                     span: Span,
                     token_tree: &[TokenTree])
                     -> Box<MacResult + 'cx> {
    if token_tree.len() > 0 {
        ecx.span_err(span, "dynasm_opmap does not take any arguments");
    }

    let mut s = String::new();
    s.push_str("% Instruction Reference\n\n");

    let mut mnemnonics: Vec<_> = arch::x64::x64data::mnemnonics().cloned().collect();
    mnemnonics.sort();
    for mnemnonic in mnemnonics {
        // get the data for this mnemnonic
        let data = arch::x64::x64data::get_mnemnonic_data(mnemnonic).unwrap();
        // format the data for the opmap docs
        let mut formats = data.into_iter()
            .map(|x| arch::x64::debug::format_opdata(mnemnonic, x))
            .flat_map(|x| x)
            .map(|x| x.replace(">>> ", ""))
            .collect::<Vec<_>>();
        formats.sort();

        // push mnemnonic name as title
        s.push_str("### ");
        s.push_str(mnemnonic);
        s.push_str("\n```\n");

        // push the formats
        s.push_str(&formats.join("\n"));
        s.push_str("\n```\n");
    }

    Box::new(DynAsmDoc {
                 ecx: ecx,
                 data: s,
             })
}

/// This struct contains all non-parsing state that dynasm! requires while parsing and compiling
pub struct State<'a> {
    pub stmts: &'a mut Vec<serialize::Stmt>,
    pub target: &'a P<ast::Expr>,
    pub crate_data: &'a DynasmData,
}

/// top-level parsing. Handles common prefix symbols and diverts to the selected architecture
/// when an assembly instruction is encountered. When parsing fails an Err() is returned, when
/// non-parsing errors happen a local error message is generated but the function returns Ok().
fn compile<'a>(ecx: &mut ExtCtxt, parser: &mut Parser<'a>) -> PResult<'a, Vec<ast::Stmt>> {
    let target = parser.parse_expr()?;

    let crate_data = crate_local_data(ecx);
    let mut crate_data = crate_data.lock().unwrap();

    let mut stmts = Vec::new();

    while !parser.check(&token::Eof) {
        parser.expect(&token::Semi)?;

        // ;; stmt
        if parser.eat(&token::Semi) {
            if let Some(stmt) = parser.parse_stmt()? {
                stmts.push(serialize::Stmt::Stmt(stmt));
            }
            continue;
        }

        // ; . directive
        if parser.eat(&token::Dot) {
            crate_data.evaluate_directive(&mut stmts, ecx, parser)?;
            continue;
        }

        // ; -> label :
        if parser.eat(&token::RArrow) {
            let span = parser.span;
            let name = parser.parse_ident()?;
            parser.expect(&token::Colon)?;
            stmts.push(serialize::Stmt::GlobalLabel(Spanned {
                                                        span: span,
                                                        node: name,
                                                    }));
            continue;
        }

        // ; => expr
        if parser.eat(&token::FatArrow) {
            let expr = parser.parse_expr()?;
            stmts.push(serialize::Stmt::DynamicLabel(expr));
            continue;
        }

        // ; label :
        if parser.token.is_ident() && parser.look_ahead(1, |t| t == &token::Colon) {
            let span = parser.span;
            let name = parser.parse_ident()?;
            parser.expect(&token::Colon)?;
            stmts.push(serialize::Stmt::LocalLabel(Spanned {
                                                       span: span,
                                                       node: name,
                                                   }));
            continue;
        }

        // anything else is an assembly instruction which should be in current_arch
        let mut state = State {
            stmts: &mut stmts,
            target: &target,
            crate_data: &*crate_data,
        };
        crate_data.current_arch.compile_instruction(&mut state, ecx, parser)?;
    }

    Ok(serialize::serialize(ecx, target, stmts))
}

// Crate local data implementation.

type DynasmStorage = HashMap<String, Mutex<DynasmData>>;

pub struct DynasmData {
    pub current_arch: Box<arch::Arch>,
    pub aliases: HashMap<String, String>,
}

impl DynasmData {
    fn new() -> DynasmData {
        DynasmData {
            current_arch:
                arch::from_str(arch::CURRENT_ARCH).expect("Default architecture is invalid"),
            aliases: HashMap::new(),
        }
    }
}

pub type CrateLocalData = OwningRef<RwLockReadGuard<'static, DynasmStorage>, Mutex<DynasmData>>;

pub fn crate_local_data(ecx: &ExtCtxt) -> CrateLocalData {
    let id = &ecx.ecfg.crate_name;

    {
        let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

        if data.get(id).is_some() {
            return data.map(|x| x.get(id).unwrap());
        }
    }

    {
        let mut lock = DYNASM_STORAGE.write().unwrap();
        lock.insert(id.clone(), Mutex::new(DynasmData::new()));
    }
    RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap()).map(|x| x.get(id).unwrap())
}

// this is where the actual storage resides.

lazy_static! {
    static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
}
<|endoftext|>


<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/. */

//! Conversions of Rust values to and from `JSVal`.
//!
//! | IDL type                | Argument type   | Return type    |
//! |-------------------------|-----------------|----------------|
//! | any                     | `JSVal`                          |
//! | boolean                 | `bool`                           |
//! | byte                    | `i8`                             |
//! | octet                   | `u8`                             |
//! | short                   | `i16`                            |
//! | unsigned short          | `u16`                            |
//! | long                    | `i32`                            |
//! | unsigned long           | `u32`                            |
//! | long long               | `i64`                            |
//! | unsigned long long      | `u64`                            |
//! | unrestricted float      | `f32`                            |
//! | float                   | `Finite<f32>`                    |
//! | unrestricted double     | `f64`                            |
//! | double                  | `Finite<f64>`                    |
//! | DOMString               | `DOMString`                      |
//! | USVString               | `USVString`                      |
//! | ByteString              | `ByteString`                     |
//! | object                  | `*mut JSObject`                  |
//! | interface types         | `&T`            | `Root<T>`      |
//! | dictionary types        | `&T`            | *unsupported*  |
//! | enumeration types       | `T`                              |
//! | callback function types | `Rc<T>`                          |
//! | nullable types          | `Option<T>`                      |
//! | sequences               | `Vec<T>`                         |
//! | union types             | `T`                              |

use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::str::{ByteString, USVString};
use dom::bindings::utils::DOMClass;
use js;
pub use js::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionBehavior};
use js::error::throw_type_error;
use js::glue::{GetProxyPrivate, IsWrapper};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
use js::jsapi::{HandleId, HandleObject, HandleValue, JS_GetClass};
use js::jsapi::{JSClass, JSContext, JSObject, MutableHandleValue};
use js::jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetReservedSlot};
use js::jsapi::{JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN};
use js::jsapi::{JS_StringHasLatin1Chars, JS_WrapValue};
use js::jsval::{ObjectValue, StringValue};
use js::rust::ToString;
use libc;
use num::Float;
use std::{ptr, slice};
use util::str::DOMString;
pub use util::str::{StringificationBehavior, jsstring_to_str};

trait As<O>: Copy {
    fn cast(self) -> O;
}

macro_rules! impl_as {
    ($I:ty, $O:ty) => (
        impl As<$O> for $I {
            fn cast(self) -> $O {
                self as $O
            }
        }
    )
}

impl_as!(f64, u8);
impl_as!(f64, u16);
impl_as!(f64, u32);
impl_as!(f64, u64);
impl_as!(f64, i8);
impl_as!(f64, i16);
impl_as!(f64, i32);
impl_as!(f64, i64);

impl_as!(u8, f64);
impl_as!(u16, f64);
impl_as!(u32, f64);
impl_as!(u64, f64);
impl_as!(i8, f64);
impl_as!(i16, f64);
impl_as!(i32, f64);
impl_as!(i64, f64);

impl_as!(i32, i8);
impl_as!(i32, u8);
impl_as!(i32, i16);
impl_as!(u16, u16);
impl_as!(i32, i32);
impl_as!(u32, u32);
impl_as!(i64, i64);
impl_as!(u64, u64);

/// A trait to check whether a given `JSObject` implements an IDL interface.
pub trait IDLInterface {
    /// Returns whether the given DOM class derives that interface.
    fn derives(&'static DOMClass) -> bool;
}

/// A trait to mark an IDL interface as deriving from another one.
#[rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`."]
pub trait DerivedFrom<T: Castable>: Castable {}

impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
    #[inline]
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let value = **self;
        value.to_jsval(cx, rval);
    }
}

impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite<T> {
    type Config = ();

    unsafe fn from_jsval(cx: *mut JSContext,
                         value: HandleValue,
                         option: ())
                         -> Result<Finite<T>, ()> {
        let result = try!(FromJSValConvertible::from_jsval(cx, value, option));
        match Finite::new(result) {
            Some(v) => Ok(v),
            None => {
                throw_type_error(cx, "this argument is not a finite floating-point value");
                Err(())
            },
        }
    }
}

/// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a
/// string, or if the string does not contain valid UTF-16.
pub fn jsid_to_str(cx: *mut JSContext, id: HandleId) -> DOMString {
    unsafe {
        assert!(RUST_JSID_IS_STRING(id));
        jsstring_to_str(cx, RUST_JSID_TO_STRING(id))
    }
}

// http://heycam.github.io/webidl/#es-USVString
impl ToJSValConvertible for USVString {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        self.0.to_jsval(cx, rval);
    }
}

// http://heycam.github.io/webidl/#es-USVString
impl FromJSValConvertible for USVString {
    type Config = ();
    unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result<USVString, ()> {
        let jsstr = ToString(cx, value);
        if jsstr.is_null() {
            debug!("ToString failed");
            return Err(());
        }
        let latin1 = JS_StringHasLatin1Chars(jsstr);
        if latin1 {
            // FIXME(ajeffrey): Convert directly from DOMString to USVString
            return Ok(USVString(String::from(jsstring_to_str(cx, jsstr))));
        }
        let mut length = 0;
        let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
        assert!(!chars.is_null());
        let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
        Ok(USVString(String::from_utf16_lossy(char_vec)))
    }
}

// http://heycam.github.io/webidl/#es-ByteString
impl ToJSValConvertible for ByteString {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let jsstr = JS_NewStringCopyN(cx,
                                      self.as_ptr() as *const libc::c_char,
                                      self.len() as libc::size_t);
        if jsstr.is_null() {
            panic!("JS_NewStringCopyN failed");
        }
        rval.set(StringValue(&*jsstr));
    }
}

// http://heycam.github.io/webidl/#es-ByteString
impl FromJSValConvertible for ByteString {
    type Config = ();
    unsafe fn from_jsval(cx: *mut JSContext,
                         value: HandleValue,
                         _option: ())
                         -> Result<ByteString, ()> {
        let string = ToString(cx, value);
        if string.is_null() {
            debug!("ToString failed");
            return Err(());
        }

        let latin1 = JS_StringHasLatin1Chars(string);
        if latin1 {
            let mut length = 0;
            let chars = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
            assert!(!chars.is_null());

            let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize);
            return Ok(ByteString::new(char_slice.to_vec()));
        }

        let mut length = 0;
        let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), string, &mut length);
        let char_vec = slice::from_raw_parts(chars, length as usize);

        if char_vec.iter().any(|&c| c > 0xFF) {
            throw_type_error(cx, "Invalid ByteString");
            Err(())
        } else {
            Ok(ByteString::new(char_vec.iter().map(|&c| c as u8).collect()))
        }
    }
}

impl ToJSValConvertible for Reflector {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let obj = self.get_jsobject().get();
        assert!(!obj.is_null());
        rval.set(ObjectValue(&*obj));
        if !JS_WrapValue(cx, rval) {
            panic!("JS_WrapValue failed.");
        }
    }
}

/// Returns whether the given `clasp` is one for a DOM object.
pub fn is_dom_class(clasp: *const JSClass) -> bool {
    unsafe {
        ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0
    }
}

/// Returns whether `obj` is a DOM object implemented as a proxy.
pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
    use js::glue::IsProxyHandlerFamily;
    unsafe {
        let clasp = JS_GetClass(obj);
        ((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj) != 0
    }
}

/// The index of the slot wherein a pointer to the reflected DOM object is
/// stored for non-proxy bindings.
// We use slot 0 for holding the raw object.  This is safe for both
// globals and non-globals.
pub const DOM_OBJECT_SLOT: u32 = 0;

/// Get the private pointer of a DOM object from a given reflector.
pub unsafe fn private_from_object(obj: *mut JSObject) -> *const libc::c_void {
    let clasp = JS_GetClass(obj);
    let value = if is_dom_class(clasp) {
        JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
    } else {
        debug_assert!(is_dom_proxy(obj));
        GetProxyPrivate(obj)
    };
    if value.is_undefined() {
        ptr::null()
    } else {
        value.to_private()
    }
}

/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()> {
    use dom::bindings::utils::DOMJSClass;
    use js::glue::GetProxyHandlerExtra;

    let clasp = JS_GetClass(obj);
    if is_dom_class(&*clasp) {
        debug!("plain old dom object");
        let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass;
        return Ok(&(&*domjsclass).dom_class);
    }
    if is_dom_proxy(obj) {
        debug!("proxy dom object");
        let dom_class: *const DOMClass = GetProxyHandlerExtra(obj) as *const DOMClass;
        return Ok(&*dom_class);
    }
    debug!("not a dom object");
    Err(())
}

/// Get a `*const libc::c_void` for the given DOM object, unwrapping any
/// wrapper around it first, and checking if the object is of the correct type.
///
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
/// not an object for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
#[inline]
pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
                                          proto_check: F)
                                          -> Result<*const libc::c_void, ()>
    where F: Fn(&'static DOMClass) -> bool
{
    let dom_class = try!(get_dom_class(obj).or_else(|_| {
        if IsWrapper(obj) {
            debug!("found wrapper");
            obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
            if obj.is_null() {
                debug!("unwrapping security wrapper failed");
                Err(())
            } else {
                assert!(!IsWrapper(obj));
                debug!("unwrapped successfully");
                get_dom_class(obj)
            }
        } else {
            debug!("not a dom wrapper");
            Err(())
        }
    }));

    if proto_check(dom_class) {
        debug!("good prototype");
        Ok(private_from_object(obj))
    } else {
        debug!("bad prototype");
        Err(())
    }
}

/// Get a `*const T` for a DOM object accessible from a `JSObject`.
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
    where T: Reflectable + IDLInterface
{
    unsafe {
        private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T)
    }
}

/// Get a `Root<T>` for the given DOM object, unwrapping any wrapper
/// around it first, and checking if the object is of the correct type.
///
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
/// not a reflector for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
pub fn root_from_object<T>(obj: *mut JSObject) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    native_from_object(obj).map(|ptr| unsafe { Root::from_ref(&*ptr) })
}

/// Get a `*const T` for a DOM object accessible from a `HandleValue`.
pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
    where T: Reflectable + IDLInterface
{
    native_from_object(v.get().to_object())
}

/// Get a `Root<T>` for a DOM object accessible from a `HandleValue`.
pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    root_from_object(v.get().to_object())
}

/// Get a `Root<T>` for a DOM object accessible from a `HandleObject`.
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    root_from_object(obj.get())
}

impl<T: Reflectable> ToJSValConvertible for Root<T> {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        self.reflector().to_jsval(cx, rval);
    }
}
<commit_msg>Auto merge of #8617 - Ms2ger:unused-as, r=jdm<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/. */

//! Conversions of Rust values to and from `JSVal`.
//!
//! | IDL type                | Argument type   | Return type    |
//! |-------------------------|-----------------|----------------|
//! | any                     | `JSVal`                          |
//! | boolean                 | `bool`                           |
//! | byte                    | `i8`                             |
//! | octet                   | `u8`                             |
//! | short                   | `i16`                            |
//! | unsigned short          | `u16`                            |
//! | long                    | `i32`                            |
//! | unsigned long           | `u32`                            |
//! | long long               | `i64`                            |
//! | unsigned long long      | `u64`                            |
//! | unrestricted float      | `f32`                            |
//! | float                   | `Finite<f32>`                    |
//! | unrestricted double     | `f64`                            |
//! | double                  | `Finite<f64>`                    |
//! | DOMString               | `DOMString`                      |
//! | USVString               | `USVString`                      |
//! | ByteString              | `ByteString`                     |
//! | object                  | `*mut JSObject`                  |
//! | interface types         | `&T`            | `Root<T>`      |
//! | dictionary types        | `&T`            | *unsupported*  |
//! | enumeration types       | `T`                              |
//! | callback function types | `Rc<T>`                          |
//! | nullable types          | `Option<T>`                      |
//! | sequences               | `Vec<T>`                         |
//! | union types             | `T`                              |

use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::str::{ByteString, USVString};
use dom::bindings::utils::DOMClass;
use js;
pub use js::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionBehavior};
use js::error::throw_type_error;
use js::glue::{GetProxyPrivate, IsWrapper};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
use js::jsapi::{HandleId, HandleObject, HandleValue, JS_GetClass};
use js::jsapi::{JSClass, JSContext, JSObject, MutableHandleValue};
use js::jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetReservedSlot};
use js::jsapi::{JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN};
use js::jsapi::{JS_StringHasLatin1Chars, JS_WrapValue};
use js::jsval::{ObjectValue, StringValue};
use js::rust::ToString;
use libc;
use num::Float;
use std::{ptr, slice};
use util::str::DOMString;
pub use util::str::{StringificationBehavior, jsstring_to_str};

/// A trait to check whether a given `JSObject` implements an IDL interface.
pub trait IDLInterface {
    /// Returns whether the given DOM class derives that interface.
    fn derives(&'static DOMClass) -> bool;
}

/// A trait to mark an IDL interface as deriving from another one.
#[rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`."]
pub trait DerivedFrom<T: Castable>: Castable {}

impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
    #[inline]
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let value = **self;
        value.to_jsval(cx, rval);
    }
}

impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite<T> {
    type Config = ();

    unsafe fn from_jsval(cx: *mut JSContext,
                         value: HandleValue,
                         option: ())
                         -> Result<Finite<T>, ()> {
        let result = try!(FromJSValConvertible::from_jsval(cx, value, option));
        match Finite::new(result) {
            Some(v) => Ok(v),
            None => {
                throw_type_error(cx, "this argument is not a finite floating-point value");
                Err(())
            },
        }
    }
}

/// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a
/// string, or if the string does not contain valid UTF-16.
pub fn jsid_to_str(cx: *mut JSContext, id: HandleId) -> DOMString {
    unsafe {
        assert!(RUST_JSID_IS_STRING(id));
        jsstring_to_str(cx, RUST_JSID_TO_STRING(id))
    }
}

// http://heycam.github.io/webidl/#es-USVString
impl ToJSValConvertible for USVString {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        self.0.to_jsval(cx, rval);
    }
}

// http://heycam.github.io/webidl/#es-USVString
impl FromJSValConvertible for USVString {
    type Config = ();
    unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result<USVString, ()> {
        let jsstr = ToString(cx, value);
        if jsstr.is_null() {
            debug!("ToString failed");
            return Err(());
        }
        let latin1 = JS_StringHasLatin1Chars(jsstr);
        if latin1 {
            // FIXME(ajeffrey): Convert directly from DOMString to USVString
            return Ok(USVString(String::from(jsstring_to_str(cx, jsstr))));
        }
        let mut length = 0;
        let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
        assert!(!chars.is_null());
        let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
        Ok(USVString(String::from_utf16_lossy(char_vec)))
    }
}

// http://heycam.github.io/webidl/#es-ByteString
impl ToJSValConvertible for ByteString {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let jsstr = JS_NewStringCopyN(cx,
                                      self.as_ptr() as *const libc::c_char,
                                      self.len() as libc::size_t);
        if jsstr.is_null() {
            panic!("JS_NewStringCopyN failed");
        }
        rval.set(StringValue(&*jsstr));
    }
}

// http://heycam.github.io/webidl/#es-ByteString
impl FromJSValConvertible for ByteString {
    type Config = ();
    unsafe fn from_jsval(cx: *mut JSContext,
                         value: HandleValue,
                         _option: ())
                         -> Result<ByteString, ()> {
        let string = ToString(cx, value);
        if string.is_null() {
            debug!("ToString failed");
            return Err(());
        }

        let latin1 = JS_StringHasLatin1Chars(string);
        if latin1 {
            let mut length = 0;
            let chars = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
            assert!(!chars.is_null());

            let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize);
            return Ok(ByteString::new(char_slice.to_vec()));
        }

        let mut length = 0;
        let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), string, &mut length);
        let char_vec = slice::from_raw_parts(chars, length as usize);

        if char_vec.iter().any(|&c| c > 0xFF) {
            throw_type_error(cx, "Invalid ByteString");
            Err(())
        } else {
            Ok(ByteString::new(char_vec.iter().map(|&c| c as u8).collect()))
        }
    }
}

impl ToJSValConvertible for Reflector {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        let obj = self.get_jsobject().get();
        assert!(!obj.is_null());
        rval.set(ObjectValue(&*obj));
        if !JS_WrapValue(cx, rval) {
            panic!("JS_WrapValue failed.");
        }
    }
}

/// Returns whether the given `clasp` is one for a DOM object.
pub fn is_dom_class(clasp: *const JSClass) -> bool {
    unsafe {
        ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0
    }
}

/// Returns whether `obj` is a DOM object implemented as a proxy.
pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
    use js::glue::IsProxyHandlerFamily;
    unsafe {
        let clasp = JS_GetClass(obj);
        ((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj) != 0
    }
}

/// The index of the slot wherein a pointer to the reflected DOM object is
/// stored for non-proxy bindings.
// We use slot 0 for holding the raw object.  This is safe for both
// globals and non-globals.
pub const DOM_OBJECT_SLOT: u32 = 0;

/// Get the private pointer of a DOM object from a given reflector.
pub unsafe fn private_from_object(obj: *mut JSObject) -> *const libc::c_void {
    let clasp = JS_GetClass(obj);
    let value = if is_dom_class(clasp) {
        JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
    } else {
        debug_assert!(is_dom_proxy(obj));
        GetProxyPrivate(obj)
    };
    if value.is_undefined() {
        ptr::null()
    } else {
        value.to_private()
    }
}

/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()> {
    use dom::bindings::utils::DOMJSClass;
    use js::glue::GetProxyHandlerExtra;

    let clasp = JS_GetClass(obj);
    if is_dom_class(&*clasp) {
        debug!("plain old dom object");
        let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass;
        return Ok(&(&*domjsclass).dom_class);
    }
    if is_dom_proxy(obj) {
        debug!("proxy dom object");
        let dom_class: *const DOMClass = GetProxyHandlerExtra(obj) as *const DOMClass;
        return Ok(&*dom_class);
    }
    debug!("not a dom object");
    Err(())
}

/// Get a `*const libc::c_void` for the given DOM object, unwrapping any
/// wrapper around it first, and checking if the object is of the correct type.
///
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
/// not an object for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
#[inline]
pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
                                          proto_check: F)
                                          -> Result<*const libc::c_void, ()>
    where F: Fn(&'static DOMClass) -> bool
{
    let dom_class = try!(get_dom_class(obj).or_else(|_| {
        if IsWrapper(obj) {
            debug!("found wrapper");
            obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
            if obj.is_null() {
                debug!("unwrapping security wrapper failed");
                Err(())
            } else {
                assert!(!IsWrapper(obj));
                debug!("unwrapped successfully");
                get_dom_class(obj)
            }
        } else {
            debug!("not a dom wrapper");
            Err(())
        }
    }));

    if proto_check(dom_class) {
        debug!("good prototype");
        Ok(private_from_object(obj))
    } else {
        debug!("bad prototype");
        Err(())
    }
}

/// Get a `*const T` for a DOM object accessible from a `JSObject`.
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
    where T: Reflectable + IDLInterface
{
    unsafe {
        private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T)
    }
}

/// Get a `Root<T>` for the given DOM object, unwrapping any wrapper
/// around it first, and checking if the object is of the correct type.
///
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
/// not a reflector for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
pub fn root_from_object<T>(obj: *mut JSObject) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    native_from_object(obj).map(|ptr| unsafe { Root::from_ref(&*ptr) })
}

/// Get a `*const T` for a DOM object accessible from a `HandleValue`.
pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
    where T: Reflectable + IDLInterface
{
    native_from_object(v.get().to_object())
}

/// Get a `Root<T>` for a DOM object accessible from a `HandleValue`.
pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    root_from_object(v.get().to_object())
}

/// Get a `Root<T>` for a DOM object accessible from a `HandleObject`.
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<Root<T>, ()>
    where T: Reflectable + IDLInterface
{
    root_from_object(obj.get())
}

impl<T: Reflectable> ToJSValConvertible for Root<T> {
    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
        self.reflector().to_jsval(cx, rval);
    }
}
<|endoftext|>