<commit_before>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
        let ast::RecordName(_, r) = rec.name;
        env::declare(interp.root, &ast::Sym(r), @mut types::RecordConstructor(@*rec));
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<commit_msg>add proper record constructors<commit_after>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
        let ast::RecordName(_, r) = rec.name;

        env::declare(interp.root, &ast::Sym(r), @mut if rec.slots.len() == 0 {
            types::Record(@*rec, @[])
        } else {
            types::RecordConstructor(@*rec)
        });
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://dtolnay.github.io/syn")]
#![cfg_attr(feature = "cargo-clippy",
            allow(const_static_lifetime, doc_markdown, large_enum_variant, match_bool,
                  redundant_closure))]

extern crate proc_macro2;
extern crate proc_macro;
extern crate unicode_xid;

#[cfg(feature = "printing")]
extern crate quote;

#[cfg(feature = "parsing")]
#[macro_use]
#[doc(hidden)]
pub mod parsers;

#[macro_use]
mod macros;

#[macro_use]
pub mod token;

mod attr;
pub use attr::{AttrStyle, Attribute, MetaItem, MetaItemList, MetaNameValue, NestedMetaItem};

mod data;
pub use data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted, Visibility};

mod expr;
pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
               ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
               ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
               ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange,
               ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType,
               ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, Member};

#[cfg(feature = "full")]
pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local,
               MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice,
               PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt};

mod generics;
pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef,
                   PredicateEq, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier,
                   TypeParam, TypeParamBound, WhereClause, WherePredicate};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TypeGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl,
               ForeignItem, ForeignItemFn, ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem,
               ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
               ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
               ItemImpl, ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait,
               ItemType, ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
               TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath, UseTree};

#[cfg(feature = "full")]
mod file;
#[cfg(feature = "full")]
pub use file::File;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Macro, MacroDelimiter};

mod derive;
pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AngleBracketedGenericArguments, BareFnArg, BareFnArgName,
             Binding, GenericArgument, ParenthesizedGenericArguments, Path,
             PathArguments, PathSegment, QSelf, ReturnType, Type, TypeArray,
             TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen,
             TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

#[cfg(feature = "parsing")]
mod cursor;
#[cfg(feature = "parsing")]
pub mod synom;
pub mod punctuated;
#[cfg(feature = "parsing")]
mod tt;

#[cfg(all(procmacro2_unstable, feature = "parsing", feature = "printing"))]
pub mod spanned;

mod gen {
    #[cfg(feature = "visit")]
    pub mod visit;

    #[cfg(feature = "visit_mut")]
    pub mod visit_mut;

    #[cfg(feature = "fold")]
    pub mod fold;

    #[path = "../gen_helper.rs"]
    mod helper;
}
pub use gen::*;

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "parsing")]
use synom::Synom;
#[cfg(feature = "parsing")]
use cursor::SynomBuffer;

#[cfg(feature = "parsing")]
mod error;
#[cfg(feature = "parsing")]
use error::ParseError;

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
pub use error::parse_error;

/// Parse tokens of source code into the chosen syn data type.
///
/// This is preferred over parsing a string because tokens are able to preserve
/// information about where in the user's code they were originally written (the
/// "span" of the token), possibly allowing the compiler to produce better error
/// messages.
///
/// # Examples
///
/// ```rust
/// extern crate proc_macro;
/// use proc_macro::TokenStream;
///
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::DeriveInput;
///
/// # const IGNORE_TOKENS: &str = stringify! {
/// #[proc_macro_derive(MyMacro)]
/// # };
/// pub fn my_macro(input: TokenStream) -> TokenStream {
///     // Parse the tokens into a syntax tree
///     let ast: DeriveInput = syn::parse(input).unwrap();
///
///     // Build the output, possibly using quasi-quotation
///     let expanded = quote! {
///         /* ... */
///     };
///
///     // Convert into a token stream and return it
///     expanded.into()
/// }
/// #
/// # fn main() {}
/// ```
#[cfg(feature = "parsing")]
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
where
    T: Synom,
{
    _parse(tokens.into())
}

#[cfg(feature = "parsing")]
fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
where
    T: Synom,
{
    let buf = SynomBuffer::new(tokens);
    let result = T::parse(buf.begin());
    let err = match result {
        Ok((t, rest)) => {
            if rest.eof() {
                return Ok(t);
            } else if rest == buf.begin() {
                // parsed nothing
                ParseError::new("failed to parse anything")
            } else {
                ParseError::new("failed to parse all tokens")
            }
        }
        Err(err) => err,
    };
    match T::description() {
        Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
        None => Err(err),
    }
}

/// Parse a string of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = "assert_eq!(u8::max_value(), 255)";
///     let expr = syn::parse_str::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
    match s.parse() {
        Ok(tts) => _parse(tts),
        Err(_) => Err(ParseError::new("error while lexing input string")),
    }
}

// FIXME the name parse_file makes it sound like you might pass in a path to a
// file, rather than the content.
/// Parse the content of a file of Rust code.
///
/// This is different from `syn::parse_str::<File>(content)` in two ways:
///
/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
///
/// If present, either of these would be an error using `from_str`.
///
/// # Examples
///
/// ```rust,no_run
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use std::fs::File;
/// use std::io::Read;
///
/// fn run() -> Result<()> {
///     let mut file = File::open("path/to/code.rs")?;
///     let mut content = String::new();
///     file.read_to_string(&mut content)?;
///
///     let ast = syn::parse_file(&content)?;
///     if let Some(shebang) = ast.shebang {
///         println!("{}", shebang);
///     }
///     println!("{} items", ast.items.len());
///
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(all(feature = "parsing", feature = "full"))]
pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
    // Strip the BOM if it is present
    const BOM: &'static str = "\u{feff}";
    if content.starts_with(BOM) {
        content = &content[BOM.len()..];
    }

    let mut shebang = None;
    if content.starts_with("#!") && !content.starts_with("#![") {
        if let Some(idx) = content.find('\n') {
            shebang = Some(content[..idx].to_string());
            content = &content[idx..];
        } else {
            shebang = Some(content.to_string());
            content = "";
        }
    }

    let mut file: File = parse_str(content)?;
    file.shebang = shebang;
    Ok(file)
}

#[cfg(all(feature = "parsing", feature = "printing"))]
#[macro_export]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        ::std::result::Result::unwrap(
            $crate::parse(
                ::std::convert::Into::into(
                    quote!($($tt)*))))
    };
}

#[cfg(feature = "printing")]
struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);

#[cfg(feature = "printing")]
impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
where
    T: quote::ToTokens + Default,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        match *self.0 {
            Some(ref t) => t.to_tokens(tokens),
            None => T::default().to_tokens(tokens),
        }
    }
}
<commit_msg>Procmacro2_unstable has been renamed<commit_after>#![doc(html_root_url = "https://dtolnay.github.io/syn")]
#![cfg_attr(feature = "cargo-clippy",
            allow(const_static_lifetime, doc_markdown, large_enum_variant, match_bool,
                  redundant_closure))]

extern crate proc_macro2;
extern crate proc_macro;
extern crate unicode_xid;

#[cfg(feature = "printing")]
extern crate quote;

#[cfg(feature = "parsing")]
#[macro_use]
#[doc(hidden)]
pub mod parsers;

#[macro_use]
mod macros;

#[macro_use]
pub mod token;

mod attr;
pub use attr::{AttrStyle, Attribute, MetaItem, MetaItemList, MetaNameValue, NestedMetaItem};

mod data;
pub use data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted, Visibility};

mod expr;
pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
               ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
               ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
               ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange,
               ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType,
               ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, Member};

#[cfg(feature = "full")]
pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local,
               MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice,
               PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt};

mod generics;
pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef,
                   PredicateEq, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier,
                   TypeParam, TypeParamBound, WhereClause, WherePredicate};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TypeGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl,
               ForeignItem, ForeignItemFn, ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem,
               ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
               ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
               ItemImpl, ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait,
               ItemType, ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
               TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath, UseTree};

#[cfg(feature = "full")]
mod file;
#[cfg(feature = "full")]
pub use file::File;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Macro, MacroDelimiter};

mod derive;
pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AngleBracketedGenericArguments, BareFnArg, BareFnArgName,
             Binding, GenericArgument, ParenthesizedGenericArguments, Path,
             PathArguments, PathSegment, QSelf, ReturnType, Type, TypeArray,
             TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen,
             TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

#[cfg(feature = "parsing")]
mod cursor;
#[cfg(feature = "parsing")]
pub mod synom;
pub mod punctuated;
#[cfg(feature = "parsing")]
mod tt;

#[cfg(all(procmacro2_semver_exempt, feature = "parsing", feature = "printing"))]
pub mod spanned;

mod gen {
    #[cfg(feature = "visit")]
    pub mod visit;

    #[cfg(feature = "visit_mut")]
    pub mod visit_mut;

    #[cfg(feature = "fold")]
    pub mod fold;

    #[path = "../gen_helper.rs"]
    mod helper;
}
pub use gen::*;

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "parsing")]
use synom::Synom;
#[cfg(feature = "parsing")]
use cursor::SynomBuffer;

#[cfg(feature = "parsing")]
mod error;
#[cfg(feature = "parsing")]
use error::ParseError;

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
pub use error::parse_error;

/// Parse tokens of source code into the chosen syn data type.
///
/// This is preferred over parsing a string because tokens are able to preserve
/// information about where in the user's code they were originally written (the
/// "span" of the token), possibly allowing the compiler to produce better error
/// messages.
///
/// # Examples
///
/// ```rust
/// extern crate proc_macro;
/// use proc_macro::TokenStream;
///
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::DeriveInput;
///
/// # const IGNORE_TOKENS: &str = stringify! {
/// #[proc_macro_derive(MyMacro)]
/// # };
/// pub fn my_macro(input: TokenStream) -> TokenStream {
///     // Parse the tokens into a syntax tree
///     let ast: DeriveInput = syn::parse(input).unwrap();
///
///     // Build the output, possibly using quasi-quotation
///     let expanded = quote! {
///         /* ... */
///     };
///
///     // Convert into a token stream and return it
///     expanded.into()
/// }
/// #
/// # fn main() {}
/// ```
#[cfg(feature = "parsing")]
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
where
    T: Synom,
{
    _parse(tokens.into())
}

#[cfg(feature = "parsing")]
fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
where
    T: Synom,
{
    let buf = SynomBuffer::new(tokens);
    let result = T::parse(buf.begin());
    let err = match result {
        Ok((t, rest)) => {
            if rest.eof() {
                return Ok(t);
            } else if rest == buf.begin() {
                // parsed nothing
                ParseError::new("failed to parse anything")
            } else {
                ParseError::new("failed to parse all tokens")
            }
        }
        Err(err) => err,
    };
    match T::description() {
        Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
        None => Err(err),
    }
}

/// Parse a string of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = "assert_eq!(u8::max_value(), 255)";
///     let expr = syn::parse_str::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
    match s.parse() {
        Ok(tts) => _parse(tts),
        Err(_) => Err(ParseError::new("error while lexing input string")),
    }
}

// FIXME the name parse_file makes it sound like you might pass in a path to a
// file, rather than the content.
/// Parse the content of a file of Rust code.
///
/// This is different from `syn::parse_str::<File>(content)` in two ways:
///
/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
///
/// If present, either of these would be an error using `from_str`.
///
/// # Examples
///
/// ```rust,no_run
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use std::fs::File;
/// use std::io::Read;
///
/// fn run() -> Result<()> {
///     let mut file = File::open("path/to/code.rs")?;
///     let mut content = String::new();
///     file.read_to_string(&mut content)?;
///
///     let ast = syn::parse_file(&content)?;
///     if let Some(shebang) = ast.shebang {
///         println!("{}", shebang);
///     }
///     println!("{} items", ast.items.len());
///
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(all(feature = "parsing", feature = "full"))]
pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
    // Strip the BOM if it is present
    const BOM: &'static str = "\u{feff}";
    if content.starts_with(BOM) {
        content = &content[BOM.len()..];
    }

    let mut shebang = None;
    if content.starts_with("#!") && !content.starts_with("#![") {
        if let Some(idx) = content.find('\n') {
            shebang = Some(content[..idx].to_string());
            content = &content[idx..];
        } else {
            shebang = Some(content.to_string());
            content = "";
        }
    }

    let mut file: File = parse_str(content)?;
    file.shebang = shebang;
    Ok(file)
}

#[cfg(all(feature = "parsing", feature = "printing"))]
#[macro_export]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        ::std::result::Result::unwrap(
            $crate::parse(
                ::std::convert::Into::into(
                    quote!($($tt)*))))
    };
}

#[cfg(feature = "printing")]
struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);

#[cfg(feature = "printing")]
impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
where
    T: quote::ToTokens + Default,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        match *self.0 {
            Some(ref t) => t.to_tokens(tokens),
            None => T::default().to_tokens(tokens),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing data plus
//! a "view" struct that can have interior references into the data.
//! The view box can be moved around as an atomic unit.
#![feature(macro_rules, globs, unboxed_closures)]

#[macro_export]
macro_rules! viewbox(
    (struct $name:ident<$d:ty, $v:ident>;) => (
        pub struct $name {
            view: $v<'static>,
            #[allow(dead_code)]
            data: Box<$d>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new<F>(data: $d, f: F) -> $name
                          where F: for<'a> FnOnce(&'a mut $d) -> $v<'a> {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name { data: d, view: v }
            }

            pub fn new_result<E,F>(data: $d,
                                   f: F)
                                   -> ::std::result::Result<$name,($d,E)>
                                   where F: for<'a> FnOnce(&'a mut $d) -> ::std::result::Result<$v<'a>,E> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => Ok($name { data: d, view: v }),
                    Err(e) => Err((*d,e))
                }
            }

            pub fn into_inner(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn view_mut<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    );
    (#[deriving(PartialEq $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &$name) -> bool { self.view() == other.view(); }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving(Show $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::fmt::Show for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
                   -> ::std::result::Result<(), ::std::fmt::FormatError> {
                self.view().fmt(fmt)
            }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving()] struct $name:ident<$d:ty, $v:ident>;) => (
        viewbox!(struct $name<$d,$v>;)
    );
)

#[cfg(test)]
mod test {
    extern crate arena;
    use self::arena::TypedArena;

    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into TestData
    struct MutView<'a> {
        x: &'a mut i32,
        y: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.into_inner();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.foo, y: &mut d.bar });

        *v.view_mut().x = 5;
        *v.view_mut().y = "Goodbye".to_string();
        let t = v.into_inner();
        assert_eq!(t, TestData { foo: 5, bar: "Goodbye".to_string() });
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }

    struct ArenaView<'a> {
        arena: &'a TypedArena<int>,
        vec: Vec<&'a int>
    }

    viewbox! {
        struct ArenaBox<TypedArena<int>, ArenaView>;
    }

    #[test]
    fn arenaview() {
        let mut vb = ArenaBox::new(
            TypedArena::new(),
            |a| ArenaView { arena: a, vec: Vec::new()});

        spawn(proc() {
            let v = vb.view_mut();
            let a = v.arena.alloc(1);
            let b = v.arena.alloc(2);
            let c = v.arena.alloc(3);
            v.vec.push(a);
            v.vec.push(b);
            v.vec.push(c);
        });
    }
}
<commit_msg>Remove use of `proc`<commit_after>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing data plus
//! a "view" struct that can have interior references into the data.
//! The view box can be moved around as an atomic unit.
#![feature(macro_rules, globs, unboxed_closures)]

#[macro_export]
macro_rules! viewbox(
    (struct $name:ident<$d:ty, $v:ident>;) => (
        pub struct $name {
            view: $v<'static>,
            #[allow(dead_code)]
            data: Box<$d>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new<F>(data: $d, f: F) -> $name
                          where F: for<'a> FnOnce(&'a mut $d) -> $v<'a> {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name { data: d, view: v }
            }

            pub fn new_result<E,F>(data: $d,
                                   f: F)
                                   -> ::std::result::Result<$name,($d,E)>
                                   where F: for<'a> FnOnce(&'a mut $d) -> ::std::result::Result<$v<'a>,E> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => Ok($name { data: d, view: v }),
                    Err(e) => Err((*d,e))
                }
            }

            pub fn into_inner(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn view_mut<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    );
    (#[deriving(PartialEq $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &$name) -> bool { self.view() == other.view(); }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving(Show $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::fmt::Show for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
                   -> ::std::result::Result<(), ::std::fmt::FormatError> {
                self.view().fmt(fmt)
            }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving()] struct $name:ident<$d:ty, $v:ident>;) => (
        viewbox!(struct $name<$d,$v>;)
    );
)

#[cfg(test)]
mod test {
    extern crate arena;
    use self::arena::TypedArena;

    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into TestData
    struct MutView<'a> {
        x: &'a mut i32,
        y: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.into_inner();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.foo, y: &mut d.bar });

        *v.view_mut().x = 5;
        *v.view_mut().y = "Goodbye".to_string();
        let t = v.into_inner();
        assert_eq!(t, TestData { foo: 5, bar: "Goodbye".to_string() });
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }

    struct ArenaView<'a> {
        arena: &'a TypedArena<int>,
        vec: Vec<&'a int>
    }

    viewbox! {
        struct ArenaBox<TypedArena<int>, ArenaView>;
    }

    #[test]
    fn arenaview() {
        let mut vb = ArenaBox::new(
            TypedArena::new(),
            |a| ArenaView { arena: a, vec: Vec::new()});

        spawn(move || {
            let v = vb.view_mut();
            let a = v.arena.alloc(1);
            let b = v.arena.alloc(2);
            let c = v.arena.alloc(3);
            v.vec.push(a);
            v.vec.push(b);
            v.vec.push(c);
        });
    }
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! If you are using [Rust-Empty](https://github.com/bvssvni/rust-empty) or Cargo, put the compiled library in the "target/cpu-vendor-platform/lib/" directory, then add the following to your source:
//!
//! ```Rust
//! #![feature(globs)] // Allow global imports
//!
//! extern crate graphics; // Link to 'graphics' library
//!
//! use graphics::*; // Use the graphics types in the module
//! ```
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

extern crate core;
extern crate std;

pub use AddBevel = add_bevel::AddBevel;
pub use AddBevelBorder = add_bevel_border::AddBevelBorder;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddImage = add_image::AddImage;
pub use AddLine = add_line::AddLine;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddRoundBorder = add_round_border::AddRoundBorder;
pub use AddSquareBorder = add_square_border::AddSquareBorder;
pub use AddTween = add_tween::AddTween;
pub use BackEnd = back_end::BackEnd;
pub use BevelBorderLineColorContext = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleColorContext = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext = bevel_rectangle_context::BevelRectangleContext;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use Context = context::Context;
pub use Draw = draw::Draw;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use Fill = fill::Fill;
pub use ImageRectangleContext = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext = image_rectangle_color_context::ImageRectangleColorContext;
pub use LineContext = line_context::LineContext;
pub use LineColorContext = line_color_context::LineColorContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RelativeColor = relative_color::RelativeColor;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use RelativeTransform2d = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use Stroke = stroke::Stroke;
pub use SquareBorderLineColorContext = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext = square_border_line_context::SquareBorderLineContext;
pub use TweenContext = tween_context::TweenContext;
pub use TweenColorContext = tween_color_context::TweenColorContext;
pub use TweenPolygonsContext = tween_polygons_context::TweenPolygonsContext;
pub use TweenPolygonsColorContext = tween_polygons_color_context::TweenPolygonsColorContext;
pub use View = view::View;

mod add_bevel;
mod add_bevel_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod clear;
mod color_context;
mod context;
mod draw;
mod ellipse_color_context;
mod ellipse_context;
mod fill;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod internal;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod stroke;
mod tween_color_context;
mod tween_context;
mod tween_polygons_color_context;
mod tween_polygons_context;
mod view;

pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// [red, green, blue, alpha]
pub struct Color(pub [f32, ..4]);

impl Clone for Color {
    #[inline(always)]
    fn clone(&self) -> Color {
        let &Color(c) = self;
        Color(c)
    }
}

/// [x1, y1, x2, y2]
pub struct Line(pub [f64, ..4]);

impl Clone for Line {
    #[inline(always)]
    fn clone(&self) -> Line {
        let &Line(c) = self;
        Line(c)
    }
}

/// [m00, m01, m02, m10, m11, m12]
///
/// The first 3 numbers transforms `x`,
/// the last 3 numbers transforms `y`:
///
/// ```
/// tx = m00 * x + m01 * y + m02;
/// ty = m10 * x + m11 * y + m12;
/// ```
pub struct Matrix2d(pub [f64, ..6]);

impl Clone for Matrix2d {
    #[inline(always)]
    fn clone(&self) -> Matrix2d {
        let &Matrix2d(m) = self;
        Matrix2d(m)
    }
}

/// [x, y, w, h]
pub struct PixelRectangle(pub [u32, ..4]);

impl Clone for PixelRectangle {
    #[inline(always)]
    fn clone(&self) -> PixelRectangle {
        let &PixelRectangle(p) = self;
        PixelRectangle(p)
    }
}

/// [x0, y0, x1, y1, ...]
pub type Polygon<'a> = &'a [f64];

/// [x, y, dir_x, dir_y]
pub type Ray = [f64, ..4];

/// [x, y, w, h]
pub struct Rectangle(pub [f64, ..4]);

impl Clone for Rectangle {
    #[inline(always)]
    fn clone(&self) -> Rectangle {
        let &Rectangle(r) = self;
        Rectangle(r)
    }
}

/// [x1, y1, x2, y2, x3, y3]
pub struct Triangle(pub [f64, ..6]);

impl Clone for Triangle {
    #[inline(always)]
    fn clone(&self) -> Triangle {
        let &Triangle(t) = self;
        Triangle(t)
    }
}

/// [x, y]
pub type Vec2d = [f64, ..2];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

impl<'a, T: Clone> Clone for Field<'a, T> {
    #[inline(always)]
    fn clone(&self) -> Field<'static, T> {
        Value(self.get().clone())
    }
}

/// Represents an image.
///
/// Images are often packed together in sprite sheets.
/// For this reason it refers to a rectangle within a texture.
///
/// The texture is a unique identifier recognized by the back-end.
/// An image contains the size of a texture to be able to
/// compute normalized coordinates.
///
/// There is no garbage collection of textures,
/// this responsibility is given to the back-end.
pub struct Image {
    /// A unique identifier of the texture, recognizable by back-end.
    pub texture_id: uint,
    /// The pixel width of the texture.
    pub texture_width: u32,
    /// The pixel height of the texture.
    pub texture_height: u32,
    /// The source rectangle in the texture.
    pub source_rect: [u32, ..4],
}

impl Clone for Image {
    #[inline(always)]
    fn clone(&self) -> Image {
        Image {
            texture_id: self.texture_id,
            texture_width: self.texture_width,
            texture_height: self.texture_height,
            source_rect: self.source_rect,
        }
    }
}

<commit_msg>Added `Polygons` type alias<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! If you are using [Rust-Empty](https://github.com/bvssvni/rust-empty) or Cargo, put the compiled library in the "target/cpu-vendor-platform/lib/" directory, then add the following to your source:
//!
//! ```Rust
//! #![feature(globs)] // Allow global imports
//!
//! extern crate graphics; // Link to 'graphics' library
//!
//! use graphics::*; // Use the graphics types in the module
//! ```
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

extern crate core;
extern crate std;

pub use AddBevel = add_bevel::AddBevel;
pub use AddBevelBorder = add_bevel_border::AddBevelBorder;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddImage = add_image::AddImage;
pub use AddLine = add_line::AddLine;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddRoundBorder = add_round_border::AddRoundBorder;
pub use AddSquareBorder = add_square_border::AddSquareBorder;
pub use AddTween = add_tween::AddTween;
pub use BackEnd = back_end::BackEnd;
pub use BevelBorderLineColorContext = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleColorContext = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext = bevel_rectangle_context::BevelRectangleContext;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use Context = context::Context;
pub use Draw = draw::Draw;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use Fill = fill::Fill;
pub use ImageRectangleContext = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext = image_rectangle_color_context::ImageRectangleColorContext;
pub use LineContext = line_context::LineContext;
pub use LineColorContext = line_color_context::LineColorContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RelativeColor = relative_color::RelativeColor;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use RelativeTransform2d = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use Stroke = stroke::Stroke;
pub use SquareBorderLineColorContext = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext = square_border_line_context::SquareBorderLineContext;
pub use TweenContext = tween_context::TweenContext;
pub use TweenColorContext = tween_color_context::TweenColorContext;
pub use TweenPolygonsContext = tween_polygons_context::TweenPolygonsContext;
pub use TweenPolygonsColorContext = tween_polygons_color_context::TweenPolygonsColorContext;
pub use View = view::View;

mod add_bevel;
mod add_bevel_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod clear;
mod color_context;
mod context;
mod draw;
mod ellipse_color_context;
mod ellipse_context;
mod fill;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod internal;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod stroke;
mod tween_color_context;
mod tween_context;
mod tween_polygons_color_context;
mod tween_polygons_context;
mod view;

pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// [red, green, blue, alpha]
pub struct Color(pub [f32, ..4]);

impl Clone for Color {
    #[inline(always)]
    fn clone(&self) -> Color {
        let &Color(c) = self;
        Color(c)
    }
}

/// [x1, y1, x2, y2]
pub struct Line(pub [f64, ..4]);

impl Clone for Line {
    #[inline(always)]
    fn clone(&self) -> Line {
        let &Line(c) = self;
        Line(c)
    }
}

/// [m00, m01, m02, m10, m11, m12]
///
/// The first 3 numbers transforms `x`,
/// the last 3 numbers transforms `y`:
///
/// ```
/// tx = m00 * x + m01 * y + m02;
/// ty = m10 * x + m11 * y + m12;
/// ```
pub struct Matrix2d(pub [f64, ..6]);

impl Clone for Matrix2d {
    #[inline(always)]
    fn clone(&self) -> Matrix2d {
        let &Matrix2d(m) = self;
        Matrix2d(m)
    }
}

/// [x, y, w, h]
pub struct PixelRectangle(pub [u32, ..4]);

impl Clone for PixelRectangle {
    #[inline(always)]
    fn clone(&self) -> PixelRectangle {
        let &PixelRectangle(p) = self;
        PixelRectangle(p)
    }
}

/// [x0, y0, x1, y1, ...]
pub type Polygon<'a> = &'a [f64];

/// A slice of polygons.
pub type Polygons<'a> = &'a [Polygon<'a>];

/// [x, y, dir_x, dir_y]
pub type Ray = [f64, ..4];

/// [x, y, w, h]
pub struct Rectangle(pub [f64, ..4]);

impl Clone for Rectangle {
    #[inline(always)]
    fn clone(&self) -> Rectangle {
        let &Rectangle(r) = self;
        Rectangle(r)
    }
}

/// [x1, y1, x2, y2, x3, y3]
pub struct Triangle(pub [f64, ..6]);

impl Clone for Triangle {
    #[inline(always)]
    fn clone(&self) -> Triangle {
        let &Triangle(t) = self;
        Triangle(t)
    }
}

/// [x, y]
pub type Vec2d = [f64, ..2];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

impl<'a, T: Clone> Clone for Field<'a, T> {
    #[inline(always)]
    fn clone(&self) -> Field<'static, T> {
        Value(self.get().clone())
    }
}

/// Represents an image.
///
/// Images are often packed together in sprite sheets.
/// For this reason it refers to a rectangle within a texture.
///
/// The texture is a unique identifier recognized by the back-end.
/// An image contains the size of a texture to be able to
/// compute normalized coordinates.
///
/// There is no garbage collection of textures,
/// this responsibility is given to the back-end.
pub struct Image {
    /// A unique identifier of the texture, recognizable by back-end.
    pub texture_id: uint,
    /// The pixel width of the texture.
    pub texture_width: u32,
    /// The pixel height of the texture.
    pub texture_height: u32,
    /// The source rectangle in the texture.
    pub source_rect: [u32, ..4],
}

impl Clone for Image {
    #[inline(always)]
    fn clone(&self) -> Image {
        Image {
            texture_id: self.texture_id,
            texture_width: self.texture_width,
            texture_height: self.texture_height,
            source_rect: self.source_rect,
        }
    }
}

<|endoftext|>


<commit_before>use sass::value_part::ValuePart;
use sass::number_value::NumberValue;
use evaluator::Evaluator;

use std::borrow::Cow;
use std::borrow::Cow::Borrowed;
use std::str::FromStr;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Op {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    LeftParen,
    RightParen,
    Comma,
}

impl FromStr for Op {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "+" => Ok(Op::Plus),
            "-" => Ok(Op::Minus),
            "*" => Ok(Op::Star),
            "/" => Ok(Op::Slash),
            "%" => Ok(Op::Percent),
            "(" => Ok(Op::LeftParen),
            ")" => Ok(Op::RightParen),
            "," => Ok(Op::Comma),
            _   => Err(()),
        }
    }
}

impl Op {
    pub fn apply<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        match (self, second) {
            (&Op::Plus, s @ ValuePart::List(..)) => self.apply_list(first, s),
            (&Op::Slash, s) => self.apply_slash(first, s, paren_level),
            (&Op::Comma, s) => {
                ValuePart::concat_into_list(
                    ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                    s,
                )
            },
            (_, s) => {
                self.apply_math(first, s)
            },
        }
    }

    fn force_list_collapse<'a>(&self, mut vp: ValuePart<'a>) -> ValuePart<'a> {
        match vp {
            ValuePart::List(ref mut l) => {
                if l.iter().any(|v| {
                    match v {
                        &ValuePart::Operator(Op::Slash) => true,
                        _ => false,
                    }
                }) {
                    let mut ve = vec![ValuePart::Operator(Op::LeftParen)];
                    l.push(ValuePart::Operator(Op::RightParen));
                    ve.append(l);
                    Evaluator::new(ve).evaluate(&HashMap::new())
                } else {
                    ValuePart::List(l.clone())
                }
            },
            _ => vp,
        }
    }

    fn apply_list<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let first_collapsed  = self.force_list_collapse(first);
        let second_collapsed = self.force_list_collapse(second);

        match (first_collapsed, second_collapsed) {
            (ValuePart::Number(fnum), ValuePart::List(mut slist)) => {
                let new_first_item_value = format!("{}{}", fnum, slist.remove(0));
                let v = ValuePart::String(new_first_item_value.into());

                ValuePart::concat_into_list(v, ValuePart::List(slist))
            },
            (ValuePart::List(mut flist), ValuePart::Number(snum)) => {
                let new_last_item_value = format!("{}{}",
                    flist.pop().unwrap_or(ValuePart::String(Borrowed(""))),
                    snum
                );
                let v = ValuePart::String(new_last_item_value.into());
                ValuePart::concat_into_list(ValuePart::List(flist), v)
            },
            (f @ ValuePart::List(..), s @ ValuePart::List(..)) => {
                ValuePart::concat_into_list(f, s)
            },
            (f @ ValuePart::Number(..), s @ ValuePart::Number(..)) => {
                self.apply_math(f, s)
            },
            (unk_first, unk_second) => {
                return ValuePart::String(format!(
                    "Unknown apply_list match:\n  first: {:?}\n  second: {:?}",
                    unk_first, unk_second
                ).into())
            },
        }
    }

    fn apply_slash<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        if paren_level == 0 {
            if first.computed_number() || second.computed_number() {
                self.apply_math(self.force_list_collapse(first), self.force_list_collapse(second))
            } else {
                ValuePart::concat_into_list(
                    ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                    second,
                )
            }
        } else {
            match first {
                ValuePart::List(..) => {
                    ValuePart::concat_into_list(
                        ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                        second,
                    )
                },
                _ => {
                    self.apply_math(first, second)
                },
            }
        }
    }

    fn apply_math<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let (f, s) = match (first, second) {
            (ValuePart::Number(f), ValuePart::Number(s)) => (f, s),
            (f, s) => return ValuePart::String(format!("Invalid apply math arguments:\n  first: {:?}\n  second: {:?}\n", f, s).into()),
        };
        let first_num = f.scalar;
        let second_num = s.scalar;
        let result_units: Option<Cow<'a, str>> = match (f.unit, s.unit) {
            (Some(u), None) => Some(u.into_owned().into()),
            (None, Some(u)) => Some(u.into_owned().into()),
            (Some(ref u1), Some(ref u2)) if u1 == u2 => {
                match *self {
                    Op::Slash => None,
                    _         => Some(u1.clone().into_owned().into()),
                }
            },
            (None, None) => None,
            (other1, other2) => return ValuePart::String(
                format!("Incompatible units: {:?} and {:?}", other1, other2).into()
            ),
        };
        let result = match *self {
            Op::Plus => first_num + second_num,
            Op::Minus => first_num - second_num,
            Op::Star => first_num * second_num,
            Op::Slash => first_num / second_num,
            Op::Percent => first_num % second_num,
            _ => 0.0,
        };
        ValuePart::Number(NumberValue {
            scalar: result,
            unit: result_units,
            computed: true,
        })
    }

    pub fn same_or_greater_precedence(self, other: Op) -> bool {
        match (self, other) {
            (Op::Plus, Op::Star) |
            (Op::Minus, Op::Star) |
            (Op::Plus, Op::Slash) |
            (Op::Minus, Op::Slash) |
            (Op::LeftParen, _) => false,
            (_, _) => true,
        }
    }
}
<commit_msg>Extract some functions from Operations<commit_after>use sass::value_part::ValuePart;
use sass::number_value::NumberValue;
use evaluator::Evaluator;

use std::borrow::Cow;
use std::borrow::Cow::*;
use std::str::FromStr;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Op {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    LeftParen,
    RightParen,
    Comma,
}

impl FromStr for Op {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "+" => Ok(Op::Plus),
            "-" => Ok(Op::Minus),
            "*" => Ok(Op::Star),
            "/" => Ok(Op::Slash),
            "%" => Ok(Op::Percent),
            "(" => Ok(Op::LeftParen),
            ")" => Ok(Op::RightParen),
            "," => Ok(Op::Comma),
            _   => Err(()),
        }
    }
}

impl Op {
    pub fn apply<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        match (self, second) {
            (&Op::Plus, s @ ValuePart::List(..)) => self.apply_list(first, s),
            (&Op::Slash, s) => self.apply_slash(first, s, paren_level),
            (&Op::Comma, s) => {
                ValuePart::concat_into_list(
                    ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                    s,
                )
            },
            (_, s) => {
                self.apply_math(first, s)
            },
        }
    }

    fn force_list_collapse<'a>(&self, mut vp: ValuePart<'a>) -> ValuePart<'a> {
        match vp {
            ValuePart::List(ref mut l) => {
                if l.iter().any(|v| {
                    match v {
                        &ValuePart::Operator(Op::Slash) => true,
                        _ => false,
                    }
                }) {
                    let mut ve = vec![ValuePart::Operator(Op::LeftParen)];
                    l.push(ValuePart::Operator(Op::RightParen));
                    ve.append(l);
                    Evaluator::new(ve).evaluate(&HashMap::new())
                } else {
                    ValuePart::List(l.clone())
                }
            },
            _ => vp,
        }
    }

    fn apply_list<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let first_collapsed  = self.force_list_collapse(first);
        let second_collapsed = self.force_list_collapse(second);

        match (first_collapsed, second_collapsed) {
            (ValuePart::Number(fnum), ValuePart::List(mut slist)) => {
                let new_first_item_value = format!("{}{}", fnum, slist.remove(0));
                let v = ValuePart::String(new_first_item_value.into());

                ValuePart::concat_into_list(v, ValuePart::List(slist))
            },
            (ValuePart::List(mut flist), ValuePart::Number(snum)) => {
                let new_last_item_value = format!("{}{}",
                    flist.pop().unwrap_or(ValuePart::String(Borrowed(""))),
                    snum
                );
                let v = ValuePart::String(new_last_item_value.into());
                ValuePart::concat_into_list(ValuePart::List(flist), v)
            },
            (f @ ValuePart::List(..), s @ ValuePart::List(..)) => {
                ValuePart::concat_into_list(f, s)
            },
            (f @ ValuePart::Number(..), s @ ValuePart::Number(..)) => {
                self.apply_math(f, s)
            },
            (unk_first, unk_second) => {
                return ValuePart::String(format!(
                    "Unknown apply_list match:\n  first: {:?}\n  second: {:?}",
                    unk_first, unk_second
                ).into())
            },
        }
    }

    fn apply_slash<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        if paren_level == 0 {
            if first.computed_number() || second.computed_number() {
                self.apply_math(self.force_list_collapse(first), self.force_list_collapse(second))
            } else {
                ValuePart::concat_into_list(
                    ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                    second,
                )
            }
        } else {
            match first {
                ValuePart::List(..) => {
                    ValuePart::concat_into_list(
                        ValuePart::concat_into_list(first, ValuePart::Operator(*self)),
                        second,
                    )
                },
                _ => {
                    self.apply_math(first, second)
                },
            }
        }
    }

    fn apply_math<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let (f, s) = match (first, second) {
            (ValuePart::Number(f), ValuePart::Number(s)) => (f, s),
            (f, s) => return ValuePart::String(format!("Invalid apply math arguments:\n  first: {:?}\n  second: {:?}\n", f, s).into()),
        };

        let result_units = self.compute_units(f.unit, s.unit);
        let result = self.compute_numbers(f.scalar, s.scalar);

        ValuePart::Number(NumberValue {
            scalar: result,
            unit: result_units,
            computed: true,
        })
    }

    fn compute_numbers(&self, first_num: f32, second_num: f32) -> f32 {
        match *self {
            Op::Plus    => first_num + second_num,
            Op::Minus   => first_num - second_num,
            Op::Star    => first_num * second_num,
            Op::Slash   => first_num / second_num,
            Op::Percent => first_num % second_num,
            _           => 0.0, // TODO: Result
        }
    }

    fn compute_units<'a>(&self, funit: Option<Cow<'a, str>>, sunit: Option<Cow<'a, str>>) -> Option<Cow<'a, str>> {
        match (funit, sunit) {
            (Some(u), None) | (None, Some(u)) => Some(u.into_owned().into()),
            (Some(ref u1), Some(ref u2)) if u1 == u2 => {
                match *self {
                    Op::Slash => None, // Divide out the units
                    // TODO: Multiplication that produces square units should return Err
                    _         => Some(u1.clone().into_owned().into()),
                }
            },
            (None, None) => None,
            (other1, other2) => {
                Some(Owned(format!("Incompatible units: {:?} and {:?}", other1, other2))) // TODO: Result
            },
        }
    }

    pub fn same_or_greater_precedence(self, other: Op) -> bool {
        match (self, other) {
            (Op::Plus, Op::Star) |
            (Op::Minus, Op::Star) |
            (Op::Plus, Op::Slash) |
            (Op::Minus, Op::Slash) |
            (Op::LeftParen, _) => false,
            (_, _) => true,
        }
    }
}
<|endoftext|>


<commit_before>
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Sub};

extern crate num;
use num::{Float, Zero, One};

#[cfg(test)]
use std::f32::consts;
#[cfg(test)]
use std::f32;

/// Dual Numbers
#[derive(Copy, Clone, PartialEq, Hash, Debug)]
pub struct Dual<F> {
    real: F,
    dual: F,
}

pub type Dual32 = Dual<f32>;
pub type Dual64 = Dual<f64>;

impl<F: Copy + Float> Dual<F> {
    pub fn new(real: F, deriv: F) -> Dual<F> {
        Dual {
            real: real,
            dual: deriv,
        }
    }

    pub fn real(self) -> F {
        self.real
    }

    pub fn derivative(self) -> F {
        self.dual
    }
}

impl<F: Copy + Float> Zero for Dual<F> {
    fn zero() -> Dual<F> {
        Dual::new(F::zero(), F::zero())
    }

    fn is_zero(&self) -> bool {
        self.real.is_zero() && self.dual.is_zero()
    }
}

impl<F: Copy + Float> One for Dual<F> {
    fn one() -> Dual<F> {
        Dual::new(One::one(), One::one())
    }
}

impl<F: Copy + Float> Add<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn add(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real + other.real, self.dual + other.dual)
    }
}

#[test]
fn test_add_struct() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 3.0);

    let z = x + y;
    assert!(z.real == 5.0);
    assert!(z.dual == 7.0);
}

impl<F: Copy + Float> Sub<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn sub(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real - other.real, self.dual - other.dual)
    }
}

#[test]
fn test_sub() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 12.0);

    let z = x - y;
    assert!(z.real == 1.0);
    assert!(z.dual == -8.0);
}

impl<F: Copy + Float + Neg<Output = F>> Neg for Dual<F> {
    type Output = Dual<F>;

    fn neg(self) -> Dual<F> {
        Dual::new(-self.real, -self.dual)
    }
}

#[test]
fn test_neg_plus() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 12.0);

    let z1 = x - y;
    let z2 = x + (-y);
    assert!(z1 == z2);
}

#[test]
fn test_neg_zero() {
    let x = Dual::new(3.0, 4.0);
    let zero: Dual32 = Zero::zero();

    let z1 = -x;
    let z2 = zero - x;
    assert!(z1 == z2);
}

impl<F: Copy + Float> Mul<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn mul(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real * other.real,
                  (self.real * other.dual) + (self.dual * other.real))
    }
}

#[test]
fn test_mul() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(1.0, 2.0);

    let z = x * y;
    assert!(z.real == 3.0);
    assert!(z.dual == 10.0);
}

impl<F: Copy + Float> Div<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn div(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real / other.real,
                  ((self.dual * other.real) - (self.real * other.dual)) / (other.real * other.real))
    }
}

#[test]
fn test_div() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(1.0, 2.0);

    let z = x / y;
    assert!(z.real == 3.0);
    assert!(z.dual == -2.0);
}

impl<F: Copy + Float> Dual<F> {
    pub fn sin(self) -> Dual<F> {
        Dual::new(self.real.sin(), self.dual * self.real.cos())
    }

    pub fn cos(self) -> Dual<F> {
        Dual::new(self.real.cos(), (-F::one()) * self.dual * self.real.sin())
    }

    pub fn tan(self) -> Dual<F> {
        self.sin() / self.cos()
    }

    pub fn exp(self) -> Dual<F> {
        Dual::new(self.real.exp(), self.dual * self.real.exp())
    }

    pub fn ln(self) -> Dual<F> {
        Dual::new(self.real.ln(), self.dual / self.real)
    }

    pub fn sqrt(self) -> Dual<F> {
        let two = F::one() + F::one();
        Dual::new(self.real.sqrt(), self.dual / (two * self.real.sqrt()))
    }
}

impl<F: Copy + Float> From<F> for Dual<F> {
    fn from(real: F) -> Dual<F> {
        Dual::new(real, F::one())
    }
}

impl<F> fmt::Display for Dual<F>
    where F: fmt::Display + Float + PartialOrd + Copy
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.real < Zero::zero() {
            write!(f, "{}-{}ε", self.real, F::zero() - self.dual)
        } else {
            write!(f, "{}+{}ε", self.real, self.dual)
        }
    }
}

#[cfg(test)]
fn diff(x: f32, y: f32) -> f32 {
    (x - y).abs()
}

#[test]
fn test_sin() {
    let x: Dual32 = From::from(0.0);
    let y = x.sin();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_cos() {
    let x: Dual32 = From::from(consts::PI);
    let y = x.cos();

    let real_diff = diff(y.real, -1.0);
    let dual_diff = diff(y.dual, 0.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_tan() {
    let x: Dual32 = From::from(0.0);
    let y = x.tan();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_exp() {
    let x: Dual32 = From::from(1.0);
    let y = x.exp();

    let real_diff = diff(y.real, consts::E);
    let dual_diff = diff(y.dual, consts::E);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_ln() {
    let x: Dual32 = From::from(1.0);
    let y = x.ln();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_sqrt() {
    let x: Dual32 = From::from(4.0);
    let y = x.sqrt();

    println!("{}", y);

    let real_diff = diff(y.real, 2.0);
    let dual_diff = diff(y.dual, 0.25);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}
<commit_msg>Remove PartialOrd requirement<commit_after>
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Sub};

extern crate num;
use num::{Float, Zero, One};

#[cfg(test)]
use std::f32::consts;
#[cfg(test)]
use std::f32;

/// Dual Numbers
#[derive(Copy, Clone, PartialEq, Hash, Debug)]
pub struct Dual<F> {
    real: F,
    dual: F,
}

pub type Dual32 = Dual<f32>;
pub type Dual64 = Dual<f64>;

impl<F: Copy + Float> Dual<F> {
    pub fn new(real: F, deriv: F) -> Dual<F> {
        Dual {
            real: real,
            dual: deriv,
        }
    }

    pub fn real(self) -> F {
        self.real
    }

    pub fn derivative(self) -> F {
        self.dual
    }
}

impl<F: Copy + Float> Zero for Dual<F> {
    fn zero() -> Dual<F> {
        Dual::new(F::zero(), F::zero())
    }

    fn is_zero(&self) -> bool {
        self.real.is_zero() && self.dual.is_zero()
    }
}

impl<F: Copy + Float> One for Dual<F> {
    fn one() -> Dual<F> {
        Dual::new(One::one(), One::one())
    }
}

impl<F: Copy + Float> Add<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn add(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real + other.real, self.dual + other.dual)
    }
}

#[test]
fn test_add_struct() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 3.0);

    let z = x + y;
    assert!(z.real == 5.0);
    assert!(z.dual == 7.0);
}

impl<F: Copy + Float> Sub<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn sub(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real - other.real, self.dual - other.dual)
    }
}

#[test]
fn test_sub() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 12.0);

    let z = x - y;
    assert!(z.real == 1.0);
    assert!(z.dual == -8.0);
}

impl<F: Copy + Float + Neg<Output = F>> Neg for Dual<F> {
    type Output = Dual<F>;

    fn neg(self) -> Dual<F> {
        Dual::new(-self.real, -self.dual)
    }
}

#[test]
fn test_neg_plus() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(2.0, 12.0);

    let z1 = x - y;
    let z2 = x + (-y);
    assert!(z1 == z2);
}

#[test]
fn test_neg_zero() {
    let x = Dual::new(3.0, 4.0);
    let zero: Dual32 = Zero::zero();

    let z1 = -x;
    let z2 = zero - x;
    assert!(z1 == z2);
}

impl<F: Copy + Float> Mul<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn mul(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real * other.real,
                  (self.real * other.dual) + (self.dual * other.real))
    }
}

#[test]
fn test_mul() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(1.0, 2.0);

    let z = x * y;
    assert!(z.real == 3.0);
    assert!(z.dual == 10.0);
}

impl<F: Copy + Float> Div<Dual<F>> for Dual<F> {
    type Output = Dual<F>;

    fn div(self, other: Dual<F>) -> Dual<F> {
        Dual::new(self.real / other.real,
                  ((self.dual * other.real) - (self.real * other.dual)) / (other.real * other.real))
    }
}

#[test]
fn test_div() {
    let x = Dual::new(3.0, 4.0);
    let y = Dual::new(1.0, 2.0);

    let z = x / y;
    assert!(z.real == 3.0);
    assert!(z.dual == -2.0);
}

impl<F: Copy + Float> Dual<F> {
    pub fn sin(self) -> Dual<F> {
        Dual::new(self.real.sin(), self.dual * self.real.cos())
    }

    pub fn cos(self) -> Dual<F> {
        Dual::new(self.real.cos(), (-F::one()) * self.dual * self.real.sin())
    }

    pub fn tan(self) -> Dual<F> {
        self.sin() / self.cos()
    }

    pub fn exp(self) -> Dual<F> {
        Dual::new(self.real.exp(), self.dual * self.real.exp())
    }

    pub fn ln(self) -> Dual<F> {
        Dual::new(self.real.ln(), self.dual / self.real)
    }

    pub fn sqrt(self) -> Dual<F> {
        let two = F::one() + F::one();
        Dual::new(self.real.sqrt(), self.dual / (two * self.real.sqrt()))
    }
}

impl<F: Copy + Float> From<F> for Dual<F> {
    fn from(real: F) -> Dual<F> {
        Dual::new(real, F::one())
    }
}

impl<F> fmt::Display for Dual<F>
    where F: Copy + Float + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.real < Zero::zero() {
            write!(f, "{}-{}ε", self.real, F::zero() - self.dual)
        } else {
            write!(f, "{}+{}ε", self.real, self.dual)
        }
    }
}

#[cfg(test)]
fn diff(x: f32, y: f32) -> f32 {
    (x - y).abs()
}

#[test]
fn test_sin() {
    let x: Dual32 = From::from(0.0);
    let y = x.sin();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_cos() {
    let x: Dual32 = From::from(consts::PI);
    let y = x.cos();

    let real_diff = diff(y.real, -1.0);
    let dual_diff = diff(y.dual, 0.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_tan() {
    let x: Dual32 = From::from(0.0);
    let y = x.tan();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_exp() {
    let x: Dual32 = From::from(1.0);
    let y = x.exp();

    let real_diff = diff(y.real, consts::E);
    let dual_diff = diff(y.dual, consts::E);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_ln() {
    let x: Dual32 = From::from(1.0);
    let y = x.ln();

    let real_diff = diff(y.real, 0.0);
    let dual_diff = diff(y.dual, 1.0);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}

#[test]
fn test_sqrt() {
    let x: Dual32 = From::from(4.0);
    let y = x.sqrt();

    println!("{}", y);

    let real_diff = diff(y.real, 2.0);
    let dual_diff = diff(y.dual, 0.25);

    assert!(real_diff < f32::EPSILON);
    assert!(dual_diff < f32::EPSILON);
}
<|endoftext|>