<commit_before>//! Track which values are live in an EBB with instruction granularity.
//!
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in an EBB.
//! The sets of live values are computed on the fly as the tracker is moved from instruction to
//! instruction, starting at the EBB header.

use dominator_tree::DominatorTree;
use entity_list::{EntityList, ListPool};
use ir::instructions::BranchInfo;
use ir::{Inst, Ebb, Value, DataFlowGraph, ProgramOrder, ExpandedProgramPoint};
use partition_slice::partition_slice;
use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;

use std::collections::HashMap;

type ValueList = EntityList<Value>;

/// Compute and track live values throughout an EBB.
pub struct LiveValueTracker {
    /// The set of values that are live at the current program point.
    live: LiveValueVec,

    /// Saved set of live values for every jump and branch that can potentially be an immediate
    /// dominator of an EBB.
    ///
    /// This is the set of values that are live *before* the branch.
    idom_sets: HashMap<Inst, ValueList>,

    /// Memory pool for the live sets.
    idom_pool: ListPool<Value>,
}

/// Information about a value that is live at the current program point.
pub struct LiveValue {
    /// The live value.
    pub value: Value,

    /// The local ending point of the live range in the current EBB, as returned by
    /// `LiveRange::def_local_end()` or `LiveRange::livein_local_end()`.
    pub endpoint: Inst,

    /// The affinity of the value as represented in its `LiveRange`.
    ///
    /// This value is simply a copy of the affinity stored in the live range. We copy it because
    /// almost all users of `LiveValue` need to look at it.
    pub affinity: Affinity,
}

struct LiveValueVec {
    /// The set of values that are live at the current program point.
    values: Vec<LiveValue>,

    /// How many values at the front of `values` are known to be live after `inst`?
    ///
    /// This is used to pass a much smaller slice to `partition_slice` when its called a second
    /// time for the same instruction.
    live_prefix: Option<(Inst, usize)>,
}

impl LiveValueVec {
    fn new() -> LiveValueVec {
        LiveValueVec {
            values: Vec::new(),
            live_prefix: None,
        }
    }

    /// Add a new live value to `values`.
    fn push(&mut self, value: Value, endpoint: Inst, affinity: Affinity) {
        self.values.push(LiveValue {
            value: value,
            endpoint: endpoint,
            affinity: affinity,
        });
    }

    /// Remove all elements.
    fn clear(&mut self) {
        self.values.clear();
        self.live_prefix = None;
    }

    /// Make sure that the values killed by `next_inst` are moved to the end of the `values`
    /// vector.
    ///
    /// Returns the number of values that will be live after `next_inst`.
    fn live_after(&mut self, next_inst: Inst) -> usize {
        // How many values at the front of the vector are already known to survive `next_inst`?
        // We don't need to pass this prefix to `partition_slice()`
        let keep = match self.live_prefix {
            Some((i, prefix)) if i == next_inst => prefix,
            _ => 0,
        };

        // Move the remaining surviving values to the front partition of the vector.
        let prefix = keep + partition_slice(&mut self.values[keep..], |v| v.endpoint != next_inst);

        // Remember the new prefix length in case we get called again for the same `next_inst`.
        self.live_prefix = Some((next_inst, prefix));
        prefix
    }

    /// Remove the values killed by `next_inst`.
    fn remove_kill_values(&mut self, next_inst: Inst) {
        let keep = self.live_after(next_inst);
        self.values.truncate(keep);
    }
}

impl LiveValueTracker {
    /// Create a new blank tracker.
    pub fn new() -> LiveValueTracker {
        LiveValueTracker {
            live: LiveValueVec::new(),
            idom_sets: HashMap::new(),
            idom_pool: ListPool::new(),
        }
    }

    /// Clear all cached information.
    pub fn clear(&mut self) {
        self.live.clear();
        self.idom_sets.clear();
        self.idom_pool.clear();
    }

    /// Get the set of currently live values.
    ///
    /// Between calls to `process_inst()` and `drop_dead()`, this includes both values killed and
    /// defined by the current instruction.
    pub fn live(&self) -> &[LiveValue] {
        &self.live.values
    }

    /// Move the current position to the top of `ebb`.
    ///
    /// This depends on the stored live value set at `ebb`'s immediate dominator, so that must have
    /// been visited first.
    ///
    /// Returns `(liveins, args)` as a pair or slices. The first slice is the set of live-in values
    /// from the immediate dominator. The second slice is the set of `ebb` arguments that are live.
    /// Dead arguments with no uses are ignored and not added to the set.
    pub fn ebb_top<PO: ProgramOrder>(&mut self,
                                     ebb: Ebb,
                                     dfg: &DataFlowGraph,
                                     liveness: &Liveness,
                                     program_order: &PO,
                                     domtree: &DominatorTree)
                                     -> (&[LiveValue], &[LiveValue]) {
        // Start over, compute the set of live values at the top of the EBB from two sources:
        //
        // 1. Values that were live before `ebb`'s immediate dominator, filtered for those that are
        //    actually live-in.
        // 2. Arguments to `ebb` that are not dead.
        //
        self.live.clear();

        // Compute the live-in values. Start by filtering the set of values that were live before
        // the immediate dominator. Just use the empty set if there's no immediate dominator (i.e.,
        // the entry block or an unreachable block).
        if let Some(idom) = domtree.idom(ebb) {
            // If the immediate dominator exits, we must have a stored list for it. This is a
            // requirement to the order EBBs are visited: All dominators must have been processed
            // before the current EBB.
            let idom_live_list =
                self.idom_sets.get(&idom).expect("No stored live set for dominator");
            // Get just the values that are live-in to `ebb`.
            for &value in idom_live_list.as_slice(&self.idom_pool) {
                let lr = liveness.get(value)
                    .expect("Immediate dominator value has no live range");

                // Check if this value is live-in here.
                if let Some(endpoint) = lr.livein_local_end(ebb, program_order) {
                    self.live.push(value, endpoint, lr.affinity);
                }
            }
        }

        // Now add all the live arguments to `ebb`.
        let first_arg = self.live.values.len();
        for value in dfg.ebb_args(ebb) {
            let lr = liveness.get(value).expect("EBB argument value has no live range");
            assert_eq!(lr.def(), ebb.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr.affinity);
                }
                ExpandedProgramPoint::Ebb(local_ebb) => {
                    // This is a dead EBB argument which is not even live into the first
                    // instruction in the EBB. We can ignore it.
                    assert_eq!(local_ebb,
                               ebb,
                               "EBB argument live range ends at wrong EBB header");
                }
            }
        }

        self.live.values.split_at(first_arg)
    }

    /// Prepare to move past `inst`.
    ///
    /// Determine the set of already live values that are killed by `inst`, and add the new defined
    /// values to the tracked set.
    ///
    /// Returns `(kills, defs)` as a pair of slices. The `defs` slice is guaranteed to be in the
    /// same order as `inst`'s results, and includes dead defines. The order of `kills` is
    /// arbitrary.
    ///
    /// The `drop_dead()` method must be called next to actually remove the dead values from the
    /// tracked set after the two returned slices are no longer needed.
    pub fn process_inst(&mut self,
                        inst: Inst,
                        dfg: &DataFlowGraph,
                        liveness: &Liveness)
                        -> (&[LiveValue], &[LiveValue]) {
        // Save a copy of the live values before any branches or jumps that could be somebody's
        // immediate dominator.
        match dfg[inst].analyze_branch() {
            BranchInfo::NotABranch => {}
            _ => self.save_idom_live_set(inst),
        }

        // Move killed values to the end of the vector.
        // Don't remove them yet, `drop_dead()` will do that.
        let first_kill = self.live.live_after(inst);

        // Add the values defined by `inst`.
        let first_def = self.live.values.len();
        for value in dfg.inst_results(inst) {
            let lr = liveness.get(value).expect("Instruction result has no live range");
            assert_eq!(lr.def(), inst.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr.affinity);
                }
                ExpandedProgramPoint::Ebb(ebb) => {
                    panic!("Instruction result live range can't end at {}", ebb);
                }
            }
        }

        (&self.live.values[first_kill..first_def], &self.live.values[first_def..])
    }

    /// Drop the values that are now dead after moving past `inst`.
    ///
    /// This removes both live values that were killed by `inst` and dead defines on `inst` itself.
    ///
    /// This must be called after `process_inst(inst)` and before proceeding to the next
    /// instruction.
    pub fn drop_dead(&mut self, inst: Inst) {
        // Remove both live values that were killed by `inst` and dead defines from `inst`.
        self.live.remove_kill_values(inst);
    }

    /// Save the current set of live values so it is associated with `idom`.
    fn save_idom_live_set(&mut self, idom: Inst) {
        let values = self.live.values.iter().map(|lv| lv.value);
        let pool = &mut self.idom_pool;
        // If there already is a set saved for `idom`, just keep it.
        self.idom_sets.entry(idom).or_insert_with(|| {
            let mut list = ValueList::default();
            list.extend(values, pool);
            list
        });
    }
}
<commit_msg>Improve assertion text for missing live ranges.<commit_after>//! Track which values are live in an EBB with instruction granularity.
//!
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in an EBB.
//! The sets of live values are computed on the fly as the tracker is moved from instruction to
//! instruction, starting at the EBB header.

use dominator_tree::DominatorTree;
use entity_list::{EntityList, ListPool};
use ir::instructions::BranchInfo;
use ir::{Inst, Ebb, Value, DataFlowGraph, ProgramOrder, ExpandedProgramPoint};
use partition_slice::partition_slice;
use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;

use std::collections::HashMap;

type ValueList = EntityList<Value>;

/// Compute and track live values throughout an EBB.
pub struct LiveValueTracker {
    /// The set of values that are live at the current program point.
    live: LiveValueVec,

    /// Saved set of live values for every jump and branch that can potentially be an immediate
    /// dominator of an EBB.
    ///
    /// This is the set of values that are live *before* the branch.
    idom_sets: HashMap<Inst, ValueList>,

    /// Memory pool for the live sets.
    idom_pool: ListPool<Value>,
}

/// Information about a value that is live at the current program point.
pub struct LiveValue {
    /// The live value.
    pub value: Value,

    /// The local ending point of the live range in the current EBB, as returned by
    /// `LiveRange::def_local_end()` or `LiveRange::livein_local_end()`.
    pub endpoint: Inst,

    /// The affinity of the value as represented in its `LiveRange`.
    ///
    /// This value is simply a copy of the affinity stored in the live range. We copy it because
    /// almost all users of `LiveValue` need to look at it.
    pub affinity: Affinity,
}

struct LiveValueVec {
    /// The set of values that are live at the current program point.
    values: Vec<LiveValue>,

    /// How many values at the front of `values` are known to be live after `inst`?
    ///
    /// This is used to pass a much smaller slice to `partition_slice` when its called a second
    /// time for the same instruction.
    live_prefix: Option<(Inst, usize)>,
}

impl LiveValueVec {
    fn new() -> LiveValueVec {
        LiveValueVec {
            values: Vec::new(),
            live_prefix: None,
        }
    }

    /// Add a new live value to `values`.
    fn push(&mut self, value: Value, endpoint: Inst, affinity: Affinity) {
        self.values.push(LiveValue {
            value: value,
            endpoint: endpoint,
            affinity: affinity,
        });
    }

    /// Remove all elements.
    fn clear(&mut self) {
        self.values.clear();
        self.live_prefix = None;
    }

    /// Make sure that the values killed by `next_inst` are moved to the end of the `values`
    /// vector.
    ///
    /// Returns the number of values that will be live after `next_inst`.
    fn live_after(&mut self, next_inst: Inst) -> usize {
        // How many values at the front of the vector are already known to survive `next_inst`?
        // We don't need to pass this prefix to `partition_slice()`
        let keep = match self.live_prefix {
            Some((i, prefix)) if i == next_inst => prefix,
            _ => 0,
        };

        // Move the remaining surviving values to the front partition of the vector.
        let prefix = keep + partition_slice(&mut self.values[keep..], |v| v.endpoint != next_inst);

        // Remember the new prefix length in case we get called again for the same `next_inst`.
        self.live_prefix = Some((next_inst, prefix));
        prefix
    }

    /// Remove the values killed by `next_inst`.
    fn remove_kill_values(&mut self, next_inst: Inst) {
        let keep = self.live_after(next_inst);
        self.values.truncate(keep);
    }
}

impl LiveValueTracker {
    /// Create a new blank tracker.
    pub fn new() -> LiveValueTracker {
        LiveValueTracker {
            live: LiveValueVec::new(),
            idom_sets: HashMap::new(),
            idom_pool: ListPool::new(),
        }
    }

    /// Clear all cached information.
    pub fn clear(&mut self) {
        self.live.clear();
        self.idom_sets.clear();
        self.idom_pool.clear();
    }

    /// Get the set of currently live values.
    ///
    /// Between calls to `process_inst()` and `drop_dead()`, this includes both values killed and
    /// defined by the current instruction.
    pub fn live(&self) -> &[LiveValue] {
        &self.live.values
    }

    /// Move the current position to the top of `ebb`.
    ///
    /// This depends on the stored live value set at `ebb`'s immediate dominator, so that must have
    /// been visited first.
    ///
    /// Returns `(liveins, args)` as a pair or slices. The first slice is the set of live-in values
    /// from the immediate dominator. The second slice is the set of `ebb` arguments that are live.
    /// Dead arguments with no uses are ignored and not added to the set.
    pub fn ebb_top<PO: ProgramOrder>(&mut self,
                                     ebb: Ebb,
                                     dfg: &DataFlowGraph,
                                     liveness: &Liveness,
                                     program_order: &PO,
                                     domtree: &DominatorTree)
                                     -> (&[LiveValue], &[LiveValue]) {
        // Start over, compute the set of live values at the top of the EBB from two sources:
        //
        // 1. Values that were live before `ebb`'s immediate dominator, filtered for those that are
        //    actually live-in.
        // 2. Arguments to `ebb` that are not dead.
        //
        self.live.clear();

        // Compute the live-in values. Start by filtering the set of values that were live before
        // the immediate dominator. Just use the empty set if there's no immediate dominator (i.e.,
        // the entry block or an unreachable block).
        if let Some(idom) = domtree.idom(ebb) {
            // If the immediate dominator exits, we must have a stored list for it. This is a
            // requirement to the order EBBs are visited: All dominators must have been processed
            // before the current EBB.
            let idom_live_list =
                self.idom_sets.get(&idom).expect("No stored live set for dominator");
            // Get just the values that are live-in to `ebb`.
            for &value in idom_live_list.as_slice(&self.idom_pool) {
                let lr = liveness.get(value)
                    .expect("Immediate dominator value has no live range");

                // Check if this value is live-in here.
                if let Some(endpoint) = lr.livein_local_end(ebb, program_order) {
                    self.live.push(value, endpoint, lr.affinity);
                }
            }
        }

        // Now add all the live arguments to `ebb`.
        let first_arg = self.live.values.len();
        for value in dfg.ebb_args(ebb) {
            let lr = liveness.get(value).expect("EBB argument value has no live range");
            assert_eq!(lr.def(), ebb.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr.affinity);
                }
                ExpandedProgramPoint::Ebb(local_ebb) => {
                    // This is a dead EBB argument which is not even live into the first
                    // instruction in the EBB. We can ignore it.
                    assert_eq!(local_ebb,
                               ebb,
                               "EBB argument live range ends at wrong EBB header");
                }
            }
        }

        self.live.values.split_at(first_arg)
    }

    /// Prepare to move past `inst`.
    ///
    /// Determine the set of already live values that are killed by `inst`, and add the new defined
    /// values to the tracked set.
    ///
    /// Returns `(kills, defs)` as a pair of slices. The `defs` slice is guaranteed to be in the
    /// same order as `inst`'s results, and includes dead defines. The order of `kills` is
    /// arbitrary.
    ///
    /// The `drop_dead()` method must be called next to actually remove the dead values from the
    /// tracked set after the two returned slices are no longer needed.
    pub fn process_inst(&mut self,
                        inst: Inst,
                        dfg: &DataFlowGraph,
                        liveness: &Liveness)
                        -> (&[LiveValue], &[LiveValue]) {
        // Save a copy of the live values before any branches or jumps that could be somebody's
        // immediate dominator.
        match dfg[inst].analyze_branch() {
            BranchInfo::NotABranch => {}
            _ => self.save_idom_live_set(inst),
        }

        // Move killed values to the end of the vector.
        // Don't remove them yet, `drop_dead()` will do that.
        let first_kill = self.live.live_after(inst);

        // Add the values defined by `inst`.
        let first_def = self.live.values.len();
        for value in dfg.inst_results(inst) {
            let lr = match liveness.get(value) {
                Some(lr) => lr,
                None => panic!("{} result {} has no live range", dfg[inst].opcode(), value),
            };
            assert_eq!(lr.def(), inst.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr.affinity);
                }
                ExpandedProgramPoint::Ebb(ebb) => {
                    panic!("Instruction result live range can't end at {}", ebb);
                }
            }
        }

        (&self.live.values[first_kill..first_def], &self.live.values[first_def..])
    }

    /// Drop the values that are now dead after moving past `inst`.
    ///
    /// This removes both live values that were killed by `inst` and dead defines on `inst` itself.
    ///
    /// This must be called after `process_inst(inst)` and before proceeding to the next
    /// instruction.
    pub fn drop_dead(&mut self, inst: Inst) {
        // Remove both live values that were killed by `inst` and dead defines from `inst`.
        self.live.remove_kill_values(inst);
    }

    /// Save the current set of live values so it is associated with `idom`.
    fn save_idom_live_set(&mut self, idom: Inst) {
        let values = self.live.values.iter().map(|lv| lv.value);
        let pool = &mut self.idom_pool;
        // If there already is a set saved for `idom`, just keep it.
        self.idom_sets.entry(idom).or_insert_with(|| {
            let mut list = ValueList::default();
            list.extend(values, pool);
            list
        });
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};
use {Class, Function, Type, TypeKind};
use std::collections::BTreeMap;

fn get_hl_type(ty: &Type) -> String {
    if ty.is_custom {
        match ty.kind {
            TypeKind::Ref => format!("{}Ref", ty.name),
            TypeKind::RefMut => format!("{}RefMut", ty.name),
            TypeKind::Value => ty.name.clone(),
        }
    } else {
        get_ll_type(ty).to_string()
    }
}

fn get_ll_type(ty: &Type) -> &str {
    match (ty.kind, ty.name.as_str()) {
        (TypeKind::Ref, "c_char") => "c_char_p",
        (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "c_void_p",
        (_, t) if !ty.is_custom => match t {
            "i8" => "c_int8",
            "i16" => "c_int16",
            "i32" => "c_int32",
            "i64" => "c_int64",
            "u8" => "c_uint8",
            "u16" => "c_uint16",
            "u32" => "c_uint32",
            "u64" => "c_uint64",
            "usize" => "c_size_t",
            "f32" => "c_float",
            "f64" => "c_double",
            "bool" => "c_bool",
            "()" => "None",
            "c_char" => "c_char",
            "Json" => "c_char_p",
            x => x,
        },
        _ => "c_void_p",
    }
}

fn map_var(var: &str) -> &str {
    if var == "this" {
        "self"
    } else {
        var
    }
}

fn write_fn<W: Write>(mut writer: W, function: &Function) -> Result<()> {
    let is_static = function.is_static();
    let has_return_type = function.has_return_type();
    let return_type = get_hl_type(&function.output);

    if is_static {
        write!(
            writer,
            r#"
    @staticmethod
    def {}("#,
            function.method
        )?;
    } else {
        write!(
            writer,
            r#"
    def {}("#,
            function.method
        )?;
    }

    for (i, &(ref name, _)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(writer, "{}", map_var(name))?;
    }

    write!(
        writer,
        r#"):
        "#
    )?;

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom {
            write!(
                writer,
                r#"if {name}.ptr == None:
            raise Exception("{name} is disposed")
        "#,
                name = map_var(name)
            )?;
        }
    }

    if has_return_type {
        if function.output.is_custom {
            write!(writer, r#"result = {}("#, return_type)?;
        } else {
            write!(writer, "result = ")?;
        }
    }

    write!(writer, r#"livesplit_core_native.{}("#, &function.name)?;

    for (i, &(ref name, ref typ)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(
            writer,
            "{}",
            if name == "this" {
                "self.ptr".to_string()
            } else if typ.is_custom {
                format!("{}.ptr", name)
            } else {
                name.to_string()
            }
        )?;
    }

    write!(writer, ")")?;

    if has_return_type && function.output.is_custom {
        write!(writer, r#")"#)?;
    }

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom && typ.kind == TypeKind::Value {
            write!(
                writer,
                r#"
        {}.ptr = None"#,
                map_var(name)
            )?;
        }
    }

    if has_return_type {
        if function.output.is_nullable && function.output.is_custom {
            write!(
                writer,
                r#"
        if result.ptr == None:
            return None"#
            )?;
        }
        write!(
            writer,
            r#"
        return result"#
        )?;
    }

    write!(
        writer,
        r#"
"#
    )?;

    Ok(())
}

pub fn write<W: Write>(mut writer: W, classes: &BTreeMap<String, Class>) -> Result<()> {
    write!(writer,
           "{}",
           r#"#!/usr/bin/env python3
# coding: utf-8

import sys, ctypes
from ctypes import c_char_p, c_void_p, c_int8, c_int16, c_int32, c_int64, c_uint8, c_uint16, c_uint32, c_uint64, c_size_t, c_float, c_double, c_bool, c_char, c_byte

prefix = {'win32': ''}.get(sys.platform, './lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
livesplit_core_native = ctypes.cdll.LoadLibrary(prefix + "livesplit_core" + extension)
"#)?;

    for class in classes.values() {
        for function in class
            .static_fns
            .iter()
            .chain(class.own_fns.iter())
            .chain(class.shared_fns.iter())
            .chain(class.mut_fns.iter())
        {
            write!(
                writer,
                r#"
livesplit_core_native.{}.argtypes = ("#,
                function.name
            )?;

            for &(_, ref typ) in &function.inputs {
                write!(writer, "{}, ", get_ll_type(typ))?;
            }

            write!(
                writer,
                r#")
livesplit_core_native.{}.restype = {}"#,
                function.name,
                get_ll_type(&function.output)
            )?;
        }
    }

    writeln!(writer)?;

    for (class_name, class) in classes {
        let class_name_ref = format!("{}Ref", class_name);
        let class_name_ref_mut = format!("{}RefMut", class_name);

        write!(
            writer,
            r#"
class {class}:"#,
            class = class_name_ref
        )?;

        for function in &class.shared_fns {
            write_fn(&mut writer, function)?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr

class {class}({base_class}):"#,
            class = class_name_ref_mut,
            base_class = class_name_ref
        )?;

        for function in &class.mut_fns {
            write_fn(&mut writer, function)?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr

class {class}({base_class}):
    def drop(self):
        if self.ptr != None:"#,
            class = class_name,
            base_class = class_name_ref_mut
        )?;

        if let Some(function) = class.own_fns.iter().find(|f| f.method == "drop") {
            write!(
                writer,
                r#"
            livesplit_core_native.{}(self.ptr)"#,
                function.name
            )?;
        }

        write!(
            writer,
            r#"
            self.ptr = None

    def __del__(self):
        self.drop()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.drop()
"#
        )?;

        for function in class.static_fns.iter().chain(class.own_fns.iter()) {
            if function.method != "drop" {
                write_fn(&mut writer, function)?;
            }
        }

        if class_name == "Run" {
            writeln!(
                writer,
                r#"
    @staticmethod
    def parse_file(file):
        bytes = bytearray(file.read())
        bufferType = c_byte * len(bytes)
        buffer = bufferType(*bytes)
        return Run.parse(buffer, len(bytes))"#
            )?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr
"#
        )?;
    }

    Ok(())
}
<commit_msg>In Python 3 we need bytes, not str, from the file read in order to parse the run. So we check to make sure we got the right data type.  The wrong type means the file was opened in the wrong mode.<commit_after>use std::io::{Result, Write};
use {Class, Function, Type, TypeKind};
use std::collections::BTreeMap;

fn get_hl_type(ty: &Type) -> String {
    if ty.is_custom {
        match ty.kind {
            TypeKind::Ref => format!("{}Ref", ty.name),
            TypeKind::RefMut => format!("{}RefMut", ty.name),
            TypeKind::Value => ty.name.clone(),
        }
    } else {
        get_ll_type(ty).to_string()
    }
}

fn get_ll_type(ty: &Type) -> &str {
    match (ty.kind, ty.name.as_str()) {
        (TypeKind::Ref, "c_char") => "c_char_p",
        (TypeKind::Ref, _) | (TypeKind::RefMut, _) => "c_void_p",
        (_, t) if !ty.is_custom => match t {
            "i8" => "c_int8",
            "i16" => "c_int16",
            "i32" => "c_int32",
            "i64" => "c_int64",
            "u8" => "c_uint8",
            "u16" => "c_uint16",
            "u32" => "c_uint32",
            "u64" => "c_uint64",
            "usize" => "c_size_t",
            "f32" => "c_float",
            "f64" => "c_double",
            "bool" => "c_bool",
            "()" => "None",
            "c_char" => "c_char",
            "Json" => "c_char_p",
            x => x,
        },
        _ => "c_void_p",
    }
}

fn map_var(var: &str) -> &str {
    if var == "this" {
        "self"
    } else {
        var
    }
}

fn write_fn<W: Write>(mut writer: W, function: &Function) -> Result<()> {
    let is_static = function.is_static();
    let has_return_type = function.has_return_type();
    let return_type = get_hl_type(&function.output);

    if is_static {
        write!(
            writer,
            r#"
    @staticmethod
    def {}("#,
            function.method
        )?;
    } else {
        write!(
            writer,
            r#"
    def {}("#,
            function.method
        )?;
    }

    for (i, &(ref name, _)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(writer, "{}", map_var(name))?;
    }

    write!(
        writer,
        r#"):
        "#
    )?;

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom {
            write!(
                writer,
                r#"if {name}.ptr == None:
            raise Exception("{name} is disposed")
        "#,
                name = map_var(name)
            )?;
        }
    }

    if has_return_type {
        if function.output.is_custom {
            write!(writer, r#"result = {}("#, return_type)?;
        } else {
            write!(writer, "result = ")?;
        }
    }

    write!(writer, r#"livesplit_core_native.{}("#, &function.name)?;

    for (i, &(ref name, ref typ)) in function.inputs.iter().enumerate() {
        if i != 0 {
            write!(writer, ", ")?;
        }
        write!(
            writer,
            "{}",
            if name == "this" {
                "self.ptr".to_string()
            } else if typ.is_custom {
                format!("{}.ptr", name)
            } else {
                name.to_string()
            }
        )?;
    }

    write!(writer, ")")?;

    if has_return_type && function.output.is_custom {
        write!(writer, r#")"#)?;
    }

    for &(ref name, ref typ) in function.inputs.iter() {
        if typ.is_custom && typ.kind == TypeKind::Value {
            write!(
                writer,
                r#"
        {}.ptr = None"#,
                map_var(name)
            )?;
        }
    }

    if has_return_type {
        if function.output.is_nullable && function.output.is_custom {
            write!(
                writer,
                r#"
        if result.ptr == None:
            return None"#
            )?;
        }
        write!(
            writer,
            r#"
        return result"#
        )?;
    }

    write!(
        writer,
        r#"
"#
    )?;

    Ok(())
}

pub fn write<W: Write>(mut writer: W, classes: &BTreeMap<String, Class>) -> Result<()> {
    write!(writer,
           "{}",
           r#"#!/usr/bin/env python3
# coding: utf-8

import sys, ctypes
from ctypes import c_char_p, c_void_p, c_int8, c_int16, c_int32, c_int64, c_uint8, c_uint16, c_uint32, c_uint64, c_size_t, c_float, c_double, c_bool, c_char, c_byte

prefix = {'win32': ''}.get(sys.platform, './lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
livesplit_core_native = ctypes.cdll.LoadLibrary(prefix + "livesplit_core" + extension)
"#)?;

    for class in classes.values() {
        for function in class
            .static_fns
            .iter()
            .chain(class.own_fns.iter())
            .chain(class.shared_fns.iter())
            .chain(class.mut_fns.iter())
        {
            write!(
                writer,
                r#"
livesplit_core_native.{}.argtypes = ("#,
                function.name
            )?;

            for &(_, ref typ) in &function.inputs {
                write!(writer, "{}, ", get_ll_type(typ))?;
            }

            write!(
                writer,
                r#")
livesplit_core_native.{}.restype = {}"#,
                function.name,
                get_ll_type(&function.output)
            )?;
        }
    }

    writeln!(writer)?;

    for (class_name, class) in classes {
        let class_name_ref = format!("{}Ref", class_name);
        let class_name_ref_mut = format!("{}RefMut", class_name);

        write!(
            writer,
            r#"
class {class}:"#,
            class = class_name_ref
        )?;

        for function in &class.shared_fns {
            write_fn(&mut writer, function)?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr

class {class}({base_class}):"#,
            class = class_name_ref_mut,
            base_class = class_name_ref
        )?;

        for function in &class.mut_fns {
            write_fn(&mut writer, function)?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr

class {class}({base_class}):
    def drop(self):
        if self.ptr != None:"#,
            class = class_name,
            base_class = class_name_ref_mut
        )?;

        if let Some(function) = class.own_fns.iter().find(|f| f.method == "drop") {
            write!(
                writer,
                r#"
            livesplit_core_native.{}(self.ptr)"#,
                function.name
            )?;
        }

        write!(
            writer,
            r#"
            self.ptr = None

    def __del__(self):
        self.drop()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.drop()
"#
        )?;

        for function in class.static_fns.iter().chain(class.own_fns.iter()) {
            if function.method != "drop" {
                write_fn(&mut writer, function)?;
            }
        }

        if class_name == "Run" {
            writeln!(
                writer,
                r#"
    @staticmethod
    def parse_file(file):
        data = file.read()
        if sys.version_info[0] > 2:
            if isinstance(data, str):
                raise TypeError("File must be opened in binary mode!")
        bytes = bytearray(data)
        bufferType = c_byte * len(bytes)
        buffer = bufferType(*bytes)
        return Run.parse(buffer, len(bytes))"#
            )?;
        }

        write!(
            writer,
            r#"
    def __init__(self, ptr):
        self.ptr = ptr
"#
        )?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

mod lib;

use clap::{App, Arg};
use lib::petname;
use std::io::Write;
use std::process;

fn main() {
    let matches = App::new("rust-petname")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generate human readable random names.")
        .after_help(concat!(
            "Based on Dustin Kirkland's petname project ",
            "<https://github.com/dustinkirkland/petname>."
        ))
        .arg(
            Arg::with_name("words")
                .short("w")
                .long("words")
                .value_name("WORDS")
                .default_value("2")
                .help("Number of words in name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("separator")
                .short("s")
                .long("separator")
                .value_name("SEP")
                .default_value("-")
                .help("Separator between words")
                .takes_value(true),
        )
        .get_matches();

    // Unwrapping is safe because these options have defaults.
    let opt_separator = matches.value_of("separator").unwrap();
    let opt_words = matches.value_of("words").unwrap();

    // Parse the words option into a number.
    let opt_words: u8 = opt_words.parse().unwrap_or_else(|error| {
        writeln!(
            std::io::stderr(),
            "--words={} could not be parsed: {}",
            opt_words,
            error
        )
        .ok();
        process::exit(1);
    });

    println!("{}", petname(opt_words, opt_separator));
}
<commit_msg>Allow selecting word list "complexity", i.e. small, medium, or large.<commit_after>#[macro_use]
extern crate clap;

mod lib;

use clap::{App, Arg};
use lib::Petnames;
use std::io::Write;
use std::process;

fn main() {
    let matches = App::new("rust-petname")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generate human readable random names.")
        .after_help(concat!(
            "Based on Dustin Kirkland's petname project ",
            "<https://github.com/dustinkirkland/petname>."
        ))
        .arg(
            Arg::with_name("words")
                .short("w")
                .long("words")
                .value_name("WORDS")
                .default_value("2")
                .help("Number of words in name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("separator")
                .short("s")
                .long("separator")
                .value_name("SEP")
                .default_value("-")
                .help("Separator between words")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("complexity")
                .short("c")
                .long("complexity")
                .value_name("COMPLEXITY")
                .possible_values(&["0", "1", "2"])
                .hide_possible_values(true)
                .default_value("0")
                .help("Use small words (0), medium words (1), or large words (2)")
                .takes_value(true),
        )
        .get_matches();

    // Unwrapping is safe because these options have defaults.
    let opt_separator = matches.value_of("separator").unwrap();
    let opt_words = matches.value_of("words").unwrap();
    let opt_complexity = matches.value_of("complexity").unwrap();

    // Parse the words option into a number.
    let opt_words: u8 = opt_words.parse().unwrap_or_else(|error| {
        writeln!(
            std::io::stderr(),
            "--words={} could not be parsed: {}",
            opt_words,
            error
        )
        .ok();
        process::exit(1);
    });

    // Select the appropriate word list.
    let petnames = match opt_complexity {
        "0" => Petnames::small(),
        "1" => Petnames::medium(),
        "2" => Petnames::large(),
        _ => Petnames::small(),
    };

    println!("{}", petnames.generate_one(opt_words, opt_separator));
}
<|endoftext|>


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

#[macro_use]
extern crate log;
#[macro_use]
extern crate objc;
extern crate objc_foundation;
extern crate cocoa;
extern crate gfx_core as core;
extern crate metal_rs as metal;
extern crate bit_set;
extern crate block;

// use cocoa::base::{selector, class};
// use cocoa::foundation::{NSUInteger};

use metal::*;

use block::{Block, ConcreteBlock};
use core::{handle, texture as tex};
use core::{QueueType, SubmissionResult};
use core::memory::{self, Usage, Bind};
use core::command::{AccessInfo, AccessGuard};

use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
// use std::{mem, ptr};

mod factory;
mod command;
mod encoder;
mod mirror;
mod map;
pub mod native;
mod pool;

pub use self::factory::Factory;
pub use self::map::*;

// Grabbed from https://developer.apple.com/metal/limits/
const MTL_MAX_TEXTURE_BINDINGS: usize = 128;
const MTL_MAX_BUFFER_BINDINGS: usize = 31;
const MTL_MAX_SAMPLER_BINDINGS: usize = 16;

pub type ShaderModel = u16;

pub fn enumerate_adapters() -> Vec<Adapter> {
    // TODO: enumerate all devices
    let device = metal::create_system_default_device(); // Returns retained

    vec![
        Adapter {
            device,
            adapter_info: core::AdapterInfo {
                name: device.name().into(),
                vendor: 0,
                device: 0,
                software_rendering: false,
            },
            queue_families: [(QueueFamily, QueueType::General)],
        }
    ]
}

#[derive(Clone)]
pub struct QueueFamily;
impl core::QueueFamily for QueueFamily {
    fn num_queues(&self) -> u32 { 1 }
}

pub struct Adapter {
    device: MTLDevice,
    adapter_info: core::AdapterInfo,
    queue_families: [(QueueFamily, QueueType); 1],
}

impl core::Adapter<Backend> for Adapter {
    fn open(&self, queue_descs: &[(&QueueFamily, QueueType, u32)])
        -> core::Device<Backend>
    {
        // Single queue family supported only
        assert_eq!(queue_descs.len(), 1);

        // Ascending order important here to get the best feature set
        use metal::MTLFeatureSet::*;
        let feature_set = [
            iOS_GPUFamily1_v1,
            iOS_GPUFamily1_v2,
            iOS_GPUFamily1_v3,
            iOS_GPUFamily1_v4,

            iOS_GPUFamily2_v1,
            iOS_GPUFamily2_v2,
            iOS_GPUFamily2_v3,
            iOS_GPUFamily2_v4,

            iOS_GPUFamily3_v1,
            iOS_GPUFamily3_v2,
            iOS_GPUFamily3_v3,

            tvOS_GPUFamily1_v1,
            tvOS_GPUFamily1_v2,
            tvOS_GPUFamily1_v3,

            macOS_GPUFamily1_v1,
            macOS_GPUFamily1_v2,
            macOS_GPUFamily1_v3,
        ].iter()
         .rev()
         .cloned()
         .find(|&f| self.device.supports_feature_set(f));

        let share = Share {
            capabilities: core::Capabilities {
                max_texture_size: 0,
                max_patch_size: 0,
                instance_base_supported: false,
                instance_call_supported: false,
                instance_rate_supported: false,
                vertex_base_supported: false,
                srgb_color_supported: false,
                constant_buffer_supported: true,
                unordered_access_view_supported: false,
                separate_blending_slots_supported: false,
                copy_buffer_supported: true,
            },
            handles: RefCell::new(handle::Manager::new()),
            feature_set: feature_set.unwrap(),
        };

        unsafe { self.device.retain(); }
        let factory = Factory::new(self.device, Arc::new(share));

        let mut device = core::Device {
            factory,
            general_queues: Vec::new(),
            graphics_queues: Vec::new(),
            compute_queues: Vec::new(),
            transfer_queues: Vec::new(),
            heap_types: Vec::new(),
            memory_heaps: Vec::new(),
            _marker: PhantomData,
        };

        let raw_queue = || {
            unsafe { self.device.retain(); }
            CommandQueue::new(self.device)
        };

        if let Some(&(_, queue_type, queue_count)) = queue_descs.iter().next() {
            for _ in 0..queue_count {
                unsafe {
                    match queue_type {
                        QueueType::General => {
                            device.general_queues.push(core::GeneralQueue::new(raw_queue()));
                        }
                        QueueType::Graphics => {
                            device.graphics_queues.push(core::GraphicsQueue::new(raw_queue()));
                        }
                        QueueType::Compute => {
                            device.compute_queues.push(core::ComputeQueue::new(raw_queue()));
                        }
                        QueueType::Transfer => {
                            device.transfer_queues.push(core::TransferQueue::new(raw_queue()));
                        }
                    }
                }
            }
        }

        device
    }

    fn get_info(&self) -> &core::AdapterInfo {
        &self.adapter_info
    }

    fn get_queue_families(&self) -> &[(QueueFamily, QueueType)] {
        &self.queue_families
    }
}

pub struct CommandQueue {
    raw: Arc<QueueInner>,
    frame_handles: handle::Manager<Resources>,
    max_resource_count: Option<usize>,
}

struct QueueInner {
    queue: MTLCommandQueue,
}

impl Drop for QueueInner {
    fn drop(&mut self) {
        unsafe {
            self.queue.release();
        }
    }
}

impl CommandQueue {
    pub fn new(device: MTLDevice) -> CommandQueue {
        let raw_queue = QueueInner { queue: device.new_command_queue() };
        CommandQueue {
            raw: Arc::new(raw_queue),
            frame_handles: handle::Manager::new(),
            max_resource_count: Some(999999),
        }
    }

    pub unsafe fn device(&self) -> MTLDevice {
        // TODO: How often do we call this and how costly is it?
        msg_send![self.raw.queue.0, device]
    }
}

impl core::CommandQueue<Backend> for CommandQueue {
    unsafe fn submit_raw<'a, I>(
        &mut self,
        submit_infos: I,
        fence: Option<&handle::Fence<Resources>>,
        access: &AccessInfo<Resources>,
    ) where I: Iterator<Item=core::RawSubmission<'a, Backend>> {
        for submit in submit_infos {
            // FIXME: wait for semaphores!

            // FIXME: multiple buffers signaling!
            let signal_block = if !submit.signal_semaphores.is_empty() {
                let semaphores_copy: Vec<_> = submit.signal_semaphores.iter().map(|semaphore| {
                    self.frame_handles.ref_semaphore(semaphore).lock().unwrap().0
                }).collect();
                Some(ConcreteBlock::new(move |cb: *mut ()| -> () {
                    for semaphore in semaphores_copy.iter() {
                        native::dispatch_semaphore_signal(*semaphore);
                    }
                }).copy())
            } else {
                None
            };

            for buffer in submit.cmd_buffers {
                let command_buffer = buffer.command_buffer;
                if let Some(ref signal_block) = signal_block {
                    msg_send![command_buffer.0, addCompletedHandler: signal_block.deref() as *const _];
                }
                // only append the fence handler to the last command buffer
                if submit as *const _ == submit_infos.last().unwrap() as *const _ &&
                   buffer as *const _ == submit.cmd_buffers.last().unwrap() as *const _ {
                    if let Some(ref fence) = fence {
                        let value_ptr = self.frame_handles.ref_fence(fence).lock().unwrap().0.clone();
                        let fence_block = ConcreteBlock::new(move |cb: *mut ()| -> () {
                            *value_ptr.lock().unwrap() = true;
                        }).copy();
                        msg_send![command_buffer.0, addCompletedHandler: fence_block.deref() as *const _];
                    }
                }
                command_buffer.commit();
            }
        }
    }

    fn pin_submitted_resources(&mut self, man: &handle::Manager<Resources>) {
        self.frame_handles.extend(man);
        match self.max_resource_count {
            Some(c) if self.frame_handles.count() > c => {
                error!("Way too many resources in the current frame. Did you call Device::cleanup()?");
                self.max_resource_count = None;
            },
            _ => (),
        }
    }

    fn cleanup(&mut self) {
        use core::handle::Producer;
        self.frame_handles.clear();
    }
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Backend {}
impl core::Backend for Backend {
    type Adapter = Adapter;
    type Resources = Resources;
    type CommandQueue = CommandQueue;
    type RawCommandBuffer = command::RawCommandBuffer;
    type SubpassCommandBuffer = command::SubpassCommandBuffer;
    type SubmitInfo = command::SubmitInfo;
    type Factory = Factory;
    type QueueFamily = QueueFamily;

    type RawCommandPool = pool::RawCommandPool;
    type SubpassCommandPool = pool::SubpassCommandPool;
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Resources {}
impl core::Resources for Resources {
    type Buffer = native::Buffer;
    type Shader = native::Shader;
    type Program = native::Program;
    type PipelineStateObject = native::Pipeline;
    type Texture = native::Texture;
    type ShaderResourceView = native::Srv;
    type UnorderedAccessView = native::Uav;
    type RenderTargetView = native::Rtv;
    type DepthStencilView = native::Dsv;
    type Sampler = native::Sampler;
    type Fence = native::Fence;
    type Semaphore = native::Semaphore;
    type Mapping = factory::RawMapping;
}

/// Internal struct of shared data.
#[doc(hidden)]
pub struct Share {
    capabilities: core::Capabilities,
    handles: RefCell<handle::Manager<Resources>>,
    feature_set: MTLFeatureSet,
}
<commit_msg>metal: Fix queue submission<commit_after>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
#[macro_use]
extern crate objc;
extern crate objc_foundation;
extern crate cocoa;
extern crate gfx_core as core;
extern crate metal_rs as metal;
extern crate bit_set;
extern crate block;

// use cocoa::base::{selector, class};
// use cocoa::foundation::{NSUInteger};

use metal::*;

use block::{Block, ConcreteBlock};
use core::{handle, texture as tex};
use core::{QueueType, SubmissionResult};
use core::memory::{self, Usage, Bind};
use core::command::{AccessInfo, AccessGuard};

use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
// use std::{mem, ptr};

mod factory;
mod command;
mod encoder;
mod mirror;
mod map;
pub mod native;
mod pool;

pub use self::factory::Factory;
pub use self::map::*;

// Grabbed from https://developer.apple.com/metal/limits/
const MTL_MAX_TEXTURE_BINDINGS: usize = 128;
const MTL_MAX_BUFFER_BINDINGS: usize = 31;
const MTL_MAX_SAMPLER_BINDINGS: usize = 16;

pub type ShaderModel = u16;

pub fn enumerate_adapters() -> Vec<Adapter> {
    // TODO: enumerate all devices
    let device = metal::create_system_default_device(); // Returns retained

    vec![
        Adapter {
            device,
            adapter_info: core::AdapterInfo {
                name: device.name().into(),
                vendor: 0,
                device: 0,
                software_rendering: false,
            },
            queue_families: [(QueueFamily, QueueType::General)],
        }
    ]
}

#[derive(Clone)]
pub struct QueueFamily;
impl core::QueueFamily for QueueFamily {
    fn num_queues(&self) -> u32 { 1 }
}

pub struct Adapter {
    device: MTLDevice,
    adapter_info: core::AdapterInfo,
    queue_families: [(QueueFamily, QueueType); 1],
}

impl core::Adapter<Backend> for Adapter {
    fn open(&self, queue_descs: &[(&QueueFamily, QueueType, u32)])
        -> core::Device<Backend>
    {
        // Single queue family supported only
        assert_eq!(queue_descs.len(), 1);

        // Ascending order important here to get the best feature set
        use metal::MTLFeatureSet::*;
        let feature_set = [
            iOS_GPUFamily1_v1,
            iOS_GPUFamily1_v2,
            iOS_GPUFamily1_v3,
            iOS_GPUFamily1_v4,

            iOS_GPUFamily2_v1,
            iOS_GPUFamily2_v2,
            iOS_GPUFamily2_v3,
            iOS_GPUFamily2_v4,

            iOS_GPUFamily3_v1,
            iOS_GPUFamily3_v2,
            iOS_GPUFamily3_v3,

            tvOS_GPUFamily1_v1,
            tvOS_GPUFamily1_v2,
            tvOS_GPUFamily1_v3,

            macOS_GPUFamily1_v1,
            macOS_GPUFamily1_v2,
            macOS_GPUFamily1_v3,
        ].iter()
         .rev()
         .cloned()
         .find(|&f| self.device.supports_feature_set(f));

        let share = Share {
            capabilities: core::Capabilities {
                max_texture_size: 0,
                max_patch_size: 0,
                instance_base_supported: false,
                instance_call_supported: false,
                instance_rate_supported: false,
                vertex_base_supported: false,
                srgb_color_supported: false,
                constant_buffer_supported: true,
                unordered_access_view_supported: false,
                separate_blending_slots_supported: false,
                copy_buffer_supported: true,
            },
            handles: RefCell::new(handle::Manager::new()),
            feature_set: feature_set.unwrap(),
        };

        unsafe { self.device.retain(); }
        let factory = Factory::new(self.device, Arc::new(share));

        let mut device = core::Device {
            factory,
            general_queues: Vec::new(),
            graphics_queues: Vec::new(),
            compute_queues: Vec::new(),
            transfer_queues: Vec::new(),
            heap_types: Vec::new(),
            memory_heaps: Vec::new(),
            _marker: PhantomData,
        };

        let raw_queue = || {
            unsafe { self.device.retain(); }
            CommandQueue::new(self.device)
        };

        if let Some(&(_, queue_type, queue_count)) = queue_descs.iter().next() {
            for _ in 0..queue_count {
                unsafe {
                    match queue_type {
                        QueueType::General => {
                            device.general_queues.push(core::GeneralQueue::new(raw_queue()));
                        }
                        QueueType::Graphics => {
                            device.graphics_queues.push(core::GraphicsQueue::new(raw_queue()));
                        }
                        QueueType::Compute => {
                            device.compute_queues.push(core::ComputeQueue::new(raw_queue()));
                        }
                        QueueType::Transfer => {
                            device.transfer_queues.push(core::TransferQueue::new(raw_queue()));
                        }
                    }
                }
            }
        }

        device
    }

    fn get_info(&self) -> &core::AdapterInfo {
        &self.adapter_info
    }

    fn get_queue_families(&self) -> &[(QueueFamily, QueueType)] {
        &self.queue_families
    }
}

pub struct CommandQueue {
    raw: Arc<QueueInner>,
    frame_handles: handle::Manager<Resources>,
    max_resource_count: Option<usize>,
}

struct QueueInner {
    queue: MTLCommandQueue,
}

impl Drop for QueueInner {
    fn drop(&mut self) {
        unsafe {
            self.queue.release();
        }
    }
}

impl CommandQueue {
    pub fn new(device: MTLDevice) -> CommandQueue {
        let raw_queue = QueueInner { queue: device.new_command_queue() };
        CommandQueue {
            raw: Arc::new(raw_queue),
            frame_handles: handle::Manager::new(),
            max_resource_count: Some(999999),
        }
    }

    pub unsafe fn device(&self) -> MTLDevice {
        // TODO: How often do we call this and how costly is it?
        msg_send![self.raw.queue.0, device]
    }
}

// Iterator extension which checks
// if are at the last element of the iterator
trait CheckLast: Iterator + Sized {
    fn check_last(mut self) -> CheckLastIter<Self> {
        CheckLastIter {
            next: self.next(),
            iterator: self,
        }
    }
}

impl<It> CheckLast for It where It: Iterator { }

struct CheckLastIter<It: Iterator> {
    iterator: It,
    next: Option<It::Item>,
}

impl<It> Iterator for CheckLastIter<It> where It: Iterator {
    type Item = (bool, It::Item);
    fn next(&mut self) -> Option<Self::Item> {
        match self.next.take() {
            Some(cur_elem) => {
                match self.iterator.next() {
                    Some(next) => {
                        self.next = Some(next);
                        Some((false, cur_elem))
                    }
                    None => {
                        self.next = None;
                        Some((true, cur_elem))
                    }
                }
            }
            None => None,
        }
    }
}

impl core::CommandQueue<Backend> for CommandQueue {
    unsafe fn submit_raw<'a, I>(
        &mut self,
        submit_infos: I,
        fence: Option<&handle::Fence<Resources>>,
        access: &AccessInfo<Resources>,
    ) where I: Iterator<Item=core::RawSubmission<'a, Backend>> {
        for (last_submission, submit) in submit_infos.check_last() {
            // FIXME: wait for semaphores!

            // FIXME: multiple buffers signaling!
            let signal_block = if !submit.signal_semaphores.is_empty() {
                let semaphores_copy: Vec<_> = submit.signal_semaphores.iter().map(|semaphore| {
                    self.frame_handles.ref_semaphore(semaphore).lock().unwrap().0
                }).collect();
                Some(ConcreteBlock::new(move |cb: *mut ()| -> () {
                    for semaphore in semaphores_copy.iter() {
                        native::dispatch_semaphore_signal(*semaphore);
                    }
                }).copy())
            } else {
                None
            };

            for (last_buffer, buffer) in submit.cmd_buffers.iter().check_last() {
                let command_buffer = buffer.command_buffer;
                if let Some(ref signal_block) = signal_block {
                    msg_send![command_buffer.0, addCompletedHandler: signal_block.deref() as *const _];
                }
                // only append the fence handler to the last command buffer
                if last_submission && last_buffer {
                    if let Some(ref fence) = fence {
                        let value_ptr = self.frame_handles.ref_fence(fence).lock().unwrap().0.clone();
                        let fence_block = ConcreteBlock::new(move |cb: *mut ()| -> () {
                            *value_ptr.lock().unwrap() = true;
                        }).copy();
                        msg_send![command_buffer.0, addCompletedHandler: fence_block.deref() as *const _];
                    }
                }
                command_buffer.commit();
            }
        }
    }

    fn pin_submitted_resources(&mut self, man: &handle::Manager<Resources>) {
        self.frame_handles.extend(man);
        match self.max_resource_count {
            Some(c) if self.frame_handles.count() > c => {
                error!("Way too many resources in the current frame. Did you call Device::cleanup()?");
                self.max_resource_count = None;
            },
            _ => (),
        }
    }

    fn cleanup(&mut self) {
        use core::handle::Producer;
        self.frame_handles.clear();
    }
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Backend {}
impl core::Backend for Backend {
    type Adapter = Adapter;
    type Resources = Resources;
    type CommandQueue = CommandQueue;
    type RawCommandBuffer = command::RawCommandBuffer;
    type SubpassCommandBuffer = command::SubpassCommandBuffer;
    type SubmitInfo = command::SubmitInfo;
    type Factory = Factory;
    type QueueFamily = QueueFamily;

    type RawCommandPool = pool::RawCommandPool;
    type SubpassCommandPool = pool::SubpassCommandPool;
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Resources {}
impl core::Resources for Resources {
    type Buffer = native::Buffer;
    type Shader = native::Shader;
    type Program = native::Program;
    type PipelineStateObject = native::Pipeline;
    type Texture = native::Texture;
    type ShaderResourceView = native::Srv;
    type UnorderedAccessView = native::Uav;
    type RenderTargetView = native::Rtv;
    type DepthStencilView = native::Dsv;
    type Sampler = native::Sampler;
    type Fence = native::Fence;
    type Semaphore = native::Semaphore;
    type Mapping = factory::RawMapping;
}

/// Internal struct of shared data.
#[doc(hidden)]
pub struct Share {
    capabilities: core::Capabilities,
    handles: RefCell<handle::Manager<Resources>>,
    feature_set: MTLFeatureSet,
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#[macro_use]
extern crate lazy_static;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson};

extern crate rs_es;
use rs_es::Client;

extern crate iron;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

extern crate logger;
use logger::Logger;

extern crate router;
use router::Router;

extern crate params;
use params::*;

extern crate searchspot;
use searchspot::resources::user::Talent;
use searchspot::config::*;
use searchspot::search::SearchResult;

use std::env;

lazy_static! {
  static ref config: Config = match env::args().nth(1) {
    Some(file) => Config::from_file(file),
    None       => Config::from_env()
  };
}

fn main() {
  let host = format!("{}:{}", config.http.host, config.http.port);

  println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"), config.es, config.http);

  let mut router = Router::new();
  router.get("/talents", talents);

  let mut chain = Chain::new(router);
  chain.link(Logger::new(None));
  Iron::new(chain).http(&*host).unwrap();
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new(&*config.es.host, config.es.port);

  let params  = req.get_ref::<Params>().ok().unwrap();
  let indexes = config.es.indexes.iter()
                                 .map(|e| &**e)
                                 .collect::<Vec<&str>>();

  let response = SearchResult {
    results: Talent::search(&mut es, indexes, params),
    params:  params.clone()
  };

  let content_type = "application/json".parse::<Mime>().unwrap();
  Ok(Response::with((content_type, status::Ok, json::encode(&response.to_json()).unwrap())))
}
<commit_msg>main: skip logging under heroku<commit_after>#![allow(non_upper_case_globals)]
#[macro_use]
extern crate lazy_static;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson};

extern crate rs_es;
use rs_es::Client;

extern crate iron;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

extern crate logger;
use logger::Logger;

extern crate router;
use router::Router;

extern crate params;
use params::*;

extern crate searchspot;
use searchspot::resources::user::Talent;
use searchspot::config::*;
use searchspot::search::SearchResult;

use std::env;

lazy_static! {
  static ref config: Config = match env::args().nth(1) {
    Some(file) => Config::from_file(file),
    None       => Config::from_env()
  };
}

fn main() {
  let host = format!("{}:{}", config.http.host, config.http.port);

  println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"), config.es, config.http);

  let mut router = Router::new();
  router.get("/talents", talents);

  let mut chain = Chain::new(router);

  // for some reasons, this link makes heroku crash
  if env::var("DYNO").is_err() {
    chain.link(Logger::new(None));
  }

  Iron::new(chain).http(&*host).unwrap();
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new(&*config.es.host, config.es.port);

  let params  = req.get_ref::<Params>().ok().unwrap();
  let indexes = config.es.indexes.iter()
                                 .map(|e| &**e)
                                 .collect::<Vec<&str>>();

  let response = SearchResult {
    results: Talent::search(&mut es, indexes, params),
    params:  params.clone()
  };

  let content_type = "application/json".parse::<Mime>().unwrap();
  Ok(Response::with((content_type, status::Ok, json::encode(&response.to_json()).unwrap())))
}
<|endoftext|>


<commit_before>extern crate getopts;

use getopts::Options;
use std::env;
use std::io::{self, Write};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, TcpStream};
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::thread;

// Max possible port
const MAX: u16 = 65535;

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("j",
                "",
                "number of threads to use for concurrent scanning",
                "THREADS");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("error parsing options: {}", e.to_string());
            return;
        }
    };

    // Present usage if '-h' or no IP address provided
    if matches.opt_present("h") || matches.free.is_empty() {
        let brief = format!("Usage: {} -j THREADS IPADDR", program);
        print!("{}", opts.usage(&brief));
        return;
    }

    // Default to 4 threads, but allow user to specify more or less
    let num_threads = match matches.opt_str("j") {
        Some(j) => j.parse().expect("flag '-j' must be an integer"),
        None => 4,
    };

    // Parse IPv4 or IPv6 address for scanning
    let addr = match parse_ip(&matches.free[0]) {
        Ok(ip) => ip,
        Err(e) => {
            println!("error parsing IP address: {}", e.to_string());
            return;
        }
    };

    // Send and receive results via channels of port numbers, scanning
    // concurrently using threads
    let (tx, rx) = channel::<u16>();
    for i in 0..num_threads {
        let tx = tx.clone();

        thread::spawn(move || {
            scan(tx, i, addr, num_threads);
        });
    }

    // Drop transmit side of channel in main thread so that for loop
    // will end once all worker threads complete
    let mut out = vec![];
    drop(tx);
    for port in rx {
        out.push(port);
    }

    // Add newline after progress, sort vector and print all ports
    println!("");
    out.sort();
    for v in out {
        println!("{} is open", v);
    }
}

// scan scans ports at an IP address and sends any open ports it finds back on its
// channel.  scan exits once MAX has been reached.
fn scan(tx: Sender<u16>, start_port: u16, addr: IpAddr, num_threads: u16) {
    let mut port: u16 = start_port + 1;

    loop {
        match TcpStream::connect((addr, port)) {
            Ok(_) => {
                // Found open port, indicate progress and send to main thread
                print!(".");
                io::stdout().flush().unwrap();
                tx.send(port).unwrap();
            }
            Err(_) => {}
        }

        // Break loop when out of ports
        if (MAX - port) <= num_threads {
            break;
        }

        port += num_threads;
    }
}

// parse_ip attempts to parse an input string as an IPv4 or IPv6 address.
fn parse_ip(addr: &str) -> Result<IpAddr, String> {
    if let Ok(ip4) = Ipv4Addr::from_str(addr) {
        return Ok(IpAddr::V4(ip4));
    }

    if let Ok(ip6) = Ipv6Addr::from_str(addr) {
        return Ok(IpAddr::V6(ip6));
    }

    Err(format!("could not parse {} as an IP address", addr).to_string())
}

#[test]
fn parse_ip_ok() {
    let test_ip4 = IpAddr::V4(Ipv4Addr::from_str("192.168.1.1").unwrap());
    let test_ip6 = IpAddr::V6(Ipv6Addr::from_str("::1").unwrap());
    let test_bad = "could not parse foobar as an IP address".to_string();

    let ip4 = parse_ip("192.168.1.1").unwrap();
    assert!(ip4 == test_ip4);

    let ip6 = parse_ip("::1").unwrap();
    assert!(ip6 == test_ip6);

    let bad = match parse_ip("foobar") {
        Ok(_) => panic!("foobar is bad input"),
        Err(e) => e,
    };
    assert!(bad == test_bad);
}
<commit_msg>main: replace custom parse_ip function with IpAddr::from_str()<commit_after>extern crate getopts;

use getopts::Options;
use std::env;
use std::io::{self, Write};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, TcpStream};
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::thread;

// Max possible port
const MAX: u16 = 65535;

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("j",
                "",
                "number of threads to use for concurrent scanning",
                "THREADS");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("error parsing options: {}", e.to_string());
            return;
        }
    };

    // Present usage if '-h' or no IP address provided
    if matches.opt_present("h") || matches.free.is_empty() {
        let brief = format!("Usage: {} -j THREADS IPADDR", program);
        print!("{}", opts.usage(&brief));
        return;
    }

    // Default to 4 threads, but allow user to specify more or less
    let num_threads = match matches.opt_str("j") {
        Some(j) => j.parse().expect("flag '-j' must be an integer"),
        None => 4,
    };

    // Parse IPv4 or IPv6 address for scanning
    let addr = IpAddr::from_str(&matches.free[0]).unwrap();

    // Send and receive results via channels of port numbers, scanning
    // concurrently using threads
    let (tx, rx) = channel::<u16>();
    for i in 0..num_threads {
        let tx = tx.clone();

        thread::spawn(move || {
            scan(tx, i, addr, num_threads);
        });
    }

    // Drop transmit side of channel in main thread so that for loop
    // will end once all worker threads complete
    let mut out = vec![];
    drop(tx);
    for port in rx {
        out.push(port);
    }

    // Add newline after progress, sort vector and print all ports
    println!("");
    out.sort();
    for v in out {
        println!("{} is open", v);
    }
}

// scan scans ports at an IP address and sends any open ports it finds back on its
// channel.  scan exits once MAX has been reached.
fn scan(tx: Sender<u16>, start_port: u16, addr: IpAddr, num_threads: u16) {
    let mut port: u16 = start_port + 1;

    loop {
        match TcpStream::connect((addr, port)) {
            Ok(_) => {
                // Found open port, indicate progress and send to main thread
                print!(".");
                io::stdout().flush().unwrap();
                tx.send(port).unwrap();
            }
            Err(_) => {}
        }

        // Break loop when out of ports
        if (MAX - port) <= num_threads {
            break;
        }

        port += num_threads;
    }
}
<|endoftext|>


<commit_before>#[crate_id(name="tead", version="1.0.0", author="papanikge")];
//
// George 'papanikge' Papanikolaou 2014
// head + tail = tead
//

extern mod extra;
use extra::getopts::{optopt, optflag, getopts};
use std::io::buffered::BufferedReader;
use std::io::fs::File;
use std::path::Path;

fn usage() {
    println("Usage: tead [options]");
    println("\t-n <number of lines to print>");
    println("\t-h --help");
    println("\t-V --version");
}

// Ideally we would use DoubleEndedIterator but that doesn't work with files,
// since we don't have access to the whole file. So, obviously this is not
// optimized, since we are loading the entire file on memory.
fn tead<T: Reader>(reader: &mut BufferedReader<T>, count: uint) {
    let all: ~[~str] = reader.lines().collect();
    // head
    for line in all.iter().take(count) {
        print(*line);
    }
    // tail
    for line in all.rev_iter().take(count) {
        print(*line);
    }
}

fn main() {
    let args = std::os::args();

    let available = [
        optopt("n"),  // Number of lines to print
        optflag("h"), optflag("help"),
        optflag("V"), optflag("version")
    ];

    // test for the available options upon the provided ones
    let given = match getopts(args.tail(), available) {
        Ok (m) =>  m,
        Err(_) => {
            usage();
            fail!();
        }
    };

    // help and version outta the way
    if given.opt_present("h") || given.opt_present("help") {
        usage();
        return;
    }
    if given.opt_present("V") || given.opt_present("version") {
        println("tead -- version 1.0.0");
        return;
    }

    // let's find out the lines requested and move on
    // Beware: Rust weirdness ahead!
    let lines = match given.opt_str("n") {
        Some(s) => {
            match from_str::<uint>(s) {
                Some(x) => { x }
                None    => { fail!("a string for number of lines, dude?") }
            }
        }
        None    => { 10u }
    };

    // let's go
    let files = given.free;
    if files.is_empty() {
        // No files provided. stdin() is a reader so we can do:
        let mut buffer = BufferedReader::new(std::io::stdin());
        tead(&mut buffer, lines);
    } else {
        for file in files.iter() {
            // the argument below needs to be a ** so we use 'as_slice'
            let path = Path::new(file.as_slice());
            // to avoid all that 'match Some' malarkey we just use 'unwrap'
            let reader = File::open(&path).unwrap();
            // opening the reader
            let mut buffer = BufferedReader::new(reader);
            tead(&mut buffer, lines);
        }
    }
}
<commit_msg>Attempt to port it to rust 1.22 - things missing<commit_after>//
// George 'papanikge' Papanikolaou 2014-2018
// tail + head = tead
//
// This was originally written in an ancient form of rust.
// Rewritten for rust 1.22.
//

extern crate getopts;
use getopts::Options; // use extra::getopts::{optopt, optflag, getopts};
// renamed to BufReader. but probaby do not want it // use std::io::buffered::BufferedReader;
use std::env;

static VERSION: &'static str = "1.1.0";
static DEFAULT_LINE_NUMBER: &'static str = "5";

fn usage(program_name: &str) {
    println!("Usage: {} [options]", program_name);
    println!("\t-n <number of lines to print>");
    println!("\t-h --help");
    println!("\t-v --version");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program_name = args[0].clone();

    let mut available = Options::new();
    available.optopt("n", "lines-number", "number of lines to print [default: 5]", "");
    available.optflag("v", "version", "print tead's version");
    available.optflag("h", "help", "print this help menu");

    let given = match available.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if given.opt_present("h") {
        usage(&program_name);
        return;
    }
    if given.opt_present("v") {
        println!("tead -- Version {}", VERSION);
        return;
    }

    let lines = given.opt_str("n").or(Some(String::from(DEFAULT_LINE_NUMBER))).unwrap();

    let files = given.free;
    if files.is_empty() {
        usage(&program_name);
        return;
        // No files provided. stdin() is a reader so we can do:
        // let mut buffer = BufferedReader::new(std::io::stdin());
        // call tead here
    } else {
        println!("temp - lines: {}", lines);
        files[0].clone();
        // call tead here
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(oak)]

extern crate oak_runtime;
use oak_runtime::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

grammar! awesome {
    program
        = ((expr / decl / stmt) terminator?)*

    decl
        = class_decl
        / method_decl

    class_decl
        = kw_class constant class_body > class_decl

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def identifier lparen param_list? rparen block > method_decl

    block
        = lbracket ((stmt / expr) terminator?)* rbracket > block

    stmt
        = if_stmt
        / while_stmt

    if_stmt
        = kw_if expr block (kw_else block)? > if_stmt

    while_stmt
        = kw_while expr block > while_stmt

    call_with_receiver
        = (receiver_expr ".")? identifier lparen arg_list? rparen

    call_no_receiver
        = identifier lparen arg_list? rparen

    assign_expr
        = identifier bind_op expr > assign_expr

    expr
        = spacing cond_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = assign_expr
          / call_with_receiver > call_with_receiver
          / receiver_expr

    receiver_expr
        = call_no_receiver > call_no_receiver
        / literal
        / constant
        / identifier
        / lparen expr rparen

    arg_list
        = (expr ("," spacing expr)*)

    param_list
        = (identifier ("," spacing identifier)*)

    digit = ["0-9"]
    identifier_char = ["A-Za-z0-9_"]

    identifier = !digit !keyword identifier_char+ spacing > identifier
    constant = !keyword !digit ["A-Z"]+ identifier_char+ spacing > constant

    literal
        = lit_string
        / lit_float
        / lit_int

    lit_int = digit+ spacing > lit_int
    lit_float = digit+ "." digit+ spacing > lit_float
    lit_string = (dbl_quot_lit_string / sng_quot_lit_string) spacing > lit_string

    dbl_quot_lit_string = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_lit_string = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \n\r\t"]
    spacing = spacing_char* -> ()

    kw_class = "class" spacing
    kw_def = "def" spacing
    kw_else = "else" spacing
    kw_false = "false" spacing
    kw_if = "if" spacing
    kw_nil = "nil" spacing
    kw_true = "true" spacing
    kw_while = "while" spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" spacing
    rparen = ")" spacing
    lbracket = "{" spacing
    rbracket = "}" spacing
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    terminator = ";" spacing

    fn lit_int(raw_text: Vec<char>) -> PExpr {
        Box::new(IntegerLiteral(to_number(raw_text)))
    }

    // FIXME: Please remove this hacky wacky '.' thingy
    fn lit_float(integer: Vec<char>, fractional: Vec<char>) -> PExpr {
        let mut buf = integer;
        buf.push('.');
        Box::new(FloatLiteral(to_float(combine(buf, fractional))))
    }

    fn lit_string(raw_text: Vec<char>) -> PExpr {
        Box::new(StringLiteral(to_string(raw_text)))
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> PExpr {
        Box::new(Constant(to_string(combine(first, rest))))
    }

    fn identifier(raw_text: Vec<char>) -> PExpr {
        Box::new(Identifier(to_string(raw_text)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn call_no_receiver(method: PExpr, args: Option<(PExpr, Vec<PExpr>)>) -> PExpr {
        Box::new(Call(None, method, args))
    }

    fn call_with_receiver(receiver: Option<PExpr>, method: PExpr, args: Option<(PExpr, Vec<PExpr>)>) -> PExpr {
        Box::new(Call(receiver, method, args))
    }

    fn assign_expr(identifier: PExpr, expr: PExpr) -> PExpr {
        Box::new(AssingExpr(identifier, expr))
    }

    fn class_decl(class: PExpr, methods: Vec<PExpr>) -> PExpr {
        Box::new(ClassDecl(class, methods))
    }

    fn method_decl(identifier: PExpr, params: Option<(PExpr, Vec<PExpr>)>, body: Vec<PExpr>) -> PExpr {
        Box::new(MethodDecl(identifier, params, body))
    }

    fn block(exprs: Vec<(PExpr, Option<()>)>) -> Vec<PExpr> {
        exprs.into_iter().map(|expr| {
            match expr {
                (e, _) => e
            }
        }).collect()
    }

    fn if_stmt(condition: PExpr, block: Vec<PExpr>, else_block: Option<Vec<PExpr>>) -> PExpr {
        Box::new(IfStatement(condition, block, else_block))
    }

    fn while_stmt(condition: PExpr,  block: Vec<PExpr>) -> PExpr {
      Box::new(WhileStatement(condition, block))
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> u32 {
        u32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f32 {
        f32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: PExpr, rest: Vec<(BinOp, PExpr)>) -> PExpr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Box::new(BinaryExpr(op, accu, expr)))
    }

    fn fold_right(front: Vec<(PExpr, BinOp)>, last: PExpr) -> PExpr {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| Box::new(BinaryExpr(op, expr, accu)))
    }

    fn combine<T: Clone>(left: Vec<T>, right: Vec<T>) -> Vec<T> {
        let mut result = left.clone();
        result.extend(right.into_iter());
        result
    }

    use std::str::FromStr;
    use self::Expression::*;
    use self::BinOp::*;

    pub type PExpr = Box<Expression>;

    #[derive(Debug)]
    pub enum Expression {
        Identifier(String),
        Constant(String),
        IntegerLiteral(u32),
        FloatLiteral(f32),
        StringLiteral(String),
        BinaryExpr(BinOp, PExpr, PExpr),
        AssingExpr(PExpr, PExpr),
        ClassDecl(PExpr, Vec<PExpr>),
        IfStatement(PExpr, Vec<PExpr>, Option<Vec<PExpr>>),
        MethodDecl(PExpr, Option<(PExpr, Vec<PExpr>)>, Vec<PExpr>),
        WhileStatement(PExpr, Vec<PExpr>),
        Call(Option<PExpr>, PExpr, Option<(PExpr, Vec<PExpr>)>),
        Block(Vec<PExpr>)
    }

    #[derive(Debug)]
    pub enum BinOp {
        Add, Sub, Mul, Div, Lt, Lte, Gt, Gte, Ne, Eq, And, Or
    }
}

fn main() {
    let f = File::open("./src/example.awm").ok().expect("failed to open file");
    let mut reader = BufReader::new(f);
    let mut contents = String::new();
    reader.read_to_string(&mut contents);
    println!("{:#?}", awesome::parse_program(contents.stream()).unwrap_data());
}
<commit_msg>Improved the way we parse arg and param lists.<commit_after>#![feature(plugin)]
#![plugin(oak)]

extern crate oak_runtime;
use oak_runtime::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

grammar! awesome {
    program
        = ((expr / decl / stmt) terminator?)*

    decl
        = class_decl
        / method_decl

    class_decl
        = kw_class constant class_body > class_decl

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def identifier lparen param_list? rparen block > method_decl

    block
        = lbracket ((stmt / expr) terminator?)* rbracket > block

    stmt
        = if_stmt
        / while_stmt

    if_stmt
        = kw_if expr block (kw_else block)? > if_stmt

    while_stmt
        = kw_while expr block > while_stmt

    call_with_receiver
        = (receiver_expr ".")? identifier lparen arg_list? rparen

    call_no_receiver
        = identifier lparen arg_list? rparen

    assign_expr
        = identifier bind_op expr > assign_expr

    expr
        = spacing cond_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = assign_expr
          / call_with_receiver > call_with_receiver
          / receiver_expr

    receiver_expr
        = call_no_receiver > call_no_receiver
        / literal
        / constant
        / identifier
        / lparen expr rparen

    arg_list
        = (expr ("," spacing expr)*) > arg_list

    param_list
        = (identifier ("," spacing identifier)*) > param_list

    digit = ["0-9"]
    identifier_char = ["A-Za-z0-9_"]

    identifier = !digit !keyword identifier_char+ spacing > identifier
    constant = !keyword !digit ["A-Z"]+ identifier_char+ spacing > constant

    literal
        = lit_string
        / lit_float
        / lit_int

    lit_int = digit+ spacing > lit_int
    lit_float = digit+ "." digit+ spacing > lit_float
    lit_string = (dbl_quot_lit_string / sng_quot_lit_string) spacing > lit_string

    dbl_quot_lit_string = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_lit_string = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \n\r\t"]
    spacing = spacing_char* -> ()

    kw_class = "class" spacing
    kw_def = "def" spacing
    kw_else = "else" spacing
    kw_false = "false" spacing
    kw_if = "if" spacing
    kw_nil = "nil" spacing
    kw_true = "true" spacing
    kw_while = "while" spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" spacing
    rparen = ")" spacing
    lbracket = "{" spacing
    rbracket = "}" spacing
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    terminator = ";" spacing

    fn lit_int(raw_text: Vec<char>) -> PExpr {
        Box::new(IntegerLiteral(to_number(raw_text)))
    }

    // FIXME: Please remove this hacky wacky '.' thingy
    fn lit_float(integer: Vec<char>, fractional: Vec<char>) -> PExpr {
        let mut buf = integer;
        buf.push('.');
        Box::new(FloatLiteral(to_float(combine(buf, fractional))))
    }

    fn lit_string(raw_text: Vec<char>) -> PExpr {
        Box::new(StringLiteral(to_string(raw_text)))
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> PExpr {
        Box::new(Constant(to_string(combine(first, rest))))
    }

    fn identifier(raw_text: Vec<char>) -> PExpr {
        Box::new(Identifier(to_string(raw_text)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn call_no_receiver(method: PExpr, args: Option<Vec<PExpr>>) -> PExpr {
        Box::new(Call(None, method, args))
    }

    fn call_with_receiver(receiver: Option<PExpr>, method: PExpr, args: Option<Vec<PExpr>>) -> PExpr {
        Box::new(Call(receiver, method, args))
    }

    fn assign_expr(identifier: PExpr, expr: PExpr) -> PExpr {
        Box::new(AssingExpr(identifier, expr))
    }

    fn class_decl(class: PExpr, methods: Vec<PExpr>) -> PExpr {
        Box::new(ClassDecl(class, methods))
    }

    fn method_decl(identifier: PExpr, params: Option<Vec<PExpr>>, body: Vec<PExpr>) -> PExpr {
        Box::new(MethodDecl(identifier, params, body))
    }

    fn block(exprs: Vec<(PExpr, Option<()>)>) -> Vec<PExpr> {
        exprs.into_iter().map(|expr| {
            match expr {
                (e, _) => e
            }
        }).collect()
    }

    fn if_stmt(condition: PExpr, block: Vec<PExpr>, else_block: Option<Vec<PExpr>>) -> PExpr {
        Box::new(IfStatement(condition, block, else_block))
    }

    fn while_stmt(condition: PExpr,  block: Vec<PExpr>) -> PExpr {
      Box::new(WhileStatement(condition, block))
    }

    fn arg_list(first: PExpr, mut rest: Vec<PExpr>) -> Vec<PExpr> {
        combine_one_with_many(first, rest)
    }

    fn param_list(first: PExpr, mut rest: Vec<PExpr>) -> Vec<PExpr> {
        combine_one_with_many(first, rest)
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> u32 {
        u32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f32 {
        f32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: PExpr, rest: Vec<(BinOp, PExpr)>) -> PExpr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Box::new(BinaryExpr(op, accu, expr)))
    }

    fn fold_right(front: Vec<(PExpr, BinOp)>, last: PExpr) -> PExpr {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| Box::new(BinaryExpr(op, expr, accu)))
    }

    fn combine<T: Clone>(left: Vec<T>, right: Vec<T>) -> Vec<T> {
        let mut result = left.clone();
        result.extend(right.into_iter());
        result
    }

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        let mut result = vec![first];
        combine(result, rest)
    }

    use std::str::FromStr;
    use self::Expression::*;
    use self::BinOp::*;

    pub type PExpr = Box<Expression>;

    #[derive(Debug, Clone)]
    pub enum Expression {
        Identifier(String),
        Constant(String),
        IntegerLiteral(u32),
        FloatLiteral(f32),
        StringLiteral(String),
        BinaryExpr(BinOp, PExpr, PExpr),
        AssingExpr(PExpr, PExpr),
        ClassDecl(PExpr, Vec<PExpr>),
        IfStatement(PExpr, Vec<PExpr>, Option<Vec<PExpr>>),
        MethodDecl(PExpr, Option<Vec<PExpr>>, Vec<PExpr>),
        WhileStatement(PExpr, Vec<PExpr>),
        Call(Option<PExpr>, PExpr, Option<Vec<PExpr>>),
        Block(Vec<PExpr>)
    }

    #[derive(Debug, Clone)]
    pub enum BinOp {
        Add, Sub, Mul, Div, Lt, Lte, Gt, Gte, Ne, Eq, And, Or
    }
}

fn main() {
    let f = File::open("./src/example.awm").ok().expect("failed to open file");
    let mut reader = BufReader::new(f);
    let mut contents = String::new();
    reader.read_to_string(&mut contents);
    println!("{:#?}", awesome::parse_program(contents.stream()).unwrap_data());
}
<|endoftext|>