<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use std::collections::{HashMap, HashSet};

use quote::quote;
use syn::{parse_quote, ForeignItem, Item, ItemForeignMod, ItemMod};

use crate::known_types::KNOWN_TYPES;
use crate::{
    additional_cpp_generator::AdditionalNeed,
    types::{make_ident, Namespace, TypeName},
};

use super::{
    api::{Api, Use},
    namespace_organizer::NamespaceEntries,
    ConvertError,
};

unzip_n::unzip_n!(pub 5);

pub(crate) struct CodegenResults {
    pub(crate) items: Vec<Item>,
    pub(crate) additional_cpp_needs: Vec<AdditionalNeed>,
}

fn remove_nones<T>(input: Vec<Option<T>>) -> Vec<T> {
    input.into_iter().flatten().collect()
}

/// Type which handles generation of code.
/// "Code" here includes a list of Items to expose in Rust,
/// and also a list of "additional C++ needs" which can be passed
/// to the C++ code generator.
/// In practice, much of the "generation" involves connecting together
/// existing lumps of code within the Api structures.
pub(crate) struct CodeGenerator<'a> {
    include_list: &'a [String],
    use_stmts_by_mod: HashMap<Namespace, Vec<Item>>,
    extern_c_mod: Option<ItemForeignMod>,
    bindgen_mod: ItemMod,
}

impl<'a> CodeGenerator<'a> {
    /// Generate code for a set of APIs that was discovered during parsing.
    pub(crate) fn generate_code(
        all_apis: Vec<Api>,
        include_list: &'a [String],
        use_stmts_by_mod: HashMap<Namespace, Vec<Item>>,
        extern_c_mod: Option<ItemForeignMod>,
        bindgen_mod: ItemMod,
    ) -> Result<CodegenResults, ConvertError> {
        let c = Self {
            include_list,
            use_stmts_by_mod,
            extern_c_mod,
            bindgen_mod,
        };
        c.codegen(all_apis)
    }

    fn codegen(mut self, all_apis: Vec<Api>) -> Result<CodegenResults, ConvertError> {
        // ... and now let's start to generate the output code.
        // First, the hierarchy of mods containing lots of 'use' statements
        // which is the final API exposed as 'ffi'.
        let mut use_statements = Self::generate_final_use_statements(&all_apis);
        // Next, the (modified) bindgen output, which we include in the
        // output as a 'bindgen' sub-mod.
        let bindgen_root_items = self.generate_final_bindgen_mods(&all_apis);
        // Both of the above are organized into sub-mods by namespace.
        // From here on, things are flat.
        let (extern_c_mod_items, all_items, bridge_items, additional_cpp_needs, deps) = all_apis
            .into_iter()
            .map(|api| {
                (
                    api.extern_c_mod_item,
                    api.global_items,
                    api.bridge_item,
                    api.additional_cpp,
                    api.deps,
                )
            })
            .unzip_n_vec();
        // Items for the [cxx::bridge] mod...
        let mut bridge_items = remove_nones(bridge_items);
        // Things to include in the "extern "C"" mod passed within the cxx::bridge
        let mut extern_c_mod_items = remove_nones(extern_c_mod_items);
        // And a list of global items to include at the top level.
        let mut all_items: Vec<Item> = all_items.into_iter().flatten().collect();
        // And finally any C++ we need to generate. And by "we" I mean autocxx not cxx.
        let mut additional_cpp_needs = remove_nones(additional_cpp_needs);
        // Determine what variably-sized C types (e.g. int) we need to include
        self.append_ctype_information(&deps, &mut extern_c_mod_items, &mut additional_cpp_needs);
        extern_c_mod_items
            .extend(self.build_include_foreign_items(!additional_cpp_needs.is_empty()));
        // We will always create an extern "C" mod even if bindgen
        // didn't generate one, e.g. because it only generated types.
        // We still want cxx to know about those types.
        let mut extern_c_mod = self
            .extern_c_mod
            .take()
            .unwrap_or_else(Self::get_blank_extern_c_mod);
        extern_c_mod.items.append(&mut extern_c_mod_items);
        bridge_items.push(Item::ForeignMod(extern_c_mod));
        // The extensive use of parse_quote here could end up
        // being a performance bottleneck. If so, we might want
        // to set the 'contents' field of the ItemMod
        // structures directly.
        if !bindgen_root_items.is_empty() {
            self.bindgen_mod.content.as_mut().unwrap().1 = vec![Item::Mod(parse_quote! {
                pub mod root {
                    #(#bindgen_root_items)*
                }
            })];
            all_items.push(Item::Mod(self.bindgen_mod));
        }
        all_items.push(Item::Mod(parse_quote! {
            #[cxx::bridge]
            pub mod cxxbridge {
                #(#bridge_items)*
            }
        }));
        all_items.append(&mut use_statements);
        Ok(CodegenResults {
            items: all_items,
            additional_cpp_needs,
        })
    }

    fn append_ctype_information(
        &self,
        deps: &Vec<HashSet<TypeName>>,
        extern_c_mod_items: &mut Vec<ForeignItem>,
        additional_cpp_needs: &mut Vec<AdditionalNeed>,
    ) {
        let ctypes: HashSet<_> = deps
            .into_iter()
            .flatten()
            .filter(|ty| KNOWN_TYPES.is_ctype(ty))
            .collect();
        for ctype in ctypes {
            let id = make_ident(ctype.get_final_ident());
            let ts = quote! {
                type #id = autocxx::#id;
            };
            extern_c_mod_items.push(ForeignItem::Verbatim(ts));
            additional_cpp_needs.push(AdditionalNeed::CTypeTypedef(ctype.clone()))
        }
    }

    fn get_blank_extern_c_mod() -> ItemForeignMod {
        parse_quote!(
            extern "C" {}
        )
    }

    fn build_include_foreign_items(&self, has_additional_cpp_needs: bool) -> Vec<ForeignItem> {
        let extra_inclusion = if has_additional_cpp_needs {
            Some("autocxxgen.h".to_string())
        } else {
            None
        };
        let chained = self.include_list.iter().chain(extra_inclusion.iter());
        chained
            .map(|inc| {
                ForeignItem::Macro(parse_quote! {
                    include!(#inc);
                })
            })
            .collect()
    }

    /// Generate lots of 'use' statements to pull cxxbridge items into the output
    /// mod hierarchy according to C++ namespaces.
    fn generate_final_use_statements(input_items: &[Api]) -> Vec<Item> {
        let mut output_items = Vec::new();
        let ns_entries = NamespaceEntries::new(input_items);
        Self::append_child_use_namespace(&ns_entries, &mut output_items);
        output_items
    }

    fn append_child_use_namespace(ns_entries: &NamespaceEntries, output_items: &mut Vec<Item>) {
        for item in ns_entries.entries() {
            let id = &item.id;
            match &item.use_stmt {
                Use::UsedWithAlias(alias) => output_items.push(Item::Use(parse_quote!(
                    pub use cxxbridge :: #id as #alias;
                ))),
                Use::Used => output_items.push(Item::Use(parse_quote!(
                    pub use cxxbridge :: #id;
                ))),
                Use::Unused => {}
            };
        }
        for (child_name, child_ns_entries) in ns_entries.children() {
            let child_id = make_ident(child_name);
            let mut new_mod: ItemMod = parse_quote!(
                pub mod #child_id {
                    use super::cxxbridge;
                }
            );
            Self::append_child_use_namespace(
                child_ns_entries,
                &mut new_mod.content.as_mut().unwrap().1,
            );
            output_items.push(Item::Mod(new_mod));
        }
    }

    fn append_uses_for_ns(&mut self, items: &mut Vec<Item>, ns: &Namespace) {
        let mut use_stmts = self.use_stmts_by_mod.remove(&ns).unwrap_or_default();
        items.append(&mut use_stmts);
    }

    fn append_child_bindgen_namespace(
        &mut self,
        ns_entries: &NamespaceEntries,
        output_items: &mut Vec<Item>,
        ns: &Namespace,
    ) {
        for item in ns_entries.entries() {
            output_items.extend(item.bindgen_mod_item.iter().cloned());
        }
        for (child_name, child_ns_entries) in ns_entries.children() {
            let new_ns = ns.push((*child_name).clone());
            let child_id = make_ident(child_name);

            let mut inner_output_items = Vec::new();
            self.append_child_bindgen_namespace(child_ns_entries, &mut inner_output_items, &new_ns);
            if !inner_output_items.is_empty() {
                let mut new_mod: ItemMod = parse_quote!(
                    pub mod #child_id {
                    }
                );
                self.append_uses_for_ns(&mut inner_output_items, &new_ns);
                new_mod.content.as_mut().unwrap().1 = inner_output_items;
                output_items.push(Item::Mod(new_mod));
            }
        }
    }

    fn generate_final_bindgen_mods(&mut self, input_items: &[Api]) -> Vec<Item> {
        let mut output_items = Vec::new();
        let ns = Namespace::new();
        let ns_entries = NamespaceEntries::new(input_items);
        self.append_child_bindgen_namespace(&ns_entries, &mut output_items, &ns);
        self.append_uses_for_ns(&mut output_items, &ns);
        output_items
    }
}
<commit_msg>Warning fix.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use std::collections::{HashMap, HashSet};

use quote::quote;
use syn::{parse_quote, ForeignItem, Item, ItemForeignMod, ItemMod};

use crate::known_types::KNOWN_TYPES;
use crate::{
    additional_cpp_generator::AdditionalNeed,
    types::{make_ident, Namespace, TypeName},
};

use super::{
    api::{Api, Use},
    namespace_organizer::NamespaceEntries,
    ConvertError,
};

unzip_n::unzip_n!(pub 5);

pub(crate) struct CodegenResults {
    pub(crate) items: Vec<Item>,
    pub(crate) additional_cpp_needs: Vec<AdditionalNeed>,
}

fn remove_nones<T>(input: Vec<Option<T>>) -> Vec<T> {
    input.into_iter().flatten().collect()
}

/// Type which handles generation of code.
/// "Code" here includes a list of Items to expose in Rust,
/// and also a list of "additional C++ needs" which can be passed
/// to the C++ code generator.
/// In practice, much of the "generation" involves connecting together
/// existing lumps of code within the Api structures.
pub(crate) struct CodeGenerator<'a> {
    include_list: &'a [String],
    use_stmts_by_mod: HashMap<Namespace, Vec<Item>>,
    extern_c_mod: Option<ItemForeignMod>,
    bindgen_mod: ItemMod,
}

impl<'a> CodeGenerator<'a> {
    /// Generate code for a set of APIs that was discovered during parsing.
    pub(crate) fn generate_code(
        all_apis: Vec<Api>,
        include_list: &'a [String],
        use_stmts_by_mod: HashMap<Namespace, Vec<Item>>,
        extern_c_mod: Option<ItemForeignMod>,
        bindgen_mod: ItemMod,
    ) -> Result<CodegenResults, ConvertError> {
        let c = Self {
            include_list,
            use_stmts_by_mod,
            extern_c_mod,
            bindgen_mod,
        };
        c.codegen(all_apis)
    }

    fn codegen(mut self, all_apis: Vec<Api>) -> Result<CodegenResults, ConvertError> {
        // ... and now let's start to generate the output code.
        // First, the hierarchy of mods containing lots of 'use' statements
        // which is the final API exposed as 'ffi'.
        let mut use_statements = Self::generate_final_use_statements(&all_apis);
        // Next, the (modified) bindgen output, which we include in the
        // output as a 'bindgen' sub-mod.
        let bindgen_root_items = self.generate_final_bindgen_mods(&all_apis);
        // Both of the above are organized into sub-mods by namespace.
        // From here on, things are flat.
        let (extern_c_mod_items, all_items, bridge_items, additional_cpp_needs, deps) = all_apis
            .into_iter()
            .map(|api| {
                (
                    api.extern_c_mod_item,
                    api.global_items,
                    api.bridge_item,
                    api.additional_cpp,
                    api.deps,
                )
            })
            .unzip_n_vec();
        // Items for the [cxx::bridge] mod...
        let mut bridge_items = remove_nones(bridge_items);
        // Things to include in the "extern "C"" mod passed within the cxx::bridge
        let mut extern_c_mod_items = remove_nones(extern_c_mod_items);
        // And a list of global items to include at the top level.
        let mut all_items: Vec<Item> = all_items.into_iter().flatten().collect();
        // And finally any C++ we need to generate. And by "we" I mean autocxx not cxx.
        let mut additional_cpp_needs = remove_nones(additional_cpp_needs);
        // Determine what variably-sized C types (e.g. int) we need to include
        self.append_ctype_information(&deps, &mut extern_c_mod_items, &mut additional_cpp_needs);
        extern_c_mod_items
            .extend(self.build_include_foreign_items(!additional_cpp_needs.is_empty()));
        // We will always create an extern "C" mod even if bindgen
        // didn't generate one, e.g. because it only generated types.
        // We still want cxx to know about those types.
        let mut extern_c_mod = self
            .extern_c_mod
            .take()
            .unwrap_or_else(Self::get_blank_extern_c_mod);
        extern_c_mod.items.append(&mut extern_c_mod_items);
        bridge_items.push(Item::ForeignMod(extern_c_mod));
        // The extensive use of parse_quote here could end up
        // being a performance bottleneck. If so, we might want
        // to set the 'contents' field of the ItemMod
        // structures directly.
        if !bindgen_root_items.is_empty() {
            self.bindgen_mod.content.as_mut().unwrap().1 = vec![Item::Mod(parse_quote! {
                pub mod root {
                    #(#bindgen_root_items)*
                }
            })];
            all_items.push(Item::Mod(self.bindgen_mod));
        }
        all_items.push(Item::Mod(parse_quote! {
            #[cxx::bridge]
            pub mod cxxbridge {
                #(#bridge_items)*
            }
        }));
        all_items.append(&mut use_statements);
        Ok(CodegenResults {
            items: all_items,
            additional_cpp_needs,
        })
    }

    fn append_ctype_information(
        &self,
        deps: &[HashSet<TypeName>],
        extern_c_mod_items: &mut Vec<ForeignItem>,
        additional_cpp_needs: &mut Vec<AdditionalNeed>,
    ) {
        let ctypes: HashSet<_> = deps
            .into_iter()
            .flatten()
            .filter(|ty| KNOWN_TYPES.is_ctype(ty))
            .collect();
        for ctype in ctypes {
            let id = make_ident(ctype.get_final_ident());
            let ts = quote! {
                type #id = autocxx::#id;
            };
            extern_c_mod_items.push(ForeignItem::Verbatim(ts));
            additional_cpp_needs.push(AdditionalNeed::CTypeTypedef(ctype.clone()))
        }
    }

    fn get_blank_extern_c_mod() -> ItemForeignMod {
        parse_quote!(
            extern "C" {}
        )
    }

    fn build_include_foreign_items(&self, has_additional_cpp_needs: bool) -> Vec<ForeignItem> {
        let extra_inclusion = if has_additional_cpp_needs {
            Some("autocxxgen.h".to_string())
        } else {
            None
        };
        let chained = self.include_list.iter().chain(extra_inclusion.iter());
        chained
            .map(|inc| {
                ForeignItem::Macro(parse_quote! {
                    include!(#inc);
                })
            })
            .collect()
    }

    /// Generate lots of 'use' statements to pull cxxbridge items into the output
    /// mod hierarchy according to C++ namespaces.
    fn generate_final_use_statements(input_items: &[Api]) -> Vec<Item> {
        let mut output_items = Vec::new();
        let ns_entries = NamespaceEntries::new(input_items);
        Self::append_child_use_namespace(&ns_entries, &mut output_items);
        output_items
    }

    fn append_child_use_namespace(ns_entries: &NamespaceEntries, output_items: &mut Vec<Item>) {
        for item in ns_entries.entries() {
            let id = &item.id;
            match &item.use_stmt {
                Use::UsedWithAlias(alias) => output_items.push(Item::Use(parse_quote!(
                    pub use cxxbridge :: #id as #alias;
                ))),
                Use::Used => output_items.push(Item::Use(parse_quote!(
                    pub use cxxbridge :: #id;
                ))),
                Use::Unused => {}
            };
        }
        for (child_name, child_ns_entries) in ns_entries.children() {
            let child_id = make_ident(child_name);
            let mut new_mod: ItemMod = parse_quote!(
                pub mod #child_id {
                    use super::cxxbridge;
                }
            );
            Self::append_child_use_namespace(
                child_ns_entries,
                &mut new_mod.content.as_mut().unwrap().1,
            );
            output_items.push(Item::Mod(new_mod));
        }
    }

    fn append_uses_for_ns(&mut self, items: &mut Vec<Item>, ns: &Namespace) {
        let mut use_stmts = self.use_stmts_by_mod.remove(&ns).unwrap_or_default();
        items.append(&mut use_stmts);
    }

    fn append_child_bindgen_namespace(
        &mut self,
        ns_entries: &NamespaceEntries,
        output_items: &mut Vec<Item>,
        ns: &Namespace,
    ) {
        for item in ns_entries.entries() {
            output_items.extend(item.bindgen_mod_item.iter().cloned());
        }
        for (child_name, child_ns_entries) in ns_entries.children() {
            let new_ns = ns.push((*child_name).clone());
            let child_id = make_ident(child_name);

            let mut inner_output_items = Vec::new();
            self.append_child_bindgen_namespace(child_ns_entries, &mut inner_output_items, &new_ns);
            if !inner_output_items.is_empty() {
                let mut new_mod: ItemMod = parse_quote!(
                    pub mod #child_id {
                    }
                );
                self.append_uses_for_ns(&mut inner_output_items, &new_ns);
                new_mod.content.as_mut().unwrap().1 = inner_output_items;
                output_items.push(Item::Mod(new_mod));
            }
        }
    }

    fn generate_final_bindgen_mods(&mut self, input_items: &[Api]) -> Vec<Item> {
        let mut output_items = Vec::new();
        let ns = Namespace::new();
        let ns_entries = NamespaceEntries::new(input_items);
        self.append_child_bindgen_namespace(&ns_entries, &mut output_items, &ns);
        self.append_uses_for_ns(&mut output_items, &ns);
        output_items
    }
}
<|endoftext|>


<commit_before>use std::convert::Into;
use unicode_segmentation::UnicodeSegmentation;

pub struct GraphemeIndex<'a> { index: usize
                             , into_str: &'a str
                             }
pub struct ByteIndex<'a> { index: usize
                         , into_str: &'a str
                         }
pub struct CharIndex<'a> { index: usize
                         , into_str: &'a str
                         }

impl<'a> Into<ByteIndex<'a>> for GraphemeIndex<'a> {
    // TODO is this reasonable?
    fn into(self) -> ByteIndex<'a> {
        self.into_str.grapheme_indices(true)
            .find(|&(i, _)| i == self.index)
            .map(|(i, _)| ByteIndex { index: i, into_str: self.into_str})
            .expect(&format!( "Grapheme index {} off the end of string {}!"
                             , self.index
                             , self.into_str))
    }
}

impl<'a> Into<CharIndex<'a>> for GraphemeIndex<'a> {
    fn into(self) -> CharIndex<'a> {
        unimplemented!()
    }
}
<commit_msg>feat(unicode): rewrote conversion of grapheme indices<commit_after>use std::fmt;
use std::iter;
use std::str;

use unicode_segmentation::UnicodeSegmentation;
use unicode_segmentation::{ GraphemeIndices as USGraphemeIndices };

/// The index of a Unicode grapheme
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct GraphemeIndex(usize);

/// The index of a byte in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct ByteIndex(usize);

/// The index of a Rust `char` in a string
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct CharIndex(usize);

impl GraphemeIndex {
    pub fn to_byte_index<'a>(&self, text: &'a str) -> ByteIndex {

        if text.grapheme_len() == self.0 {
            ByteIndex(text.len())
        } else {
            text.grapheme_indices(true)
                .find(|&(offset, _)| offset == self.0)
                .map( |(offset, _)| ByteIndex(offset))
                .expect(&format!( "grapheme index {} is greater than the length\
                                   of text {:?}"
                                 , self.0, text))
        }

    }

    pub fn to_char_index<'a>(&self, text: &'a str) -> CharIndex  {

        text.graphemes(true)
            .scan(0usize, |char_count, grapheme| {
                    *char_count += grapheme.char_len();
                    Some(CharIndex(*char_count))
                })
            .nth(self.0)
            .expect(&format!( "grapheme index {} is greater than the length\
                               of text {:?}"
                             , self.0, text))
    }
}

impl CharIndex {
    fn to_byte_index<'a>(&self, into: &'a str) -> ByteIndex  {

        unimplemented!()
    }

    fn to_grapheme_index<'a>(&self, into: &'a str) -> GraphemeIndex {

        unimplemented!()
    }
}

impl ByteIndex {
    fn to_char_index<'a>(&self, into: &'a str) -> CharIndex {

        unimplemented!()
    }

    fn to_grapheme_index<'a>(&self, into: &'a str) -> GraphemeIndex  {

        unimplemented!()
    }
}

pub trait Unicode<'a> {
    // type GraphemeIndices: Iterator<Item = (usize, &'a str)>;
    // type CharIndices: Iterator<Item = (usize, char)>;
    // type ByteIndices: Iterator<Item = (usize, u8)>;
    //
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices;
    // fn char_indices(&'a self) -> Self::CharIndices;
    // fn byte_indices(&'a self) -> Self::ByteIndices;

    fn char_len(&self) -> usize;
    fn grapheme_len(&self) -> usize;
    fn byte_len(&self) -> usize;
}

impl<'a> Unicode<'a> for str {
    // type GraphemeIndices = USGraphemeIndices<'a>;
    // type CharIndices = str::CharIndices<'a>;
    // type ByteIndices = iter::Enumerate<str::Bytes<'a>>;
    //
    // #[inline]
    // fn grapheme_indices(&'a self) -> Self::GraphemeIndices {
    //     UnicodeSegmentation::grapheme_indices(self, true)
    // }
    //
    // #[inline]
    // fn char_indices(&'a self) -> Self::CharIndices { self.char_indices() }
    //
    // #[inline]
    // fn byte_indices(&'a self) -> Self::ByteIndices { self.bytes().enumerate() }

    #[inline]
    fn byte_len(&self) -> usize { self.len() }

    #[inline]
    fn char_len(&self) -> usize { self.chars().count() }

    #[inline]
    fn grapheme_len(&self) -> usize { self.graphemes(true).count() }
}
<|endoftext|>


<commit_before><commit_msg>Formatting test 2.<commit_after><|endoftext|>


<commit_before><commit_msg>add TODO<commit_after><|endoftext|>


<commit_before>//! An "interner" is a data structure that associates values with usize tags and
//! allows bidirectional lookup; i.e., given a value, one can easily find the
//! type, and vice versa.

use std::cmp::PartialEq;
use std::fmt;
use std::hash::Hash;
use std::lazy::SyncLazy;
use std::str;

include!(concat!(env!("OUT_DIR"), "/symbol.rs"));

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Symbol(pub u32);

static INTERNER: SyncLazy<Interner> = SyncLazy::new(|| Interner::fresh());

impl Symbol {
    const fn new(n: u32) -> Self {
        Symbol(n)
    }

    pub fn as_str(&self) -> &'static str {
        INTERNER.strings[self.0 as usize]
    }
}

#[derive(Default)]
pub struct Interner {
    pub strings: Vec<&'static str>,
}

impl Interner {
    fn prefill(init: &[&'static str]) -> Self {
        Interner {
            strings: init.into(),
        }
    }
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.as_str(), f)
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.as_str(), f)
    }
}

// This module has a very short name because it's used a lot.
/// This module contains all the defined keyword `Symbol`s.
///
/// Given that `kw` is imported, use them like `kw::keyword_name`.
/// For example `kw::Loop` or `kw::Break`.
pub mod kw {
    pub use super::kw_generated::*;
}

// This module has a very short name because it's used a lot.
/// This module contains all the defined non-keyword `Symbol`s.
///
/// Given that `sym` is imported, use them like `sym::symbol_name`.
/// For example `sym::rustfmt` or `sym::u8`.
pub mod sym {
    #[doc(inline)]
    pub use super::sym_generated::*;

    // Used from a macro in `librustc_feature/accepted.rs`
    pub use super::kw::MacroRules as macro_rules;
}
<commit_msg>Use `sync::LazyLock` instead of `lazy::SyncLazy` in `attributes-info`<commit_after>//! An "interner" is a data structure that associates values with usize tags and
//! allows bidirectional lookup; i.e., given a value, one can easily find the
//! type, and vice versa.

use std::cmp::PartialEq;
use std::fmt;
use std::hash::Hash;
use std::str;
use std::sync::LazyLock;

include!(concat!(env!("OUT_DIR"), "/symbol.rs"));

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Symbol(pub u32);

static INTERNER: LazyLock<Interner> = LazyLock::new(|| Interner::fresh());

impl Symbol {
    const fn new(n: u32) -> Self {
        Symbol(n)
    }

    pub fn as_str(&self) -> &'static str {
        INTERNER.strings[self.0 as usize]
    }
}

#[derive(Default)]
pub struct Interner {
    pub strings: Vec<&'static str>,
}

impl Interner {
    fn prefill(init: &[&'static str]) -> Self {
        Interner {
            strings: init.into(),
        }
    }
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.as_str(), f)
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.as_str(), f)
    }
}

// This module has a very short name because it's used a lot.
/// This module contains all the defined keyword `Symbol`s.
///
/// Given that `kw` is imported, use them like `kw::keyword_name`.
/// For example `kw::Loop` or `kw::Break`.
pub mod kw {
    pub use super::kw_generated::*;
}

// This module has a very short name because it's used a lot.
/// This module contains all the defined non-keyword `Symbol`s.
///
/// Given that `sym` is imported, use them like `sym::symbol_name`.
/// For example `sym::rustfmt` or `sym::u8`.
pub mod sym {
    #[doc(inline)]
    pub use super::sym_generated::*;

    // Used from a macro in `librustc_feature/accepted.rs`
    pub use super::kw::MacroRules as macro_rules;
}
<|endoftext|>


<commit_before>iface foo { fn foo(); }

impl of foo for uint {}

impl of foo for uint { fn foo() -> int {} }

impl of int for uint { fn foo() {} } //~ ERROR interface

fn main() {}
<commit_msg>test: Remove failing parts of the failing test (requires intertwining of resolve and typechecking)<commit_after>iface foo { fn foo(); }

impl of int for uint { fn foo() {} } //~ ERROR interface

fn main() {}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("02.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

fn get_char_histogram(input: &str) -> HashMap<char, usize> {
    let mut result = HashMap::new();

    for c in input.chars() {
        let v = match result.get(&c) {
            Some(&v) => v,
            None => 0
        };

        result.insert(c, v + 1);
    }

    result
}

fn get_checksum(ids: &Vec<String>) -> usize {
    let histograms: Vec<HashMap<char, usize>> = ids.iter()
        .map(|x| get_char_histogram(x))
        .collect();

    let exactly_two = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 2))
        .count();

    let exactly_three = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 3))
        .count();

    return exactly_two * exactly_three
}

fn diff_id(id1: &str, id2: &str) -> usize {
    id1.chars()
    .zip(id2.chars())
    .filter(|(c1, c2)| c1 != c2)
    .count()
}

fn find_correct_ids(ids: &Vec<String>) -> Option<(&str, &str)> {
    for (i, id1) in ids.iter().enumerate() {
        for id2 in ids.iter().skip(i + 1) {
            let diff = diff_id(id1, id2);

            if diff == 1 {
                return Some((id1, id2));
            }
        }
    }

    None
}

fn main() {
    let ids: Vec<String> = get_input().unwrap()
        .lines()
        .map(|x| x.to_string())
        .filter(|x| x != "")
        .collect();

    println!("Part 1: {}", get_checksum(&ids));

    if let Some((id1, id2)) = find_correct_ids(&ids) {
        let chars = id1.chars()
            .zip(id2.chars())
            .filter(|(c1, c2)| c1 == c2)
            .fold(String::new(), |acc, (c, _)| acc + &c.to_string());

        println!("Part 2: {}", chars);
    }
}
<commit_msg>Use slicing instead of skipping<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("02.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

fn get_char_histogram(input: &str) -> HashMap<char, usize> {
    let mut result = HashMap::new();

    for c in input.chars() {
        let v = match result.get(&c) {
            Some(&v) => v,
            None => 0
        };

        result.insert(c, v + 1);
    }

    result
}

fn get_checksum(ids: &Vec<String>) -> usize {
    let histograms: Vec<HashMap<char, usize>> = ids.iter()
        .map(|x| get_char_histogram(x))
        .collect();

    let exactly_two = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 2))
        .count();

    let exactly_three = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 3))
        .count();

    return exactly_two * exactly_three
}

fn diff_id(id1: &str, id2: &str) -> usize {
    id1.chars()
    .zip(id2.chars())
    .filter(|(c1, c2)| c1 != c2)
    .count()
}

fn find_correct_ids(ids: &Vec<String>) -> Option<(&str, &str)> {
    for (i, id1) in ids.iter().enumerate() {
        for id2 in ids[i + 1..].iter() {
            let diff = diff_id(id1, id2);

            if diff == 1 {
                return Some((id1, id2));
            }
        }
    }

    None
}

fn main() {
    let ids: Vec<String> = get_input().unwrap()
        .lines()
        .map(|x| x.to_string())
        .filter(|x| x != "")
        .collect();

    println!("Part 1: {}", get_checksum(&ids));

    if let Some((id1, id2)) = find_correct_ids(&ids) {
        let chars = id1.chars()
            .zip(id2.chars())
            .filter(|(c1, c2)| c1 == c2)
            .fold(String::new(), |acc, (c, _)| acc + &c.to_string());

        println!("Part 2: {}", chars);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::VecDeque;

mod intcode;
use intcode::*;

#[derive(Debug, Copy, Clone)]
enum NetworkAction {
  Continue,
  Halt
}

#[derive(Debug, Clone)]
struct NetworkPackage {
  from: usize,
  to: usize,
  x: i64,
  y: i64
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("23.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn simulate_network<F>(program: &[i64], count: usize, on_package: F)
where F: Fn(&NetworkPackage) -> NetworkAction {
  let mut nics = (0..count)
    .map(|_| ProgramState::new(program.to_vec()))
    .collect::<Vec<_>>();

  let mut started = nics.iter()
    .map(|_| false)
    .collect::<Vec<_>>();

  let mut queues = nics.iter()
    .map(|_| VecDeque::<NetworkPackage>::new())
    .collect::<Vec<_>>();

  loop {
    for id in 0..count {
      let inputs = {
        let mut inputs = if !started[id] {
          started[id] = true;
          vec![id as i64]
        } else {
          vec![]
        };

        inputs.append(
          &mut queues[id].pop_front()
          .map(|package| vec![package.x, package.y])
          .unwrap_or_else(|| vec![-1])
        );

        inputs
      };

      let (outputs, _) = run_program_with_inputs(&mut nics[id], inputs.into_iter());
      let mut outputs = outputs.into_iter();

      while let (Some(to), Some(x), Some(y)) = (outputs.next(), outputs.next(), outputs.next()) {
        let package = NetworkPackage {
          from: id,
          to: to as usize,
          x,
          y
        };

        if let NetworkAction::Halt = on_package(&package) {
          return;
        }

        queues[to as usize].push_back(package);
      }
    }
  }
}

fn main() {
  let input = get_input().unwrap();
  let program = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  simulate_network(&program, 50, |package| {
    if package.to == 255 {
      println!("Part 1: {}", package.y);
      NetworkAction::Halt
    } else {
      NetworkAction::Continue
    }
  });
}
<commit_msg>Rewrite network as a struct w/events as iterator<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::VecDeque;

mod intcode;
use intcode::*;

#[derive(Debug, Clone)]
struct NetworkPackage {
  from: usize,
  to: usize,
  x: i64,
  y: i64
}

#[derive(Debug)]
enum NetworkEvent {
  OnPackage(NetworkPackage),
  OnTick
}

struct Network {
  nics: Vec<ProgramState>,
  queues: Vec<VecDeque<NetworkPackage>>,
  started: Vec<bool>,
  idle: Vec<bool>,
  event_queue: VecDeque<NetworkEvent>
}

impl Network {
  fn new(program: &[i64], count: usize) -> Network {
    let nics = (0..count)
      .map(|_| ProgramState::new(program.to_vec()))
      .collect::<Vec<_>>();
    let queues = nics.iter()
      .map(|_| VecDeque::<NetworkPackage>::new())
      .collect::<Vec<_>>();
    let started = nics.iter()
      .map(|_| false)
      .collect::<Vec<_>>();
    let idle = nics.iter()
      .map(|_| true)
      .collect::<Vec<_>>();

    Network {
      nics, queues, started, idle,
      event_queue: VecDeque::new()
    }
  }
}

impl Iterator for Network {
  type Item = NetworkEvent;

  fn next(&mut self) -> Option<NetworkEvent> {
    if let Some(event) = self.event_queue.pop_front() {
      return Some(event);
    }

    let count = self.nics.len();

    for id in 0..count {
      let (inputs, has_incoming_package) = {
        let mut inputs = if !self.started[id] {
          self.started[id] = true;
          vec![id as i64]
        } else {
          vec![]
        };

        let has_incoming_package = self.queues[id].len() > 0;

        inputs.append(
          &mut self.queues[id].pop_front()
          .map(|package| vec![package.x, package.y])
          .unwrap_or_else(|| vec![-1])
        );

        (inputs, has_incoming_package)
      };

      let (outputs, _) = run_program_with_inputs(&mut self.nics[id], inputs.into_iter());
      let mut outputs = outputs.into_iter();
      let mut has_outgoing_package = false;

      while let (Some(to), Some(x), Some(y)) = (outputs.next(), outputs.next(), outputs.next()) {
        has_outgoing_package = true;

        let package = NetworkPackage {
          from: id,
          to: to as usize,
          x, y
        };

        self.event_queue.push_back(NetworkEvent::OnPackage(package.clone()));

        if let Some(queue) = self.queues.get_mut(to as usize) {
          queue.push_back(package);
        }
      }

      self.idle[id] = !has_incoming_package && !has_outgoing_package;
      self.event_queue.push_back(NetworkEvent::OnTick);
    }

    self.event_queue.pop_front()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("23.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn main() {
  let input = get_input().unwrap();
  let program = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let mut print_part1 = true;
  let mut nat = None;
  let network = Network::new(&program, 50);

  for event in network {
    match event {
      NetworkEvent::OnPackage(package) => {
        println!("{:?}", package);
        if package.to == 255 {
          if print_part1 {
            println!("Part 1: {}", package.y);
            print_part1 = false;
          }

          nat = Some((package.x, package.y));
        }
      },
      NetworkEvent::OnTick => {}
    }
  }
}
<|endoftext|>


<commit_before>use std::{
    env,
    ffi::OsStr,
    fs::File,
    ops::Range,
    os::unix::{
        io::{AsRawFd, FromRawFd, RawFd},
        net::{UnixListener, UnixStream},
    },
    path::PathBuf,
};

use nix::{
    fcntl::{flock, open, FlockArg, OFlag},
    sys::stat::{lstat, Mode},
    unistd::unlink,
};

#[derive(Debug)]
pub struct ListeningSocket {
    listener: UnixListener,
    _lock: File,
    socket_path: PathBuf,
    lock_path: PathBuf,
}

impl ListeningSocket {
    pub fn bind<S: AsRef<OsStr>>(socket_name: S) -> Result<ListeningSocket, BindError> {
        let runtime_dir: PathBuf =
            env::var("XDG_RUNTIME_DIR").map_err(|_| BindError::RuntimeDirNotSet)?.into();
        let socket_path = runtime_dir.join(socket_name.as_ref());
        let lock_path = socket_path.with_extension("lock");

        // open the lockfile
        let lock_fd = open(
            &lock_path,
            OFlag::O_CREAT | OFlag::O_CLOEXEC | OFlag::O_RDWR,
            Mode::S_IRUSR | Mode::S_IWUSR | Mode::S_IRGRP | Mode::S_IWGRP,
        )
        .map_err(|_| BindError::PermissionDenied)?;

        let _lock = unsafe { File::from_raw_fd(lock_fd) };

        // lock the lockfile
        if flock(lock_fd, FlockArg::LockExclusiveNonblock).is_err() {
            return Err(BindError::AlreadyInUse);
        }

        // check if an old socket exists, and cleanup if relevant
        match lstat(&socket_path) {
            Err(nix::Error::ENOENT) => {
                // none exist, good
            }
            Ok(_) => {
                // one exist, remove it
                unlink(&socket_path).map_err(|_| BindError::AlreadyInUse)?;
            }
            Err(e) => {
                // some error stat-ing the socket?
                return Err(BindError::Io(e.into()));
            }
        }

        // At this point everything is good to start listening on the socket
        let listener = UnixListener::bind(&socket_path).map_err(BindError::Io)?;

        listener.set_nonblocking(true).map_err(BindError::Io)?;

        Ok(ListeningSocket { listener, _lock, socket_path, lock_path })
    }

    pub fn bind_auto(basename: &str, range: Range<usize>) -> Result<Self, BindError> {
        for i in range {
            // early return on any error except AlreadyInUse
            match ListeningSocket::bind(&format!("{}-{}", basename, i)) {
                Ok(socket) => return Ok(socket),
                Err(BindError::RuntimeDirNotSet) => return Err(BindError::RuntimeDirNotSet),
                Err(BindError::PermissionDenied) => return Err(BindError::PermissionDenied),
                Err(BindError::Io(e)) => return Err(BindError::Io(e)),
                Err(BindError::AlreadyInUse) => {}
            }
        }
        Err(BindError::AlreadyInUse)
    }

    pub fn accept(&self) -> std::io::Result<Option<UnixStream>> {
        match self.listener.accept() {
            Ok((stream, _)) => Ok(Some(stream)),
            Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }
}

impl AsRawFd for ListeningSocket {
    fn as_raw_fd(&self) -> RawFd {
        self.listener.as_raw_fd()
    }
}

impl Drop for ListeningSocket {
    fn drop(&mut self) {
        let _ = unlink(&self.socket_path);
        let _ = unlink(&self.lock_path);
    }
}

#[derive(Debug, thiserror::Error)]
pub enum BindError {
    #[error("Environment variable XDG_RUNTIME_DIR is not set")]
    RuntimeDirNotSet,
    #[error("Could not write to XDG_RUNTIME_DIR")]
    PermissionDenied,
    #[error("Requested socket name is already in use")]
    AlreadyInUse,
    #[error("I/O error: {0}")]
    Io(#[source] std::io::Error),
}
<commit_msg>server: add way to get listening socket name<commit_after>use std::{
    env,
    ffi::{OsStr, OsString},
    fs::File,
    io,
    ops::Range,
    os::unix::{
        io::{AsRawFd, FromRawFd, RawFd},
        net::{UnixListener, UnixStream},
    },
    path::PathBuf,
};

use nix::{
    fcntl::{flock, open, FlockArg, OFlag},
    sys::stat::{lstat, Mode},
    unistd::unlink,
};

#[derive(Debug)]
pub struct ListeningSocket {
    listener: UnixListener,
    _lock: File,
    socket_path: PathBuf,
    lock_path: PathBuf,
    socket_name: OsString,
}

impl ListeningSocket {
    pub fn bind<S: AsRef<OsStr>>(socket_name: S) -> Result<ListeningSocket, BindError> {
        let runtime_dir: PathBuf =
            env::var("XDG_RUNTIME_DIR").map_err(|_| BindError::RuntimeDirNotSet)?.into();
        let socket_path = runtime_dir.join(socket_name.as_ref());
        let lock_path = socket_path.with_extension("lock");

        // open the lockfile
        let lock_fd = open(
            &lock_path,
            OFlag::O_CREAT | OFlag::O_CLOEXEC | OFlag::O_RDWR,
            Mode::S_IRUSR | Mode::S_IWUSR | Mode::S_IRGRP | Mode::S_IWGRP,
        )
        .map_err(|_| BindError::PermissionDenied)?;

        // SAFETY: We have just opened the file descriptor.
        let _lock = unsafe { File::from_raw_fd(lock_fd) };

        // lock the lockfile
        if flock(lock_fd, FlockArg::LockExclusiveNonblock).is_err() {
            return Err(BindError::AlreadyInUse);
        }

        // check if an old socket exists, and cleanup if relevant
        match lstat(&socket_path) {
            Err(nix::Error::ENOENT) => {
                // none exist, good
            }
            Ok(_) => {
                // one exist, remove it
                unlink(&socket_path).map_err(|_| BindError::AlreadyInUse)?;
            }
            Err(e) => {
                // some error stat-ing the socket?
                return Err(BindError::Io(e.into()));
            }
        }

        // At this point everything is good to start listening on the socket
        let listener = UnixListener::bind(&socket_path).map_err(BindError::Io)?;

        listener.set_nonblocking(true).map_err(BindError::Io)?;

        Ok(ListeningSocket {
            listener,
            _lock,
            socket_path,
            lock_path,
            socket_name: socket_name.as_ref().to_owned(),
        })
    }

    pub fn bind_auto(basename: &str, range: Range<usize>) -> Result<Self, BindError> {
        for i in range {
            // early return on any error except AlreadyInUse
            match ListeningSocket::bind(&format!("{}-{}", basename, i)) {
                Ok(socket) => return Ok(socket),
                Err(BindError::RuntimeDirNotSet) => return Err(BindError::RuntimeDirNotSet),
                Err(BindError::PermissionDenied) => return Err(BindError::PermissionDenied),
                Err(BindError::Io(e)) => return Err(BindError::Io(e)),
                Err(BindError::AlreadyInUse) => {}
            }
        }
        Err(BindError::AlreadyInUse)
    }

    #[must_use = "the client must be initialized by the display using `Display::insert_client` or else the client will hang forever"]
    pub fn accept(&self) -> io::Result<Option<UnixStream>> {
        match self.listener.accept() {
            Ok((stream, _)) => Ok(Some(stream)),
            Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Returns the name of the listening socket.
    pub fn socket_name(&self) -> &OsStr {
        &self.socket_name
    }
}

impl AsRawFd for ListeningSocket {
    /// Returns a file descriptor that may be polled for readiness.
    ///
    /// This file descriptor may be polled using apis such as epoll and kqueue to be told when a client has
    /// found the socket and is trying to connect.
    ///
    /// When the polling system reports the file descriptor is ready, you can use [`ListeningSocket::accept`]
    /// to get a stream to the new client.
    fn as_raw_fd(&self) -> RawFd {
        self.listener.as_raw_fd()
    }
}

impl Drop for ListeningSocket {
    fn drop(&mut self) {
        let _ = unlink(&self.socket_path);
        let _ = unlink(&self.lock_path);
    }
}

#[derive(Debug, thiserror::Error)]
pub enum BindError {
    #[error("Environment variable XDG_RUNTIME_DIR is not set")]
    RuntimeDirNotSet,
    #[error("Could not write to XDG_RUNTIME_DIR")]
    PermissionDenied,
    #[error("Requested socket name is already in use")]
    AlreadyInUse,
    #[error("I/O error: {0}")]
    Io(#[source] io::Error),
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use itertools::Itertools;

use ir;
use std::io::prelude::*;
use std::io;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    let mut globals = HashMap::new();
    for decl in &tu.declarations {
        register_declaration(decl, &mut globals);
    }

    for declaration in tu.declarations {
        gen_declaration(f, declaration, &mut globals)?;
    }
    Ok(())
}

fn register_declaration(decl: &ir::Declaration, globals: &mut HashMap<String, ir::Type>) {
    match *decl {
        ir::Declaration::ExternFunction { ref name, ref ty } |
        ir::Declaration::Function { ref name, ref ty, .. } => {
            globals.insert(name.clone(), ir::Type::Function(ty.clone()));
        }
    }
}

fn gen_declaration<F: Write>(f: &mut F,
                             declaration: ir::Declaration,
                             globals: &mut HashMap<String, ir::Type>)
                             -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "declare {} @{}({}{})",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "),
                     if ty.variadic { ", ..." } else { "" })?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "define {} @{}({}) {{\nentry:",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} %arg{}", ty, index))
                         .join(", "))?;

            let mut function_generator = FunctionGenerator {
                var_writer: Vec::new(),
                writer: Vec::new(),
                globals: globals,
                locals: HashMap::new(),
            };
            for local in locals {
                function_generator.gen_local(local)?;
            }

            let first_bb_id = bbs[0].id.0;
            for bb in bbs {
                function_generator.gen_basic_block(bb)?;
            }
            writeln!(function_generator.var_writer,
                     "\tbr label %bb{}",
                     first_bb_id)?;

            writeln!(f, "{}", function_generator.into_string())?;
            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

struct FunctionGenerator<'a> {
    var_writer: Vec<u8>,
    writer: Vec<u8>,
    globals: &'a mut HashMap<String, ir::Type>,
    locals: HashMap<ir::LocalVarId, ir::Type>,
}

impl<'a> FunctionGenerator<'a> {
    fn into_string(self) -> String {
        format!("{}\n{}",
                String::from_utf8(self.var_writer).unwrap(),
                String::from_utf8(self.writer).unwrap())
    }

    fn gen_local(&mut self, local: ir::LocalVar) -> io::Result<()> {
        self.locals.insert(local.id, local.ty.clone());

        writeln!(self.var_writer,
                 "\t%local_{} = alloca {}, i32 {}",
                 local.id.0,
                 type_to_string(local.ty.clone()),
                 local.size)?;
        if let Some(index) = local.param_index {
            writeln!(self.var_writer,
                     "\tstore {0} %arg{1}, {0}* %local_{2}",
                     type_to_string(local.ty),
                     index,
                     local.id.0)?;
        }

        Ok(())
    }

    fn gen_basic_block(&mut self, bb: ir::BasicBlock) -> io::Result<()> {
        writeln!(self.writer, "bb{}:", bb.id.0)?;
        for stmt in bb.stmts {
            self.gen_statement(stmt)?;
        }

        self.gen_terminator(bb.terminator)?;
        Ok(())
    }

    fn gen_statement(&mut self, stmt: ir::Statement) -> io::Result<()> {
        match stmt {
            ir::Statement::LValueSet(dest, val) => {
                writeln!(self.writer,
                         "\tstore {} %temp_{}, {} %temp_{}",
                         type_to_string(val.ty),
                         val.id,
                         type_to_string(dest.ty),
                         dest.id)
            }
            ir::Statement::Assign(dest, expr) => {
                if dest.ty != ir::Type::Unit {
                    write!(self.writer, "\t%temp_{} = ", dest.id)?;
                } else {
                    write!(self.writer, "\t")?;
                }
                self.gen_expr(expr)?;
                writeln!(self.writer, "")
            }
        }
    }

    fn gen_expr(&mut self, expr: ir::Expression) -> io::Result<()> {
        match expr {
            ir::Expression::LocalVarLoad(id) => {
                let ty = self.locals[&id].clone();
                // TODO change to bitcast
                write!(self.writer,
                       "getelementptr {0}, {0}* %local_{1}, i64 0",
                       type_to_string(ty),
                       id.0)
            }
            ir::Expression::GlobalLoad(name) => {
                let ty = self.globals.get(&name).unwrap().clone();
                write!(self.writer,
                         "bitcast {0}* @{1} to {0}*",
                         type_to_string(ty),
                         name)
            }
            ir::Expression::LValueLoad(val) => {
                if let ir::Type::LValue(ty) = val.ty {
                    write!(self.writer,
                           "load {0}, {0}* %temp_{1}",
                           type_to_string(*ty),
                           val.id)
                } else {
                    unreachable!()
                }
            }
            ir::Expression::BinOp(op, lhs, rhs) => {
                if op == ir::BinOpCode::PtrAdd {
                    if let ir::Type::Ptr(sub_ty) = lhs.ty {
                        write!(self.writer,
                               "getelementptr {0}, {0}* %temp_{1}, {2} %temp_{3}",
                               type_to_string(*sub_ty),
                               lhs.id,
                               type_to_string(rhs.ty),
                               rhs.id)
                    } else {
                        unreachable!()
                    }
                } else {
                    use ir::BinOpCode::*;
                    let op = match op {
                        PtrAdd => unreachable!(),
                        IntAdd => "add i32",
                        DoubleAdd => "fadd double",
                        IntSub => "sub i32",
                        DoubleSub => "fsub double",
                        IntTimes => "mul i32",
                        DoubleTimes => "fmul double",
                        IntDivide => "sdiv i32",
                        DoubleDivide => "fdiv double",
                        IntMod => "srem i32",
                        IntLess => "icmp slt i32",
                        DoubleLess => "fcmp olt double",
                        IntLessEqual => "icmp sle i32",
                        DoubleLessEqual => "fcmp ole double",
                        IntGreater => "icmp sgt i32",
                        DoubleGreater => "fcmp ogt double",
                        IntGreaterEqual => "icmp sge i32",
                        DoubleGreaterEqual => "fcmp oge double",
                        IntEqual => "icmp eq i32",
                        BoolEqual => "icmp eq i1",
                        DoubleEqual => "fcmp oeq double",
                        IntNotEqual => "icmp ne i32",
                        BoolNotEqual => "icmp ne i1",
                        DoubleNotEqual => "fcmp one double",
                    };
                    write!(self.writer, "{} %temp_{}, %temp_{}", op, lhs.id, rhs.id)
                }
            }
            ir::Expression::UnOp(op, sub) => {
                use ir::UnOpCode::*;
                match op {
                    IntMinus => write!(self.writer, "sub i32 0, %temp_{}", sub.id),
                    DoubleMinus => write!(self.writer, "fsub double 0.0, %temp_{}", sub.id),
                    BoolLogicalNot => write!(self.writer, "xor i1 1, %temp_{}", sub.id),
                    // in fact we represent lvalue and ptr by ptr so AddressOf and PtrDeref are noop
                    AddressOf => {
                        if let ir::Type::LValue(ty) = sub.ty {
                            write!(self.writer,
                                   "getelementptr {0}, {0}* %temp_{1}, i64 0",
                                   type_to_string(*ty),
                                   sub.id)
                        } else {
                            unreachable!()
                        }
                    }
                    PtrDeref => {
                        if let ir::Type::Ptr(ty) = sub.ty {
                            write!(self.writer,
                                   "getelementptr {0}, {0}* %temp_{1}, i64 0",
                                   type_to_string(*ty),
                                   sub.id)
                        } else {
                            unreachable!()
                        }
                    }
                }
            }
            ir::Expression::CastOp(op, expr) => {
                use ir::CastCode::*;
                match op {
                    IntToDouble => {
                        write!(self.writer,
                               "sitofp {} %temp_{} to double",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    DoubleToInt => {
                        write!(self.writer,
                               "fptosi {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    IntToChar => {
                        write!(self.writer,
                               "trunc {} %temp_{} to i8",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    CharToInt => {
                        write!(self.writer,
                               "zext {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    IntToBool => {
                        write!(self.writer,
                               "icmp ne {} %temp_{}, 0",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    BoolToInt => {
                        write!(self.writer,
                               "zext {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                }
            }
            ir::Expression::FuncCall(func, params) => {

                let func_ty = match func.ty {
                    ir::Type::Ptr(sub_ty) => *sub_ty,
                    _ => unreachable!()
                };

                write!(self.writer,
                       "call {} %temp_{}({})",
                       type_to_string(func_ty),
                       func.id,
                       params
                           .into_iter()
                           .map(|val| format!("{} %temp_{}", type_to_string(val.ty), val.id))
                           .join(", "))
            }
            ir::Expression::Literal(lit) => {
                match lit {
                    ir::Literal::Int(val) => {
                        write!(self.writer, "select i1 true, i32 {}, i32 0", val)
                    }
                    ir::Literal::Double(val) => {
                        write!(self.writer,
                               "select i1 true, double {:.10}, double 0.0",
                               val)
                    }
                    ir::Literal::Bool(val) => {
                        write!(self.writer,
                               "select i1 true, i1 {}, i1 0",
                               if val { 1 } else { 0 })
                    }
                    ir::Literal::Char(val) => {
                        write!(self.writer, "select i1 true, i8 {}, i8 0", val)
                    }
                    ir::Literal::Unit => Ok(()),

                }
            }
        }
    }

    fn gen_terminator(&mut self, term: ir::Terminator) -> io::Result<()> {
        match term {
            ir::Terminator::Br(id) => writeln!(self.writer, "\tbr label %bb{}", id.0),
            ir::Terminator::BrCond(value, id1, id2) => {
                writeln!(self.writer,
                         "\tbr i1 %temp_{}, label %bb{}, label %bb{}",
                         value.id,
                         id1.0,
                         id2.0)
            }
            ir::Terminator::Ret(value) => {
                if value.ty != ir::Type::Unit {
                    writeln!(self.writer,
                             "\tret {} %temp_{};",
                             type_to_string(value.ty),
                             value.id)
                } else {
                    writeln!(self.writer, "\tret void")
                }
            }
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => "void".to_string(),
        ir::Type::Bool => "i1".to_string(), // cause c you know
        ir::Type::Int => "i32".to_string(),
        ir::Type::Double => "double".to_string(),
        ir::Type::Char => "i8".to_string(),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}({}{})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "),
                    if func.variadic { ", ..." } else { "" })
        }
        ir::Type::Struct(_) => unimplemented!(),
    }
}
<commit_msg>Implemented a TODO in llvm_gen<commit_after>use std::collections::HashMap;
use itertools::Itertools;

use ir;
use std::io::prelude::*;
use std::io;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    let mut globals = HashMap::new();
    for decl in &tu.declarations {
        register_declaration(decl, &mut globals);
    }

    for declaration in tu.declarations {
        gen_declaration(f, declaration, &mut globals)?;
    }
    Ok(())
}

fn register_declaration(decl: &ir::Declaration, globals: &mut HashMap<String, ir::Type>) {
    match *decl {
        ir::Declaration::ExternFunction { ref name, ref ty } |
        ir::Declaration::Function { ref name, ref ty, .. } => {
            globals.insert(name.clone(), ir::Type::Function(ty.clone()));
        }
    }
}

fn gen_declaration<F: Write>(f: &mut F,
                             declaration: ir::Declaration,
                             globals: &mut HashMap<String, ir::Type>)
                             -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "declare {} @{}({}{})",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "),
                     if ty.variadic { ", ..." } else { "" })?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "define {} @{}({}) {{\nentry:",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} %arg{}", ty, index))
                         .join(", "))?;

            let mut function_generator = FunctionGenerator {
                var_writer: Vec::new(),
                writer: Vec::new(),
                globals: globals,
                locals: HashMap::new(),
            };
            for local in locals {
                function_generator.gen_local(local)?;
            }

            let first_bb_id = bbs[0].id.0;
            for bb in bbs {
                function_generator.gen_basic_block(bb)?;
            }
            writeln!(function_generator.var_writer,
                     "\tbr label %bb{}",
                     first_bb_id)?;

            writeln!(f, "{}", function_generator.into_string())?;
            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

struct FunctionGenerator<'a> {
    var_writer: Vec<u8>,
    writer: Vec<u8>,
    globals: &'a mut HashMap<String, ir::Type>,
    locals: HashMap<ir::LocalVarId, ir::Type>,
}

impl<'a> FunctionGenerator<'a> {
    fn into_string(self) -> String {
        format!("{}\n{}",
                String::from_utf8(self.var_writer).unwrap(),
                String::from_utf8(self.writer).unwrap())
    }

    fn gen_local(&mut self, local: ir::LocalVar) -> io::Result<()> {
        self.locals.insert(local.id, local.ty.clone());

        writeln!(self.var_writer,
                 "\t%local_{} = alloca {}, i32 {}",
                 local.id.0,
                 type_to_string(local.ty.clone()),
                 local.size)?;
        if let Some(index) = local.param_index {
            writeln!(self.var_writer,
                     "\tstore {0} %arg{1}, {0}* %local_{2}",
                     type_to_string(local.ty),
                     index,
                     local.id.0)?;
        }

        Ok(())
    }

    fn gen_basic_block(&mut self, bb: ir::BasicBlock) -> io::Result<()> {
        writeln!(self.writer, "bb{}:", bb.id.0)?;
        for stmt in bb.stmts {
            self.gen_statement(stmt)?;
        }

        self.gen_terminator(bb.terminator)?;
        Ok(())
    }

    fn gen_statement(&mut self, stmt: ir::Statement) -> io::Result<()> {
        match stmt {
            ir::Statement::LValueSet(dest, val) => {
                writeln!(self.writer,
                         "\tstore {} %temp_{}, {} %temp_{}",
                         type_to_string(val.ty),
                         val.id,
                         type_to_string(dest.ty),
                         dest.id)
            }
            ir::Statement::Assign(dest, expr) => {
                if dest.ty != ir::Type::Unit {
                    write!(self.writer, "\t%temp_{} = ", dest.id)?;
                } else {
                    write!(self.writer, "\t")?;
                }
                self.gen_expr(expr)?;
                writeln!(self.writer, "")
            }
        }
    }

    fn gen_expr(&mut self, expr: ir::Expression) -> io::Result<()> {
        match expr {
            ir::Expression::LocalVarLoad(id) => {
                let ty = self.locals[&id].clone();
                write!(self.writer,
                       "bitcast {0}* %local_{1} to {0}*",
                       type_to_string(ty),
                       id.0)
            }
            ir::Expression::GlobalLoad(name) => {
                let ty = self.globals[&name].clone();
                write!(self.writer,
                       "bitcast {0}* @{1} to {0}*",
                       type_to_string(ty),
                       name)
            }
            ir::Expression::LValueLoad(val) => {
                if let ir::Type::LValue(ty) = val.ty {
                    write!(self.writer,
                           "load {0}, {0}* %temp_{1}",
                           type_to_string(*ty),
                           val.id)
                } else {
                    unreachable!()
                }
            }
            ir::Expression::BinOp(op, lhs, rhs) => {
                if op == ir::BinOpCode::PtrAdd {
                    if let ir::Type::Ptr(sub_ty) = lhs.ty {
                        write!(self.writer,
                               "getelementptr {0}, {0}* %temp_{1}, {2} %temp_{3}",
                               type_to_string(*sub_ty),
                               lhs.id,
                               type_to_string(rhs.ty),
                               rhs.id)
                    } else {
                        unreachable!()
                    }
                } else {
                    use ir::BinOpCode::*;
                    let op = match op {
                        PtrAdd => unreachable!(),
                        IntAdd => "add i32",
                        DoubleAdd => "fadd double",
                        IntSub => "sub i32",
                        DoubleSub => "fsub double",
                        IntTimes => "mul i32",
                        DoubleTimes => "fmul double",
                        IntDivide => "sdiv i32",
                        DoubleDivide => "fdiv double",
                        IntMod => "srem i32",
                        IntLess => "icmp slt i32",
                        DoubleLess => "fcmp olt double",
                        IntLessEqual => "icmp sle i32",
                        DoubleLessEqual => "fcmp ole double",
                        IntGreater => "icmp sgt i32",
                        DoubleGreater => "fcmp ogt double",
                        IntGreaterEqual => "icmp sge i32",
                        DoubleGreaterEqual => "fcmp oge double",
                        IntEqual => "icmp eq i32",
                        BoolEqual => "icmp eq i1",
                        DoubleEqual => "fcmp oeq double",
                        IntNotEqual => "icmp ne i32",
                        BoolNotEqual => "icmp ne i1",
                        DoubleNotEqual => "fcmp one double",
                    };
                    write!(self.writer, "{} %temp_{}, %temp_{}", op, lhs.id, rhs.id)
                }
            }
            ir::Expression::UnOp(op, sub) => {
                use ir::UnOpCode::*;
                match op {
                    IntMinus => write!(self.writer, "sub i32 0, %temp_{}", sub.id),
                    DoubleMinus => write!(self.writer, "fsub double 0.0, %temp_{}", sub.id),
                    BoolLogicalNot => write!(self.writer, "xor i1 1, %temp_{}", sub.id),
                    // in fact we represent lvalue and ptr by ptr so AddressOf and PtrDeref are noop
                    AddressOf => {
                        if let ir::Type::LValue(ty) = sub.ty {
                            write!(self.writer,
                                   "getelementptr {0}, {0}* %temp_{1}, i64 0",
                                   type_to_string(*ty),
                                   sub.id)
                        } else {
                            unreachable!()
                        }
                    }
                    PtrDeref => {
                        if let ir::Type::Ptr(ty) = sub.ty {
                            write!(self.writer,
                                   "getelementptr {0}, {0}* %temp_{1}, i64 0",
                                   type_to_string(*ty),
                                   sub.id)
                        } else {
                            unreachable!()
                        }
                    }
                }
            }
            ir::Expression::CastOp(op, expr) => {
                use ir::CastCode::*;
                match op {
                    IntToDouble => {
                        write!(self.writer,
                               "sitofp {} %temp_{} to double",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    DoubleToInt => {
                        write!(self.writer,
                               "fptosi {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    IntToChar => {
                        write!(self.writer,
                               "trunc {} %temp_{} to i8",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    CharToInt => {
                        write!(self.writer,
                               "zext {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    IntToBool => {
                        write!(self.writer,
                               "icmp ne {} %temp_{}, 0",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                    BoolToInt => {
                        write!(self.writer,
                               "zext {} %temp_{} to i32",
                               type_to_string(expr.ty),
                               expr.id)
                    }
                }
            }
            ir::Expression::FuncCall(func, params) => {

                let func_ty = match func.ty {
                    ir::Type::Ptr(sub_ty) => *sub_ty,
                    _ => unreachable!(),
                };

                write!(self.writer,
                       "call {} %temp_{}({})",
                       type_to_string(func_ty),
                       func.id,
                       params
                           .into_iter()
                           .map(|val| format!("{} %temp_{}", type_to_string(val.ty), val.id))
                           .join(", "))
            }
            ir::Expression::Literal(lit) => {
                match lit {
                    ir::Literal::Int(val) => {
                        write!(self.writer, "select i1 true, i32 {}, i32 0", val)
                    }
                    ir::Literal::Double(val) => {
                        write!(self.writer,
                               "select i1 true, double {:.10}, double 0.0",
                               val)
                    }
                    ir::Literal::Bool(val) => {
                        write!(self.writer,
                               "select i1 true, i1 {}, i1 0",
                               if val { 1 } else { 0 })
                    }
                    ir::Literal::Char(val) => {
                        write!(self.writer, "select i1 true, i8 {}, i8 0", val)
                    }
                    ir::Literal::Unit => Ok(()),

                }
            }
        }
    }

    fn gen_terminator(&mut self, term: ir::Terminator) -> io::Result<()> {
        match term {
            ir::Terminator::Br(id) => writeln!(self.writer, "\tbr label %bb{}", id.0),
            ir::Terminator::BrCond(value, id1, id2) => {
                writeln!(self.writer,
                         "\tbr i1 %temp_{}, label %bb{}, label %bb{}",
                         value.id,
                         id1.0,
                         id2.0)
            }
            ir::Terminator::Ret(value) => {
                if value.ty != ir::Type::Unit {
                    writeln!(self.writer,
                             "\tret {} %temp_{};",
                             type_to_string(value.ty),
                             value.id)
                } else {
                    writeln!(self.writer, "\tret void")
                }
            }
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => "void".to_string(),
        ir::Type::Bool => "i1".to_string(), // cause c you know
        ir::Type::Int => "i32".to_string(),
        ir::Type::Double => "double".to_string(),
        ir::Type::Char => "i8".to_string(),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}({}{})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "),
                    if func.variadic { ", ..." } else { "" })
        }
        ir::Type::Struct(_) => unimplemented!(),
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::fmt::Display;

#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
use unicode_width::UnicodeWidthStr;

use args::AnyArg;
use args::settings::ArgSettings;
use term;
use strext::_StrExt;

#[cfg(any(not(feature = "wrap_help"), target_os = "windows"))]
fn str_width(s: &str) -> usize {
    s.len()
}

#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
fn str_width(s: &str) -> usize {
    UnicodeWidthStr::width(s)
}

const TAB: &'static str = "    ";

pub struct HelpWriter<'a, A> where A: 'a {
    a: &'a A,
    l: usize,
    nlh: bool,
    pub skip_pv: bool,
    term_w: Option<usize>,
}

impl<'a, 'n, 'e, A> HelpWriter<'a, A> where A: AnyArg<'n, 'e> + Display {
    pub fn new(a: &'a A, l: usize, nlh: bool) -> Self {
        HelpWriter {
            a: a,
            l: l,
            nlh: nlh,
            skip_pv: false,
            term_w: term::dimensions().map(|(w, _)| w),
        }
    }
    pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        debugln!("fn=write_to;");
        try!(self.short(w));
        try!(self.long(w));
        try!(self.val(w));
        try!(self.help(w));
        write!(w, "\n")
    }

    fn short<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=short;");
        try!(write!(w, "{}", TAB));
        if let Some(s) = self.a.short() {
            write!(w, "-{}", s)
        } else if self.a.has_switch() {
            write!(w, "{}", TAB)
        } else {
            Ok(())
        }
    }

    fn long<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=long;");
        if !self.a.has_switch() {
            return Ok(());
        }
        if self.a.takes_value() {
            if let Some(l) = self.a.long() {
                try!(write!(w, "{}--{}", if self.a.short().is_some() { ", " } else { "" }, l));
            }
            try!(write!(w, " "));
        } else {
            if let Some(l) = self.a.long() {
                try!(write!(w, "{}--{}", if self.a.short().is_some() { ", " } else { "" }, l));
                if !self.nlh || !self.a.is_set(ArgSettings::NextLineHelp) {
                    write_spaces!((self.l + 4) - (l.len() + 2), w);
                }
            } else {
                if !self.nlh || !self.a.is_set(ArgSettings::NextLineHelp) {
                    // 6 is tab (4) + -- (2)
                    write_spaces!((self.l + 6), w);
                }
            }
        }
        Ok(())
    }

    fn val<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=val;");
        if !self.a.takes_value() {
            return Ok(());
        }
        if let Some(ref vec) = self.a.val_names() {
            let mut it = vec.iter().peekable();
            while let Some((_, val)) = it.next() {
                try!(write!(w, "<{}>", val));
                if it.peek().is_some() { try!(write!(w, " ")); }
            }
            let num = vec.len();
            if self.a.is_set(ArgSettings::Multiple) && num == 1 {
                try!(write!(w, "..."));
            }
        } else if let Some(num) = self.a.num_vals() {
            let mut it = (0..num).peekable();
            while let Some(_) = it.next() {
                try!(write!(w, "<{}>", self.a.name()));
                if it.peek().is_some() { try!(write!(w, " ")); }
            }
        } else {
            try!(write!(w, "{}", self.a));
        }
        if self.a.has_switch() {
            if !(self.nlh || self.a.is_set(ArgSettings::NextLineHelp)) {
                let self_len = self.a.to_string().len();
                // subtract ourself
                let mut spcs = self.l - self_len;
                // Since we're writing spaces from the tab point we first need to know if we
                // had a long and short, or just short
                if self.a.long().is_some() {
                    // Only account 4 after the val
                    spcs += 4;
                } else {
                    // Only account for ', --' + 4 after the val
                    spcs += 8;
                }
                write_spaces!(spcs, w);
            }
        } else if !(self.nlh || self.a.is_set(ArgSettings::NextLineHelp)) {
            write_spaces!(self.l + 4 - (self.a.to_string().len()), w);
        }
        Ok(())
    }

    fn help<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=help;");
        let spec_vals = self.spec_vals();
        let mut help = String::new();
        let h = self.a.help().unwrap_or("");
        let spcs = if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
            8 // "tab" + "tab"
        } else {
            self.l + 12
        };
        // determine if our help fits or needs to wrap
        let width = self.term_w.unwrap_or(0);
        debugln!("Term width...{}", width);
        let too_long = self.term_w.is_some() && (spcs + str_width(h) + str_width(&*spec_vals) >= width);
        debugln!("Too long...{:?}", too_long);

        // Is help on next line, if so newline + 2x tab
        if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
            try!(write!(w, "\n{}{}", TAB, TAB));
        }

        debug!("Too long...");
        if too_long {
            sdebugln!("Yes");
            help.push_str(h);
            help.push_str(&*spec_vals);
            debugln!("help: {}", help);
            debugln!("help width: {}", str_width(&*help));
            // Determine how many newlines we need to insert
            let avail_chars = width - spcs;
            debugln!("Usable space: {}", avail_chars);
            let longest_w = {
                let mut lw = 0;
                for l in help.split(' ').map(|s| str_width(s)) {
                    if l > lw {
                        lw = l;
                    }
                }
                lw
            };
            debugln!("Longest word...{}", longest_w);
            debug!("Enough space to wrap...");
            if longest_w < avail_chars {
                sdebugln!("Yes");
                let mut indices = vec![];
                let mut idx = 0;
                loop {
                    idx += avail_chars - 1;
                    if idx >= help.len() { break; }
                    // 'a' arbitrary non space char
                    if help.chars().nth(idx).unwrap_or('a') != ' ' {
                        idx = find_idx_of_space(&*help, idx);
                    }
                    debugln!("Adding idx: {}", idx);
                    debugln!("At {}: {:?}", idx, help.chars().nth(idx));
                    indices.push(idx);
                    if str_width(&help[idx..]) <= avail_chars {
                        break;
                    }
                }
                for (i, idx) in indices.iter().enumerate() {
                    debugln!("iter;i={},idx={}", i, idx);
                    let j = idx + (2 * i);
                    debugln!("removing: {}", j);
                    debugln!("at {}: {:?}", j, help.chars().nth(j));
                    help.remove(j);
                    help.insert(j, '{');
                    help.insert(j + 1 , 'n');
                    help.insert(j + 2, '}');
                }
            } else {
                sdebugln!("No");
            }
        } else { sdebugln!("No"); }
        let help = if !help.is_empty() {
            &*help
        } else if !spec_vals.is_empty() {
            help.push_str(h);
            help.push_str(&*spec_vals);
            &*help
        } else {
            h
        };
        if help.contains("{n}") {
            if let Some(part) = help.split("{n}").next() {
                try!(write!(w, "{}", part));
            }
            for part in help.split("{n}").skip(1) {
                try!(write!(w, "\n"));
                if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
                    try!(write!(w, "{}{}", TAB, TAB));
                } else if self.a.has_switch() {
                    write_spaces!(self.l + 12, w);
                } else {
                    write_spaces!(self.l + 8, w);
                }
                try!(write!(w, "{}", part));
            }
        } else {
            try!(write!(w, "{}", help));
        }
        Ok(())
    }

    fn spec_vals(&self) -> String {
        debugln!("fn=spec_vals;");
        if let Some(ref pv) = self.a.default_val() {
            debugln!("Writing defaults");
            return format!(" [default: {}] {}", pv,
                if !self.skip_pv {
                    if let Some(ref pv) = self.a.possible_vals() {
                        format!(" [values: {}]", pv.join(", "))
                    } else { "".into() }
                } else { "".into() }
            );
        } else if !self.skip_pv {
            debugln!("Writing values");
            if let Some(ref pv) = self.a.possible_vals() {
                debugln!("Possible vals...{:?}", pv);
                return format!(" [values: {}]", pv.join(", "));
            }
        }
        String::new()
    }
}

fn find_idx_of_space(full: &str, mut start: usize) -> usize {
    debugln!("fn=find_idx_of_space;");
    let haystack = if full._is_char_boundary(start) {
        &full[..start]
    } else {
        while !full._is_char_boundary(start) { start -= 1; }
        &full[..start]
    };
    debugln!("haystack: {}", haystack);
    for (i, c) in haystack.chars().rev().enumerate() {
        debugln!("iter;c={},i={}", c, i);
        if c == ' ' {
            debugln!("Found space returning start-i...{}", start - (i + 1));
            return start - (i + 1);
        }
    }
    0
}
<commit_msg>fix(Help Message): fixes bug where arg name is printed twice<commit_after>use std::io;
use std::fmt::Display;

#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
use unicode_width::UnicodeWidthStr;

use args::AnyArg;
use args::settings::ArgSettings;
use term;
use strext::_StrExt;

#[cfg(any(not(feature = "wrap_help"), target_os = "windows"))]
fn str_width(s: &str) -> usize {
    s.len()
}

#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
fn str_width(s: &str) -> usize {
    UnicodeWidthStr::width(s)
}

const TAB: &'static str = "    ";

pub struct HelpWriter<'a, A> where A: 'a {
    a: &'a A,
    l: usize,
    nlh: bool,
    pub skip_pv: bool,
    term_w: Option<usize>,
}

impl<'a, 'n, 'e, A> HelpWriter<'a, A> where A: AnyArg<'n, 'e> + Display {
    pub fn new(a: &'a A, l: usize, nlh: bool) -> Self {
        HelpWriter {
            a: a,
            l: l,
            nlh: nlh,
            skip_pv: false,
            term_w: term::dimensions().map(|(w, _)| w),
        }
    }
    pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        debugln!("fn=write_to;");
        try!(self.short(w));
        try!(self.long(w));
        try!(self.val(w));
        try!(self.help(w));
        write!(w, "\n")
    }

    fn short<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=short;");
        try!(write!(w, "{}", TAB));
        if let Some(s) = self.a.short() {
            write!(w, "-{}", s)
        } else if self.a.has_switch() {
            write!(w, "{}", TAB)
        } else {
            Ok(())
        }
    }

    fn long<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=long;");
        if !self.a.has_switch() {
            return Ok(());
        }
        if self.a.takes_value() {
            if let Some(l) = self.a.long() {
                try!(write!(w, "{}--{}", if self.a.short().is_some() { ", " } else { "" }, l));
            }
            try!(write!(w, " "));
        } else {
            if let Some(l) = self.a.long() {
                try!(write!(w, "{}--{}", if self.a.short().is_some() { ", " } else { "" }, l));
                if !self.nlh || !self.a.is_set(ArgSettings::NextLineHelp) {
                    write_spaces!((self.l + 4) - (l.len() + 2), w);
                }
            } else {
                if !self.nlh || !self.a.is_set(ArgSettings::NextLineHelp) {
                    // 6 is tab (4) + -- (2)
                    write_spaces!((self.l + 6), w);
                }
            }
        }
        Ok(())
    }

    fn val<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=val;");
        if !self.a.takes_value() {
            return Ok(());
        }
        if let Some(ref vec) = self.a.val_names() {
            let mut it = vec.iter().peekable();
            while let Some((_, val)) = it.next() {
                try!(write!(w, "<{}>", val));
                if it.peek().is_some() { try!(write!(w, " ")); }
            }
            let num = vec.len();
            if self.a.is_set(ArgSettings::Multiple) && num == 1 {
                try!(write!(w, "..."));
            }
        } else if let Some(num) = self.a.num_vals() {
            let mut it = (0..num).peekable();
            while let Some(_) = it.next() {
                try!(write!(w, "<{}>", self.a.name()));
                if it.peek().is_some() { try!(write!(w, " ")); }
            }
        } else if self.a.has_switch() {
            try!(write!(w, "<{}>", self.a.name()));
        } else {
            try!(write!(w, "{}", self.a));
        }
        if self.a.has_switch() {
            if !(self.nlh || self.a.is_set(ArgSettings::NextLineHelp)) {
                let self_len = self.a.to_string().len();
                // subtract ourself
                let mut spcs = self.l - self_len;
                // Since we're writing spaces from the tab point we first need to know if we
                // had a long and short, or just short
                if self.a.long().is_some() {
                    // Only account 4 after the val
                    spcs += 4;
                } else {
                    // Only account for ', --' + 4 after the val
                    spcs += 8;
                }
                write_spaces!(spcs, w);
            }
        } else if !(self.nlh || self.a.is_set(ArgSettings::NextLineHelp)) {
            write_spaces!(self.l + 4 - (self.a.to_string().len()), w);
        }
        Ok(())
    }

    fn help<W>(&self, w: &mut W) -> io::Result<()>
        where W: io::Write
    {
        debugln!("fn=help;");
        let spec_vals = self.spec_vals();
        let mut help = String::new();
        let h = self.a.help().unwrap_or("");
        let spcs = if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
            8 // "tab" + "tab"
        } else {
            self.l + 12
        };
        // determine if our help fits or needs to wrap
        let width = self.term_w.unwrap_or(0);
        debugln!("Term width...{}", width);
        let too_long = self.term_w.is_some() && (spcs + str_width(h) + str_width(&*spec_vals) >= width);
        debugln!("Too long...{:?}", too_long);

        // Is help on next line, if so newline + 2x tab
        if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
            try!(write!(w, "\n{}{}", TAB, TAB));
        }

        debug!("Too long...");
        if too_long {
            sdebugln!("Yes");
            help.push_str(h);
            help.push_str(&*spec_vals);
            debugln!("help: {}", help);
            debugln!("help width: {}", str_width(&*help));
            // Determine how many newlines we need to insert
            let avail_chars = width - spcs;
            debugln!("Usable space: {}", avail_chars);
            let longest_w = {
                let mut lw = 0;
                for l in help.split(' ').map(|s| str_width(s)) {
                    if l > lw {
                        lw = l;
                    }
                }
                lw
            };
            debugln!("Longest word...{}", longest_w);
            debug!("Enough space to wrap...");
            if longest_w < avail_chars {
                sdebugln!("Yes");
                let mut indices = vec![];
                let mut idx = 0;
                loop {
                    idx += avail_chars - 1;
                    if idx >= help.len() { break; }
                    // 'a' arbitrary non space char
                    if help.chars().nth(idx).unwrap_or('a') != ' ' {
                        idx = find_idx_of_space(&*help, idx);
                    }
                    debugln!("Adding idx: {}", idx);
                    debugln!("At {}: {:?}", idx, help.chars().nth(idx));
                    indices.push(idx);
                    if str_width(&help[idx..]) <= avail_chars {
                        break;
                    }
                }
                for (i, idx) in indices.iter().enumerate() {
                    debugln!("iter;i={},idx={}", i, idx);
                    let j = idx + (2 * i);
                    debugln!("removing: {}", j);
                    debugln!("at {}: {:?}", j, help.chars().nth(j));
                    help.remove(j);
                    help.insert(j, '{');
                    help.insert(j + 1 , 'n');
                    help.insert(j + 2, '}');
                }
            } else {
                sdebugln!("No");
            }
        } else { sdebugln!("No"); }
        let help = if !help.is_empty() {
            &*help
        } else if !spec_vals.is_empty() {
            help.push_str(h);
            help.push_str(&*spec_vals);
            &*help
        } else {
            h
        };
        if help.contains("{n}") {
            if let Some(part) = help.split("{n}").next() {
                try!(write!(w, "{}", part));
            }
            for part in help.split("{n}").skip(1) {
                try!(write!(w, "\n"));
                if self.nlh || self.a.is_set(ArgSettings::NextLineHelp) {
                    try!(write!(w, "{}{}", TAB, TAB));
                } else if self.a.has_switch() {
                    write_spaces!(self.l + 12, w);
                } else {
                    write_spaces!(self.l + 8, w);
                }
                try!(write!(w, "{}", part));
            }
        } else {
            try!(write!(w, "{}", help));
        }
        Ok(())
    }

    fn spec_vals(&self) -> String {
        debugln!("fn=spec_vals;");
        if let Some(ref pv) = self.a.default_val() {
            debugln!("Writing defaults");
            return format!(" [default: {}] {}", pv,
                if !self.skip_pv {
                    if let Some(ref pv) = self.a.possible_vals() {
                        format!(" [values: {}]", pv.join(", "))
                    } else { "".into() }
                } else { "".into() }
            );
        } else if !self.skip_pv {
            debugln!("Writing values");
            if let Some(ref pv) = self.a.possible_vals() {
                debugln!("Possible vals...{:?}", pv);
                return format!(" [values: {}]", pv.join(", "));
            }
        }
        String::new()
    }
}

fn find_idx_of_space(full: &str, mut start: usize) -> usize {
    debugln!("fn=find_idx_of_space;");
    let haystack = if full._is_char_boundary(start) {
        &full[..start]
    } else {
        while !full._is_char_boundary(start) { start -= 1; }
        &full[..start]
    };
    debugln!("haystack: {}", haystack);
    for (i, c) in haystack.chars().rev().enumerate() {
        debugln!("iter;c={},i={}", c, i);
        if c == ' ' {
            debugln!("Found space returning start-i...{}", start - (i + 1));
            return start - (i + 1);
        }
    }
    0
}
<|endoftext|>


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

extern crate rustc_serialize;
extern crate docopt;

docopt!(pub Args derive Debug, "
Usage: sassaurs_spec [options] [<spec-dir>]
       sassaurs_spec --help

Options:
  -c COMMAND, --command COMMAND
                     Sets a specific binary to run
                     [default: sassc]
  -s, --skip         Skip tests that fail to exit successfully.
  -t, --tap          Output TAP compatible report.
  -v, --verbose      Run verbosely.
  --limit NUMBER     Limit the number of tests run to this positive integer.
  --filter PATTERN   Run tests that match the pattern you provide
  --ignore-todo      Skip any folder named 'todo'.
  --silent           Don't show any logs.
  --nuke             Write a new expected_output for every test.
  --unexpected-pass  When running the todo tests, flag as an error when a test
                     passes which is marked as todo.
",
flag_limit: Option<usize>,
flag_filter: Option<String>,
arg_spec_dir: Option<String>);

fn main() {
    let args: Args = Args::docopt()
        .decode()
        .unwrap_or_else(|e| e.exit());
}
<commit_msg>Start outputing the start of the run.<commit_after>#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate rustc_serialize;
extern crate docopt;

docopt!(pub Args derive Debug, "
Usage: sassaurs_spec [options] [<spec-dir>]
       sassaurs_spec --help

Options:
  -c COMMAND, --command COMMAND
                     Sets a specific binary to run
                     [default: sassc]
  -s, --skip         Skip tests that fail to exit successfully.
  -t, --tap          Output TAP compatible report.
  -v, --verbose      Run verbosely.
  --limit NUMBER     Limit the number of tests run to this positive integer.
  --filter PATTERN   Run tests that match the pattern you provide
  --ignore-todo      Skip any folder named 'todo'.
  --silent           Don't show any logs.
  --nuke             Write a new expected_output for every test.
  --unexpected-pass  When running the todo tests, flag as an error when a test
                     passes which is marked as todo.
",
flag_limit: Option<usize>,
flag_filter: Option<String>,
arg_spec_dir: Option<String>);

fn main() {
    let args: Args = Args::docopt()
        .decode()
        .unwrap_or_else(|e| e.exit());

    let directory = match args.arg_spec_dir {
        None => "sass-spec/spec",
        Some(ref dir) => dir.as_ref()
    };

    if !args.flag_silent && !args.flag_tap {
        println!("Recursively searching under directory '{}' \
            for test files to test '{}' with.",
            directory,
            args.flag_command);
    }
}
<|endoftext|>