<commit_before>//! `ra_assists` crate provides a bunch of code assists, also known as code
//! actions (in LSP) or intentions (in IntelliJ).
//!
//! An assist is a micro-refactoring, which is automatically activated in
//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
//! becomes available.

#[allow(unused)]
macro_rules! eprintln {
    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
}

mod assist_ctx;
mod marks;
#[cfg(test)]
mod doc_tests;
pub mod utils;
pub mod ast_transform;

use ra_db::FileRange;
use ra_ide_db::RootDatabase;
use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::TextEdit;

pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler};
use hir::Semantics;

/// Unique identifier of the assist, should not be shown to the user
/// directly.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AssistId(pub &'static str);

#[derive(Debug, Clone)]
pub struct AssistLabel {
    /// Short description of the assist, as shown in the UI.
    pub label: String,
    pub id: AssistId,
}

#[derive(Clone, Debug)]
pub struct GroupLabel(pub String);

impl AssistLabel {
    pub(crate) fn new(label: String, id: AssistId) -> AssistLabel {
        // FIXME: make fields private, so that this invariant can't be broken
        assert!(label.starts_with(|c: char| c.is_uppercase()));
        AssistLabel { label, id }
    }
}

#[derive(Debug, Clone)]
pub struct AssistAction {
    pub edit: TextEdit,
    pub cursor_position: Option<TextUnit>,
    // FIXME: This belongs to `AssistLabel`
    pub target: Option<TextRange>,
}

#[derive(Debug, Clone)]
pub struct ResolvedAssist {
    pub label: AssistLabel,
    pub group_label: Option<GroupLabel>,
    pub action: AssistAction,
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits.
pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> {
    let sema = Semantics::new(db);
    let ctx = AssistCtx::new(&sema, range, false);
    handlers::all()
        .iter()
        .filter_map(|f| f(ctx.clone()))
        .flat_map(|it| it.0)
        .map(|a| a.label)
        .collect()
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
    let sema = Semantics::new(db);
    let ctx = AssistCtx::new(&sema, range, true);
    let mut a = handlers::all()
        .iter()
        .filter_map(|f| f(ctx.clone()))
        .flat_map(|it| it.0)
        .map(|it| it.into_resolved().unwrap())
        .collect::<Vec<_>>();
    a.sort_by_key(|it| it.action.target.map_or(TextUnit::from(!0u32), |it| it.len()));
    a
}

mod handlers {
    use crate::AssistHandler;

    mod add_custom_impl;
    mod add_derive;
    mod add_explicit_type;
    mod add_function;
    mod add_impl;
    mod add_missing_impl_members;
    mod add_new;
    mod apply_demorgan;
    mod auto_import;
    mod change_visibility;
    mod early_return;
    mod fill_match_arms;
    mod flip_binexpr;
    mod flip_comma;
    mod flip_trait_bound;
    mod inline_local_variable;
    mod introduce_variable;
    mod invert_if;
    mod merge_imports;
    mod merge_match_arms;
    mod move_bounds;
    mod move_guard;
    mod raw_string;
    mod remove_dbg;
    mod remove_mut;
    mod replace_if_let_with_match;
    mod replace_let_with_if_let;
    mod replace_qualified_name_with_use;
    mod replace_unwrap_with_match;
    mod split_import;
    mod add_from_impl_for_enum;

    pub(crate) fn all() -> &'static [AssistHandler] {
        &[
            add_custom_impl::add_custom_impl,
            add_derive::add_derive,
            add_explicit_type::add_explicit_type,
            add_function::add_function,
            add_impl::add_impl,
            add_missing_impl_members::add_missing_default_members,
            add_missing_impl_members::add_missing_impl_members,
            add_new::add_new,
            apply_demorgan::apply_demorgan,
            auto_import::auto_import,
            change_visibility::change_visibility,
            early_return::convert_to_guarded_return,
            fill_match_arms::fill_match_arms,
            flip_binexpr::flip_binexpr,
            flip_comma::flip_comma,
            flip_trait_bound::flip_trait_bound,
            inline_local_variable::inline_local_variable,
            introduce_variable::introduce_variable,
            invert_if::invert_if,
            merge_imports::merge_imports,
            merge_match_arms::merge_match_arms,
            move_bounds::move_bounds_to_where_clause,
            move_guard::move_arm_cond_to_match_guard,
            move_guard::move_guard_to_arm_body,
            raw_string::add_hash,
            raw_string::make_raw_string,
            raw_string::make_usual_string,
            raw_string::remove_hash,
            remove_dbg::remove_dbg,
            remove_mut::remove_mut,
            replace_if_let_with_match::replace_if_let_with_match,
            replace_let_with_if_let::replace_let_with_if_let,
            replace_qualified_name_with_use::replace_qualified_name_with_use,
            replace_unwrap_with_match::replace_unwrap_with_match,
            split_import::split_import,
            add_from_impl_for_enum::add_from_impl_for_enum,
        ]
    }
}

#[cfg(test)]
mod helpers {
    use std::sync::Arc;

    use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
    use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
    use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset};

    use crate::{AssistCtx, AssistHandler};
    use hir::Semantics;

    pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
        let (mut db, file_id) = RootDatabase::with_single_file(text);
        // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
        // but it looks like this might need specialization? :(
        db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)]));
        (db, file_id)
    }

    pub(crate) fn check_assist(
        assist: AssistHandler,
        ra_fixture_before: &str,
        ra_fixture_after: &str,
    ) {
        check(assist, ra_fixture_before, ExpectedResult::After(ra_fixture_after));
    }

    // FIXME: instead of having a separate function here, maybe use
    // `extract_ranges` and mark the target as `<target> </target>` in the
    // fixuture?
    pub(crate) fn check_assist_target(assist: AssistHandler, ra_fixture: &str, target: &str) {
        check(assist, ra_fixture, ExpectedResult::Target(target));
    }

    pub(crate) fn check_assist_not_applicable(assist: AssistHandler, ra_fixture: &str) {
        check(assist, ra_fixture, ExpectedResult::NotApplicable);
    }

    enum ExpectedResult<'a> {
        NotApplicable,
        After(&'a str),
        Target(&'a str),
    }

    fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) {
        let (text_without_caret, file_with_caret_id, range_or_offset, db) =
            if before.contains("//-") {
                let (mut db, position) = RootDatabase::with_position(before);
                db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)]));
                (
                    db.file_text(position.file_id).as_ref().to_owned(),
                    position.file_id,
                    RangeOrOffset::Offset(position.offset),
                    db,
                )
            } else {
                let (range_or_offset, text_without_caret) = extract_range_or_offset(before);
                let (db, file_id) = with_single_file(&text_without_caret);
                (text_without_caret, file_id, range_or_offset, db)
            };

        let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };

        let sema = Semantics::new(&db);
        let assist_ctx = AssistCtx::new(&sema, frange, true);

        match (assist(assist_ctx), expected) {
            (Some(assist), ExpectedResult::After(after)) => {
                let action = assist.0[0].action.clone().unwrap();

                let mut actual = action.edit.apply(&text_without_caret);
                match action.cursor_position {
                    None => {
                        if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
                            let off = action
                                .edit
                                .apply_to_offset(before_cursor_pos)
                                .expect("cursor position is affected by the edit");
                            actual = add_cursor(&actual, off)
                        }
                    }
                    Some(off) => actual = add_cursor(&actual, off),
                };

                assert_eq_text!(after, &actual);
            }
            (Some(assist), ExpectedResult::Target(target)) => {
                let action = assist.0[0].action.clone().unwrap();
                let range = action.target.expect("expected target on action");
                assert_eq_text!(&text_without_caret[range], target);
            }
            (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
            (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => {
                panic!("code action is not applicable")
            }
            (None, ExpectedResult::NotApplicable) => (),
        };
    }
}

#[cfg(test)]
mod tests {
    use ra_db::FileRange;
    use ra_syntax::TextRange;
    use test_utils::{extract_offset, extract_range};

    use crate::{helpers, resolved_assists};

    #[test]
    fn assist_order_field_struct() {
        let before = "struct Foo { <|>bar: u32 }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, file_id) = helpers::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = resolved_assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(
            assists.next().expect("expected assist").label.label,
            "Change visibility to pub(crate)"
        );
        assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`");
    }

    #[test]
    fn assist_order_if_expr() {
        let before = "
        pub fn test_some_range(a: int) -> bool {
            if let 2..6 = <|>5<|> {
                true
            } else {
                false
            }
        }";
        let (range, before) = extract_range(before);
        let (db, file_id) = helpers::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assists = resolved_assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable");
        assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match");
    }
}
<commit_msg>Fix add missing items assist order<commit_after>//! `ra_assists` crate provides a bunch of code assists, also known as code
//! actions (in LSP) or intentions (in IntelliJ).
//!
//! An assist is a micro-refactoring, which is automatically activated in
//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
//! becomes available.

#[allow(unused)]
macro_rules! eprintln {
    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
}

mod assist_ctx;
mod marks;
#[cfg(test)]
mod doc_tests;
pub mod utils;
pub mod ast_transform;

use ra_db::FileRange;
use ra_ide_db::RootDatabase;
use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::TextEdit;

pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler};
use hir::Semantics;

/// Unique identifier of the assist, should not be shown to the user
/// directly.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AssistId(pub &'static str);

#[derive(Debug, Clone)]
pub struct AssistLabel {
    /// Short description of the assist, as shown in the UI.
    pub label: String,
    pub id: AssistId,
}

#[derive(Clone, Debug)]
pub struct GroupLabel(pub String);

impl AssistLabel {
    pub(crate) fn new(label: String, id: AssistId) -> AssistLabel {
        // FIXME: make fields private, so that this invariant can't be broken
        assert!(label.starts_with(|c: char| c.is_uppercase()));
        AssistLabel { label, id }
    }
}

#[derive(Debug, Clone)]
pub struct AssistAction {
    pub edit: TextEdit,
    pub cursor_position: Option<TextUnit>,
    // FIXME: This belongs to `AssistLabel`
    pub target: Option<TextRange>,
}

#[derive(Debug, Clone)]
pub struct ResolvedAssist {
    pub label: AssistLabel,
    pub group_label: Option<GroupLabel>,
    pub action: AssistAction,
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits.
pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> {
    let sema = Semantics::new(db);
    let ctx = AssistCtx::new(&sema, range, false);
    handlers::all()
        .iter()
        .filter_map(|f| f(ctx.clone()))
        .flat_map(|it| it.0)
        .map(|a| a.label)
        .collect()
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
    let sema = Semantics::new(db);
    let ctx = AssistCtx::new(&sema, range, true);
    let mut a = handlers::all()
        .iter()
        .filter_map(|f| f(ctx.clone()))
        .flat_map(|it| it.0)
        .map(|it| it.into_resolved().unwrap())
        .collect::<Vec<_>>();
    a.sort_by_key(|it| it.action.target.map_or(TextUnit::from(!0u32), |it| it.len()));
    a
}

mod handlers {
    use crate::AssistHandler;

    mod add_custom_impl;
    mod add_derive;
    mod add_explicit_type;
    mod add_function;
    mod add_impl;
    mod add_missing_impl_members;
    mod add_new;
    mod apply_demorgan;
    mod auto_import;
    mod change_visibility;
    mod early_return;
    mod fill_match_arms;
    mod flip_binexpr;
    mod flip_comma;
    mod flip_trait_bound;
    mod inline_local_variable;
    mod introduce_variable;
    mod invert_if;
    mod merge_imports;
    mod merge_match_arms;
    mod move_bounds;
    mod move_guard;
    mod raw_string;
    mod remove_dbg;
    mod remove_mut;
    mod replace_if_let_with_match;
    mod replace_let_with_if_let;
    mod replace_qualified_name_with_use;
    mod replace_unwrap_with_match;
    mod split_import;
    mod add_from_impl_for_enum;

    pub(crate) fn all() -> &'static [AssistHandler] {
        &[
            // These are alphabetic for the foolish consistency
            add_custom_impl::add_custom_impl,
            add_derive::add_derive,
            add_explicit_type::add_explicit_type,
            add_function::add_function,
            add_impl::add_impl,
            add_new::add_new,
            apply_demorgan::apply_demorgan,
            auto_import::auto_import,
            change_visibility::change_visibility,
            early_return::convert_to_guarded_return,
            fill_match_arms::fill_match_arms,
            flip_binexpr::flip_binexpr,
            flip_comma::flip_comma,
            flip_trait_bound::flip_trait_bound,
            inline_local_variable::inline_local_variable,
            introduce_variable::introduce_variable,
            invert_if::invert_if,
            merge_imports::merge_imports,
            merge_match_arms::merge_match_arms,
            move_bounds::move_bounds_to_where_clause,
            move_guard::move_arm_cond_to_match_guard,
            move_guard::move_guard_to_arm_body,
            raw_string::add_hash,
            raw_string::make_raw_string,
            raw_string::make_usual_string,
            raw_string::remove_hash,
            remove_dbg::remove_dbg,
            remove_mut::remove_mut,
            replace_if_let_with_match::replace_if_let_with_match,
            replace_let_with_if_let::replace_let_with_if_let,
            replace_qualified_name_with_use::replace_qualified_name_with_use,
            replace_unwrap_with_match::replace_unwrap_with_match,
            split_import::split_import,
            add_from_impl_for_enum::add_from_impl_for_enum,
            // These are manually sorted for better priorities
            add_missing_impl_members::add_missing_impl_members,
            add_missing_impl_members::add_missing_default_members,
        ]
    }
}

#[cfg(test)]
mod helpers {
    use std::sync::Arc;

    use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
    use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
    use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset};

    use crate::{AssistCtx, AssistHandler};
    use hir::Semantics;

    pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
        let (mut db, file_id) = RootDatabase::with_single_file(text);
        // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
        // but it looks like this might need specialization? :(
        db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)]));
        (db, file_id)
    }

    pub(crate) fn check_assist(
        assist: AssistHandler,
        ra_fixture_before: &str,
        ra_fixture_after: &str,
    ) {
        check(assist, ra_fixture_before, ExpectedResult::After(ra_fixture_after));
    }

    // FIXME: instead of having a separate function here, maybe use
    // `extract_ranges` and mark the target as `<target> </target>` in the
    // fixuture?
    pub(crate) fn check_assist_target(assist: AssistHandler, ra_fixture: &str, target: &str) {
        check(assist, ra_fixture, ExpectedResult::Target(target));
    }

    pub(crate) fn check_assist_not_applicable(assist: AssistHandler, ra_fixture: &str) {
        check(assist, ra_fixture, ExpectedResult::NotApplicable);
    }

    enum ExpectedResult<'a> {
        NotApplicable,
        After(&'a str),
        Target(&'a str),
    }

    fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) {
        let (text_without_caret, file_with_caret_id, range_or_offset, db) =
            if before.contains("//-") {
                let (mut db, position) = RootDatabase::with_position(before);
                db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)]));
                (
                    db.file_text(position.file_id).as_ref().to_owned(),
                    position.file_id,
                    RangeOrOffset::Offset(position.offset),
                    db,
                )
            } else {
                let (range_or_offset, text_without_caret) = extract_range_or_offset(before);
                let (db, file_id) = with_single_file(&text_without_caret);
                (text_without_caret, file_id, range_or_offset, db)
            };

        let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };

        let sema = Semantics::new(&db);
        let assist_ctx = AssistCtx::new(&sema, frange, true);

        match (assist(assist_ctx), expected) {
            (Some(assist), ExpectedResult::After(after)) => {
                let action = assist.0[0].action.clone().unwrap();

                let mut actual = action.edit.apply(&text_without_caret);
                match action.cursor_position {
                    None => {
                        if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
                            let off = action
                                .edit
                                .apply_to_offset(before_cursor_pos)
                                .expect("cursor position is affected by the edit");
                            actual = add_cursor(&actual, off)
                        }
                    }
                    Some(off) => actual = add_cursor(&actual, off),
                };

                assert_eq_text!(after, &actual);
            }
            (Some(assist), ExpectedResult::Target(target)) => {
                let action = assist.0[0].action.clone().unwrap();
                let range = action.target.expect("expected target on action");
                assert_eq_text!(&text_without_caret[range], target);
            }
            (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
            (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => {
                panic!("code action is not applicable")
            }
            (None, ExpectedResult::NotApplicable) => (),
        };
    }
}

#[cfg(test)]
mod tests {
    use ra_db::FileRange;
    use ra_syntax::TextRange;
    use test_utils::{extract_offset, extract_range};

    use crate::{helpers, resolved_assists};

    #[test]
    fn assist_order_field_struct() {
        let before = "struct Foo { <|>bar: u32 }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, file_id) = helpers::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = resolved_assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(
            assists.next().expect("expected assist").label.label,
            "Change visibility to pub(crate)"
        );
        assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`");
    }

    #[test]
    fn assist_order_if_expr() {
        let before = "
        pub fn test_some_range(a: int) -> bool {
            if let 2..6 = <|>5<|> {
                true
            } else {
                false
            }
        }";
        let (range, before) = extract_range(before);
        let (db, file_id) = helpers::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assists = resolved_assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable");
        assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match");
    }
}
<|endoftext|>


<commit_before>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;

pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = try!(system.next()) {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), &platform));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    info!(target: "Streamer",
          "{:7.2} s | job #{:3} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, job.name, job.units, job.duration(), kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<commit_msg>Eliminate a warning<commit_after>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;

pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = try!(system.next()) {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), &platform));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    info!(target: "Streamer",
          "{:7.2} s | job #{:3} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, job.name, job.units, job.duration(), kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::Write;
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Provides the ability to retry an operation until it succeeds.
//!
//! # Examples
//!
//! ```
//! use std::time::Duration;
//! use std::io;
//! use std::io::Write;
//! use std::error::Error;
//!
//! fn find_answer(answer: &str) -> io::Result<()> {
//!     print!("Please enter the correct answer: ");
//!     io::stdout().flush()?;
//!
//!     let mut buf = String::new();
//!     io::stdin().read_line(&mut buf)?;
//!
//!     return if buf.trim() == answer {
//!         Ok(())
//!     } else {
//!         Err(io::Error::new(io::ErrorKind::Other, "Sorry, that is not the answer."))
//!     }
//! }
//!
//! fn retry_progress(retry: &retry::Retry,
//!                   err: &io::Error,
//!                   remaining: u32,
//!                   delay: Duration) -> bool {
//!     println!("Error: {} ({} attempt(s) remaining. Retrying in ~{} seconds...)",
//!         err.description(),
//!         remaining,
//!         delay.as_secs()
//!     );
//!     true
//! }
//!
//! let result = retry::Retry::new()
//!     .with_retries(4)
//!     .with_delay(Duration::from_secs(1))
//!     .with_max_delay(Duration::from_secs(4))
//!     .call(|| find_answer("42"), retry_progress);
//!
//! match result {
//!     Ok(()) => println!("Correct!"),
//!     Err(err) => println!("{}", err),
//! };
//! ```

// TODO: Allow specifying a non-integer exponential backoff factor.
// TODO: Allow jittering to further help avoid the "thundering herd" problem by
// keeping retries from stacking up. Jittering is just adjusting the delay by a
// random offset within an interval. If the interval length is 0, there is
// effectively no jittering.

use std::thread::sleep;
use std::time::Duration;
use std::cmp::min;
use std::error::Error;

#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
pub struct Retry {
    /// The number of times to *retry* a function. Note that the function is
    /// always called at least once.
    pub retries: u32,

    /// The initial duration to wait. For each retry, this is multiplied by the
    /// exponential backoff factor. Set to a duration of 0 for no delay.
    pub delay: Duration,

    /// The backoff factor. A value of 1 means linear backoff. A value of 2
    /// means exponential backoff. A value of 0 means no delay at all.
    pub backoff: u32,

    /// The maximum possible delay. If `None`, there is no maximum delay.
    pub max_delay: Option<Duration>,
}

impl Default for Retry {
    fn default() -> Retry {
        Retry {
            retries: 0,
            delay: Duration::from_secs(1),
            backoff: 2,
            max_delay: None,
        }
    }
}

impl Retry {
    /// Initializes a default `Retry`.
    #[allow(unused)]
    pub fn new() -> Retry {
        Retry::default()
    }

    /// Sets the number of retries.
    #[allow(unused)]
    pub fn with_retries(mut self, retries: u32) -> Retry {
        self.retries = retries;
        self
    }

    /// Sets the initial delay.
    #[allow(unused)]
    pub fn with_delay(mut self, delay: Duration) -> Retry {
        self.delay = delay;
        self
    }

    /// Sets the backoff.
    #[allow(unused)]
    pub fn with_backoff(mut self, backoff: u32) -> Retry {
        self.backoff = backoff;
        self
    }

    /// Sets the maximum possible delay.
    #[allow(unused)]
    pub fn with_max_delay(mut self, max_delay: Duration) -> Retry {
        self.max_delay = Some(max_delay);
        self
    }

    /// Calls the function until it returns a `Ok` result. If an `Ok` result is
    /// never produced, returns the `Result` from the last call to the function
    /// that failed.
    pub fn call<F, T, E, P>(&self, mut f: F, mut progress: P) -> Result<T, E>
        where F: FnMut() -> Result<T, E>,
              P: FnMut(&Retry, &E, u32, Duration) -> bool
    {
        let mut attempt = self.retries + 1;
        let mut delay = self.delay;

        loop {
            match f() {
                Ok(value) => return Ok(value),
                Err(err) => {
                    attempt -= 1;

                    if attempt > 0 {
                        if !progress(&self, &err, attempt, delay) {
                            return Err(err);
                        }

                        sleep(delay);

                        // Increase the delay.
                        delay = match self.max_delay {
                            Some(max_delay) => {
                                min(delay * self.backoff, max_delay)
                            }
                            None => delay * self.backoff,
                        };
                    } else {
                        // No more remaining attempts.
                        return Err(err);
                    }
                }
            }
        }
    }
}

/// Dummy progress callback function. If you don't want to report progress on
/// for each retry, use this function.
#[allow(unused_variables)]
pub fn progress_dummy<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool {
    // Keep going.
    true
}

/// Progress callback function for simply printing the progress of each retry.
#[allow(unused)]
pub fn progress_print<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool
    where E: Error
{
    println!("Error: {} ({}/{} attempt(s) remaining. Retrying in ~{} seconds...)",
             err.description(),
             remaining,
             retry.retries,
             delay.as_secs());
    true
}
<commit_msg>Fix doc test<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Provides the ability to retry an operation until it succeeds.
//!
//! # Examples
//!
//! ```
//! use std::time::Duration;
//! use std::io;
//! use std::io::Write;
//! use std::error::Error;
//!
//! use button::retry::Retry;
//!
//! fn find_answer(answer: &str) -> io::Result<()> {
//!     print!("Please enter the correct answer: ");
//!     io::stdout().flush()?;
//!
//!     let mut buf = String::new();
//!     io::stdin().read_line(&mut buf)?;
//!
//!     return if buf.trim() == answer {
//!         Ok(())
//!     } else {
//!         Err(io::Error::new(io::ErrorKind::Other, "Sorry, that is not the answer."))
//!     }
//! }
//!
//! fn retry_progress(retry: &Retry,
//!                   err: &io::Error,
//!                   remaining: u32,
//!                   delay: Duration) -> bool {
//!     println!("Error: {} ({} attempt(s) remaining. Retrying in ~{} seconds...)",
//!         err.description(),
//!         remaining,
//!         delay.as_secs()
//!     );
//!     true
//! }
//!
//! let result = Retry::new()
//!     .with_retries(4)
//!     .with_delay(Duration::from_secs(1))
//!     .with_max_delay(Duration::from_secs(4))
//!     .call(|| find_answer("42"), retry_progress);
//!
//! match result {
//!     Ok(()) => println!("Correct!"),
//!     Err(err) => println!("{}", err),
//! };
//! ```

// TODO: Allow specifying a non-integer exponential backoff factor.
// TODO: Allow jittering to further help avoid the "thundering herd" problem by
// keeping retries from stacking up. Jittering is just adjusting the delay by a
// random offset within an interval. If the interval length is 0, there is
// effectively no jittering.

use std::thread::sleep;
use std::time::Duration;
use std::cmp::min;
use std::error::Error;

#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
pub struct Retry {
    /// The number of times to *retry* a function. Note that the function is
    /// always called at least once.
    pub retries: u32,

    /// The initial duration to wait. For each retry, this is multiplied by the
    /// exponential backoff factor. Set to a duration of 0 for no delay.
    pub delay: Duration,

    /// The backoff factor. A value of 1 means linear backoff. A value of 2
    /// means exponential backoff. A value of 0 means no delay at all.
    pub backoff: u32,

    /// The maximum possible delay. If `None`, there is no maximum delay.
    pub max_delay: Option<Duration>,
}

impl Default for Retry {
    fn default() -> Retry {
        Retry {
            retries: 0,
            delay: Duration::from_secs(1),
            backoff: 2,
            max_delay: None,
        }
    }
}

impl Retry {
    /// Initializes a default `Retry`.
    #[allow(unused)]
    pub fn new() -> Retry {
        Retry::default()
    }

    /// Sets the number of retries.
    #[allow(unused)]
    pub fn with_retries(mut self, retries: u32) -> Retry {
        self.retries = retries;
        self
    }

    /// Sets the initial delay.
    #[allow(unused)]
    pub fn with_delay(mut self, delay: Duration) -> Retry {
        self.delay = delay;
        self
    }

    /// Sets the backoff.
    #[allow(unused)]
    pub fn with_backoff(mut self, backoff: u32) -> Retry {
        self.backoff = backoff;
        self
    }

    /// Sets the maximum possible delay.
    #[allow(unused)]
    pub fn with_max_delay(mut self, max_delay: Duration) -> Retry {
        self.max_delay = Some(max_delay);
        self
    }

    /// Calls the function until it returns a `Ok` result. If an `Ok` result is
    /// never produced, returns the `Result` from the last call to the function
    /// that failed.
    pub fn call<F, T, E, P>(&self, mut f: F, mut progress: P) -> Result<T, E>
        where F: FnMut() -> Result<T, E>,
              P: FnMut(&Retry, &E, u32, Duration) -> bool
    {
        let mut attempt = self.retries + 1;
        let mut delay = self.delay;

        loop {
            match f() {
                Ok(value) => return Ok(value),
                Err(err) => {
                    attempt -= 1;

                    if attempt > 0 {
                        if !progress(&self, &err, attempt, delay) {
                            return Err(err);
                        }

                        sleep(delay);

                        // Increase the delay.
                        delay = match self.max_delay {
                            Some(max_delay) => {
                                min(delay * self.backoff, max_delay)
                            }
                            None => delay * self.backoff,
                        };
                    } else {
                        // No more remaining attempts.
                        return Err(err);
                    }
                }
            }
        }
    }
}

/// Dummy progress callback function. If you don't want to report progress on
/// for each retry, use this function.
#[allow(unused_variables)]
pub fn progress_dummy<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool {
    // Keep going.
    true
}

/// Progress callback function for simply printing the progress of each retry.
#[allow(unused)]
pub fn progress_print<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool
    where E: Error
{
    println!("Error: {} ({}/{} attempt(s) remaining. Retrying in ~{} seconds...)",
             err.description(),
             remaining,
             retry.retries,
             delay.as_secs());
    true
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::marker::PhantomData;
use std::str::{FromStr, from_utf8};

use nom::{IResult, is_space};
use num_traits::One;

use cfg::{LetterT, CFGComposition, CFGRule, CFG};
use util::parsing::*;

impl<N, T, W> FromStr for CFG<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut it = s.lines();
        let mut rules = Vec::new();
        let initial;

        match it.next() {
            Some(l) => {
                match parse_initials(l.as_bytes()) {
                    IResult::Done(_, result)
                        => initial = result,
                    _
                        => return Err(format!("Malformed declaration of initial nonterminals: {}", l))
                }
            },
            _ => return Err("Given string is empty.".to_string())
        }

        for l in s.lines() {
            if !l.is_empty() && !l.starts_with("initial: ") {
                rules.push(l.trim().parse()?);
            }
        }

        Ok(CFG {
            _dummy: PhantomData,
            initial,
            rules,
        })

    }
}

impl<N, T, W> FromStr for CFGRule<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match parse_cfg_rule(s.as_bytes()) {
            IResult::Done(_, result) => Ok(result),
            _                        => Err(format!("Could not parse {}", s))
        }
    }
}

fn parse_cfg_rule<N, T, W>(input: &[u8]) -> IResult<&[u8], CFGRule<N, T, W>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    do_parse!(
        input,
        head: parse_token >>
            take_while!(is_space) >>
            alt!(tag!("→") | tag!("->") | tag!("=>")) >>
            take_while!(is_space) >>
            composition: parse_composition >>
            take_while!(is_space) >>
            weight_o: opt!(
                complete!(
                    do_parse!(
                        tag!("#") >>
                            take_while!(is_space) >>
                            weight_s: map_res!(is_not!(" "), from_utf8) >>
                            (weight_s.parse().unwrap())
                    )
                )
            ) >>
            take_while!(is_space) >>
            many0!(tag!("%")) >>
            take_while!(|_| true) >>
            (CFGRule {
                head: head,
                composition: CFGComposition { composition: composition },
                weight: weight_o.unwrap_or(W::one()),
            })
    )
}

fn parse_letter_t<N, T>(input: &[u8]) -> IResult<&[u8], LetterT<N,T>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    do_parse!(
        input,
        result: alt!(
            do_parse!(
                tag!("Nt") >>
                    take_while!(is_space) >>
                    token: parse_token >>
                    (LetterT::Label(token))
            ) |
            do_parse!(
                tag!("T") >>
                    take_while!(is_space) >>
                    token: parse_token >>
                    (LetterT::Value(token))
            )
        ) >>
            (result)
    )
}

fn parse_composition<N, T>(input: &[u8]) -> IResult<&[u8], Vec<LetterT<N,T>>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    parse_vec(input, parse_letter_t, "[", "]", ",")
}

#[cfg(test)]
pub mod tests {
    use super::*;

    #[test]
    fn test_cfg_from_str_leading_comment() {
        let grammar = "% leading comment\n\
                       initial: [S]\n\n\
                       S → [T a]";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_end_of_line_comment() {
        let grammar = "initial: [S] % end-of-line comment 1\n\n\
                       S → [T a] % end-of-line comment 2";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_trailing_comment() {
        let grammar = "initial: [S]\n\n\
                       S → [T a]\n\
                       % trailing comment";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }
}
<commit_msg>src/cfg/from_str.rs: fixed behaviour of parse_cfg_rule()<commit_after>use std::fmt::Debug;
use std::marker::PhantomData;
use std::str::{FromStr, from_utf8};

use nom::{IResult, is_space};
use num_traits::One;

use cfg::{LetterT, CFGComposition, CFGRule, CFG};
use util::parsing::*;

impl<N, T, W> FromStr for CFG<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut it = s.lines();
        let mut rules = Vec::new();
        let initial;

        match it.next() {
            Some(l) => {
                match parse_initials(l.as_bytes()) {
                    IResult::Done(_, result)
                        => initial = result,
                    _
                        => return Err(format!("Malformed declaration of initial nonterminals: {}", l))
                }
            },
            _ => return Err("Given string is empty.".to_string())
        }

        for l in s.lines() {
            if !l.is_empty() && !l.starts_with("initial: ") {
                rules.push(l.trim().parse()?);
            }
        }

        Ok(CFG {
            _dummy: PhantomData,
            initial,
            rules,
        })

    }
}

impl<N, T, W> FromStr for CFGRule<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match parse_cfg_rule(s.as_bytes()) {
            IResult::Done(_, result) => Ok(result),
            _                        => Err(format!("Could not parse {}", s))
        }
    }
}

fn parse_cfg_rule<N, T, W>(input: &[u8]) -> IResult<&[u8], CFGRule<N, T, W>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    do_parse!(
        input,
        head: parse_token >>
        take_while!(is_space) >>
        alt!(tag!("→") | tag!("->") | tag!("=>")) >>
        take_while!(is_space) >>
        composition: parse_composition >>
        take_while!(is_space) >>
        weight_o: opt!(
            complete!(
                do_parse!(
                    tag!("#") >>
                    take_while!(is_space) >>
                    weight_s: map_res!(is_not!(" "), from_utf8) >>
                    weight: expr_res!(weight_s.parse()) >>
                    (weight)
                )
            )
        ) >>
        take_while!(is_space) >>
        alt!(
            eof!() |
            preceded!(tag!("%"), take_while!(|_| true))
        ) >>
        (CFGRule {
            head: head,
            composition: CFGComposition { composition: composition },
            weight: weight_o.unwrap_or(W::one()),
        })
    )
}

fn parse_letter_t<N, T>(input: &[u8]) -> IResult<&[u8], LetterT<N,T>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    do_parse!(
        input,
        result: alt!(
            do_parse!(
                tag!("Nt") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Label(token))
            ) |
            do_parse!(
                tag!("T") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Value(token))
            )
        ) >>
        (result)
    )
}

fn parse_composition<N, T>(input: &[u8]) -> IResult<&[u8], Vec<LetterT<N,T>>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    parse_vec(input, parse_letter_t, "[", "]", ",")
}

#[cfg(test)]
pub mod tests {
    use super::*;

    #[test]
    fn test_cfg_from_str_leading_comment() {
        let grammar = "% leading comment\n\
                       initial: [S]\n\n\
                       S → [T a]";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_end_of_line_comment() {
        let grammar = "initial: [S] % end-of-line comment 1\n\n\
                       S → [T a] % end-of-line comment 2";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_trailing_comment() {
        let grammar = "initial: [S]\n\n\
                       S → [T a]\n\
                       % trailing comment";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }
}
<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                let expectations_obj = &meth.expectations_obj();
                quote!(#attrs #name: #modname::#expectations_obj::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                let expectations_obj = &meth.expectations_obj();
                quote!(#attrs #name: #modname::#expectations_obj)
            }).collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics: mockable.generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: trait_.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits(&modname));
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[doc(hidden)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        // TODO: try removing the type names, and just use
                        // "default"
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let default_inits = self.methods.default_inits(&modname);
        let field_definitions = self.methods.field_definitions(&modname);
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[doc(hidden)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<commit_msg>Don't emit docs for private trait impl structs<commit_after>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                let expectations_obj = &meth.expectations_obj();
                quote!(#attrs #name: #modname::#expectations_obj::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                let expectations_obj = &meth.expectations_obj();
                quote!(#attrs #name: #modname::#expectations_obj)
            }).collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics: mockable.generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: trait_.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits(&modname));
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[doc(hidden)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        // TODO: try removing the type names, and just use
                        // "default"
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs_nodocs = format_attrs(&self.attrs, false);
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let default_inits = self.methods.default_inits(&modname);
        let field_definitions = self.methods.field_definitions(&modname);
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[doc(hidden)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #attrs_nodocs
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::convert::From;
use std::iter::repeat;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::fmt;
use ast::Type;
use span::Span;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ErrorCode
{
    UnexpectedEOF,
    IOError,
    UnexpectedChar,
    UnexpectedToken,
    ExpectedIdentifier,
    ExpectedIntLiteral,
    ExpectedOperator,
    InvalidOperator,
    InvalidUnaryOperator,
    InvalidBinaryOperator,
    InvalidFloatingPoint,
    InvalidInteger,
    TypeError,
    UnknownName,
    MissingType,
    CallingNonCallable,
    CodegenError,
    RedefinitionOfVariable,
    RedefinitionOfFunction,
    RedefinitionOfStruct,
    GenericTypeSubstitutionError,
    ExpressionNotAllowedAtTopLevel,
    LambdaDoesNotMatch,
    WrongArgumentCount,
    UnknownType(String, Type), // Name and expected type
    UnknownStructMember,
    FileNotFound,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CompileError
{
    pub span: Span,
    pub error: ErrorCode,
    pub msg: String,
}

impl CompileError
{
    pub fn new(span: &Span, error: ErrorCode, msg: String) -> CompileError
    {
        CompileError{
            span: span.clone(),
            error: error,
            msg: msg,
        }
    }

    pub fn print(&self)
    {
        let prefix = "> ";
        println!("{}{}: {}", prefix, self.span, self.msg);
        if let Ok(file) = File::open(&self.span.file) {
            let start_line = if self.span.start.line >= 4 {self.span.start.line - 4} else {0};
            let reader = io::BufReader::new(file);

            for (idx, line) in reader.lines().enumerate().skip(start_line)
            {
                let line = line.unwrap();
                let line_idx = idx + 1;
                println!("{}{}", prefix, line);
                if line_idx == self.span.start.line
                {
                    let end = if line_idx == self.span.end.line {self.span.end.offset} else {line.len()};
                    let carets = repeat_string("^", end - self.span.start.offset + 1);
                    let whitespace = repeat_string(" ", self.span.start.offset - 1);
                    println!("{}{}{}", prefix, whitespace, carets);
                }
                else if line_idx == self.span.end.line
                {
                    let carets = repeat_string("^", self.span.end.offset);
                    println!("{}{}", prefix, carets);
                }
                else if line_idx > self.span.start.line && line_idx < self.span.end.line
                {
                    let carets = repeat_string("^", line.len());
                    println!("{}{}", prefix, carets);
                }

                if line_idx >= self.span.end.line + 3 {break;}
            }
        }
    }
}

pub type CompileResult<T> = Result<T, CompileError>;

pub fn err<T: Sized>(span: &Span, e: ErrorCode, msg: String) -> CompileResult<T>
{
    Err(CompileError::new(span, e, msg))
}

pub fn unknown_name(span: &Span, name: &str) -> CompileError
{
    CompileError::new(span, ErrorCode::UnknownName, format!("Unable to resolve name {}", name))
}

fn repeat_string(s: &str, count: usize) -> String
{
    repeat(s).take(count).collect()
}

impl fmt::Display for CompileError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        writeln!(f, "{}: {}", self.span, self.msg)
    }
}

impl Error for CompileError
{
    fn description(&self) -> &str
    {
        "Compile error"
    }
}

impl From<io::Error> for CompileError
{
    fn from(e: io::Error) -> Self
    {
        CompileError{
            span: Span::default(),
            error: ErrorCode::IOError,
            msg: format!("IO Error: {}", e),
        }
    }
}
<commit_msg>Improve error printing<commit_after>use std::error::Error;
use std::convert::From;
use std::iter::repeat;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::fmt;
use ast::Type;
use span::Span;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ErrorCode
{
    UnexpectedEOF,
    IOError,
    UnexpectedChar,
    UnexpectedToken,
    ExpectedIdentifier,
    ExpectedIntLiteral,
    ExpectedOperator,
    InvalidOperator,
    InvalidUnaryOperator,
    InvalidBinaryOperator,
    InvalidFloatingPoint,
    InvalidInteger,
    TypeError,
    UnknownName,
    MissingType,
    CallingNonCallable,
    CodegenError,
    RedefinitionOfVariable,
    RedefinitionOfFunction,
    RedefinitionOfStruct,
    GenericTypeSubstitutionError,
    ExpressionNotAllowedAtTopLevel,
    LambdaDoesNotMatch,
    WrongArgumentCount,
    UnknownType(String, Type), // Name and expected type
    UnknownStructMember,
    FileNotFound,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CompileError
{
    pub span: Span,
    pub error: ErrorCode,
    pub msg: String,
}

impl CompileError
{
    pub fn new(span: &Span, error: ErrorCode, msg: String) -> CompileError
    {
        CompileError{
            span: span.clone(),
            error: error,
            msg: msg,
        }
    }

    pub fn print(&self)
    {
        let prefix = "> ";
        println!("{}{}: {}", prefix, self.span, self.msg);
        if let Ok(file) = File::open(&self.span.file) {
            let start_line = if self.span.start.line >= 4 {self.span.start.line - 4} else {0};
            let reader = io::BufReader::new(file);

            for (idx, line) in reader.lines().enumerate().skip(start_line)
            {
                let line = line.unwrap();
                let line_idx = idx + 1;
                println!("{:>4}{}{}", line_idx, prefix, line);
                if line_idx == self.span.start.line
                {
                    let end = if line_idx == self.span.end.line {self.span.end.offset} else {line.len()};
                    let carets = repeat_string("^", end - self.span.start.offset + 1);
                    let whitespace = repeat_string(" ", self.span.start.offset - 1);
                    println!("{:>4}{}{}{}", line_idx, prefix, whitespace, carets);
                }
                else if line_idx == self.span.end.line
                {
                    let carets = repeat_string("^", self.span.end.offset);
                    println!("{}{}", prefix, carets);
                }
                else if line_idx > self.span.start.line && line_idx < self.span.end.line
                {
                    let carets = repeat_string("^", line.len());
                    println!("{}{}", prefix, carets);
                }

                if line_idx >= self.span.end.line + 3 {break;}
            }
        }
    }
}

pub type CompileResult<T> = Result<T, CompileError>;

pub fn err<T: Sized>(span: &Span, e: ErrorCode, msg: String) -> CompileResult<T>
{
    Err(CompileError::new(span, e, msg))
}

pub fn unknown_name(span: &Span, name: &str) -> CompileError
{
    CompileError::new(span, ErrorCode::UnknownName, format!("Unable to resolve name {}", name))
}

fn repeat_string(s: &str, count: usize) -> String
{
    repeat(s).take(count).collect()
}

impl fmt::Display for CompileError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        writeln!(f, "{}: {}", self.span, self.msg)
    }
}

impl Error for CompileError
{
    fn description(&self) -> &str
    {
        "Compile error"
    }
}

impl From<io::Error> for CompileError
{
    fn from(e: io::Error) -> Self
    {
        CompileError{
            span: Span::default(),
            error: ErrorCode::IOError,
            msg: format!("IO Error: {}", e),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::FuzzTarget;
use failure::prelude::*;
use libra_proptest_helpers::ValueGenerator;
use sha1::{Digest, Sha1};
use std::{
    env,
    ffi::OsString,
    fs,
    io::Write,
    path::{Path, PathBuf},
    process::Command,
};

/// Generates data for this fuzz target into the output directory. Returns the number of items
/// generated.
///
/// The corpus directory should be present at the time this method is called.
pub fn make_corpus(
    target: FuzzTarget,
    num_items: usize,
    corpus_dir: &Path,
    debug: bool,
) -> Result<usize> {
    // TODO: Allow custom proptest configs?
    let mut gen = ValueGenerator::new();

    let mut sha1 = Sha1::new();

    let mut idx = 0;
    while idx < num_items {
        let result = match target.generate(idx, &mut gen) {
            Some(bytes) => bytes,
            None => {
                // No value could be generated. Assume that corpus generation has been exhausted.
                break;
            }
        };

        // Use the SHA-1 of the result as the file name.
        sha1.input(&result);
        let hash = sha1.result_reset();
        let name = hex::encode(hash.as_slice());
        let path = corpus_dir.join(name);
        let mut f = fs::File::create(&path)
            .with_context(|_| format!("Failed to create file: {:?}", path))?;
        if debug {
            println!("Writing {} bytes to file: {:?}", result.len(), path);
        }

        f.write_all(&result)
            .with_context(|_| format!("Failed to write to file: {:?}", path))?;
        idx += 1;
    }
    Ok(idx)
}

/// Fuzz a target by running `cargo fuzz run`.
pub fn fuzz_target(
    target: FuzzTarget,
    corpus_dir: PathBuf,
    artifact_dir: PathBuf,
    mut args: Vec<OsString>,
) -> Result<()> {
    static FUZZ_RUNNER: &str = "fuzz_runner";

    // Do a bit of arg parsing -- look for a "--" and insert the target and corpus directory
    // before that.
    let dash_dash_pos = args.iter().position(|x| x == "--");
    let splice_pos = dash_dash_pos.unwrap_or_else(|| args.len());
    args.splice(
        splice_pos..splice_pos,
        vec![FUZZ_RUNNER.into(), corpus_dir.into()],
    );

    // The artifact dir goes at the end.
    if dash_dash_pos.is_none() {
        args.push("--".into());
    }
    let mut artifact_arg: OsString = "-artifact_prefix=".into();
    artifact_arg.push(&artifact_dir);
    // Add a trailing slash as required by libfuzzer to put the artifact in a directory.
    artifact_arg.push("/");
    args.push(artifact_arg);

    // Pass the target name in as an environment variable.
    // Use the manifest directory as the current one.
    let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").ok_or_else(|| {
        format_err!("Fuzzing requires CARGO_MANIFEST_DIR to be set (are you using `cargo run`?)")
    })?;

    let status = Command::new("cargo")
        .arg("fuzz")
        .arg("run")
        .args(args)
        .current_dir(manifest_dir)
        .env(FuzzTarget::ENV_VAR, target.name())
        .status()
        .context("cargo fuzz run errored")?;
    if !status.success() {
        bail!("cargo fuzz run failed with status {}", status);
    }
    Ok(())
}

/// List all known fuzz targets.
pub fn list_targets(no_desc: bool) {
    for target in FuzzTarget::all_targets() {
        if no_desc {
            println!("{}", target.name())
        } else {
            println!("  * {0: <24}    {1}", target.name(), target.description())
        }
    }
}
<commit_msg>[libra-fuzzer] allow fuzzing to work on the beta compiler<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::FuzzTarget;
use failure::prelude::*;
use libra_proptest_helpers::ValueGenerator;
use sha1::{Digest, Sha1};
use std::{
    env,
    ffi::OsString,
    fs,
    io::Write,
    path::{Path, PathBuf},
    process::Command,
};

/// Generates data for this fuzz target into the output directory. Returns the number of items
/// generated.
///
/// The corpus directory should be present at the time this method is called.
pub fn make_corpus(
    target: FuzzTarget,
    num_items: usize,
    corpus_dir: &Path,
    debug: bool,
) -> Result<usize> {
    // TODO: Allow custom proptest configs?
    let mut gen = ValueGenerator::new();

    let mut sha1 = Sha1::new();

    let mut idx = 0;
    while idx < num_items {
        let result = match target.generate(idx, &mut gen) {
            Some(bytes) => bytes,
            None => {
                // No value could be generated. Assume that corpus generation has been exhausted.
                break;
            }
        };

        // Use the SHA-1 of the result as the file name.
        sha1.input(&result);
        let hash = sha1.result_reset();
        let name = hex::encode(hash.as_slice());
        let path = corpus_dir.join(name);
        let mut f = fs::File::create(&path)
            .with_context(|_| format!("Failed to create file: {:?}", path))?;
        if debug {
            println!("Writing {} bytes to file: {:?}", result.len(), path);
        }

        f.write_all(&result)
            .with_context(|_| format!("Failed to write to file: {:?}", path))?;
        idx += 1;
    }
    Ok(idx)
}

/// Fuzz a target by running `cargo fuzz run`.
pub fn fuzz_target(
    target: FuzzTarget,
    corpus_dir: PathBuf,
    artifact_dir: PathBuf,
    mut args: Vec<OsString>,
) -> Result<()> {
    static FUZZ_RUNNER: &str = "fuzz_runner";

    // Do a bit of arg parsing -- look for a "--" and insert the target and corpus directory
    // before that.
    let dash_dash_pos = args.iter().position(|x| x == "--");
    let splice_pos = dash_dash_pos.unwrap_or_else(|| args.len());
    args.splice(
        splice_pos..splice_pos,
        vec![FUZZ_RUNNER.into(), corpus_dir.into()],
    );

    // The artifact dir goes at the end.
    if dash_dash_pos.is_none() {
        args.push("--".into());
    }
    let mut artifact_arg: OsString = "-artifact_prefix=".into();
    artifact_arg.push(&artifact_dir);
    // Add a trailing slash as required by libfuzzer to put the artifact in a directory.
    artifact_arg.push("/");
    args.push(artifact_arg);

    // Pass the target name in as an environment variable.
    // Use the manifest directory as the current one.
    let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").ok_or_else(|| {
        format_err!("Fuzzing requires CARGO_MANIFEST_DIR to be set (are you using `cargo run`?)")
    })?;

    let status = Command::new("cargo")
        .arg("fuzz")
        .arg("run")
        .args(args)
        .current_dir(manifest_dir)
        .env(FuzzTarget::ENV_VAR, target.name())
        // We want to fuzz with the same version of the compiler as production, but cargo-fuzz only
        // runs on nightly. This is a test-only environment so this use of RUSTC_BOOTSTRAP seems
        // appropriate.
        .env("RUSTC_BOOTSTRAP", "1")
        .status()
        .context("cargo fuzz run errored")?;
    if !status.success() {
        bail!("cargo fuzz run failed with status {}", status);
    }
    Ok(())
}

/// List all known fuzz targets.
pub fn list_targets(no_desc: bool) {
    for target in FuzzTarget::all_targets() {
        if no_desc {
            println!("{}", target.name())
        } else {
            println!("  * {0: <24}    {1}", target.name(), target.description())
        }
    }
}
<|endoftext|>


<commit_before>use uuid::Uuid;
use std::rc::Rc;

use action::Action;
use conditions::Conditions;
use message::Message;
use state::State;
use timer::TimerEvent;

pub struct BaseContext {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Box<Action>>,
}

impl BaseContext {
    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn name(&self) -> Option<&String> {
        self.name.as_ref()
    }

    pub fn actions(&self) -> &[Box<Action>] {
        &self.actions
    }
}

pub struct BaseContextBuilder {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Box<Action>>,
}

impl BaseContextBuilder {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContextBuilder {
        BaseContextBuilder {
            name: None,
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new(),
        }
    }

    pub fn name(mut self, name: Option<String>) -> BaseContextBuilder {
        self.name = name;
        self
    }

    pub fn actions(mut self, actions: Vec<Box<Action>>) -> BaseContextBuilder {
        self.actions = actions;
        self
    }

    pub fn build(self) -> BaseContext {
        let BaseContextBuilder {name, uuid, conditions, actions} = self;
        BaseContext {
            name: name,
            uuid: uuid,
            conditions: conditions,
            actions: actions,
        }
    }
}
<commit_msg>BaseContext: remove some unused imports<commit_after>use uuid::Uuid;

use action::Action;
use conditions::Conditions;

pub struct BaseContext {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Box<Action>>,
}

impl BaseContext {
    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn name(&self) -> Option<&String> {
        self.name.as_ref()
    }

    pub fn actions(&self) -> &[Box<Action>] {
        &self.actions
    }
}

pub struct BaseContextBuilder {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Box<Action>>,
}

impl BaseContextBuilder {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContextBuilder {
        BaseContextBuilder {
            name: None,
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new(),
        }
    }

    pub fn name(mut self, name: Option<String>) -> BaseContextBuilder {
        self.name = name;
        self
    }

    pub fn actions(mut self, actions: Vec<Box<Action>>) -> BaseContextBuilder {
        self.actions = actions;
        self
    }

    pub fn build(self) -> BaseContext {
        let BaseContextBuilder {name, uuid, conditions, actions} = self;
        BaseContext {
            name: name,
            uuid: uuid,
            conditions: conditions,
            actions: actions,
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use common::types::{PlayerId, MapPos, Size2, ZInt};
use core::{CoreEvent};
use internal_state::{InternalState};
use map::{Map};
use fov::{fov};

/// Fog of War
pub struct Fow {
    map: Map<bool>,
    player_id: PlayerId,
}

impl Fow {
    pub fn new(map_size: &Size2<ZInt>, player_id: &PlayerId) -> Fow {
        Fow {
            map: Map::new(map_size, false),
            player_id: player_id.clone(),
        }
    }

    pub fn is_visible(&self, pos: &MapPos) -> bool {
        *self.map.tile(pos)
    }

    fn clear_fow(&mut self) {
        for pos in self.map.get_iter() {
            *self.map.tile_mut(&pos) = false;
        }
    }

    fn reset_fow(&mut self, state: &InternalState) {
        self.clear_fow();
        for (_, unit) in state.units.iter() {
            if unit.player_id == self.player_id {
                *self.map.tile_mut(&unit.pos) = true;
                fov(&state.map, &mut self.map, &unit.pos);
            }
        }
    }

    pub fn apply_event(&mut self, state: &InternalState, event: &CoreEvent) {
        match event {
            &CoreEvent::Move{ref unit_id, ref path} => {
                let unit = state.units.get(unit_id)
                    .expect("BAD MOVE UNIT ID"); // TODO: fix errmsg
                if unit.player_id == self.player_id {
                    for path_node in path.nodes() {
                        fov(&state.map, &mut self.map, &path_node.pos);
                    }
                }
            },
            &CoreEvent::EndTurn{ref new_id, ..} => {
                if self.player_id == *new_id {
                    self.reset_fow(state);
                }
            },
            &CoreEvent::CreateUnit{ref pos, ref player_id, ..} => {
                if self.player_id == *player_id {
                    fov(&state.map, &mut self.map, pos);
                }
            },
            &CoreEvent::AttackUnit{..} => {},
            &CoreEvent::ShowUnit{..} => {},
            &CoreEvent::HideUnit{..} => {},
        }
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>fow.rs: Do not manually mark unit`s tile as visible in `reset_fow`<commit_after>// See LICENSE file for copyright and license details.

use common::types::{PlayerId, MapPos, Size2, ZInt};
use core::{CoreEvent};
use internal_state::{InternalState};
use map::{Map};
use fov::{fov};

/// Fog of War
pub struct Fow {
    map: Map<bool>,
    player_id: PlayerId,
}

impl Fow {
    pub fn new(map_size: &Size2<ZInt>, player_id: &PlayerId) -> Fow {
        Fow {
            map: Map::new(map_size, false),
            player_id: player_id.clone(),
        }
    }

    pub fn is_visible(&self, pos: &MapPos) -> bool {
        *self.map.tile(pos)
    }

    fn clear_fow(&mut self) {
        for pos in self.map.get_iter() {
            *self.map.tile_mut(&pos) = false;
        }
    }

    fn reset_fow(&mut self, state: &InternalState) {
        self.clear_fow();
        for (_, unit) in state.units.iter() {
            if unit.player_id == self.player_id {
                fov(&state.map, &mut self.map, &unit.pos);
            }
        }
    }

    pub fn apply_event(&mut self, state: &InternalState, event: &CoreEvent) {
        match event {
            &CoreEvent::Move{ref unit_id, ref path} => {
                let unit = state.units.get(unit_id)
                    .expect("BAD MOVE UNIT ID"); // TODO: fix errmsg
                if unit.player_id == self.player_id {
                    for path_node in path.nodes() {
                        fov(&state.map, &mut self.map, &path_node.pos);
                    }
                }
            },
            &CoreEvent::EndTurn{ref new_id, ..} => {
                if self.player_id == *new_id {
                    self.reset_fow(state);
                }
            },
            &CoreEvent::CreateUnit{ref pos, ref player_id, ..} => {
                if self.player_id == *player_id {
                    fov(&state.map, &mut self.map, pos);
                }
            },
            &CoreEvent::AttackUnit{..} => {},
            &CoreEvent::ShowUnit{..} => {},
            &CoreEvent::HideUnit{..} => {},
        }
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>