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

#[derive(Debug)]
struct Power {
    base: i32,
    exp: i32,
}

fn main() {
    let boundary = 100; // boundary >= 2

    let max_base = (boundary as f64).sqrt() as i32;

    let mut max_power = 0;
    let mut tmp_boundary = boundary;
    while tmp_boundary >= 2 {
        tmp_boundary /= 2;
        max_power += 1;
    }

    let mut records: HashMap<i32, Power> = HashMap::new();
    for n in 2..max_power + 1 {
        for c in 2..max_base + 1 {
            let key = c.pow(n as u32);
            if key <= boundary {
                let tmp_power = Power { base: c, exp: n };
                records.insert(key, tmp_power);
            }
        }
    }

    println!("max_base: {}, max_power: {}", max_base, max_power);
    println!("===============================");
    for key in records.keys() {
        println!("key is: {}", key);
        println!("{:?}", records.get(&key));
        println!("-----------------------------------");
    }
}
<commit_msg>update rust solution: find all the possibilities<commit_after>use std::collections::HashMap;

fn get_duplicated(boundary: i32, base: i32, exp: i32) -> i32 {
    match base.pow(exp as u32) {
        4 => 49,
        9 => 49,
        25 => 49,
        36 => 49,
        49 => 49,
        100 => 49,
        32 => 48,
        8 => 49,
        27 => 49,
        16 => 58,
        81 => 58,
        64 => 62,
        _ => 0,
    }
}

fn main() {
    let boundary = 100; // boundary >= 2

    let max_base = (boundary as f64).sqrt() as i32;

    let mut max_power = 0;
    let mut tmp_boundary = boundary;
    while tmp_boundary >= 2 {
        tmp_boundary /= 2;
        max_power += 1;
    }

    let mut records: HashMap<i32, HashMap<&str, i32>> = HashMap::new();
    for n in 2..max_power + 1 {
        for c in 2..max_base + 1 {
            let key = c.pow(n as u32);
            if key <= boundary {
                let mut tmp_power = HashMap::new();
                tmp_power.insert("base", c);
                tmp_power.insert("exp", n);
                records.insert(key, tmp_power);
            }
        }
    }

    let mut result = 99 * 99;
    for (key, record) in &records{
        result -= get_duplicated(boundary, record[&"base"], record[&"exp"]);
    }

    println!("{}", result);
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // Redraw window
        self.window.set([0, 0, 0, 255]);

        for (y, row) in self.text.iter().enumerate() {
            for (x, c) in row.iter().enumerate() {
                if self.cursor().x == x && self.cursor().y == y {
                    self.window.rect(8 * (y - self.scroll_y) as isize,
                                     16 * (x - self.scroll_x) as isize,
                                     8,
                                     16,
                                     [255, 255, 255, 255]);
                    self.window.char(8 * (y - self.scroll_y) as isize,
                                     16 * (x - self.scroll_x) as isize,
                                     *c,
                                     [0, 0, 0, 255]);
                } else {
                    self.window.char(8 * (y - self.scroll_y) as isize,
                                     16 * (x - self.scroll_x) as isize,
                                     *c,
                                     [255, 255, 255, 255]);
                }
            }
        }
        self.window.sync();
    }
}
<commit_msg>Swap x and y<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // Redraw window
        self.window.set([0, 0, 0, 255]);

        for (y, row) in self.text.iter().enumerate() {
            for (x, c) in row.iter().enumerate() {
                if self.cursor().x == x && self.cursor().y == y {
                    self.window.rect(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     8,
                                     16,
                                     [255, 255, 255, 255]);
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [0, 0, 0, 255]);
                } else {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [255, 255, 255, 255]);
                }
            }
        }
        self.window.sync();
    }
}
<|endoftext|>


<commit_before>generate_error_module!(
    generate_error_types!(MailError, MailErrorKind,
        IOError => "IO Error"
    );
);

pub use self::error::MailError;
pub use self::error::MailErrorKind;
pub use self::error::MapErrInto;

<commit_msg>Add error kind if ref could not be created<commit_after>generate_error_module!(
    generate_error_types!(MailError, MailErrorKind,
        RefCreationError => "Error creating a reference to a file/directory",
        IOError => "IO Error"
    );
);

pub use self::error::MailError;
pub use self::error::MailErrorKind;
pub use self::error::MapErrInto;

<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::result::Result as RResult;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use logger::ImagLogger;

use libimagstore::store::Store;

pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Configuration,
    cli_matches: ArgMatches<'a, 'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /**
     * Gets the CLI spec for the program and retreives the config file path (or uses the default on
     * in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
     * and builds the Runtime object with it.
     *
     * The cli_spec object should be initially build with the ::get_default_cli_builder() function.
     *
     */
    pub fn new(cli_spec: App<'a, 'a, 'a, 'a, 'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        let matches = cli_spec.get_matches();
        let rtp : PathBuf = matches.value_of("runtimepath").unwrap_or("~/.imag/").into();
        let storepath = matches.value_of("storepath")
                                .map(PathBuf::from)
                                .unwrap_or({
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                });
        Store::new(storepath).map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: Configuration::new(&rtp).unwrap_or(Configuration::default()),
                rtp: rtp,
                store: store,
            }
        })
        .map_err(|e| {
            RuntimeError::new(RuntimeErrorKind::Instantiate, Some(Box::new(e)))
        })
    }

    /**
     * Get a commandline-interface builder object from `clap`
     *
     * This commandline interface builder object already contains some predefined interface flags:
     *   * -v | --verbose for verbosity
     *   * --debug for debugging
     *   * -c <file> | --config <file> for alternative configuration file
     *   * -r <path> | --rtp <path> for alternative runtimepath
     *   * --store <path> for alternative store path
     * Each has the appropriate help text included.
     *
     * The `appname` shall be "imag-<command>".
     */
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a, 'a, 'a, 'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name("verbosity")
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("debugging")
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("config")
                .short("c")
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("runtimepath")
                .short("r")
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("storepath")
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))
    }

    /**
     * Initialize the internal logger
     */
    pub fn init_logger(&self) {
        let lvl = if self.is_debugging() {
            LogLevelFilter::Debug
        } else if self.is_verbose() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
        .map_err(|_| {
            panic!("Could not setup logger");
        })
        .ok();
    }

    /**
     * Get the verbosity flag value
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /**
     * Get the debugging flag value
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /**
     * Get the runtimepath
     */
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /**
     * Get the commandline interface matches
     */
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

}

<commit_msg>rt/runtime: Remove unused imports<commit_after>use std::path::PathBuf;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use logger::ImagLogger;

use libimagstore::store::Store;

pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Configuration,
    cli_matches: ArgMatches<'a, 'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /**
     * Gets the CLI spec for the program and retreives the config file path (or uses the default on
     * in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
     * and builds the Runtime object with it.
     *
     * The cli_spec object should be initially build with the ::get_default_cli_builder() function.
     *
     */
    pub fn new(cli_spec: App<'a, 'a, 'a, 'a, 'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        let matches = cli_spec.get_matches();
        let rtp : PathBuf = matches.value_of("runtimepath").unwrap_or("~/.imag/").into();
        let storepath = matches.value_of("storepath")
                                .map(PathBuf::from)
                                .unwrap_or({
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                });
        Store::new(storepath).map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: Configuration::new(&rtp).unwrap_or(Configuration::default()),
                rtp: rtp,
                store: store,
            }
        })
        .map_err(|e| {
            RuntimeError::new(RuntimeErrorKind::Instantiate, Some(Box::new(e)))
        })
    }

    /**
     * Get a commandline-interface builder object from `clap`
     *
     * This commandline interface builder object already contains some predefined interface flags:
     *   * -v | --verbose for verbosity
     *   * --debug for debugging
     *   * -c <file> | --config <file> for alternative configuration file
     *   * -r <path> | --rtp <path> for alternative runtimepath
     *   * --store <path> for alternative store path
     * Each has the appropriate help text included.
     *
     * The `appname` shall be "imag-<command>".
     */
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a, 'a, 'a, 'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name("verbosity")
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("debugging")
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("config")
                .short("c")
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("runtimepath")
                .short("r")
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("storepath")
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))
    }

    /**
     * Initialize the internal logger
     */
    pub fn init_logger(&self) {
        let lvl = if self.is_debugging() {
            LogLevelFilter::Debug
        } else if self.is_verbose() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
        .map_err(|_| {
            panic!("Could not setup logger");
        })
        .ok();
    }

    /**
     * Get the verbosity flag value
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /**
     * Get the debugging flag value
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /**
     * Get the runtimepath
     */
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /**
     * Get the commandline interface matches
     */
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

}

<|endoftext|>


<commit_before>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::BTreeSet;
use std::mem;
use std::cell::RefCell;
use std::marker::PhantomData;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl StewardData for GetVarying {}

pub trait IterateUniquelyOwnedPredictions <Steward: TimeSteward> {
  fn iterate_predictions <F: FnMut (& Steward::EventHandle)> (&self, callback: &mut F) {}
}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: StewardData, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: Vec<(<Steward as TimeSteward>::EventHandle, Option <VaryingData>)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: BTreeSet<<Steward as TimeSteward>::EventHandle>,
}

impl <VaryingData: StewardData, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: Vec::new(),
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.
    match self.changes.last() {
      None => return Err(0),
      Some (&(ref event, ref data)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }
    self.changes[..self.changes.len()-1].binary_search_by_key (&time, | change | change.0.extended_time())
  }
}
impl <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  fn remove_present_and_future <Accessor: FutureCleanupAccessor<Steward = Steward>> (&mut self, accessor: &Accessor) {
    let removed = split_off_greater_set (&mut self.other_dependent_events, accessor.extended_now());
    for event in removed {
      accessor.invalidate_execution(&event);
    }
    while let Some (change) = self.changes.pop() {
      if change.0.extended_time() < accessor.extended_now() {
        if let Some(data) = change.1.as_ref() {
          IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.change_prediction_destroyer (prediction, None));
        }
        self.changes.push (change);
        break
      }
      if let Some(data) = change.1.as_ref() {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.change_prediction_destroyer (prediction, Some(& change.0)));
      }
      if change.0.extended_time() > accessor.extended_now() {
        accessor.invalidate_execution(&change.0);
      }
    }
  }

  fn modify <Accessor: EventAccessor<Steward = Steward>> (&mut self, modification: Option <VaryingData>, accessor: &Accessor){
    if let Some(last) = self.changes.last() {
      assert!(& last.0 <= accessor.handle(), "All future changes should have been cleared before calling modify() ");
      if let Some (data) = last.1.as_ref() {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.destroy_prediction (prediction));
      }
    }
    // we don't need to create incoming predictions, because they can't be incoming unless they were already created
    self.changes.push ((accessor.handle().clone(), modification));
  }
}

impl <VaryingData: StewardData, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let slice = match self.search_changes(&time) {
      Ok(index) => &self.changes [index.saturating_sub (1).. index+1],
      Err (index) => &self.changes [index.saturating_sub (1)..index],
    };
    SimpleTimeline {
      changes: slice.to_vec(),
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let retained = self.other_dependent_events.split_off (time);
    mem::replace (&mut self.other_dependent_events, retained);

    if self.changes.len() > 0 && self.changes [self.changes.len()/2].0.extended_time() < time {
      let keep_from_index = match self.search_changes(&time) {
        Ok (index) => index,
        Err(index) => index - 1,
      };
      self.changes = self.changes.split_off (keep_from_index);
    }
  }
}
impl <VaryingData: StewardData, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = Option <(ExtendedTime <Self::Basics>, VaryingData)>;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>, offset: QueryOffset)->Self::QueryResult {
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => match offset {QueryOffset::After => index, QueryOffset::Before => index.wrapping_sub (1)},
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).and_then (| change | change.1.as_ref().map (| data | (change.0.extended_time().clone(), data.clone())))
  }
}

pub fn tracking_query <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, offset: QueryOffset)->Option <(ExtendedTime <Steward::Basics>, VaryingData)> {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  accessor.query (handle, &GetVarying, offset)
}
pub fn modify_simple_timeline <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: Option <VaryingData>) {
  #[cfg (debug_assertions)]
  let confirm1 = accessor.query (handle, &GetVarying, QueryOffset::Before);
  #[cfg (debug_assertions)]
  let confirm2 = modification.clone().map(|data|(accessor.extended_now().clone(), data));

  let mut do_modify = true;
  if let Some(accessor) = accessor.future_cleanup() {
    match accessor.query (handle, &GetVarying, QueryOffset::After) {
      Some((time, data)) =>
        if let Some (new_data) = modification.as_ref() {
          if &time == accessor.extended_now() && &data == new_data {
            do_modify = false;
          }
        },
      None =>
        if modification.is_none() {do_modify = false;}
    };
    if do_modify {
      accessor.peek_mut(handle).remove_present_and_future (accessor);
    }
  }
  if do_modify {
    accessor.modify (handle, move |timeline| {
      timeline.modify(modification, accessor);
    });
  }

  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm1);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm2);
}
pub fn unmodify_simple_timeline <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: FutureCleanupAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  #[cfg (debug_assertions)]
  let confirm = accessor.query (handle, &GetVarying, QueryOffset::Before);

  if let Some((time, _)) = accessor.query (handle, &GetVarying, QueryOffset::After) { if &time == accessor.extended_now() {
    accessor.peek_mut(handle).remove_present_and_future (accessor);
  }}

  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm);
}

} //mod

  };
}

<commit_msg>Use VecDeque for SimpleTimeline so forget_before() can properly drop all possible old event handles<commit_after>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::{BTreeSet, VecDeque};
use std::mem;
use std::cell::RefCell;
use std::marker::PhantomData;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl StewardData for GetVarying {}

pub trait IterateUniquelyOwnedPredictions <Steward: TimeSteward> {
  fn iterate_predictions <F: FnMut (& Steward::EventHandle)> (&self, callback: &mut F) {}
}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: StewardData, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: VecDeque<(<Steward as TimeSteward>::EventHandle, Option <VaryingData>)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: BTreeSet<<Steward as TimeSteward>::EventHandle>,
}

impl <VaryingData: StewardData, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: VecDeque::new(),
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.

    match self.changes.back() {
      None => return Err(0),
      Some (&(ref event, ref data)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }

    let mut drop = 2;
    let mut max = self.changes.len()-1;
    let mut min;
    loop {
      if let Some(further) = self.changes.len().checked_sub (drop) {
        let change = self.changes.get (further).unwrap();
        match change.0.extended_time().cmp(time) {
          Ordering::Greater => {
            max = further;
            drop *= 2;
          },
          Ordering::Equal => return Ok(further),
          Ordering::Less => {
            min = further;
            break;
          },
        }
      }
      else {
        min = 0;
        break;
      }
    }
    while max >= min+2 {
      let mid = (max + min) >> 1;
      let change = self.changes.get (mid).unwrap();
      match change.0.extended_time().cmp(time) {
        Ordering::Greater => max = mid,
        Ordering::Equal => return Ok(mid),
        Ordering::Less => min = mid,
      }
    }

    if self.changes.get (min).unwrap().0.extended_time() > time {
      return Err (min)
    }
    Err(max)
  }
}
impl <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  fn remove_present_and_future <Accessor: FutureCleanupAccessor<Steward = Steward>> (&mut self, accessor: &Accessor) {
    let removed = split_off_greater_set (&mut self.other_dependent_events, accessor.extended_now());
    for event in removed {
      accessor.invalidate_execution(&event);
    }
    while let Some (change) = self.changes.pop_back() {
      if change.0.extended_time() < accessor.extended_now() {
        if let Some(data) = change.1.as_ref() {
          IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.change_prediction_destroyer (prediction, None));
        }
        self.changes.push_back (change);
        break
      }
      if let Some(data) = change.1.as_ref() {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.change_prediction_destroyer (prediction, Some(& change.0)));
      }
      if change.0.extended_time() > accessor.extended_now() {
        accessor.invalidate_execution(&change.0);
      }
    }
  }

  fn modify <Accessor: EventAccessor<Steward = Steward>> (&mut self, modification: Option <VaryingData>, accessor: &Accessor){
    if let Some(last) = self.changes.back() {
      assert!(& last.0 <= accessor.handle(), "All future changes should have been cleared before calling modify() ");
      if let Some (data) = last.1.as_ref() {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (data, &mut | prediction | accessor.destroy_prediction (prediction));
      }
    }
    // we don't need to create incoming predictions, because they can't be incoming unless they were already created
    self.changes.push_back ((accessor.handle().clone(), modification));
  }
}

impl <VaryingData: StewardData, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let mut changes = VecDeque::new();
    match self.search_changes(&time) {
      Ok(index) => {
        if let Some(previous) = index.checked_sub (1) {changes.push_back (self.changes [previous].clone());}
        changes.push_back (self.changes [index].clone());
      },
      Err (index) => if let Some(previous) = index.checked_sub (1) {changes.push_back (self.changes [previous].clone());},
    };
    SimpleTimeline {
      changes: changes,
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let retained = self.other_dependent_events.split_off (time);
    mem::replace (&mut self.other_dependent_events, retained);

    while self.changes.front().map_or (false, | change | change.0.extended_time() < time) {
      self.changes.pop_front ();
    }
  }
}
impl <VaryingData: StewardData, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = Option <(ExtendedTime <Self::Basics>, VaryingData)>;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>, offset: QueryOffset)->Self::QueryResult {
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => match offset {QueryOffset::After => index, QueryOffset::Before => index.wrapping_sub (1)},
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).and_then (| change | change.1.as_ref().map (| data | (change.0.extended_time().clone(), data.clone())))
  }
}

pub fn tracking_query <VaryingData: StewardData, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, offset: QueryOffset)->Option <(ExtendedTime <Steward::Basics>, VaryingData)> {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  accessor.query (handle, &GetVarying, offset)
}
pub fn modify_simple_timeline <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: Option <VaryingData>) {
  #[cfg (debug_assertions)]
  let confirm1 = accessor.query (handle, &GetVarying, QueryOffset::Before);
  #[cfg (debug_assertions)]
  let confirm2 = modification.clone().map(|data|(accessor.extended_now().clone(), data));

  let mut do_modify = true;
  if let Some(accessor) = accessor.future_cleanup() {
    match accessor.query (handle, &GetVarying, QueryOffset::After) {
      Some((time, data)) =>
        if let Some (new_data) = modification.as_ref() {
          if &time == accessor.extended_now() && &data == new_data {
            do_modify = false;
          }
        },
      None =>
        if modification.is_none() {do_modify = false;}
    };
    if do_modify {
      accessor.peek_mut(handle).remove_present_and_future (accessor);
    }
  }
  if do_modify {
    accessor.modify (handle, move |timeline| {
      timeline.modify(modification, accessor);
    });
  }

  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm1);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm2);
}
pub fn unmodify_simple_timeline <VaryingData: StewardData + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: FutureCleanupAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  #[cfg (debug_assertions)]
  let confirm = accessor.query (handle, &GetVarying, QueryOffset::Before);

  if let Some((time, _)) = accessor.query (handle, &GetVarying, QueryOffset::After) { if &time == accessor.extended_now() {
    accessor.peek_mut(handle).remove_present_and_future (accessor);
  }}

  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::After) == confirm);
}

} //mod

  };
}

<|endoftext|>


<commit_before>//! This module contains the compiler. The compiler parses source code and generates byte code
//! suitable for execution by the VM.
//!
//! The complation process can be divided into the following phases:
//!
//! 1. Parsing
//! 2. Checking
//! 3. Resolving
//! 4. Linting / Optimizing
//! 5. Emitting
//!
//! This module provides several helper methods that will either wrap up the whole compilation
//! process or stop after a step, to enable more advanced uses of the compiler.
//!
//! Below is a brief description of what each phase does.
//!
//! ## Parsing
//!
//! This phase runs the generated Lea parser. It is generated at compile-time from the Parsing
//! Expression Grammar (PEG) in `lea.rustpeg` with help of the `rust-peg` crate.
//!
//! After the generated parser was run, an additional expression parser is run. The generated
//! parser will collect binary expressions in a list, ignoring operator precedences. It returns a
//! `ERawOp` node for all expressions. The expression parser in `expr_parser.rs` runs over all
//! `ERawOp`s, applies the shunting-yard algorithm, builds a tree of `EBinOp`s, and replaces the
//! AST node with the result.
//!
//! This could be done in the PEG parser, but since `rust-peg` doesn't support memoization, it
//! leads to a significant slowdown. Additionally, this would require redefining all operator
//! precedences as PEG rules (which duplicates code that shouldn't ever be duplicate), and
//! supporting both left- and right-associative operators is easier in a shunting-yard parser.
//!
//! ## Checking
//!
//! In `check.rs`, a `Checker` visitor is implemented, which runs over an AST and verifies that all
//! statements and expressions are used in a valid context. Since the PEG parser has no state, it
//! cannot do this (and it is better - though slower - to do it this way, since it separates
//! syntax error and context-dependant errors).
//!
//! For example, the checker will deny a `break` statement used outside of a loop and the varargs
//! expression `...` outside of a varargs function.
//!
//! ## Resolving
//!
//! The resolver implemented in `resolve.rs` transforms any named variable (`VNamed` in the AST) to
//! a local, upvalue, or global reference. This makes it easy to see which identifier refers to
//! which variable (might be useful for code highlighting in IDEs) and makes the emitter a bit
//! simpler, since it doesn't have to figure out what an identifier means if it encounters it: It
//! already knows, since the resolver stored it in the AST.
//!
//! ## Linting / Optimizing
//!
//! In this step, all configured Linters and Optimizers are run on the resolved AST. Internally, we
//! make to distinction between a Linter and an Optimizer: Both take a `Function` node, do
//! something to it, and return a transformed `Function` along with a list of warnings to be
//! issued.
//!
//! Most Linters will just return the unmodified function and generate some warnings, while most
//! optimizers will modify the AST, but return no warnings. Of course, there might be exceptions.
//!
//! Linters and Optimizers are implemented in the files inside the "transform" directory:
//!
//! * `fold.rs` implements a constant folding optimization that looks for operators that are
//!   applied to literals, applies them at compile-time, and replaces the node with the result.
//!   This is a basic optimization performed by most compilers (Lua does this too).
//!
//! * `globalwrite.rs` implements a Linter that will issue a warning for all assignments to
//!   globals. Global variables are generally meant to hold the standard library functions, and not
//!   much more. User code should always prefer locals, and modules are meant to return the module
//!   when loaded, which should be assigned to a local by the code that `require`d the module. If
//!   you still need to access a global (for example, when setting up a sandbox), you can do so
//!   explicitly by indexing `_ENV`.
//!
//! * `deprecated_ops.rs` is a Linter that emits a warning whenever a Lua operator is used that has
//!   an equivalent replacement in Lea.
//!
//! ## Emitting
//!
//! The byte code emitter for the compiler still needs to be written. It will take an AST and
//! convert it to machine code for the virtual machine.

#![allow(trivial_casts)]

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate rustc_serialize;
extern crate term;
extern crate unicode_segmentation;

extern crate lea_core;
extern crate lea_ast as ast;
extern crate lea_parser as parser;

use transform::{Transform, LintMode};
use emitter::emit_func;

use ast::Function;

use std::default::Default;

mod errors;
pub mod transform;
pub mod check;
pub mod emitter;
pub mod prettyprint;
pub mod resolve;

pub use errors::*;
pub use lea_core::fndata::FnData;

/// Defines options that can be used to tweak the compilation process (optimizations, linters, ...)
pub struct CompileConfig<'a> {
    /// AST transforms to apply. All transforms are applied in the order specified here.
    trans: Vec<(&'a Transform, LintMode)>,
}

impl <'a> CompileConfig<'a> {
    /// Creates an empty `CompileConfig` that applies no optimizations or lints
    pub fn empty() -> CompileConfig<'a> {
        CompileConfig {
            trans: vec![],
        }
    }

    /// Creates a `CompileConfig` that will apply named lints. Returns `None` if a Lint doesn't
    /// exist (TODO).
    pub fn named_lints(names: &[&str]) -> Option<CompileConfig<'a>> {
        let mut conf = CompileConfig::empty();
        for name in names {
            match transform::TRANSFORMS.get(name) {
                None => { return None; },
                Some(tr) => {
                    conf.trans.push((tr, LintMode::Warn));
                }
            }
        }

        Some(conf)
    }

    pub fn add_transform(&mut self, tr: &'a Transform, mode: LintMode) {
        self.trans.push((tr, mode));
    }
}

impl <'a> Default for CompileConfig<'a> {
    /// Creates a default `CompileConfig` that applies the default set of optimizers and linters
    fn default() -> CompileConfig<'a> {
        CompileConfig {
            trans: transform::TRANSFORMS_DEFAULT.iter().map(|&(name, lvl)| (transform::TRANSFORMS.get(name).unwrap(), lvl)).collect(),
        }
    }
}

/// Output of a successful compilation.
pub struct CompileOutput<'a> {
    /// Warnings generated by Linters
    pub warns: Vec<Warning>,
    /// AST node of main function
    pub main: Function<'a>,
    /// Prototype of main function, to be instantiated and run by the VM
    pub mainproto: FnData,
}

/// Parses and checks the given source code (stops after compilation step 2). Returns a valid
/// `Function` node on success.
///
/// If this succeeds, this means that the program described by the source code is valid and can be
/// compiled.
pub fn parse_and_check<'a>(code: &'a str) -> CompileResult<Function<'a>> {
    match parser::parse_main(code) {
        Err(e) => Err(ErrParse(e)),
        Ok(main) => {
            let res = check::check_func(&main);
            match res {
                Err(errs) => Err(ErrCheck(errs)),
                Ok(()) => {
                    Ok(main)
                }
            }
        }
    }
}

/// Parses, checks and resolves the given source code (stops after compilation step 3). Returns the
/// resolved main function on success.
pub fn parse_and_resolve<'a>(code: &'a str) -> CompileResult<Function<'a>> {
    let mut main = try!(parse_and_check(code));
    main = resolve::resolve_func(main);

    Ok(main)
}

/// Applies all transforms in the given `CompileConfig` to a `main` function. Returns all warnings
/// generated by the transforms. `main` must be resolved beforehand.
///
/// If any transform is configured to cause a compilation error, a corresponding error will be
/// returned.
pub fn apply_transforms<'a>(mut main: Function<'a>, conf: &CompileConfig) -> (Function<'a>, CompileResult<Vec<Warning>>) {
    let mut warnings: Vec<Warning> = Vec::new();
    let mut errwarns: Vec<Warning> = Vec::new();  // warnings handled as errors
    for &(tr, mode) in &conf.trans {
        let (newmain, new_warns) = tr(main);
        main = newmain;

        if mode == LintMode::Error && new_warns.len() > 0 {
            errwarns.extend(new_warns);
        } else {
            warnings.extend(new_warns);
        }
    }

    (main, if errwarns.is_empty() {
        Ok(warnings)
    } else {
        Err(ErrLint(errwarns))
    })
}

/// Compiles source code into an `FnData` instance. This executes the whole compilation process and
/// emits byte code (TODO).
///
/// Note that this will not return the `Function` node on error, even if parsing succeeded.
///
/// # Parameters
///
/// * `code` - The source code to compile
/// * `source_name` - The name of this source code. Used when reporting errors. This should be
///   a file name or something similar.
/// * `conf` - The `CompileConfig` to use for this compilation
pub fn compile_str<'a>(code: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parse_and_resolve(code));
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}
<commit_msg>Remove #![allow(trivial_casts)]<commit_after>//! This module contains the compiler. The compiler parses source code and generates byte code
//! suitable for execution by the VM.
//!
//! The complation process can be divided into the following phases:
//!
//! 1. Parsing
//! 2. Checking
//! 3. Resolving
//! 4. Linting / Optimizing
//! 5. Emitting
//!
//! This module provides several helper methods that will either wrap up the whole compilation
//! process or stop after a step, to enable more advanced uses of the compiler.
//!
//! Below is a brief description of what each phase does.
//!
//! ## Parsing
//!
//! This phase runs the generated Lea parser. It is generated at compile-time from the Parsing
//! Expression Grammar (PEG) in `lea.rustpeg` with help of the `rust-peg` crate.
//!
//! After the generated parser was run, an additional expression parser is run. The generated
//! parser will collect binary expressions in a list, ignoring operator precedences. It returns a
//! `ERawOp` node for all expressions. The expression parser in `expr_parser.rs` runs over all
//! `ERawOp`s, applies the shunting-yard algorithm, builds a tree of `EBinOp`s, and replaces the
//! AST node with the result.
//!
//! This could be done in the PEG parser, but since `rust-peg` doesn't support memoization, it
//! leads to a significant slowdown. Additionally, this would require redefining all operator
//! precedences as PEG rules (which duplicates code that shouldn't ever be duplicate), and
//! supporting both left- and right-associative operators is easier in a shunting-yard parser.
//!
//! ## Checking
//!
//! In `check.rs`, a `Checker` visitor is implemented, which runs over an AST and verifies that all
//! statements and expressions are used in a valid context. Since the PEG parser has no state, it
//! cannot do this (and it is better - though slower - to do it this way, since it separates
//! syntax error and context-dependant errors).
//!
//! For example, the checker will deny a `break` statement used outside of a loop and the varargs
//! expression `...` outside of a varargs function.
//!
//! ## Resolving
//!
//! The resolver implemented in `resolve.rs` transforms any named variable (`VNamed` in the AST) to
//! a local, upvalue, or global reference. This makes it easy to see which identifier refers to
//! which variable (might be useful for code highlighting in IDEs) and makes the emitter a bit
//! simpler, since it doesn't have to figure out what an identifier means if it encounters it: It
//! already knows, since the resolver stored it in the AST.
//!
//! ## Linting / Optimizing
//!
//! In this step, all configured Linters and Optimizers are run on the resolved AST. Internally, we
//! make to distinction between a Linter and an Optimizer: Both take a `Function` node, do
//! something to it, and return a transformed `Function` along with a list of warnings to be
//! issued.
//!
//! Most Linters will just return the unmodified function and generate some warnings, while most
//! optimizers will modify the AST, but return no warnings. Of course, there might be exceptions.
//!
//! Linters and Optimizers are implemented in the files inside the "transform" directory:
//!
//! * `fold.rs` implements a constant folding optimization that looks for operators that are
//!   applied to literals, applies them at compile-time, and replaces the node with the result.
//!   This is a basic optimization performed by most compilers (Lua does this too).
//!
//! * `globalwrite.rs` implements a Linter that will issue a warning for all assignments to
//!   globals. Global variables are generally meant to hold the standard library functions, and not
//!   much more. User code should always prefer locals, and modules are meant to return the module
//!   when loaded, which should be assigned to a local by the code that `require`d the module. If
//!   you still need to access a global (for example, when setting up a sandbox), you can do so
//!   explicitly by indexing `_ENV`.
//!
//! * `deprecated_ops.rs` is a Linter that emits a warning whenever a Lua operator is used that has
//!   an equivalent replacement in Lea.
//!
//! ## Emitting
//!
//! The byte code emitter for the compiler still needs to be written. It will take an AST and
//! convert it to machine code for the virtual machine.

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate rustc_serialize;
extern crate term;
extern crate unicode_segmentation;

extern crate lea_core;
extern crate lea_ast as ast;
extern crate lea_parser as parser;

use transform::{Transform, LintMode};
use emitter::emit_func;

use ast::Function;

use std::default::Default;

mod errors;
pub mod transform;
pub mod check;
pub mod emitter;
pub mod prettyprint;
pub mod resolve;

pub use errors::*;
pub use lea_core::fndata::FnData;

/// Defines options that can be used to tweak the compilation process (optimizations, linters, ...)
pub struct CompileConfig<'a> {
    /// AST transforms to apply. All transforms are applied in the order specified here.
    trans: Vec<(&'a Transform, LintMode)>,
}

impl <'a> CompileConfig<'a> {
    /// Creates an empty `CompileConfig` that applies no optimizations or lints
    pub fn empty() -> CompileConfig<'a> {
        CompileConfig {
            trans: vec![],
        }
    }

    /// Creates a `CompileConfig` that will apply named lints. Returns `None` if a Lint doesn't
    /// exist (TODO).
    pub fn named_lints(names: &[&str]) -> Option<CompileConfig<'a>> {
        let mut conf = CompileConfig::empty();
        for name in names {
            match transform::TRANSFORMS.get(name) {
                None => { return None; },
                Some(tr) => {
                    conf.trans.push((tr, LintMode::Warn));
                }
            }
        }

        Some(conf)
    }

    pub fn add_transform(&mut self, tr: &'a Transform, mode: LintMode) {
        self.trans.push((tr, mode));
    }
}

impl <'a> Default for CompileConfig<'a> {
    /// Creates a default `CompileConfig` that applies the default set of optimizers and linters
    fn default() -> CompileConfig<'a> {
        CompileConfig {
            trans: transform::TRANSFORMS_DEFAULT.iter().map(|&(name, lvl)| (transform::TRANSFORMS.get(name).unwrap(), lvl)).collect(),
        }
    }
}

/// Output of a successful compilation.
pub struct CompileOutput<'a> {
    /// Warnings generated by Linters
    pub warns: Vec<Warning>,
    /// AST node of main function
    pub main: Function<'a>,
    /// Prototype of main function, to be instantiated and run by the VM
    pub mainproto: FnData,
}

/// Parses and checks the given source code (stops after compilation step 2). Returns a valid
/// `Function` node on success.
///
/// If this succeeds, this means that the program described by the source code is valid and can be
/// compiled.
pub fn parse_and_check<'a>(code: &'a str) -> CompileResult<Function<'a>> {
    match parser::parse_main(code) {
        Err(e) => Err(ErrParse(e)),
        Ok(main) => {
            let res = check::check_func(&main);
            match res {
                Err(errs) => Err(ErrCheck(errs)),
                Ok(()) => {
                    Ok(main)
                }
            }
        }
    }
}

/// Parses, checks and resolves the given source code (stops after compilation step 3). Returns the
/// resolved main function on success.
pub fn parse_and_resolve<'a>(code: &'a str) -> CompileResult<Function<'a>> {
    let mut main = try!(parse_and_check(code));
    main = resolve::resolve_func(main);

    Ok(main)
}

/// Applies all transforms in the given `CompileConfig` to a `main` function. Returns all warnings
/// generated by the transforms. `main` must be resolved beforehand.
///
/// If any transform is configured to cause a compilation error, a corresponding error will be
/// returned.
pub fn apply_transforms<'a>(mut main: Function<'a>, conf: &CompileConfig) -> (Function<'a>, CompileResult<Vec<Warning>>) {
    let mut warnings: Vec<Warning> = Vec::new();
    let mut errwarns: Vec<Warning> = Vec::new();  // warnings handled as errors
    for &(tr, mode) in &conf.trans {
        let (newmain, new_warns) = tr(main);
        main = newmain;

        if mode == LintMode::Error && new_warns.len() > 0 {
            errwarns.extend(new_warns);
        } else {
            warnings.extend(new_warns);
        }
    }

    (main, if errwarns.is_empty() {
        Ok(warnings)
    } else {
        Err(ErrLint(errwarns))
    })
}

/// Compiles source code into an `FnData` instance. This executes the whole compilation process and
/// emits byte code (TODO).
///
/// Note that this will not return the `Function` node on error, even if parsing succeeded.
///
/// # Parameters
///
/// * `code` - The source code to compile
/// * `source_name` - The name of this source code. Used when reporting errors. This should be
///   a file name or something similar.
/// * `conf` - The `CompileConfig` to use for this compilation
pub fn compile_str<'a>(code: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parse_and_resolve(code));
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}
<|endoftext|>


<commit_before>
extern crate ndarray;
extern crate ndarray_odeint;
extern crate ndarray_numtest;
extern crate ndarray_linalg;

use ndarray::*;
use ndarray_linalg::prelude::*;
use ndarray_numtest::prelude::*;

use ndarray_odeint::prelude::*;
use ndarray_odeint::lyapunov::*;

#[test]
fn jacobian_linearity() {
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, 0.01);
    let x0 = rcarr1(&[1.0, 0.0, 0.0]);
    let j = jacobian(&teo, x0, 1e-7);
    let v = Array1::real_normal_init(3, 1.0, 1.0);
    let w = Array1::real_normal_init(3, 1.0, 1.0);
    all_close_l2(&(j.dot(&v) + j.dot(&w)), &j.dot(&(v + w)), 1e-5).unwrap();
}

#[test]
fn jacobian_matrix_shape() {
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, 0.01);
    let x0 = rcarr1(&[1.0, 0.0, 0.0]);
    let j = jacobian(&teo, x0, 1e-7);
    let v = Array2::real_normal_init((3, 2), 1.0, 1.0);
    let jv = j.dot(&v);
    assert!(jv.shape() == v.shape());
}

#[test]
fn exponents_l63() {
    let dt = 0.01;
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, dt);
    let l = exponents(&teo, rcarr1(&[1.0, 0.0, 0.0]), 1e-7, 100000);
    all_close_max(&l, &arr1(&[0.906, 0.0, -14.572]), 1e-2).unwrap();
    // value from http://sprott.physics.wisc.edu/chaos/lorenzle.htm
}
<commit_msg>Ignore exponent test<commit_after>
extern crate ndarray;
extern crate ndarray_odeint;
extern crate ndarray_numtest;
extern crate ndarray_linalg;

use ndarray::*;
use ndarray_linalg::prelude::*;
use ndarray_numtest::prelude::*;

use ndarray_odeint::prelude::*;
use ndarray_odeint::lyapunov::*;

#[test]
fn jacobian_linearity() {
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, 0.01);
    let x0 = rcarr1(&[1.0, 0.0, 0.0]);
    let j = jacobian(&teo, x0, 1e-7);
    let v = Array1::real_normal_init(3, 1.0, 1.0);
    let w = Array1::real_normal_init(3, 1.0, 1.0);
    all_close_l2(&(j.dot(&v) + j.dot(&w)), &j.dot(&(v + w)), 1e-5).unwrap();
}

#[test]
fn jacobian_matrix_shape() {
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, 0.01);
    let x0 = rcarr1(&[1.0, 0.0, 0.0]);
    let j = jacobian(&teo, x0, 1e-7);
    let v = Array2::real_normal_init((3, 2), 1.0, 1.0);
    let jv = j.dot(&v);
    assert!(jv.shape() == v.shape());
}

#[test]
#[ignore]
fn exponents_l63() {
    let dt = 0.01;
    let eom = Lorenz63::default();
    let teo = explicit::rk4(eom, dt);
    let l = exponents(&teo, rcarr1(&[1.0, 0.0, 0.0]), 1e-7, 100000);
    all_close_max(&l, &arr1(&[0.906, 0.0, -14.572]), 1e-2).unwrap();
    // value from http://sprott.physics.wisc.edu/chaos/lorenzle.htm
}
<|endoftext|>


<commit_before>
extern crate clap;
extern crate num_integer;

// Time Start: Tue, 10 Dec 2019 16:01:02 -0500
// Time Finish 1: Tue, 10 Dec 2019 17:26:44 -0500 (1 hour, 25 minutes, 42 seconds)
// Time Finish 2: Tue, 10 Dec 2019 19:03:18 -0500 (1 hour, 36 minutes, 34 seconds)
// Time Total: 3 hours, 2 minutes, 16 seconds

use std::fs;

use clap::{Arg, App};
use num_integer::Integer;

struct Point(i32, i32);

struct Map {
    map: Vec<String>,
}
impl Map {
    pub fn new(fname: &String) -> Map {
        let contents = fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        let map = contents.trim().split_ascii_whitespace().map(|s| String::from(s)).collect::<Vec<String>>();
        return Map { map: map };
    }

    pub fn width(&self)  -> i32 { self.map.get(0).map_or(0, |row| row.len() as i32) }
    pub fn height(&self) -> i32 { self.map.len() as i32 }

    pub fn get(&self, i: i32, j: i32) -> char {
        if i < 0 || j < 0 { return '?' }
        self.map.get(j as usize).map_or('?', |row| row.chars().nth(i as usize).unwrap_or('?'))
    }

    pub fn visible_asteroids(&self, i: i32, j: i32) -> i32 {
        let w = self.width() as i32;
        let h = self.height() as i32;
        let mut asteroids = 0;

        for x in 0..w {
            for y in 0..h {
                let dx = x - i;
                let dy = y - j;

                if dx.gcd(&dy) == 1 { // (0,0) excluded since gcd is 0  (see tests)
                    let mut mult = 1;
                    let mut ch = self.get(i+dx, j+dy);
                    while ch == '.' {
                        mult += 1;
                        ch = self.get(i+mult*dx, j+mult*dy);
                    }

                    match ch {
                        '#' => { asteroids += 1 },
                        '?' => (), // edge of map
                         _  => unreachable!("Should have hit something by now!"),
                    }
                }
            }
        }
        return asteroids;
    }

    // Need a clockwise comparable "angle" starting with (0,-1) being at "0"
    pub fn direction(&self, dx: &i32, dy: &i32) -> i32 {
        // y.atan2(x) : but we want (0,-1) to be at 0, so swap x and y
        let deg = 180.0 - (*dx as f64).atan2(*dy as f64).to_degrees();
        let dir = (1e6 * deg).round() as i32; // scale so we can compare integers
        return if dir == 360000000 { 0 } else { dir }; // Above generates ( 0 .. 360000000 ], change side of "]"
    }

    pub fn laser_targets(&self, i: i32, j: i32) -> Vec<Point> {
        //                   mult, dir, point
        let mut targets: Vec<(i32, i32, Point)> = Vec::new();

        let w = self.width() as i32;
        let h = self.height() as i32;
        for x in 0..w {
            for y in 0..h {
                let dx = x - i;
                let dy = y - j;

                if dx.gcd(&dy) == 1 { // (0,0) excluded since gcd is 0  (see tests)
                    let dir = self.direction(&dx, &dy);
                    let mut mult = 1;
                    let mut rotation = 1;
                    let mut ch = self.get(i+dx, j+dy);
                    while ch != '?' {
                        if ch == '#' {
                            targets.push( (rotation, dir, Point(i+mult*dx, j+mult*dy)) );
                            rotation += 1;
                        }
                        mult += 1;
                        ch = self.get(i+mult*dx, j+mult*dy);
                    }
                }
            }
        }

        targets.sort_unstable_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
        return targets.iter().map(|t| Point((t.2).0, (t.2).1)).collect::<Vec<Point>>();
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 10")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("10.in"));

    let map = Map::new(&fname);

    let w = map.width();
    let h = map.height();
    let mut best = (0, 0, 0);

    for x in 0..w {
        for y in 1..h {
            if '#' == map.get(x, y) { // Can only build outpost on an asteroid!
                let seen = map.visible_asteroids(x, y);
                if seen > best.2 {
                    best = (x, y, seen);
                }
            }
        }
    }

    println!("Can see {} asteroids from ({}, {})", best.2, best.0, best.1);

    let targets = map.laser_targets(best.0, best.1);
    if let Some(target) = targets.get(0) {
        println!("The 1st asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(9) {
        println!("The 10th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(99) {
        println!("The 100th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(199) {
        println!("The 200th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
}

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

    #[test]
    fn sanity() {
        assert_eq!(0_i32.gcd(&1), 1);
        assert_eq!(1_i32.gcd(&0), 1);
        assert_eq!(0_i32.gcd(&0), 0);
        assert_eq!(5_i32.gcd(&0), 5);
        assert_eq!(0_i32.gcd(&2), 2);

        assert_eq!(1.0_f64.atan2(0.0).to_degrees().round() as i32, 90);
        assert_eq!(0.0_f64.atan2(1.0).to_degrees().round() as i32, 0);
        assert_eq!(-1.0_f64.atan2(0.0).to_degrees().round() as i32, -90);
        assert_eq!(0.0_f64.atan2(-1.0).to_degrees().round() as i32, 180);

        let map = Map::new(&String::from("test.1"));
        assert_eq!(map.direction(&0, &-1), 0);
        assert_eq!(map.direction(&1, &0), 90_000_000);
        assert_eq!(map.direction(&0, &1), 180_000_000);
        assert_eq!(map.direction(&-1, &0), 270_000_000);
    }
}
<commit_msg>clarify mult vs rotation<commit_after>
extern crate clap;
extern crate num_integer;

// Time Start: Tue, 10 Dec 2019 16:01:02 -0500
// Time Finish 1: Tue, 10 Dec 2019 17:26:44 -0500 (1 hour, 25 minutes, 42 seconds)
// Time Finish 2: Tue, 10 Dec 2019 19:03:18 -0500 (1 hour, 36 minutes, 34 seconds)
// Time Total: 3 hours, 2 minutes, 16 seconds

use std::fs;

use clap::{Arg, App};
use num_integer::Integer;

struct Point(i32, i32);

struct Map {
    map: Vec<String>,
}
impl Map {
    pub fn new(fname: &String) -> Map {
        let contents = fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        let map = contents.trim().split_ascii_whitespace().map(|s| String::from(s)).collect::<Vec<String>>();
        return Map { map: map };
    }

    pub fn width(&self)  -> i32 { self.map.get(0).map_or(0, |row| row.len() as i32) }
    pub fn height(&self) -> i32 { self.map.len() as i32 }

    pub fn get(&self, i: i32, j: i32) -> char {
        if i < 0 || j < 0 { return '?' }
        self.map.get(j as usize).map_or('?', |row| row.chars().nth(i as usize).unwrap_or('?'))
    }

    pub fn visible_asteroids(&self, i: i32, j: i32) -> i32 {
        let w = self.width() as i32;
        let h = self.height() as i32;
        let mut asteroids = 0;

        for x in 0..w {
            for y in 0..h {
                let dx = x - i;
                let dy = y - j;

                if dx.gcd(&dy) == 1 { // (0,0) excluded since gcd is 0  (see tests)
                    let mut mult = 1;
                    let mut ch = self.get(i+dx, j+dy);
                    while ch == '.' {
                        mult += 1;
                        ch = self.get(i+mult*dx, j+mult*dy);
                    }

                    match ch {
                        '#' => { asteroids += 1 },
                        '?' => (), // edge of map
                         _  => unreachable!("Should have hit something by now!"),
                    }
                }
            }
        }
        return asteroids;
    }

    // Need a clockwise comparable "angle" starting with (0,-1) being at "0"
    pub fn direction(&self, dx: &i32, dy: &i32) -> i32 {
        // y.atan2(x) : but we want (0,-1) to be at 0, so swap x and y
        let deg = 180.0 - (*dx as f64).atan2(*dy as f64).to_degrees();
        let dir = (1e6 * deg).round() as i32; // scale so we can compare integers
        return if dir == 360000000 { 0 } else { dir }; // Above generates ( 0 .. 360000000 ], change side of "]"
    }

    pub fn laser_targets(&self, i: i32, j: i32) -> Vec<Point> {
        //                   mult, dir, point
        let mut targets: Vec<(i32, i32, Point)> = Vec::new();

        let w = self.width() as i32;
        let h = self.height() as i32;
        for x in 0..w {
            for y in 0..h {
                let dx = x - i;
                let dy = y - j;

                if dx.gcd(&dy) == 1 { // (0,0) excluded since gcd is 0  (see tests)
                    let dir = self.direction(&dx, &dy);
                    let mut mult = 1;      // current multiple of ratio
                    let mut rotation = 1;  // laser rotation number of hit
                    let mut ch = self.get(i+dx, j+dy);
                    while ch != '?' {
                        if ch == '#' {
                            targets.push( (rotation, dir, Point(i+mult*dx, j+mult*dy)) );
                            rotation += 1;
                        }
                        mult += 1;
                        ch = self.get(i+mult*dx, j+mult*dy);
                    }
                }
            }
        }

        targets.sort_unstable_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
        return targets.iter().map(|t| Point((t.2).0, (t.2).1)).collect::<Vec<Point>>();
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 10")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("10.in"));

    let map = Map::new(&fname);

    let w = map.width();
    let h = map.height();
    let mut best = (0, 0, 0);

    for x in 0..w {
        for y in 1..h {
            if '#' == map.get(x, y) { // Can only build outpost on an asteroid!
                let seen = map.visible_asteroids(x, y);
                if seen > best.2 {
                    best = (x, y, seen);
                }
            }
        }
    }

    println!("Can see {} asteroids from ({}, {})", best.2, best.0, best.1);

    let targets = map.laser_targets(best.0, best.1);
    if let Some(target) = targets.get(0) {
        println!("The 1st asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(9) {
        println!("The 10th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(99) {
        println!("The 100th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
    if let Some(target) = targets.get(199) {
        println!("The 200th asteroid to be vaporized is at ({}, {})", target.0, target.1);
    }
}

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

    #[test]
    fn sanity() {
        assert_eq!(0_i32.gcd(&1), 1);
        assert_eq!(1_i32.gcd(&0), 1);
        assert_eq!(0_i32.gcd(&0), 0);
        assert_eq!(5_i32.gcd(&0), 5);
        assert_eq!(0_i32.gcd(&2), 2);

        assert_eq!(1.0_f64.atan2(0.0).to_degrees().round() as i32, 90);
        assert_eq!(0.0_f64.atan2(1.0).to_degrees().round() as i32, 0);
        assert_eq!(-1.0_f64.atan2(0.0).to_degrees().round() as i32, -90);
        assert_eq!(0.0_f64.atan2(-1.0).to_degrees().round() as i32, 180);

        let map = Map::new(&String::from("test.1"));
        assert_eq!(map.direction(&0, &-1), 0);
        assert_eq!(map.direction(&1, &0), 90_000_000);
        assert_eq!(map.direction(&0, &1), 180_000_000);
        assert_eq!(map.direction(&-1, &0), 270_000_000);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "attribute"]
#![experimental]
#![comment = "Attribute Library"]
#![license = "Apache v2"]
#![crate_type = "dylib"]

#![feature(globs)]

extern crate rustc;
extern crate syntax;

pub mod model;
pub mod model_checker;
pub mod compile_error;
<commit_msg>globs are not gated anymore, remove the feature gate.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "attribute"]
#![experimental]
#![comment = "Attribute Library"]
#![license = "Apache v2"]
#![crate_type = "dylib"]

extern crate rustc;
extern crate syntax;

pub mod model;
pub mod model_checker;
pub mod compile_error;
<|endoftext|>


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

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // If a manual nodejs was added to the config,
    // of if a nodejs install is detected through config, use it.
    if build.config.nodejs.is_some() {
        need_cmd("nodejs".as_ref())
    }

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") ||
           target.contains("emscripten") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<commit_msg>tweaking the nodejs cmd sanity check<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // If a manual nodejs was added to the config,
    // of if a nodejs install is detected through config, use it.
    if let Some(ref s) = build.config.nodejs {
        need_cmd(s.as_ref());
    }

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") ||
           target.contains("emscripten") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<|endoftext|>