<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use libc::c_char;
use glib::translate::{ToGlib, ToGlibPtr, IterToGlibPtr, Stash, IterStash};

pub struct RecentData {
    display_name: String,
    description: String,
    mime_type: String,
    app_name: String,
    app_exec: String,
    groups: Vec<String>,
    is_private: bool
}

impl <'a> ToGlibPtr<'a, *mut ffi::C_GtkRecentData> for RecentData {
    type Storage = (Box<ffi::C_GtkRecentData>,
                    [Stash<'a, *const c_char, String>; 5],
                    IterStash<'a, *mut *const c_char, Vec<String>>);

    fn to_glib_none(&'a self)
        -> Stash<*mut ffi::C_GtkRecentData, RecentData> {
        let display_name = self.display_name.to_glib_none();
        let description = self.description.to_glib_none();
        let mime_type = self.mime_type.to_glib_none();
        let app_name = self.app_name.to_glib_none();
        let app_exec = self.app_exec.to_glib_none();
        let groups = self.groups.to_glib_none();

        let mut data = Box::new(ffi::C_GtkRecentData {
            display_name: display_name.0 as *mut c_char,
            description: description.0 as *mut c_char,
            mime_type: mime_type.0 as *mut c_char,
            app_name: app_name.0 as *mut c_char,
            app_exec: app_exec.0 as *mut c_char,
            groups: groups.0 as *mut *mut c_char,
            is_private: self.is_private.to_glib(),
        });

        Stash(&mut *data, (data, [display_name, description, mime_type,
                                  app_name, app_exec], groups))
    }
}
<commit_msg>Tweak ToGlibPtr lifetimes<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use libc::c_char;
use glib::translate::{ToGlib, ToGlibPtr, IterToGlibPtr, Stash, IterStash};

pub struct RecentData {
    display_name: String,
    description: String,
    mime_type: String,
    app_name: String,
    app_exec: String,
    groups: Vec<String>,
    is_private: bool
}

impl <'a> ToGlibPtr<'a, *mut ffi::C_GtkRecentData> for &'a RecentData {
    type Storage = (Box<ffi::C_GtkRecentData>,
                    [Stash<'a, *const c_char, String>; 5],
                    IterStash<'a, *mut *const c_char, Vec<String>>);

    fn to_glib_none(&self)
        -> Stash<'a, *mut ffi::C_GtkRecentData, &'a RecentData> {
        let display_name = self.display_name.to_glib_none();
        let description = self.description.to_glib_none();
        let mime_type = self.mime_type.to_glib_none();
        let app_name = self.app_name.to_glib_none();
        let app_exec = self.app_exec.to_glib_none();
        let groups = self.groups.to_glib_none();

        let mut data = Box::new(ffi::C_GtkRecentData {
            display_name: display_name.0 as *mut c_char,
            description: description.0 as *mut c_char,
            mime_type: mime_type.0 as *mut c_char,
            app_name: app_name.0 as *mut c_char,
            app_exec: app_exec.0 as *mut c_char,
            groups: groups.0 as *mut *mut c_char,
            is_private: self.is_private.to_glib(),
        });

        Stash(&mut *data, (data, [display_name, description, mime_type,
                                  app_name, app_exec], groups))
    }
}
<|endoftext|>


<commit_before>//! VM implementation, traits and structs
//!
//! ### Lifecycle
//!
//! A VM can be started given a `Context` and a `BlockHeader`. The
//! user can then `fire` or `step` to run it. Those functions would
//! only fail if it needs some information (accounts in the current
//! block, or block hashes of previous blocks). If this happens, one
//! can use the function `commit_account` and `commit_blockhash` to
//! commit those information to the VM, and `fire` or `step` again
//! until it succeeds. The current VM status can always be obtained
//! using the `status` function.

mod memory;
mod stack;
mod pc;
mod storage;
mod params;
mod eval;
mod commit;
mod patch;
pub mod errors;

pub use self::memory::{Memory, SeqMemory};
pub use self::stack::Stack;
pub use self::pc::{PC, Instruction};
pub use self::storage::Storage;
pub use self::params::*;
pub use self::patch::*;
pub use self::eval::{State, Machine, MachineStatus};
pub use self::commit::{AccountCommitment, Account};

use std::collections::hash_map;
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use self::errors::{RequireError, CommitError, VMError};

/// A sequencial VM. It uses sequencial memory representation and hash
/// map storage for accounts.
pub type SeqVM = VM<SeqMemory>;

/// A VM that executes using a context and block information.
pub struct VM<M>(Vec<Machine<M>>, Vec<Context>);

#[derive(Debug, Clone)]
/// VM Status
pub enum VMStatus {
    /// A running VM.
    Running,
    /// VM is stopped with out errors.
    ExitedOk,
    /// VM is stopped due to an error. The state of the VM is before
    /// the last failing instruction.
    ExitedErr(VMError),
}

impl<M: Memory + Default> VM<M> {
    /// Create a new VM using the given context, block header and patch.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch) -> VM<M> {
        let mut machines = Vec::new();
        machines.push(Machine::new(context, block, patch, 1));
        VM(machines, Vec::new())
    }

    /// Commit an account information to this VM. This should only be
    /// used when receiving `RequireError`.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_account(commitment.clone())?;
        }
        Ok(())
    }

    /// Commit a block hash to this VM. This should only be used when
    /// receiving `RequireError`.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_blockhash(number, hash)?;
        }
        Ok(())
    }

    /// Returns the current status of the VM.
    pub fn status(&self) -> VMStatus {
        match self.0[0].status() {
            MachineStatus::Running | MachineStatus::InvokeCreate(_) | MachineStatus::InvokeCall(_, _) => VMStatus::Running,
            MachineStatus::ExitedOk => VMStatus::ExitedOk,
            MachineStatus::ExitedErr(err) => VMStatus::ExitedErr(err.into()),
        }
    }

    /// Run one instruction and return. If it succeeds, VM status can
    /// still be `Running`. If the call stack has more than one items,
    /// this will only executes the last items' one single
    /// instruction.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match self.0.last().unwrap().status().clone() {
            MachineStatus::Running => {
                self.0.last_mut().unwrap().step()
            },
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => {
                if self.0.len() <= 1 {
                    Ok(())
                } else {
                    let finished = self.0.pop().unwrap();
                    self.0.last_mut().unwrap().apply_sub(finished);
                    Ok(())
                }
            },
            MachineStatus::InvokeCall(context, _) | MachineStatus::InvokeCreate(context) => {
                self.1.push(context.clone());
                let sub = self.0.last().unwrap().derive(context);
                self.0.push(sub);
                Ok(())
            },
        }
    }

    /// Run instructions until it reaches a `RequireError` or
    /// exits. If this function succeeds, the VM status can only be
    /// either `ExitedOk` or `ExitedErr`.
    pub fn fire(&mut self) -> Result<(), RequireError> {
        loop {
            match self.status() {
                VMStatus::Running => self.step()?,
                VMStatus::ExitedOk | VMStatus::ExitedErr(_) => return Ok(()),
            }
        }
    }

    /// Returns the changed or committed accounts information up to
    /// current execution status.
    pub fn accounts(&self) -> hash_map::Values<Address, Account> {
        self.0[0].state().account_state.accounts()
    }

    /// Returns the out value, if any.
    pub fn out(&self) -> &[u8] {
        self.0[0].state().out.as_slice()
    }

    /// Returns the available gas of this VM.
    pub fn available_gas(&self) -> Gas {
        self.0[0].state().available_gas()
    }

    /// Returns the used gas of this VM.
    pub fn used_gas(&self) -> Gas {
        self.0[0].state().used_gas
    }

    /// Returns the refunded gas of this VM.
    pub fn refunded_gas(&self) -> Gas {
        self.0[0].state().refunded_gas
    }

    /// Returns logs to be appended to the current block if the user
    /// decided to accept the running status of this VM.
    pub fn logs(&self) -> &[Log] {
        self.0[0].state().logs.as_slice()
    }

    /// Returns the call create history. Only used in testing.
    pub fn history(&self) -> &[Context] {
        self.1.as_slice()
    }
}
<commit_msg>Problem: VM's self.0 is not totally clear<commit_after>//! VM implementation, traits and structs
//!
//! ### Lifecycle
//!
//! A VM can be started given a `Context` and a `BlockHeader`. The
//! user can then `fire` or `step` to run it. Those functions would
//! only fail if it needs some information (accounts in the current
//! block, or block hashes of previous blocks). If this happens, one
//! can use the function `commit_account` and `commit_blockhash` to
//! commit those information to the VM, and `fire` or `step` again
//! until it succeeds. The current VM status can always be obtained
//! using the `status` function.

mod memory;
mod stack;
mod pc;
mod storage;
mod params;
mod eval;
mod commit;
mod patch;
pub mod errors;

pub use self::memory::{Memory, SeqMemory};
pub use self::stack::Stack;
pub use self::pc::{PC, Instruction};
pub use self::storage::Storage;
pub use self::params::*;
pub use self::patch::*;
pub use self::eval::{State, Machine, MachineStatus};
pub use self::commit::{AccountCommitment, Account};

use std::collections::hash_map;
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use self::errors::{RequireError, CommitError, VMError};

/// A sequencial VM. It uses sequencial memory representation and hash
/// map storage for accounts.
pub type SeqVM = VM<SeqMemory>;

/// A VM that executes using a context and block information.
pub struct VM<M> {
    machines: Vec<Machine<M>>,
    history: Vec<Context>
}

#[derive(Debug, Clone)]
/// VM Status
pub enum VMStatus {
    /// A running VM.
    Running,
    /// VM is stopped with out errors.
    ExitedOk,
    /// VM is stopped due to an error. The state of the VM is before
    /// the last failing instruction.
    ExitedErr(VMError),
}

impl<M: Memory + Default> VM<M> {
    /// Create a new VM using the given context, block header and patch.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch) -> VM<M> {
        let mut machines = Vec::new();
        machines.push(Machine::new(context, block, patch, 1));
        VM {
            machines,
            history: Vec::new()
        }
    }

    /// Commit an account information to this VM. This should only be
    /// used when receiving `RequireError`.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        for machine in &mut self.machines {
            machine.commit_account(commitment.clone())?;
        }
        Ok(())
    }

    /// Commit a block hash to this VM. This should only be used when
    /// receiving `RequireError`.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        for machine in &mut self.machines {
            machine.commit_blockhash(number, hash)?;
        }
        Ok(())
    }

    /// Returns the current status of the VM.
    pub fn status(&self) -> VMStatus {
        match self.machines[0].status() {
            MachineStatus::Running | MachineStatus::InvokeCreate(_) | MachineStatus::InvokeCall(_, _) => VMStatus::Running,
            MachineStatus::ExitedOk => VMStatus::ExitedOk,
            MachineStatus::ExitedErr(err) => VMStatus::ExitedErr(err.into()),
        }
    }

    /// Run one instruction and return. If it succeeds, VM status can
    /// still be `Running`. If the call stack has more than one items,
    /// this will only executes the last items' one single
    /// instruction.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match self.machines.last().unwrap().status().clone() {
            MachineStatus::Running => {
                self.machines.last_mut().unwrap().step()
            },
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => {
                if self.machines.len() <= 1 {
                    Ok(())
                } else {
                    let finished = self.machines.pop().unwrap();
                    self.machines.last_mut().unwrap().apply_sub(finished);
                    Ok(())
                }
            },
            MachineStatus::InvokeCall(context, _) | MachineStatus::InvokeCreate(context) => {
                self.history.push(context.clone());
                let sub = self.machines.last().unwrap().derive(context);
                self.machines.push(sub);
                Ok(())
            },
        }
    }

    /// Run instructions until it reaches a `RequireError` or
    /// exits. If this function succeeds, the VM status can only be
    /// either `ExitedOk` or `ExitedErr`.
    pub fn fire(&mut self) -> Result<(), RequireError> {
        loop {
            match self.status() {
                VMStatus::Running => self.step()?,
                VMStatus::ExitedOk | VMStatus::ExitedErr(_) => return Ok(()),
            }
        }
    }

    /// Returns the changed or committed accounts information up to
    /// current execution status.
    pub fn accounts(&self) -> hash_map::Values<Address, Account> {
        self.machines[0].state().account_state.accounts()
    }

    /// Returns the out value, if any.
    pub fn out(&self) -> &[u8] {
        self.machines[0].state().out.as_slice()
    }

    /// Returns the available gas of this VM.
    pub fn available_gas(&self) -> Gas {
        self.machines[0].state().available_gas()
    }

    /// Returns the used gas of this VM.
    pub fn used_gas(&self) -> Gas {
        self.machines[0].state().used_gas
    }

    /// Returns the refunded gas of this VM.
    pub fn refunded_gas(&self) -> Gas {
        self.machines[0].state().refunded_gas
    }

    /// Returns logs to be appended to the current block if the user
    /// decided to accept the running status of this VM.
    pub fn logs(&self) -> &[Log] {
        self.machines[0].state().logs.as_slice()
    }

    /// Returns the call create history. Only used in testing.
    pub fn history(&self) -> &[Context] {
        self.history.as_slice()
    }
}
<|endoftext|>


<commit_before>//! The `ast` module contains a lot of useful functionality
//! to create and walk through the ast (abstract syntaxtree)

use frontend::lexer::Token;
use backend::zcode::zfile;
use backend::zcode::zfile::{FormattingState, ZOP};
use std::collections::HashMap;

//==============================
// ast

pub struct AST {
    passages: Vec<ASTNode>
}

 /// add zcode based on tokens
fn gen_zcode<'a>(node: &'a ASTNode, mut out: &mut zfile::Zfile, mut manager: &mut CodeGenManager<'a>) -> Vec<ZOP> {
    let mut state_copy = manager.format_state.clone();
    let mut set_formatting = false;

    match node {
        &ASTNode::Passage(ref node) => {
            let mut code: Vec<ZOP> = vec![];
            match &node.category {
                &Token::TokPassageName(ref name) => {
                    code.push(ZOP::Routine{name: name.to_string(), count_variables: 0});
                },
                _ => {
                    debug!("no match 1");
                }
            };

            for child in &node.childs {
                for instr in gen_zcode(child, out, manager) {
                    code.push(instr);
                }

            }

            code.push(ZOP::Newline);
            code.push(ZOP::Call{jump_to_label: "system_check_links".to_string()});
            code
        },
        &ASTNode::Default(ref t) => {
            let mut code: Vec<ZOP> = match &t.category {
                &Token::TokText(ref s) => {
                    vec![ZOP::PrintOps{text: s.to_string()}]
                },
                &Token::TokNewLine => {
                    vec![ZOP::Newline]
                },
                &Token::TokFormatBoldStart => {
                    state_copy.bold = true;
                    set_formatting = true;
                    vec![ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}]
                },
                &Token::TokFormatItalicStart => {
                    state_copy.italic = true;
                    set_formatting = true;
                    vec![ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}]
                },
                &Token::TokPassageLink (ref name, ref link) => {
                    set_formatting = true;
                    vec![
                    ZOP::CallWithAddress{jump_to_label: "system_add_link".to_string(), address: link.to_string()},
                    ZOP::SetTextStyle{bold: state_copy.bold, reverse: true, monospace: state_copy.mono, italic: state_copy.italic},
                    ZOP::Print{text: format!("{}[", name)},
                    ZOP::PrintNumVar{variable: 16},
                    ZOP::Print{text: "]".to_string()},
                    ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}
                    ]
                },
                &Token::TokAssign(ref var, ref operator) => {
                    if operator == "=" || operator == "to" {
                        if !manager.symbol_table.is_known_symbol(var) {
                            manager.symbol_table.insert_new_symbol(&var);
                        }
                        let symbol_id = manager.symbol_table.get_symbol_id(var);
                        if t.childs.len() == 1 {
                            match t.childs[0].as_default().category {
                                Token::TokInt(value) => {
                                    vec![ZOP::StoreU16{variable: symbol_id, value: value as u16}]
                                },
                                Token::TokBoolean(ref bool_val) => {
                                    vec![ZOP::StoreU8{variable: symbol_id, value: boolstr_to_u8(&*bool_val)}]
                                }
                                _ => { vec![] }
                            }
                        } else {
                            debug!("Assign Expression currently not supported.");
                            vec![]
                        }

                    } else { vec![] }
                },
                &Token::TokIf => {
                    if t.childs.len() < 2 {
                        panic!("Unsupported if-expression!");
                    }

                    let mut compare: u8 = 1;

                    // check if the first node is a pseudonode
                    let pseudo_node = match t.childs[0].as_default().category {
                        Token::TokPseudo => t.childs[0].as_default(),
                        _ =>  panic!("Unsupported if-expression!")
                    };

                    // Check if first token is variable
                    let var_name = match pseudo_node.childs[0].as_default().category {
                        Token::TokVariable(ref var) => var,
                        _ =>  panic!("Unsupported if-expression!")
                    };

                    if pseudo_node.childs.len() > 1 {
                        // Check if second token is compare operator
                        match pseudo_node.childs[1].as_default().category {
                            Token::TokCompOp(ref op) => {
                                match &*(*op) {
                                    "==" | "is" => {} ,
                                    _ => panic!("Unsupported Compare Operator!")
                                }
                            }, _ =>  panic!("Unsupported if-expression!")
                        }

                        // Check if third token is number
                        compare = match pseudo_node.childs[2].as_default().category {
                            Token::TokInt(ref value) => {
                                *value as u8
                            },
                            Token::TokBoolean(ref bool_val) => {
                                boolstr_to_u8(&*bool_val)
                            }, _ => panic!("Unsupported assign value!")
                        };
                    }

                    let symbol_id = manager.symbol_table.get_symbol_id(&*var_name);
                    let if_id = manager.ids_if.start_next();

                    let if_label = format!("if_{}", if_id);
                    let after_if_label = format!("after_if_{}", if_id);
                    let after_else_label = format!("after_else_{}", if_id);
                    let mut code: Vec<ZOP> = vec![
                        ZOP::JE{local_var_id: symbol_id, equal_to_const: compare, jump_to_label: if_label.to_string()},
                        ZOP::Jump{jump_to_label: after_if_label.to_string()},
                        ZOP::Label{name: if_label.to_string()}
                    ];

                    for i in 1..t.childs.len() {
                        for instr in gen_zcode(&t.childs[i], out, manager) {
                            code.push(instr);
                        }
                    }

                    code.push(ZOP::Jump{jump_to_label: after_else_label.to_string()});
                    code.push(ZOP::Label{name: after_if_label.to_string()});
                    code
                },
                &Token::TokElse => {
                    let mut code: Vec<ZOP> = vec![];
                    for child in &t.childs {
                        for instr in gen_zcode(child, out, manager) {
                            code.push(instr);
                        }
                    }
                    code
                },
                &Token::TokEndIf => {
                    let after_else_label = format!("after_else_{}", manager.ids_if.pop_id());
                    vec![ZOP::Label{name: after_else_label}]
                },
                _ => {
                    debug!("no match 2");
                    vec![]
                }
            };
            if set_formatting {
                for child in &t.childs {
                    for instr in gen_zcode(child, out, manager) {
                        code.push(instr);
                    }
                }
                code.push(ZOP::SetTextStyle{bold: false, reverse: false, monospace: false, italic: false});
                let state = manager.format_state;
                code.push(ZOP::SetTextStyle{bold: state.bold, reverse: state.inverted, monospace: state.mono, italic: state.italic});
            }
            code
        }
    }

}

fn boolstr_to_u8(string: &str) -> u8 {
    match string {
        "true" => 1 as u8,
        _ => 0 as u8
    }
}

impl AST {
    /// convert ast to zcode
    pub fn to_zcode(& self, out: &mut zfile::Zfile) {
        let mut manager = CodeGenManager::new();
        let mut code: Vec<ZOP> = vec![];
        for child in &self.passages {
            for instr in gen_zcode(child, out, &mut manager) {
                code.push(instr);
            }
        }
        debug!("emit zcode:");
        for instr in &code {
            debug!("{:?}", instr);
        }
        out.emit(code);
    }

    pub fn new() -> AST {
        AST {
            passages: Vec::new()
        }
    }

    /// prints the tree
    pub fn print(&self) {
        debug!("Abstract Syntax Tree: ");
        for child in &self.passages {
            child.print(0);
        }
        debug!("");
    }

    /// adds a passage to the path in the ast
    pub fn add_passage(&mut self, token: Token) {
        let node = ASTNode::Passage(NodePassage { category: token, childs: Vec::new() });
        self.passages.push(node);
    }

    /// adds a child to the path in the ast
    pub fn add_child(&mut self, path: &Vec<usize>, token: Token) {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            self.passages[*index].add_child(new_path, token)
        } else {
            self.passages.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() }));
        }
    }

    /// counts the childs of the path in the asts
    pub fn count_childs(&self, path: Vec<usize>) -> usize {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            self.passages[*index].count_childs(new_path)
        } else {
            self.passages.len()
        }
    }
}

// ================================
// node types
enum ASTNode {
    Default (NodeDefault),
    Passage (NodePassage)
}

struct NodePassage {
    category: Token,
    pub childs: Vec<ASTNode>,
    /*tags: Vec<ASTNode>*/
}

struct NodeDefault {
    category: Token,
    childs: Vec<ASTNode>
}

struct CodeGenManager<'a> {
    ids_if: IdentifierProvider,
    symbol_table: SymbolTable<'a>,
    format_state: FormattingState
}

struct IdentifierProvider {
    current_id: u32,
    id_stack: Vec<u32>
}

struct SymbolTable<'a> {
    current_id: u8,
    symbol_map: HashMap<&'a str, u8>
}

impl <'a> CodeGenManager<'a> {
    pub fn new() -> CodeGenManager<'a> {
        CodeGenManager {
            ids_if: IdentifierProvider::new(),
            symbol_table: SymbolTable::new(),
            format_state: FormattingState {bold: false, italic: false, mono: false, inverted: false}
        }
    }
}

impl IdentifierProvider {
    pub fn new() -> IdentifierProvider {
        IdentifierProvider {
            current_id: 0,
            id_stack: Vec::new()
        }
    }

    // Returns a new id and pushes it onto the stack
    pub fn start_next(&mut self) -> u32 {
        let id = self.current_id;
        self.current_id += 1;
        self.id_stack.push(id);
        id
    }

    // Pops the last id from the stack
    pub fn pop_id(&mut self) -> u32 {
        self.id_stack.pop().unwrap()
    }
}

impl <'a> SymbolTable<'a> {
    pub fn new() -> SymbolTable<'a> {
        SymbolTable {
            current_id: 25,
            symbol_map: HashMap::<&str, u8>::new()
        }
    }

    // Inserts a symbol into the table, assigning a new id
    pub fn insert_new_symbol(&mut self, symbol: &'a str) {
        debug!("Assigned id {} to variable {}", self.current_id, symbol);
        self.symbol_map.insert(symbol, self.current_id);
        self.current_id += 1;
    }

    // Checks if the symbol is already existent in the table
    pub fn is_known_symbol(&self, symbol: &str) -> bool {
        self.symbol_map.contains_key(symbol)
    }

    // Returns the id for a given symbol
    // (check if is_known_symbol, otherwise panics)
    pub fn get_symbol_id(&self, symbol: &str) -> u8 {
        *self.symbol_map.get(symbol).unwrap()
    }
}

impl ASTNode {
    /// adds an child to the path in the ast
    pub fn add_child(&mut self, path: Vec<usize>, token: Token) {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            match self {
                &mut ASTNode::Default(ref mut node) => node.childs[*index].add_child(new_path, token),
                &mut ASTNode::Passage(ref mut node) => node.childs[*index].add_child(new_path, token),
            }
        } else {
            match self {
                &mut ASTNode::Default(ref mut node) => node.childs.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() } )),
                &mut ASTNode::Passage(ref mut node) => node.childs.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() } )),
            }
        }
    }

    /// counts the childs of the current path in the ast
    pub fn count_childs(&self, path: Vec<usize>) -> usize {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            match self {
                &ASTNode::Default(ref node) => node.childs[*index].count_childs(new_path),
                &ASTNode::Passage(ref node) => node.childs[*index].count_childs(new_path),
            }
        } else {
            match self {
                &ASTNode::Default(ref node) => node.childs.len(),
                &ASTNode::Passage(ref node) => node.childs.len(),
            }
        }
    }

    /// prints an node of an ast
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &ASTNode::Passage(ref t) => {
                debug!("{}|- : {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            },
            &ASTNode::Default(ref t) => {
                debug!("{}|- : {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            }
        }
    }

    pub fn as_default(&self) -> &NodeDefault {
        match self {
            &ASTNode::Default(ref def) => def,
            _ => panic!("Node cannot be unwrapped as NodeDefault!")
        }
    }
}
<commit_msg>remove whitespace and unnecessary string copy<commit_after>//! The `ast` module contains a lot of useful functionality
//! to create and walk through the ast (abstract syntaxtree)

use frontend::lexer::Token;
use backend::zcode::zfile;
use backend::zcode::zfile::{FormattingState, ZOP};
use std::collections::HashMap;

//==============================
// ast

pub struct AST {
    passages: Vec<ASTNode>
}

 /// add zcode based on tokens
fn gen_zcode<'a>(node: &'a ASTNode, mut out: &mut zfile::Zfile, mut manager: &mut CodeGenManager<'a>) -> Vec<ZOP> {
    let mut state_copy = manager.format_state.clone();
    let mut set_formatting = false;

    match node {
        &ASTNode::Passage(ref node) => {
            let mut code: Vec<ZOP> = vec![];
            match &node.category {
                &Token::TokPassageName(ref name) => {
                    code.push(ZOP::Routine{name: name.to_string(), count_variables: 0});
                },
                _ => {
                    debug!("no match 1");
                }
            };

            for child in &node.childs {
                for instr in gen_zcode(child, out, manager) {
                    code.push(instr);
                }

            }

            code.push(ZOP::Newline);
            code.push(ZOP::Call{jump_to_label: "system_check_links".to_string()});
            code
        },
        &ASTNode::Default(ref t) => {
            let mut code: Vec<ZOP> = match &t.category {
                &Token::TokText(ref s) => {
                    vec![ZOP::PrintOps{text: s.to_string()}]
                },
                &Token::TokNewLine => {
                    vec![ZOP::Newline]
                },
                &Token::TokFormatBoldStart => {
                    state_copy.bold = true;
                    set_formatting = true;
                    vec![ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}]
                },
                &Token::TokFormatItalicStart => {
                    state_copy.italic = true;
                    set_formatting = true;
                    vec![ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}]
                },
                &Token::TokPassageLink (ref name, ref link) => {
                    set_formatting = true;
                    vec![
                    ZOP::CallWithAddress{jump_to_label: "system_add_link".to_string(), address: link.to_string()},
                    ZOP::SetTextStyle{bold: state_copy.bold, reverse: true, monospace: state_copy.mono, italic: state_copy.italic},
                    ZOP::Print{text: format!("{}[", name)},
                    ZOP::PrintNumVar{variable: 16},
                    ZOP::Print{text: "]".to_string()},
                    ZOP::SetTextStyle{bold: state_copy.bold, reverse: state_copy.inverted, monospace: state_copy.mono, italic: state_copy.italic}
                    ]
                },
                &Token::TokAssign(ref var, ref operator) => {
                    if operator == "=" || operator == "to" {
                        if !manager.symbol_table.is_known_symbol(var) {
                            manager.symbol_table.insert_new_symbol(&var);
                        }
                        let symbol_id = manager.symbol_table.get_symbol_id(var);
                        if t.childs.len() == 1 {
                            match t.childs[0].as_default().category {
                                Token::TokInt(value) => {
                                    vec![ZOP::StoreU16{variable: symbol_id, value: value as u16}]
                                },
                                Token::TokBoolean(ref bool_val) => {
                                    vec![ZOP::StoreU8{variable: symbol_id, value: boolstr_to_u8(&*bool_val)}]
                                }
                                _ => { vec![] }
                            }
                        } else {
                            debug!("Assign Expression currently not supported.");
                            vec![]
                        }
                    } else { vec![] }
                },
                &Token::TokIf => {
                    if t.childs.len() < 2 {
                        panic!("Unsupported if-expression!");
                    }

                    let mut compare: u8 = 1;

                    // check if the first node is a pseudonode
                    let pseudo_node = match t.childs[0].as_default().category {
                        Token::TokPseudo => t.childs[0].as_default(),
                        _ =>  panic!("Unsupported if-expression!")
                    };

                    // Check if first token is variable
                    let var_name = match pseudo_node.childs[0].as_default().category {
                        Token::TokVariable(ref var) => var,
                        _ =>  panic!("Unsupported if-expression!")
                    };

                    if pseudo_node.childs.len() > 1 {
                        // Check if second token is compare operator
                        match pseudo_node.childs[1].as_default().category {
                            Token::TokCompOp(ref op) => {
                                match &*(*op) {
                                    "==" | "is" => {} ,
                                    _ => panic!("Unsupported Compare Operator!")
                                }
                            }, _ =>  panic!("Unsupported if-expression!")
                        }

                        // Check if third token is number
                        compare = match pseudo_node.childs[2].as_default().category {
                            Token::TokInt(ref value) => {
                                *value as u8
                            },
                            Token::TokBoolean(ref bool_val) => {
                                boolstr_to_u8(&*bool_val)
                            }, _ => panic!("Unsupported assign value!")
                        };
                    }

                    let symbol_id = manager.symbol_table.get_symbol_id(&*var_name);
                    let if_id = manager.ids_if.start_next();

                    let if_label = format!("if_{}", if_id);
                    let after_if_label = format!("after_if_{}", if_id);
                    let after_else_label = format!("after_else_{}", if_id);
                    let mut code: Vec<ZOP> = vec![
                        ZOP::JE{local_var_id: symbol_id, equal_to_const: compare, jump_to_label: if_label.to_string()},
                        ZOP::Jump{jump_to_label: after_if_label.to_string()},
                        ZOP::Label{name: if_label.to_string()}
                    ];

                    for i in 1..t.childs.len() {
                        for instr in gen_zcode(&t.childs[i], out, manager) {
                            code.push(instr);
                        }
                    }

                    code.push(ZOP::Jump{jump_to_label: after_else_label});
                    code.push(ZOP::Label{name: after_if_label});
                    code
                },
                &Token::TokElse => {
                    let mut code: Vec<ZOP> = vec![];
                    for child in &t.childs {
                        for instr in gen_zcode(child, out, manager) {
                            code.push(instr);
                        }
                    }
                    code
                },
                &Token::TokEndIf => {
                    let after_else_label = format!("after_else_{}", manager.ids_if.pop_id());
                    vec![ZOP::Label{name: after_else_label}]
                },
                _ => {
                    debug!("no match 2");
                    vec![]
                }
            };
            if set_formatting {
                for child in &t.childs {
                    for instr in gen_zcode(child, out, manager) {
                        code.push(instr);
                    }
                }
                code.push(ZOP::SetTextStyle{bold: false, reverse: false, monospace: false, italic: false});
                let state = manager.format_state;
                code.push(ZOP::SetTextStyle{bold: state.bold, reverse: state.inverted, monospace: state.mono, italic: state.italic});
            }
            code
        }
    }

}

fn boolstr_to_u8(string: &str) -> u8 {
    match string {
        "true" => 1 as u8,
        _ => 0 as u8
    }
}

impl AST {
    /// convert ast to zcode
    pub fn to_zcode(& self, out: &mut zfile::Zfile) {
        let mut manager = CodeGenManager::new();
        let mut code: Vec<ZOP> = vec![];
        for child in &self.passages {
            for instr in gen_zcode(child, out, &mut manager) {
                code.push(instr);
            }
        }
        debug!("emit zcode:");
        for instr in &code {
            debug!("{:?}", instr);
        }
        out.emit(code);
    }

    pub fn new() -> AST {
        AST {
            passages: Vec::new()
        }
    }

    /// prints the tree
    pub fn print(&self) {
        debug!("Abstract Syntax Tree: ");
        for child in &self.passages {
            child.print(0);
        }
        debug!("");
    }

    /// adds a passage to the path in the ast
    pub fn add_passage(&mut self, token: Token) {
        let node = ASTNode::Passage(NodePassage { category: token, childs: Vec::new() });
        self.passages.push(node);
    }

    /// adds a child to the path in the ast
    pub fn add_child(&mut self, path: &Vec<usize>, token: Token) {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            self.passages[*index].add_child(new_path, token)
        } else {
            self.passages.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() }));
        }
    }

    /// counts the childs of the path in the asts
    pub fn count_childs(&self, path: Vec<usize>) -> usize {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            self.passages[*index].count_childs(new_path)
        } else {
            self.passages.len()
        }
    }
}

// ================================
// node types
enum ASTNode {
    Default (NodeDefault),
    Passage (NodePassage)
}

struct NodePassage {
    category: Token,
    pub childs: Vec<ASTNode>,
    /*tags: Vec<ASTNode>*/
}

struct NodeDefault {
    category: Token,
    childs: Vec<ASTNode>
}

struct CodeGenManager<'a> {
    ids_if: IdentifierProvider,
    symbol_table: SymbolTable<'a>,
    format_state: FormattingState
}

struct IdentifierProvider {
    current_id: u32,
    id_stack: Vec<u32>
}

struct SymbolTable<'a> {
    current_id: u8,
    symbol_map: HashMap<&'a str, u8>
}

impl <'a> CodeGenManager<'a> {
    pub fn new() -> CodeGenManager<'a> {
        CodeGenManager {
            ids_if: IdentifierProvider::new(),
            symbol_table: SymbolTable::new(),
            format_state: FormattingState {bold: false, italic: false, mono: false, inverted: false}
        }
    }
}

impl IdentifierProvider {
    pub fn new() -> IdentifierProvider {
        IdentifierProvider {
            current_id: 0,
            id_stack: Vec::new()
        }
    }

    // Returns a new id and pushes it onto the stack
    pub fn start_next(&mut self) -> u32 {
        let id = self.current_id;
        self.current_id += 1;
        self.id_stack.push(id);
        id
    }

    // Pops the last id from the stack
    pub fn pop_id(&mut self) -> u32 {
        self.id_stack.pop().unwrap()
    }
}

impl <'a> SymbolTable<'a> {
    pub fn new() -> SymbolTable<'a> {
        SymbolTable {
            current_id: 25,
            symbol_map: HashMap::<&str, u8>::new()
        }
    }

    // Inserts a symbol into the table, assigning a new id
    pub fn insert_new_symbol(&mut self, symbol: &'a str) {
        debug!("Assigned id {} to variable {}", self.current_id, symbol);
        self.symbol_map.insert(symbol, self.current_id);
        self.current_id += 1;
    }

    // Checks if the symbol is already existent in the table
    pub fn is_known_symbol(&self, symbol: &str) -> bool {
        self.symbol_map.contains_key(symbol)
    }

    // Returns the id for a given symbol
    // (check if is_known_symbol, otherwise panics)
    pub fn get_symbol_id(&self, symbol: &str) -> u8 {
        *self.symbol_map.get(symbol).unwrap()
    }
}

impl ASTNode {
    /// adds an child to the path in the ast
    pub fn add_child(&mut self, path: Vec<usize>, token: Token) {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            match self {
                &mut ASTNode::Default(ref mut node) => node.childs[*index].add_child(new_path, token),
                &mut ASTNode::Passage(ref mut node) => node.childs[*index].add_child(new_path, token),
            }
        } else {
            match self {
                &mut ASTNode::Default(ref mut node) => node.childs.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() } )),
                &mut ASTNode::Passage(ref mut node) => node.childs.push(ASTNode::Default(NodeDefault { category: token, childs: Vec::new() } )),
            }
        }
    }

    /// counts the childs of the current path in the ast
    pub fn count_childs(&self, path: Vec<usize>) -> usize {
        if let Some(index) = path.first() {
            let mut new_path: Vec<usize> = path.to_vec();
            new_path.remove(0);

            match self {
                &ASTNode::Default(ref node) => node.childs[*index].count_childs(new_path),
                &ASTNode::Passage(ref node) => node.childs[*index].count_childs(new_path),
            }
        } else {
            match self {
                &ASTNode::Default(ref node) => node.childs.len(),
                &ASTNode::Passage(ref node) => node.childs.len(),
            }
        }
    }

    /// prints an node of an ast
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &ASTNode::Passage(ref t) => {
                debug!("{}|- : {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            },
            &ASTNode::Default(ref t) => {
                debug!("{}|- : {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            }
        }
    }

    pub fn as_default(&self) -> &NodeDefault {
        match self {
            &ASTNode::Default(ref def) => def,
            _ => panic!("Node cannot be unwrapped as NodeDefault!")
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate indep;
#[macro_use]
extern crate log;
//`sync` mod contains DI set for multi-threaded environments (uses Rc<RefCell<>> as an abstraction).

//We pretend that all the DI module traits and implementations are separated into different mods.

//Base trait for all depencencies. May contain no functions, `init` here is just an example.
pub mod base {
    pub trait Base {
        fn init(&mut self);
    }
}

//Sample trait #1
pub mod t1 {
    pub trait Trait1 {
        fn do1(&self);
    }
}

//Sample trait #1
pub mod t2 {
    pub trait Trait2 {
        fn do2(&self) -> String;
    }
}

//Sample trait #1
pub mod t3 {
    pub trait Trait3 {
        fn do3(&mut self);
    }
}

//Sample implementation struct #1 - implements trait #1 and trait #2 (and, of course, trait Base).
pub mod i1 {
    use super::{Dependency,Dependent,Implementation};

    use super::base::Base;
    use super::t1::Trait1;
    use super::t2::Trait2;

    use std::rc::Rc;
    use std::cell::RefCell;

    struct Impl1;

    impl Impl1 {
        pub fn foo(&self) {
            println!("foo from Impl1");
        }

        pub fn new() -> Impl1 {
            Impl1
        }
    }

    impl Trait1 for Box<Impl1> {
        fn do1(&self) {
            self.foo();
        }
    }

    impl Trait2 for Box<Impl1> {
        fn do2(&self) -> String {
            format!("Impl1 says 'Trait2'")
        }
    }

    impl Base for Box<Impl1> {
        fn init(&mut self) {
            self.foo();
        }
    }

    //Here comes `indep`.
    //This macro defines requirements of the DI module implementation.
    //The syntax is {Impl_Name, [requirement_name_1: requirement_trait_1, requirement_name_2: requirement_trait_2], ... }.
    //Here `Impl1` does not have dependecies, so its requirement array is empty.
    indep_reqs_sync!{Impl1, []}

    //This macro defines the implementations of the DI module. The syntax is {Impl_Name, Base_Trait_Name, [trait_1, trait_2, ... ]}
    //`Impl1` implements `Trait1` and `Trait2`, so it is stated in a macro.
    indep_impls_sync!{Impl1, Base, [Trait1,Trait2]}

    //This macro generates default implementation of the `new()` function, that returns Box<Dependency>.
    //The `Dependency` itself is an trait that DI pool accepts. Internally it is always implemented by a struct `RcRefCellBox`,
    //which is a wrapper for Rc<RefCell<Box<Impl1>>>. This wrapper is required for Rust typecasting.
    indep_default_new_sync!{Impl1}
}

//Sample implementation struct #2 - implements trait #2 (and trait Base). Depends on `Trait1` - see the mention of `indep_reqs_sync` below.
pub mod i2 {
    use super::{Dependency,Dependent,Implementation};

    use super::t1::Trait1;
    use super::t2::Trait2;
    use super::base::Base;

    use std::rc::Rc;
    use std::cell::RefCell;

    struct Impl2 {
    	//It is an Indep library requirement to have injectable dependencies in a form of Option<Rc<RefCell<Trait>>>
        t1: Option<Rc<RefCell<Trait1>>>
    }

    impl Impl2 {
        pub fn boo(&self) {
            println!("boo from Impl2");
            let b = self.t1.as_ref().unwrap();
            b.borrow().do1();
        }

        pub fn new() -> Impl2 {
            Impl2 {
                t1:None
            }
        }
    }

    impl Trait2 for Box<Impl2> {
        fn do2(&self) -> String {
            self.boo();
            format!("Impl2 says 'Trait2'")
        }
    }

    impl Base for Box<Impl2> {
        fn init(&mut self) {
            self.boo();
        }
    }

    //`Impl2` requires `Trait1` inside as member named `t1`. `t1` should have type Option<Rc<RefCell<Trait1>>>.
    indep_reqs_sync!{Impl2, [Trait1: [t1]]}

    //See corresponding statement for `Impl1` above. The implementation struct should (obviously) implement at least one DI trait.
    indep_impls_sync!{Impl2, Base, [Trait2]}

    //See corresponding statement for `Impl1` above.
    indep_default_new_sync!{Impl2}
}

//Sample implementation struct #3 - implements trait #3 (and trait Base). Depends on `Trait1` as `t1_1`,
//`Trait2` as `t2_1` and `t2_2` (sepatare instances) - see the mention of `indep_reqs_async` below.
pub mod i3 {
    use super::{Dependency,Dependent,Implementation};

    use super::t3::Trait3;
    use super::t2::Trait2;
    use super::t1::Trait1;
    use super::base::Base;

    use std::rc::Rc;
    use std::cell::RefCell;

    //It is an Indep library requirement to have injectable dependencies in a form of Option<Rc<RefCell<Trait>>>
    struct Impl3 {
        t2_1: Option<Rc<RefCell<Trait2>>>,
        t2_2: Option<Rc<RefCell<Trait2>>>,
        t1_1: Option<Rc<RefCell<Trait1>>>
    }

    impl Impl3 {
        pub fn oo(&mut self) {
            let b1 = self.t2_1.as_mut().unwrap();
            let b2 = self.t2_2.as_mut().unwrap();
            let b3 = self.t1_1.as_mut().unwrap();
            println!("oo from Impl3: \n1: {}\n2: {}",
                b1.borrow_mut().do2(),
                b2.borrow_mut().do2()
            );
            b3.borrow().do1();
        }

        pub fn new() -> Impl3 {
            Impl3 {
                t1_1: None,
                t2_1: None,
                t2_2: None,
            }
        }
    }

    impl Trait3 for Box<Impl3> {
        fn do3(&mut self) {
            self.oo();
        }
    }

    impl Base for Box<Impl3> {
        fn init(&mut self) {
            self.oo();
        }
    }

    //`Impl3` depends on `Trait1` and two different instances of `Trait2`.
    indep_reqs_sync!{Impl3, [Trait1: [t1_1], Trait2: [t2_1,t2_2]]}

    //See corresponding statement for `Impl1` above. The implementation struct should (obviously) implement at least one DI trait.
    indep_impls_sync!{Impl3, Base, [Trait3]}

    //See corresponding statement for `Impl1` above.
    indep_default_new_sync!{Impl3}
}

use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::{Display,Formatter,Result};

use self::t3::Trait3;
use self::t2::Trait2;
use self::t1::Trait1;
use self::base::Base;

//Initialize all the DI classes and traits  The syntax is {Base_Trait, Trait1, Trait2, ... }, where Trait# is a trait which needs to be DI-enabled.
indep_pool_sync!{Base, Trait1,Trait2,Trait3}

fn main() {
	//`Pool` is a structure created by `indep_pool_async` macro.
    let mut pool = Pool::new();

    let t1 = i1::new_dep();
    let t2 = i2::new_dep();
    let t3 = i3::new_dep();

    //Here we mark this struct with a special tag so it will be injected only to similarly named member of a dependent struct.
    pool.add_tagged(t1, vec!["t1_1".to_string()]);
    //Add DI dependency with no tag, which means it will be injected to any struct that has a dependency of the corresponding trait.
	pool.add(t2);
	//Same here.
	pool.add(t3);

	//`stat()` is a simple utility method of a `Pool` that shows its content name-wise.
	println!("Pool stat: {}", pool.stat());
}<commit_msg>Docu fixed<commit_after>#[macro_use]
extern crate indep;
#[macro_use]
extern crate log;
//`sync` mod contains DI set for single-threaded environments (uses Rc<RefCell<>> as an abstraction).

//We pretend that all the DI module traits and implementations are separated into different mods.

//Base trait for all depencencies. May contain no functions, `init` here is just an example.
pub mod base {
    pub trait Base {
        fn init(&mut self);
    }
}

//Sample trait #1
pub mod t1 {
    pub trait Trait1 {
        fn do1(&self);
    }
}

//Sample trait #1
pub mod t2 {
    pub trait Trait2 {
        fn do2(&self) -> String;
    }
}

//Sample trait #1
pub mod t3 {
    pub trait Trait3 {
        fn do3(&mut self);
    }
}

//Sample implementation struct #1 - implements trait #1 and trait #2 (and, of course, trait Base).
pub mod i1 {
    use super::{Dependency,Dependent,Implementation};

    use super::base::Base;
    use super::t1::Trait1;
    use super::t2::Trait2;

    use std::rc::Rc;
    use std::cell::RefCell;

    struct Impl1;

    impl Impl1 {
        pub fn foo(&self) {
            println!("foo from Impl1");
        }

        pub fn new() -> Impl1 {
            Impl1
        }
    }

    impl Trait1 for Box<Impl1> {
        fn do1(&self) {
            self.foo();
        }
    }

    impl Trait2 for Box<Impl1> {
        fn do2(&self) -> String {
            format!("Impl1 says 'Trait2'")
        }
    }

    impl Base for Box<Impl1> {
        fn init(&mut self) {
            self.foo();
        }
    }

    //Here comes `indep`.
    //This macro defines requirements of the DI module implementation.
    //The syntax is {Impl_Name, [requirement_name_1: requirement_trait_1, requirement_name_2: requirement_trait_2], ... }.
    //Here `Impl1` does not have dependecies, so its requirement array is empty.
    indep_reqs_sync!{Impl1, []}

    //This macro defines the implementations of the DI module. The syntax is {Impl_Name, Base_Trait_Name, [trait_1, trait_2, ... ]}
    //`Impl1` implements `Trait1` and `Trait2`, so it is stated in a macro.
    indep_impls_sync!{Impl1, Base, [Trait1,Trait2]}

    //This macro generates default implementation of the `new()` function, that returns Box<Dependency>.
    //The `Dependency` itself is an trait that DI pool accepts. Internally it is always implemented by a struct `RcRefCellBox`,
    //which is a wrapper for Rc<RefCell<Box<Impl1>>>. This wrapper is required for Rust typecasting.
    indep_default_new_sync!{Impl1}
}

//Sample implementation struct #2 - implements trait #2 (and trait Base). Depends on `Trait1` - see the mention of `indep_reqs_sync` below.
pub mod i2 {
    use super::{Dependency,Dependent,Implementation};

    use super::t1::Trait1;
    use super::t2::Trait2;
    use super::base::Base;

    use std::rc::Rc;
    use std::cell::RefCell;

    struct Impl2 {
    	//It is an Indep library requirement to have injectable dependencies in a form of Option<Rc<RefCell<Trait>>>
        t1: Option<Rc<RefCell<Trait1>>>
    }

    impl Impl2 {
        pub fn boo(&self) {
            println!("boo from Impl2");
            let b = self.t1.as_ref().unwrap();
            b.borrow().do1();
        }

        pub fn new() -> Impl2 {
            Impl2 {
                t1:None
            }
        }
    }

    impl Trait2 for Box<Impl2> {
        fn do2(&self) -> String {
            self.boo();
            format!("Impl2 says 'Trait2'")
        }
    }

    impl Base for Box<Impl2> {
        fn init(&mut self) {
            self.boo();
        }
    }

    //`Impl2` requires `Trait1` inside as member named `t1`. `t1` should have type Option<Rc<RefCell<Trait1>>>.
    indep_reqs_sync!{Impl2, [Trait1: [t1]]}

    //See corresponding statement for `Impl1` above. The implementation struct should (obviously) implement at least one DI trait.
    indep_impls_sync!{Impl2, Base, [Trait2]}

    //See corresponding statement for `Impl1` above.
    indep_default_new_sync!{Impl2}
}

//Sample implementation struct #3 - implements trait #3 (and trait Base). Depends on `Trait1` as `t1_1`,
//`Trait2` as `t2_1` and `t2_2` (sepatare instances) - see the mention of `indep_reqs_async` below.
pub mod i3 {
    use super::{Dependency,Dependent,Implementation};

    use super::t3::Trait3;
    use super::t2::Trait2;
    use super::t1::Trait1;
    use super::base::Base;

    use std::rc::Rc;
    use std::cell::RefCell;

    //It is an Indep library requirement to have injectable dependencies in a form of Option<Rc<RefCell<Trait>>>
    struct Impl3 {
        t2_1: Option<Rc<RefCell<Trait2>>>,
        t2_2: Option<Rc<RefCell<Trait2>>>,
        t1_1: Option<Rc<RefCell<Trait1>>>
    }

    impl Impl3 {
        pub fn oo(&mut self) {
            let b1 = self.t2_1.as_mut().unwrap();
            let b2 = self.t2_2.as_mut().unwrap();
            let b3 = self.t1_1.as_mut().unwrap();
            println!("oo from Impl3: \n1: {}\n2: {}",
                b1.borrow_mut().do2(),
                b2.borrow_mut().do2()
            );
            b3.borrow().do1();
        }

        pub fn new() -> Impl3 {
            Impl3 {
                t1_1: None,
                t2_1: None,
                t2_2: None,
            }
        }
    }

    impl Trait3 for Box<Impl3> {
        fn do3(&mut self) {
            self.oo();
        }
    }

    impl Base for Box<Impl3> {
        fn init(&mut self) {
            self.oo();
        }
    }

    //`Impl3` depends on `Trait1` and two different instances of `Trait2`.
    indep_reqs_sync!{Impl3, [Trait1: [t1_1], Trait2: [t2_1,t2_2]]}

    //See corresponding statement for `Impl1` above. The implementation struct should (obviously) implement at least one DI trait.
    indep_impls_sync!{Impl3, Base, [Trait3]}

    //See corresponding statement for `Impl1` above.
    indep_default_new_sync!{Impl3}
}

use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::{Display,Formatter,Result};

use self::t3::Trait3;
use self::t2::Trait2;
use self::t1::Trait1;
use self::base::Base;

//Initialize all the DI classes and traits  The syntax is {Base_Trait, Trait1, Trait2, ... }, where Trait# is a trait which needs to be DI-enabled.
indep_pool_sync!{Base, Trait1,Trait2,Trait3}

fn main() {
	//`Pool` is a structure created by `indep_pool_async` macro.
    let mut pool = Pool::new();

    let t1 = i1::new_dep();
    let t2 = i2::new_dep();
    let t3 = i3::new_dep();

    //Here we mark this struct with a special tag so it will be injected only to similarly named member of a dependent struct.
    pool.add_tagged(t1, vec!["t1_1".to_string()]);
    //Add DI dependency with no tag, which means it will be injected to any struct that has a dependency of the corresponding trait.
	pool.add(t2);
	//Same here.
	pool.add(t3);

	//`stat()` is a simple utility method of a `Pool` that shows its content name-wise.
	println!("Pool stat: {}", pool.stat());
}<|endoftext|>


<commit_before>extern crate lexer;
use std::io;
use std::io::Write;
use lexer::{Item, StateFn, Lexer};

const NUMBER_SIGNS: &'static str = "+-";
const NUMBERS: &'static str = "0123456789";
const DECIMAL_SIGN: &'static str = ".";
const NEGATE_SIGN: char = '-';

#[derive(Debug, PartialEq)]
pub enum ItemType {
    Number,
    GroupStart,
    GroupEnd,
    OperatorPlus,
    OperatorMinus,
    OperatorMul,
    OperatorDiv,
    OperatorNegate,
}

fn ignore_whitespace(l: &mut Lexer<ItemType>) -> Option<()> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(_) => {
                l.backup();
                break;
            }
        }
    }
    Some(())
}

// fn lex_unary_op(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
//     if let None = ignore_whitespace(l) {
//         return None;
//     }
//
//     if l.accept(NEGATE_SIGN) {
//         match l.peek() {
//             Some(ch) if NUMBERS.contains(ch) => {
//                 l.backup();
//                 return Some(StateFn(lex_number));
//             },
//             _ => {},
//         };
//
//         l.emit(ItemType::OperatorNegate);
//     }
//
//     Some(StateFn(lex_group_or_number))
// }

fn lex_binary_op(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(')') => l.emit(ItemType::GroupEnd),
            Some(ch) => {
                match ch {
                    '+' => l.emit(ItemType::OperatorPlus),
                    '-' => l.emit(ItemType::OperatorMinus),
                    '*' => l.emit(ItemType::OperatorMul),
                    '/' => l.emit(ItemType::OperatorDiv),
                    _ => panic!("unexpected: {}, expected operator", ch)
                }
                break;
            },
        }
    }

    Some(StateFn(lex_group_or_number))
}

fn lex_group_or_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(ch) if ch == NEGATE_SIGN => {
                if l.peek().map_or(false, |ch| NUMBERS.contains(ch)) {
                    l.backup();
                    return Some(StateFn(lex_number));
                }
                l.emit(ItemType::OperatorNegate);
            },
            Some('(') => {
                l.emit(ItemType::GroupStart);
            },
            Some(')') => {
                l.emit(ItemType::GroupEnd);
                return Some(StateFn(lex_binary_op));
            },
            Some(_) => {
                l.backup();
                return Some(StateFn(lex_number));
            }
        }
    }
}

fn lex_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    if let None = ignore_whitespace(l) {
        return None;
    }

    l.accept(NUMBER_SIGNS);

    if !l.accept_run(NUMBERS) {
        l.backup();
        panic!("unexpected: {:?}, expected number", l.next());
    }

    if l.accept(DECIMAL_SIGN) {
        l.accept_run(NUMBERS);
    }

    l.emit(ItemType::Number);

    Some(StateFn(lex_binary_op))
}

fn evaluate_group(items: &[Item<ItemType>]) -> f64 {
    let end_pos = items.iter()
                        .position(|item| item.typ == ItemType::GroupEnd)
                        .expect("unclosed group");

    evaluate_binary_op(&items[end_pos+1..], evaluate(&items[..end_pos]))
}

fn evaluate_binary_op(items: &[Item<ItemType>], op_a: f64) -> f64 {
    match items.len() {
        0 => op_a,
        n if n >=2 => {
            let op_b = evaluate(&items[1..]);
            apply_binary_op(&items[0], op_a, op_b)
        }
        _ => panic!("malformed operator")
    }
}

fn apply_binary_op(item: &Item<ItemType>, op_a: f64, op_b: f64) -> f64 {
    match item.typ {
        ItemType::OperatorPlus => op_a + op_b,
        ItemType::OperatorMinus => op_a - op_b,
        ItemType::OperatorMul => op_a * op_b,
        ItemType::OperatorDiv => op_a / op_b,
        _ => panic!("invalid operator item: {:?}", item),
    }
}

fn evaluate(items: &[Item<ItemType>]) -> f64 {
    if items.len() == 0 {
        return 0.0
    }
    let item = &items[0];

    match item.typ {
        ItemType::GroupStart => evaluate_group(&items[1..]),
        ItemType::OperatorNegate => -evaluate(&items[1..]),
        ItemType::Number => {
            let op_a = item.val.parse().unwrap();
            evaluate_binary_op(&items[1..], op_a)
        },
        _ => panic!("unable to evaluate: {:?}", item),
    }
}

fn main() {
    loop {
        println!("Input an expression or q to quit");
        print!(">>> ");
        io::stdout().flush().ok().expect("failed to flush stdout");

        let input = {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).ok().expect("read error");
            buffer.trim().to_owned()
        };

        if input == "q" {
            return
        }

        let items = lexer::lex(&input, lex_group_or_number);

        if items.len() == 0 {
            continue;
        }

        println!("{}", evaluate(&items));
    }
}

#[test]
fn test_parser() {
    let data = "-( 123 + 2 * 3 ) * 4 + -5 * -(5+6)";
    let expected_items = vec!(
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "123" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "2" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "3" },
        Item { typ: ItemType::GroupEnd, val: ")" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "4" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "-5" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "5" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "6" },
        Item { typ: ItemType::GroupEnd, val: ")" },
    );
    let items = lexer::lex(data, lex_group_or_number);
    println!("data: {:?}", data);
    println!("items: {:?}", items);
    assert_eq!(expected_items, items);
}
<commit_msg>removed dead code<commit_after>extern crate lexer;
use std::io;
use std::io::Write;
use lexer::{Item, StateFn, Lexer};

const NUMBER_SIGNS: &'static str = "+-";
const NUMBERS: &'static str = "0123456789";
const DECIMAL_SIGN: &'static str = ".";
const NEGATE_SIGN: char = '-';

#[derive(Debug, PartialEq)]
pub enum ItemType {
    Number,
    GroupStart,
    GroupEnd,
    OperatorPlus,
    OperatorMinus,
    OperatorMul,
    OperatorDiv,
    OperatorNegate,
}

fn ignore_whitespace(l: &mut Lexer<ItemType>) -> Option<()> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(_) => {
                l.backup();
                break;
            }
        }
    }
    Some(())
}

fn lex_binary_op(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(')') => l.emit(ItemType::GroupEnd),
            Some(ch) => {
                match ch {
                    '+' => l.emit(ItemType::OperatorPlus),
                    '-' => l.emit(ItemType::OperatorMinus),
                    '*' => l.emit(ItemType::OperatorMul),
                    '/' => l.emit(ItemType::OperatorDiv),
                    _ => panic!("unexpected: {}, expected operator", ch)
                }
                break;
            },
        }
    }

    Some(StateFn(lex_group_or_number))
}

fn lex_group_or_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(ch) if ch == NEGATE_SIGN => {
                if l.peek().map_or(false, |ch| NUMBERS.contains(ch)) {
                    l.backup();
                    return Some(StateFn(lex_number));
                }
                l.emit(ItemType::OperatorNegate);
            },
            Some('(') => {
                l.emit(ItemType::GroupStart);
            },
            Some(')') => {
                l.emit(ItemType::GroupEnd);
                return Some(StateFn(lex_binary_op));
            },
            Some(_) => {
                l.backup();
                return Some(StateFn(lex_number));
            }
        }
    }
}

fn lex_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    if let None = ignore_whitespace(l) {
        return None;
    }

    l.accept(NUMBER_SIGNS);

    if !l.accept_run(NUMBERS) {
        l.backup();
        panic!("unexpected: {:?}, expected number", l.next());
    }

    if l.accept(DECIMAL_SIGN) {
        l.accept_run(NUMBERS);
    }

    l.emit(ItemType::Number);

    Some(StateFn(lex_binary_op))
}

fn evaluate_group(items: &[Item<ItemType>]) -> f64 {
    let end_pos = items.iter()
                        .position(|item| item.typ == ItemType::GroupEnd)
                        .expect("unclosed group");

    evaluate_binary_op(&items[end_pos+1..], evaluate(&items[..end_pos]))
}

fn evaluate_binary_op(items: &[Item<ItemType>], op_a: f64) -> f64 {
    match items.len() {
        0 => op_a,
        n if n >=2 => {
            let op_b = evaluate(&items[1..]);
            apply_binary_op(&items[0], op_a, op_b)
        }
        _ => panic!("malformed operator")
    }
}

fn apply_binary_op(item: &Item<ItemType>, op_a: f64, op_b: f64) -> f64 {
    match item.typ {
        ItemType::OperatorPlus => op_a + op_b,
        ItemType::OperatorMinus => op_a - op_b,
        ItemType::OperatorMul => op_a * op_b,
        ItemType::OperatorDiv => op_a / op_b,
        _ => panic!("invalid operator item: {:?}", item),
    }
}

fn evaluate(items: &[Item<ItemType>]) -> f64 {
    if items.len() == 0 {
        return 0.0
    }
    let item = &items[0];

    match item.typ {
        ItemType::GroupStart => evaluate_group(&items[1..]),
        ItemType::OperatorNegate => -evaluate(&items[1..]),
        ItemType::Number => {
            let op_a = item.val.parse().unwrap();
            evaluate_binary_op(&items[1..], op_a)
        },
        _ => panic!("unable to evaluate: {:?}", item),
    }
}

fn main() {
    loop {
        println!("Input an expression or q to quit");
        print!(">>> ");
        io::stdout().flush().ok().expect("failed to flush stdout");

        let input = {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).ok().expect("read error");
            buffer.trim().to_owned()
        };

        if input == "q" {
            return
        }

        let items = lexer::lex(&input, lex_group_or_number);

        if items.len() == 0 {
            continue;
        }

        println!("{}", evaluate(&items));
    }
}

#[test]
fn test_parser() {
    let data = "-( 123 + 2 * 3 ) * 4 + -5 * -(5+6)";
    let expected_items = vec!(
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "123" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "2" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "3" },
        Item { typ: ItemType::GroupEnd, val: ")" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "4" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "-5" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "5" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "6" },
        Item { typ: ItemType::GroupEnd, val: ")" },
    );
    let items = lexer::lex(data, lex_group_or_number);
    println!("data: {:?}", data);
    println!("items: {:?}", items);
    assert_eq!(expected_items, items);
}
<|endoftext|>


<commit_before>#[macro_use] extern crate nom;
extern crate vqa_parser;
extern crate portaudio;

use vqa_parser::{VQAHeader, SND2Chunk};
use vqa_parser::{form_chunk, vqa_header, snd2_chunk};
use vqa_parser::audio::CodecState;
use portaudio::PortAudio;

use std::collections::VecDeque;

named!(parse_vqaheader<VQAHeader>,
    do_parse!(
        form_chunk            >>
        tag!("WVQA")          >>
        vqaheader: vqa_header >>
        (
            vqaheader
        )
    )
);

named!(next_snd2_chunk<SND2Chunk>,
    do_parse!(
        take_until!("SND2") >>
        chunk: snd2_chunk   >>
        (chunk)
    )
);

named!(all_snd2_chunks<Vec<SND2Chunk>>,
    many0!(
        next_snd2_chunk
    )
);

fn main() {
    let vqa_wwlogo = include_bytes!("wwlogo.vqa");

    let vqa = parse_vqaheader(vqa_wwlogo).unwrap().1;
    let snd2_chunks = all_snd2_chunks(vqa_wwlogo).unwrap().1;

    println!("{:#?}", vqa);
    println!("parsed {} snd2 chunks", snd2_chunks.len());

    play_chunks(&snd2_chunks);
}

fn get_samples(chunks: &Vec<SND2Chunk>) -> VecDeque<i16> {
    let mut samples = VecDeque::new();

    let mut ch1_state = CodecState::new();
    let mut ch2_state = CodecState::new();
    for chunk in chunks {
        let left = vqa_parser::audio::decompress(&mut ch1_state, &chunk.data[..chunk.data.len()/2]);
        let right = vqa_parser::audio::decompress(&mut ch2_state, &chunk.data[..chunk.data.len()/2]);

        // interleave data
        for i in 0..left.len() {
            samples.push_back(left[i] as i16);
            samples.push_back(right[i] as i16);
        }
    }

    samples
}

fn play_chunks(chunks: &Vec<SND2Chunk>) {
    const CHANNELS: i32 = 2;
    const SAMPLE_RATE: f64 = 22050.0;
    const FRAMES_PER_BUFFER: u32 = 256;

    let pa = PortAudio::new().unwrap();
    let settings = pa.default_output_stream_settings(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER).unwrap();

    let mut sampledata = get_samples(chunks);

    // This routine will be called by the PortAudio engine when audio is needed. It may called at
    // interrupt level on some machines so don't do anything that could mess up the system like
    // dynamic resource allocation or IO.
    let callback = move |portaudio::OutputStreamCallbackArgs { buffer, frames, .. }| {
        let mut idx = 0;
        for _ in 0..frames {
            if sampledata.len() > 0 {
                buffer[idx]   = sampledata.pop_front().unwrap();
                buffer[idx+1] = sampledata.pop_front().unwrap();
            }
            idx += 2;
        }

        if sampledata.len() == 0 {
            return portaudio::Complete;
        } else {
            return portaudio::Continue;
        }
    };

    let mut stream = pa.open_non_blocking_stream(settings, callback).unwrap();

    stream.start().unwrap();
    pa.sleep(10 * 1_000);
    stream.stop().unwrap();
    stream.close().unwrap();
}
<commit_msg>example: wait for all sound samples finish playing<commit_after>#[macro_use] extern crate nom;
extern crate vqa_parser;
extern crate portaudio;

use vqa_parser::{VQAHeader, SND2Chunk};
use vqa_parser::{form_chunk, vqa_header, snd2_chunk};
use vqa_parser::audio::CodecState;
use portaudio::PortAudio;

use std::collections::VecDeque;

named!(parse_vqaheader<VQAHeader>,
    do_parse!(
        form_chunk            >>
        tag!("WVQA")          >>
        vqaheader: vqa_header >>
        (
            vqaheader
        )
    )
);

named!(next_snd2_chunk<SND2Chunk>,
    do_parse!(
        take_until!("SND2") >>
        chunk: snd2_chunk   >>
        (chunk)
    )
);

named!(all_snd2_chunks<Vec<SND2Chunk>>,
    many0!(
        next_snd2_chunk
    )
);

fn main() {
    let vqa_wwlogo = include_bytes!("wwlogo.vqa");

    let vqa = parse_vqaheader(vqa_wwlogo).unwrap().1;
    let snd2_chunks = all_snd2_chunks(vqa_wwlogo).unwrap().1;

    println!("{:#?}", vqa);
    println!("parsed {} snd2 chunks", snd2_chunks.len());

    play_chunks(&snd2_chunks);
}

fn get_samples(chunks: &Vec<SND2Chunk>) -> VecDeque<i16> {
    let mut samples = VecDeque::new();

    let mut ch1_state = CodecState::new();
    let mut ch2_state = CodecState::new();
    for chunk in chunks {
        let left = vqa_parser::audio::decompress(&mut ch1_state, &chunk.data[..chunk.data.len()/2]);
        let right = vqa_parser::audio::decompress(&mut ch2_state, &chunk.data[..chunk.data.len()/2]);

        // interleave data
        for i in 0..left.len() {
            samples.push_back(left[i] as i16);
            samples.push_back(right[i] as i16);
        }
    }

    samples
}

fn play_chunks(chunks: &Vec<SND2Chunk>) {
    const CHANNELS: i32 = 2;
    const SAMPLE_RATE: f64 = 22050.0;
    const FRAMES_PER_BUFFER: u32 = 256;

    let pa = PortAudio::new().unwrap();
    let settings = pa.default_output_stream_settings(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER).unwrap();

    let mut sampledata = get_samples(chunks);

    // This routine will be called by the PortAudio engine when audio is needed. It may called at
    // interrupt level on some machines so don't do anything that could mess up the system like
    // dynamic resource allocation or IO.
    let callback = move |portaudio::OutputStreamCallbackArgs { buffer, frames, .. }| {
        let mut idx = 0;
        for _ in 0..frames {
            if sampledata.len() > 0 {
                buffer[idx]   = sampledata.pop_front().unwrap();
                buffer[idx+1] = sampledata.pop_front().unwrap();
            }
            idx += 2;
        }

        if sampledata.len() == 0 {
            return portaudio::Complete;
        } else {
            return portaudio::Continue;
        }
    };

    let mut stream = pa.open_non_blocking_stream(settings, callback).unwrap();

    stream.start().unwrap();
    while let Ok(active) = stream.is_active() {
        if active {
            pa.sleep(50); // sleep 50ms
        } else {
            break;
        }
    }
    stream.stop().unwrap();
    stream.close().unwrap();
}
<|endoftext|>


<commit_before>//HACK: This is how we're splitting the maze example into multiple files since
// cargo doesn't properly support examples with multiple files yet
#[path = "maze/wall.rs"]
mod wall;
#[path = "maze/cell.rs"]
mod cell;
#[path = "maze/maze.rs"]
mod maze;
#[path = "maze/grid.rs"]
mod grid;

extern crate turtle;

use turtle::Turtle;

pub use maze::Maze;
use grid::{GridCellIter};

// Dimensions of the maze in turtle steps (pixels)
const WIDTH: f64 = 600.0; // px
const HEIGHT: f64 = 600.0; // px

fn main() {
    let maze = Maze::generate();

    let mut turtle = Turtle::new();
    turtle.set_speed(10);
    turtle.set_background_color("#A5D6A7");
    turtle.set_pen_color("#03A9F4");
    turtle.set_pen_size(2.0);

    // Get to the top left corner
    turtle.pen_up();
    turtle.forward(HEIGHT / 2.0);
    turtle.right(90.0);
    turtle.backward(WIDTH / 2.0);
    turtle.pen_down();

    let cell_width = WIDTH/(maze.row_size() as f64);
    let cell_height = HEIGHT/(maze.col_size() as f64);

    // Draw rows
    draw_rows(
        &mut turtle,
        cell_width,
        cell_height,
        maze.first_row().map(|cell| cell.north.is_closed()),
        maze.rows(),
        |row| row.map(|cell| cell.south.is_closed()),
        false,
    );

    // Draw columns
    turtle.left(90.0);
    draw_rows(
        &mut turtle,
        cell_height,
        cell_width,
        maze.last_col().rev().map(|cell| cell.east.is_closed()),
        maze.cols().rev(),
        |col| col.map(|cell| cell.west.is_closed()).rev(),
        true,
    );
}

fn draw_rows<
    'a,
    R: Iterator<Item=bool>,
    G: Iterator<Item=GridCellIter<'a>>,
    F: Fn(GridCellIter<'a>) -> X,
    X: Iterator<Item=bool> + DoubleEndedIterator
>(
    turtle: &mut Turtle,
    // size of each cell in the row
    cell_size: f64,
    // gap between rows
    cell_gap: f64,
    first_row: R,
    rows: G,
    row_walls: F,
    rotate_left: bool,
) {
    draw_row(turtle, cell_size, first_row);

    // Direction of rotation for all turns
    let rotation = if rotate_left { -1.0 } else { 1.0 };
    for (i, row) in rows.enumerate() {
        turtle.pen_up();

        // Direction of rotation for these turns
        let direction = rotation * if i % 2 == 0 { 1.0 } else { -1.0 };
        turtle.right(direction * 90.0);
        turtle.forward(cell_gap);
        turtle.right(direction * 90.0);
        turtle.pen_down();

        let walls = row_walls(row);

        // Every second row needs to be reversed so the turtle can zig-zag back and
        // forth instead of wasting too much time moving all the way to the left of
        // each row
        if i % 2 == 0 {
            draw_row(turtle, cell_size, walls.rev());
        }
        else {
            draw_row(turtle, cell_size, walls);
        }
    }
}

fn draw_row<I: Iterator<Item=bool>>(turtle: &mut Turtle, wall_size: f64, walls: I) {
    for should_draw in walls {
        if !should_draw {
            turtle.pen_up();
        }
        turtle.forward(wall_size);
        turtle.pen_down();
    }
}
<commit_msg>Much better background color<commit_after>//HACK: This is how we're splitting the maze example into multiple files since
// cargo doesn't properly support examples with multiple files yet
#[path = "maze/wall.rs"]
mod wall;
#[path = "maze/cell.rs"]
mod cell;
#[path = "maze/maze.rs"]
mod maze;
#[path = "maze/grid.rs"]
mod grid;

extern crate turtle;

use turtle::Turtle;

pub use maze::Maze;
use grid::{GridCellIter};

// Dimensions of the maze in turtle steps (pixels)
const WIDTH: f64 = 600.0; // px
const HEIGHT: f64 = 600.0; // px

fn main() {
    let maze = Maze::generate();

    let mut turtle = Turtle::new();
    turtle.set_speed(10);
    turtle.set_background_color("#BDBDBD");
    turtle.set_pen_color("#03A9F4");
    turtle.set_pen_size(2.0);

    // Get to the top left corner
    turtle.pen_up();
    turtle.forward(HEIGHT / 2.0);
    turtle.right(90.0);
    turtle.backward(WIDTH / 2.0);
    turtle.pen_down();

    let cell_width = WIDTH/(maze.row_size() as f64);
    let cell_height = HEIGHT/(maze.col_size() as f64);

    // Draw rows
    draw_rows(
        &mut turtle,
        cell_width,
        cell_height,
        maze.first_row().map(|cell| cell.north.is_closed()),
        maze.rows(),
        |row| row.map(|cell| cell.south.is_closed()),
        false,
    );

    // Draw columns
    turtle.left(90.0);
    draw_rows(
        &mut turtle,
        cell_height,
        cell_width,
        maze.last_col().rev().map(|cell| cell.east.is_closed()),
        maze.cols().rev(),
        |col| col.map(|cell| cell.west.is_closed()).rev(),
        true,
    );
}

fn draw_rows<
    'a,
    R: Iterator<Item=bool>,
    G: Iterator<Item=GridCellIter<'a>>,
    F: Fn(GridCellIter<'a>) -> X,
    X: Iterator<Item=bool> + DoubleEndedIterator
>(
    turtle: &mut Turtle,
    // size of each cell in the row
    cell_size: f64,
    // gap between rows
    cell_gap: f64,
    first_row: R,
    rows: G,
    row_walls: F,
    rotate_left: bool,
) {
    draw_row(turtle, cell_size, first_row);

    // Direction of rotation for all turns
    let rotation = if rotate_left { -1.0 } else { 1.0 };
    for (i, row) in rows.enumerate() {
        turtle.pen_up();

        // Direction of rotation for these turns
        let direction = rotation * if i % 2 == 0 { 1.0 } else { -1.0 };
        turtle.right(direction * 90.0);
        turtle.forward(cell_gap);
        turtle.right(direction * 90.0);
        turtle.pen_down();

        let walls = row_walls(row);

        // Every second row needs to be reversed so the turtle can zig-zag back and
        // forth instead of wasting too much time moving all the way to the left of
        // each row
        if i % 2 == 0 {
            draw_row(turtle, cell_size, walls.rev());
        }
        else {
            draw_row(turtle, cell_size, walls);
        }
    }
}

fn draw_row<I: Iterator<Item=bool>>(turtle: &mut Turtle, wall_size: f64, walls: I) {
    for should_draw in walls {
        if !should_draw {
            turtle.pen_up();
        }
        turtle.forward(wall_size);
        turtle.pen_down();
    }
}
<|endoftext|>


<commit_before>use std::hash::{hash,Hash};
use std::collections::HashMap;
use std::thunk::Invoke;
use std::mem::replace;
use std::sync::Arc;

// "One big memo table" design

pub trait Adapton {
    fn new () -> Self ;
    fn name_of_string (self:&mut Self, String) -> Name ;
    fn name_of_u64 (self:&mut Self, u64) -> Name ;
    fn name_pair (self: &Self, Name, Name) -> Name ;
    fn name_fork (self:&mut Self, Name) -> (Name, Name) ;

    fn cell<T:Eq+Hash> (self:&mut Self, ArtId, T) -> Art<T> ;

    fn thunk<Arg:Eq+Hash,T:Eq+Hash>
        (self:&mut Self, id:ArtId, fn_body:Box<Invoke<Arg,T>+'static>, arg:Arg) -> Art<T> ;

    fn force<T:Eq+Hash> (self:&mut Self, Art<T>) -> T ;
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum Lineage {
    Unknown,
    Root,
    Taken,
    Pair(Arc<Lineage>,Arc<Lineage>),
    ForkL(Arc<Lineage>),
    ForkR(Arc<Lineage>),
    String(String),
    U64(u64),
    Arc(Arc<Lineage>),
}

#[derive(Hash,Show,PartialEq,Eq)]
pub struct Name {
    hash : u64,
    lineage : Arc<Lineage>,
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum Art<T> {
    Hash(u64),
    Box(Box<T>),
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum ArtId {
    None,
    Structural,
    Nominal(Name),
}

pub struct AdaptonState {
    memo_table : HashMap<ArtId, *mut ()>, // memo table
    curr_nmspc : Name, // current_namespace
    curr_artnm : Name, // current articulation point
}

impl Adapton for AdaptonState {
    fn new () -> AdaptonState {
        let root = Arc::new(Lineage::Root);
        let root1 = Name{hash:0, lineage:root.clone()};
        let root2 = Name{hash:0, lineage:root};
        AdaptonState {
            memo_table : HashMap::new (),
            curr_nmspc : root1,
            curr_artnm : root2,
        }
    }
    fn name_of_string (self:&mut AdaptonState, sym:String) -> Name {
        let h = hash::<_>(&sym) ;
        let s = Lineage::String(sym) ;
        Name{ hash:h, lineage:Arc::new(s) }
    }
    fn name_of_u64 (self:&mut AdaptonState, sym:u64) -> Name {
        let h = hash::<_>(&sym) ;
        let s = Lineage::U64(sym) ;
        Name{ hash:h, lineage:Arc::new(s) }
    }
    fn name_pair (self: &AdaptonState, fst: Name, snd: Name) -> Name {
        let h = hash::<_>( &(&fst,&snd) ) ;
        let p = Lineage::Pair(fst.lineage, snd.lineage) ;
        Name{ hash:h, lineage:Arc::new(p) }
    }
    fn name_fork (self:&mut AdaptonState, nm:Name) -> (Name, Name) {
        panic!("")
    }
    fn cell<T:Eq+Hash> (self:&mut AdaptonState, id:ArtId, x:T) -> Art<T> {
        panic!("")
    }
    fn thunk<Arg:Eq+Hash,T:Eq+Hash>
        (self:&mut AdaptonState,
         id:ArtId, fn_body:Box<Invoke<Arg,T>+'static>, arg:Arg) -> Art<T>
    {
        panic!("")
    }
    fn force<T:Eq+Hash> (self:&mut AdaptonState, art:Art<T>) -> T {
        panic!("")
    }
}

pub fn main () {

}
<commit_msg>wrote fork<commit_after>use std::hash::{hash,Hash};
use std::collections::HashMap;
use std::thunk::Invoke;
use std::mem::replace;
use std::sync::Arc;

// "One big memo table" design

pub trait Adapton {
    fn new () -> Self ;
    fn name_of_string (self:&mut Self, String) -> Name ;
    fn name_of_u64 (self:&mut Self, u64) -> Name ;
    fn name_pair (self: &Self, Name, Name) -> Name ;
    fn name_fork (self:&mut Self, Name) -> (Name, Name) ;

    fn cell<T:Eq+Hash> (self:&mut Self, ArtId, T) -> Art<T> ;

    fn thunk<Arg:Eq+Hash,T:Eq+Hash>
        (self:&mut Self, id:ArtId, fn_body:Box<Invoke<Arg,T>+'static>, arg:Arg) -> Art<T> ;

    fn force<T:Eq+Hash> (self:&mut Self, Art<T>) -> T ;
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum Lineage {
    Unknown,
    Root,
    Taken,
    Pair(Arc<Lineage>,Arc<Lineage>),
    ForkL(Arc<Lineage>),
    ForkR(Arc<Lineage>),
    String(String),
    U64(u64),
    Arc(Arc<Lineage>),
}

#[derive(Hash,Show,PartialEq,Eq)]
pub struct Name {
    hash : u64,
    lineage : Arc<Lineage>,
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum Art<T> {
    Hash(u64),
    Box(Box<T>),
}

#[derive(Hash,Show,PartialEq,Eq)]
pub enum ArtId {
    None,
    Structural,
    Nominal(Name),
}

pub struct AdaptonState {
    memo_table : HashMap<ArtId, *mut ()>, // memo table
    curr_nmspc : Name, // current_namespace
    curr_artnm : Name, // current articulation point
}

impl Adapton for AdaptonState {
    fn new () -> AdaptonState {
        let root = Arc::new(Lineage::Root);
        let root1 = Name{hash:0, lineage:root.clone()};
        let root2 = Name{hash:0, lineage:root};
        AdaptonState {
            memo_table : HashMap::new (),
            curr_nmspc : root1,
            curr_artnm : root2,
        }
    }
    fn name_of_string (self:&mut AdaptonState, sym:String) -> Name {
        let h = hash::<_>(&sym) ;
        let s = Lineage::String(sym) ;
        Name{ hash:h, lineage:Arc::new(s) }
    }
    fn name_of_u64 (self:&mut AdaptonState, sym:u64) -> Name {
        let h = hash::<_>(&sym) ;
        let s = Lineage::U64(sym) ;
        Name{ hash:h, lineage:Arc::new(s) }
    }
    fn name_pair (self: &AdaptonState, fst: Name, snd: Name) -> Name {
        let h = hash::<_>( &(&fst,&snd) ) ;
        let p = Lineage::Pair(fst.lineage, snd.lineage) ;
        Name{ hash:h, lineage:Arc::new(p) }
    }
    fn name_fork (self:&mut AdaptonState, nm:Name) -> (Name, Name) {
        let h1 = hash::<_>( &(&nm, 1) ) ;
        let h2 = hash::<_>( &(&nm, 2) );
        ( Name{ hash:h1, lineage:Arc::new(Lineage::ForkL(nm.lineage.clone())) } ,
          Name{ hash:h2, lineage:Arc::new(Lineage::ForkR(nm.lineage)) } )
    }
    fn cell<T:Eq+Hash> (self:&mut AdaptonState, id:ArtId, x:T) -> Art<T> {
        panic!("")
    }
    fn thunk<Arg:Eq+Hash,T:Eq+Hash>
        (self:&mut AdaptonState,
         id:ArtId, fn_body:Box<Invoke<Arg,T>+'static>, arg:Arg) -> Art<T>
    {
        panic!("")
    }
    fn force<T:Eq+Hash> (self:&mut AdaptonState, art:Art<T>) -> T {
        panic!("")
    }
}

pub fn main () {

}
<|endoftext|>


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

use target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: vec!(
            // GNU-style linkers will use this to omit linking to libraries
            // which don't actually fulfill any relocations, but only for
            // libraries which follow this flag.  Thus, use it before
            // specifying libraries to link to.
            "-Wl,--as-needed".to_string(),
        ),
        position_independent_executables: true,
        archive_format: "bsd".to_string(),
        .. Default::default()
    }
}
<commit_msg>Auto merge of #27144 - semarie:openbsd-archive_format, r=alexcrichton<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: vec!(
            // GNU-style linkers will use this to omit linking to libraries
            // which don't actually fulfill any relocations, but only for
            // libraries which follow this flag.  Thus, use it before
            // specifying libraries to link to.
            "-Wl,--as-needed".to_string(),
        ),
        position_independent_executables: true,
        archive_format: "gnu".to_string(),
        .. Default::default()
    }
}
<|endoftext|>