<commit_before>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// 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.

use dat::EmpiresDbRef;
use ecs::component::*;
use specs::{self, Join};
use super::super::System;
use types::{Fixed, Norm, Vector3};

const THRESHOLD: Fixed = fixed_const!(0.1);

pub struct MoveToPositionActionSystem {
    empires: EmpiresDbRef,
}

impl MoveToPositionActionSystem {
    pub fn new(empires: EmpiresDbRef) -> MoveToPositionActionSystem {
        MoveToPositionActionSystem { empires: empires }
    }
}

impl System for MoveToPositionActionSystem {
    fn update(&mut self, arg: specs::RunArg, _time_step: Fixed) {
        fetch_components!(arg, _entities, [
            components(transforms: TransformComponent),
            components(units: UnitComponent),
            mut components(mtps: MoveToPositionActionComponent),
            mut components(velocities: VelocityComponent),
            mut components(graphics: GraphicComponent),
            mut components(action_queues: ActionQueueComponent),
        ]);

        let items = (&mut velocities, &transforms, &units, &mut graphics, &mut mtps, &mut action_queues);
        for (mut velocity, transform, unit, mut graphic, mut mtps, mut action_queue) in items.iter() {
            let target = *mtps.path.first().unwrap();
            let mut direction = target - *transform.position();
            let distance = direction.normalize();

            let done = if distance <= THRESHOLD {
                mtps.path.remove(0);
                mtps.path.is_empty()
            } else {
                match unit.db(&self.empires).motion_params {
                    Some(ref params) => {
                        if params.walking_graphics[0].is_some() &&
                           graphic.graphic_id != params.walking_graphics[0] {
                            graphic.set_graphic(params.walking_graphics[0])
                        }
                        let speed: Fixed = params.speed.into();
                        velocity.velocity = direction * speed;
                        false
                    }
                    None => true,
                }
            };

            if done {
                let unit_info = unit.db(&self.empires);
                graphic.set_graphic(unit_info.standing_graphic);
                velocity.velocity = Vector3::new(0.into(), 0.into(), 0.into());
                action_queue.mark_current_done();
            }
        }
    }
}
<commit_msg>Fix crash on empty path<commit_after>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// 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.

use dat::EmpiresDbRef;
use ecs::component::*;
use specs::{self, Join};
use super::super::System;
use types::{Fixed, Norm, Vector3};

const THRESHOLD: Fixed = fixed_const!(0.1);

pub struct MoveToPositionActionSystem {
    empires: EmpiresDbRef,
}

impl MoveToPositionActionSystem {
    pub fn new(empires: EmpiresDbRef) -> MoveToPositionActionSystem {
        MoveToPositionActionSystem { empires: empires }
    }
}

impl System for MoveToPositionActionSystem {
    fn update(&mut self, arg: specs::RunArg, _time_step: Fixed) {
        fetch_components!(arg, _entities, [
            components(transforms: TransformComponent),
            components(units: UnitComponent),
            mut components(mtps: MoveToPositionActionComponent),
            mut components(velocities: VelocityComponent),
            mut components(graphics: GraphicComponent),
            mut components(action_queues: ActionQueueComponent),
        ]);

        let items = (&mut velocities, &transforms, &units, &mut graphics, &mut mtps, &mut action_queues);
        for (mut velocity, transform, unit, mut graphic, mut mtps, mut action_queue) in items.iter() {
            let mut done = false;
            if !mtps.path.is_empty() {
                let target = *mtps.path.first().unwrap();
                let mut direction = target - *transform.position();
                let distance = direction.normalize();

                let done = if distance <= THRESHOLD {
                    mtps.path.remove(0);
                    mtps.path.is_empty()
                } else {
                    match unit.db(&self.empires).motion_params {
                        Some(ref params) => {
                            if params.walking_graphics[0].is_some() &&
                            graphic.graphic_id != params.walking_graphics[0] {
                                graphic.set_graphic(params.walking_graphics[0])
                            }
                            let speed: Fixed = params.speed.into();
                            velocity.velocity = direction * speed;
                            false
                        }
                        None => true,
                    }
                };
            } else {
                done = true;
            }

            if done {
                let unit_info = unit.db(&self.empires);
                graphic.set_graphic(unit_info.standing_graphic);
                velocity.velocity = Vector3::new(0.into(), 0.into(), 0.into());
                action_queue.mark_current_done();
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

// This test case tests the incremental compilation hash (ICH) implementation
// for closure expression.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change closure body ---------------------------------------------------------
#[cfg(cfail1)]
fn change_closure_body() {
    let _ = || 1u32;
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn change_closure_body() {
    let _ = || 3u32;
}

// Add parameter ---------------------------------------------------------------
#[cfg(cfail1)]
fn add_parameter() {
    let x = 0u32;
    let _ = || x + 1;
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn add_parameter() {
    let x = 0u32;
    let _ = |x: u32| x + 1;
}

// Change parameter pattern ----------------------------------------------------
#[cfg(cfail1)]
fn change_parameter_pattern() {
    let _ = |x: &u32| x;
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn change_parameter_pattern() {
    let _ = |&x: &u32| x;
}

// Add `move` to closure -------------------------------------------------------
#[cfg(cfail1)]
fn add_move() {
    let _ = || 1;
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn add_move() {
    let _ = move || 1;
}

// Add type ascription to parameter --------------------------------------------
#[cfg(cfail1)]
fn add_type_ascription_to_parameter() {
    let closure = |x| x + 1u32;
    let _: u32 = closure(1);
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn add_type_ascription_to_parameter() {
    let closure = |x: u32| x + 1u32;
    let _: u32 = closure(1);
}

// Change parameter type -------------------------------------------------------
#[cfg(cfail1)]
fn change_parameter_type() {
    let closure = |x: u32| (x as u64) + 1;
    let _ = closure(1);
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
fn change_parameter_type() {
    let closure = |x: u16| (x as u64) + 1;
    let _ = closure(1);
}
<commit_msg>Update closure expression fingerprint hash tests<commit_after>// Copyright 2016 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.

// This test case tests the incremental compilation hash (ICH) implementation
// for closure expression.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change closure body ---------------------------------------------------------
#[cfg(cfail1)]
pub fn change_closure_body() {
    let _ = || 1u32;
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn change_closure_body() {
    let _ = || 3u32;
}

// Add parameter ---------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_parameter() {
    let x = 0u32;
    let _ = || x + 1;
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, MirOptimized, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn add_parameter() {
    let x = 0u32;
    let _ = |x: u32| x + 1;
}

// Change parameter pattern ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_parameter_pattern() {
    let _ = |x: &u32| x;
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, MirOptimized, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn change_parameter_pattern() {
    let _ = |&x: &u32| x;
}

// Add `move` to closure -------------------------------------------------------
#[cfg(cfail1)]
pub fn add_move() {
    let _ = || 1;
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_move() {
    let _ = move || 1;
}

// Add type ascription to parameter --------------------------------------------
#[cfg(cfail1)]
pub fn add_type_ascription_to_parameter() {
    let closure = |x| x + 1u32;
    let _: u32 = closure(1);
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_ascription_to_parameter() {
    let closure = |x: u32| x + 1u32;
    let _: u32 = closure(1);
}

// Change parameter type -------------------------------------------------------
#[cfg(cfail1)]
pub fn change_parameter_type() {
    let closure = |x: u32| (x as u64) + 1;
    let _ = closure(1);
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, MirOptimized, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn change_parameter_type() {
    let closure = |x: u16| (x as u64) + 1;
    let _ = closure(1);
}
<|endoftext|>


<commit_before>use lalafell::commands::prelude::*;

use serenity::model::id::UserId;
use serenity::model::channel::Channel;
use serenity::builder::CreateEmbed;

use lalafell::error::*;

use std::boxed::FnBox;

const USAGE: &str = "!poll <poll text>\n<option>\n<option>...";

#[derive(Default)]
pub struct PollCommand;

impl PollCommand {
  fn nick_or_name(&self, guild: GuildId, user: UserId) -> Option<String> {
    match guild.member(user) {
      Ok(m) => Some(m.display_name().to_string()),
      Err(_) => None
    }
  }
}

impl<'a> Command<'a> for PollCommand {
  fn run(&self, _: &Context, msg: &Message, _: &[&str]) -> CommandResult<'a> {
    let lines: Vec<&str> = msg.content.split('\n').collect();
    let params: Vec<&str> = lines[0].split_whitespace().skip(1).collect();
    let options = &lines[1..];
    if params.is_empty() || options.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    if options.len() > 9 {
      return Err("No more than nine poll options can be specified.".into());
    }
    let message = params.join(" ");
    let channel = match msg.channel_id.get() {
      Ok(Channel::Guild(c)) => c,
      _ => return Err("This command must be used in a guild channel.".into())
    };
    msg.delete().chain_err(|| "could not delete original message")?;
    let name = self.nick_or_name(channel.read().guild_id, msg.author.id).unwrap_or_else(|| "someone".into());
    let poll = Poll::new(name, &message, options);
    let embed = channel.read().send_message(|c| c.embed(poll.create_embed())).chain_err(|| "could not send embed")?;
    for i in 0..poll.options.len() {
      embed.react(format!("{}⃣", i + 1)).chain_err(|| "could not add reaction")?;
    }
    Ok(CommandSuccess::default())
  }
}

struct Poll {
  author: String,
  text: String,
  options: Vec<String>
}

impl Poll {
  fn new(author: String, text: &str, options: &[&str]) -> Poll {
    Poll {
      author,
      text: text.to_string(),
      options: options.iter().map(|x| x.to_string()).collect()
    }
  }

  fn create_embed(&self) -> Box<FnBox(CreateEmbed) -> CreateEmbed> {
    let name = self.author.clone();
    let options = self.options.iter()
      .enumerate()
      .map(|(i, x)| format!("{}⃣ – {}", i + 1, x))
      .collect::<Vec<_>>()
      .join("\n");
    let desc = format!("{}\n{}", self.text, options);
    box move |e: CreateEmbed| {
      e
        .title(&format!("Poll by {}", name))
        .description(&desc)
        .footer(|f| f.text("Loading poll ID..."))
    }
  }
}
<commit_msg>refactor: use CreateEmbed::reactions<commit_after>use lalafell::commands::prelude::*;

use serenity::model::id::UserId;
use serenity::model::channel::Channel;
use serenity::builder::CreateEmbed;

use lalafell::error::*;

use std::boxed::FnBox;

const USAGE: &str = "!poll <poll text>\n<option>\n<option>...";

#[derive(Default)]
pub struct PollCommand;

impl PollCommand {
  fn nick_or_name(&self, guild: GuildId, user: UserId) -> Option<String> {
    match guild.member(user) {
      Ok(m) => Some(m.display_name().to_string()),
      Err(_) => None
    }
  }
}

impl<'a> Command<'a> for PollCommand {
  fn run(&self, _: &Context, msg: &Message, _: &[&str]) -> CommandResult<'a> {
    let lines: Vec<&str> = msg.content.split('\n').collect();
    let params: Vec<&str> = lines[0].split_whitespace().skip(1).collect();
    let options = &lines[1..];
    if params.is_empty() || options.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: CreateEmbed| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    if options.len() > 9 {
      return Err("No more than nine poll options can be specified.".into());
    }
    let message = params.join(" ");
    let channel = match msg.channel_id.get() {
      Ok(Channel::Guild(c)) => c,
      _ => return Err("This command must be used in a guild channel.".into())
    };
    msg.delete().chain_err(|| "could not delete original message")?;
    let name = self.nick_or_name(channel.read().guild_id, msg.author.id).unwrap_or_else(|| "someone".into());
    let poll = Poll::new(name, &message, options);
    channel.read().send_message(|c| c
      .embed(poll.create_embed())
      .reactions((0..poll.options.len()).map(|i| format!("{}⃣", i + 1))))
      .chain_err(|| "could not send embed")?;
    Ok(CommandSuccess::default())
  }
}

struct Poll {
  author: String,
  text: String,
  options: Vec<String>
}

impl Poll {
  fn new(author: String, text: &str, options: &[&str]) -> Poll {
    Poll {
      author,
      text: text.to_string(),
      options: options.iter().map(|x| x.to_string()).collect()
    }
  }

  fn create_embed(&self) -> Box<FnBox(CreateEmbed) -> CreateEmbed> {
    let name = self.author.clone();
    let options = self.options.iter()
      .enumerate()
      .map(|(i, x)| format!("{}⃣ – {}", i + 1, x))
      .collect::<Vec<_>>()
      .join("\n");
    let desc = format!("{}\n{}", self.text, options);
    box move |e: CreateEmbed| {
      e
        .title(&format!("Poll by {}", name))
        .description(&desc)
        .footer(|f| f.text("Loading poll ID..."))
    }
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// The task that handles all rendering/painting.

use azure::{AzFloat, AzGLContext};
use azure::azure_hl::{B8G8R8A8, DrawTarget};
use display_list::DisplayList;
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
use servo_msg::compositor_msg::{LayerBufferSet, Epoch};
use servo_msg::constellation_msg::PipelineId;
use font_context::FontContext;
use geom::matrix2d::Matrix2D;
use geom::size::Size2D;
use geom::rect::Rect;
use opts::Opts;
use render_context::RenderContext;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::arc::Arc;

use servo_util::time::{ProfilerChan, profile};
use servo_util::time;

use buffer_map::BufferMap;

pub struct RenderLayer<T> {
    display_list: Arc<DisplayList<T>>,
    size: Size2D<uint>
}

pub enum Msg<T> {
    RenderMsg(RenderLayer<T>),
    ReRenderMsg(~[BufferRequest], f32, Epoch),
    UnusedBufferMsg(~[~LayerBuffer]),
    PaintPermissionGranted,
    PaintPermissionRevoked,
    ExitMsg(Chan<()>),
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[deriving(Clone)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    screen_rect: Rect<uint>,

    // The rect in page coordinates that this tile represents
    page_rect: Rect<f32>,
}

pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferRequest {
    BufferRequest {
        screen_rect: screen_rect,
        page_rect: page_rect,
    }
}

#[deriving(Clone)]
pub struct RenderChan<T> {
    chan: SharedChan<Msg<T>>,
}

impl<T> RenderChan<T> {
    pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
        RenderChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: Msg<T>) {
        self.chan.send(msg);
    }
}

struct RenderTask<C,T> {
    id: PipelineId,
    port: Port<Msg<T>>,
    compositor: C,
    font_ctx: @mut FontContext,
    opts: Opts,

    /// A channel to the profiler.
    profiler_chan: ProfilerChan,

    share_gl_context: AzGLContext,

    /// The layer to be rendered
    render_layer: Option<RenderLayer<T>>,
    /// Permission to send paint messages to the compositor
    paint_permission: bool,
    /// Cached copy of last layers rendered
    last_paint_msg: Option<~LayerBufferSet>,
    /// A counter for epoch messages
    epoch: Epoch,
    /// A data structure to store unused LayerBuffers
    buffer_map: BufferMap<~LayerBuffer>,
}

impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
    pub fn create(id: PipelineId,
                  port: Port<Msg<T>>,
                  compositor: C,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {
        let compositor = Cell::new(compositor);
        let opts = Cell::new(opts);
        let port = Cell::new(port);
        let profiler_chan = Cell::new(profiler_chan);

        do spawn {
            let compositor = compositor.take();
            let share_gl_context = compositor.get_gl_context();
            let opts = opts.take();
            let profiler_chan = profiler_chan.take();

            // FIXME: rust/#5967
            let mut render_task = RenderTask {
                id: id,
                port: port.take(),
                compositor: compositor,
                font_ctx: @mut FontContext::new(opts.render_backend.clone(),
                                                false,
                                                profiler_chan.clone()),
                opts: opts,
                profiler_chan: profiler_chan,
                share_gl_context: share_gl_context,
                render_layer: None,

                paint_permission: false,
                last_paint_msg: None,
                epoch: Epoch(0),
                buffer_map: BufferMap::new(10000000),
            };

            render_task.start();
        }
    }

    fn start(&mut self) {
        debug!("render_task: beginning rendering loop");

        loop {
            match self.port.recv() {
                RenderMsg(render_layer) => {
                    if self.paint_permission {
                        self.epoch.next();
                        self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                    }
                    self.render_layer = Some(render_layer);
                }
                ReRenderMsg(tiles, scale, epoch) => {
                    if self.epoch == epoch {
                        self.render(tiles, scale);
                    } else {
                        debug!("renderer epoch mismatch: %? != %?", self.epoch, epoch);
                    }
                }
                UnusedBufferMsg(unused_buffers) => {
                    // move_rev_iter is more efficient
                    for buffer in unused_buffers.move_rev_iter() {
                        self.buffer_map.insert(buffer);
                    }
                }
                PaintPermissionGranted => {
                    self.paint_permission = true;
                    match self.render_layer {
                        Some(ref render_layer) => {
                            self.epoch.next();
                            self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                        }
                        None => {}
                    }
                    // FIXME: This sends the last paint request, anticipating what
                    // the compositor will ask for. However, even if it sends the right
                    // tiles, the compositor still asks for them, and they will be
                    // re-rendered redundantly.
                    match self.last_paint_msg {
                        Some(ref layer_buffer_set) => {
                            self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
                        }
                        None => {} // Nothing to do
                    }
                }
                PaintPermissionRevoked => {
                    self.paint_permission = false;
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }

    fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
        let render_layer;
        match self.render_layer {
            Some(ref r_layer) => {
                render_layer = r_layer;
            }
            _ => return, // nothing to do
        }

        self.compositor.set_render_state(RenderingRenderState);
        do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {

            // FIXME: Try not to create a new array here.
            let mut new_buffers = ~[];

            // Divide up the layer into tiles.
            do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
                for tile in tiles.iter() {
                    let width = tile.screen_rect.size.width;
                    let height = tile.screen_rect.size.height;

                    let buffer = match self.buffer_map.find(tile.screen_rect.size) {
                        Some(buffer) => {
                            let mut buffer = buffer;
                            buffer.rect = tile.page_rect;
                            buffer.screen_pos = tile.screen_rect;
                            buffer.resolution = scale;
                            buffer
                        }
                        None => ~LayerBuffer {
                            draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
                                                                  self.share_gl_context,
                                                                  Size2D(width as i32, height as i32),
                                                                  B8G8R8A8),
                            rect: tile.page_rect,
                            screen_pos: tile.screen_rect,
                            resolution: scale,
                            stride: (width * 4) as uint
                        }
                    };

                    {
                        // Build the render context.
                        let ctx = RenderContext {
                            canvas: &buffer,
                            font_ctx: self.font_ctx,
                            opts: &self.opts
                        };

                        // Apply the translation to render the tile we want.
                        let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
                        let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
                        let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat,
                                                      -(buffer.rect.origin.y) as AzFloat);

                        ctx.canvas.draw_target.set_transform(&matrix);

                        // Clear the buffer.
                        ctx.clear();

                        // Draw the display list.
                        do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
                            render_layer.display_list.get().draw_into_context(&ctx);
                            ctx.canvas.draw_target.flush();
                        }
                    }

                    new_buffers.push(buffer);

                }

            }

            let layer_buffer_set = ~LayerBufferSet {
                buffers: new_buffers,
            };

            debug!("render_task: returning surface");
            if self.paint_permission {
                self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
            }
            debug!("caching paint msg");
            self.last_paint_msg = Some(layer_buffer_set);
            self.compositor.set_render_state(IdleRenderState);
        }
    }
}

<commit_msg>auto merge of #761 : eschweic/servo/quadtree-crash, r=pcwalton<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// The task that handles all rendering/painting.

use azure::{AzFloat, AzGLContext};
use azure::azure_hl::{B8G8R8A8, DrawTarget};
use display_list::DisplayList;
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
use servo_msg::compositor_msg::{LayerBufferSet, Epoch};
use servo_msg::constellation_msg::PipelineId;
use font_context::FontContext;
use geom::matrix2d::Matrix2D;
use geom::size::Size2D;
use geom::rect::Rect;
use opts::Opts;
use render_context::RenderContext;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::arc::Arc;

use servo_util::time::{ProfilerChan, profile};
use servo_util::time;

use buffer_map::BufferMap;

pub struct RenderLayer<T> {
    display_list: Arc<DisplayList<T>>,
    size: Size2D<uint>
}

pub enum Msg<T> {
    RenderMsg(RenderLayer<T>),
    ReRenderMsg(~[BufferRequest], f32, Epoch),
    UnusedBufferMsg(~[~LayerBuffer]),
    PaintPermissionGranted,
    PaintPermissionRevoked,
    ExitMsg(Chan<()>),
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[deriving(Clone)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    screen_rect: Rect<uint>,

    // The rect in page coordinates that this tile represents
    page_rect: Rect<f32>,
}

pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferRequest {
    BufferRequest {
        screen_rect: screen_rect,
        page_rect: page_rect,
    }
}

#[deriving(Clone)]
pub struct RenderChan<T> {
    chan: SharedChan<Msg<T>>,
}

impl<T> RenderChan<T> {
    pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
        RenderChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: Msg<T>) {
        self.chan.send(msg);
    }
}

struct RenderTask<C,T> {
    id: PipelineId,
    port: Port<Msg<T>>,
    compositor: C,
    font_ctx: @mut FontContext,
    opts: Opts,

    /// A channel to the profiler.
    profiler_chan: ProfilerChan,

    share_gl_context: AzGLContext,

    /// The layer to be rendered
    render_layer: Option<RenderLayer<T>>,
    /// Permission to send paint messages to the compositor
    paint_permission: bool,
    /// Cached copy of last layers rendered
    last_paint_msg: Option<~LayerBufferSet>,
    /// A counter for epoch messages
    epoch: Epoch,
    /// A data structure to store unused LayerBuffers
    buffer_map: BufferMap<~LayerBuffer>,
}

impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
    pub fn create(id: PipelineId,
                  port: Port<Msg<T>>,
                  compositor: C,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {
        let compositor = Cell::new(compositor);
        let opts = Cell::new(opts);
        let port = Cell::new(port);
        let profiler_chan = Cell::new(profiler_chan);

        do spawn {
            let compositor = compositor.take();
            let share_gl_context = compositor.get_gl_context();
            let opts = opts.take();
            let profiler_chan = profiler_chan.take();

            // FIXME: rust/#5967
            let mut render_task = RenderTask {
                id: id,
                port: port.take(),
                compositor: compositor,
                font_ctx: @mut FontContext::new(opts.render_backend.clone(),
                                                false,
                                                profiler_chan.clone()),
                opts: opts,
                profiler_chan: profiler_chan,
                share_gl_context: share_gl_context,
                render_layer: None,

                paint_permission: false,
                last_paint_msg: None,
                epoch: Epoch(0),
                buffer_map: BufferMap::new(10000000),
            };

            render_task.start();
        }
    }

    fn start(&mut self) {
        debug!("render_task: beginning rendering loop");

        loop {
            match self.port.recv() {
                RenderMsg(render_layer) => {
                    if self.paint_permission {
                        self.epoch.next();
                        self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                    }
                    self.render_layer = Some(render_layer);
                    self.last_paint_msg = None;
                }
                ReRenderMsg(tiles, scale, epoch) => {
                    if self.epoch == epoch {
                        self.render(tiles, scale);
                    } else {
                        debug!("renderer epoch mismatch: %? != %?", self.epoch, epoch);
                    }
                }
                UnusedBufferMsg(unused_buffers) => {
                    // move_rev_iter is more efficient
                    for buffer in unused_buffers.move_rev_iter() {
                        self.buffer_map.insert(buffer);
                    }
                }
                PaintPermissionGranted => {
                    self.paint_permission = true;
                    match self.render_layer {
                        Some(ref render_layer) => {
                            self.epoch.next();
                            self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                        }
                        None => {}
                    }
                    // FIXME: This sends the last paint request, anticipating what
                    // the compositor will ask for. However, even if it sends the right
                    // tiles, the compositor still asks for them, and they will be
                    // re-rendered redundantly.
                    match self.last_paint_msg {
                        Some(ref layer_buffer_set) => {
                            self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
                        }
                        None => {} // Nothing to do
                    }
                }
                PaintPermissionRevoked => {
                    self.paint_permission = false;
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }

    fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
        let render_layer;
        match self.render_layer {
            Some(ref r_layer) => {
                render_layer = r_layer;
            }
            _ => return, // nothing to do
        }

        self.compositor.set_render_state(RenderingRenderState);
        do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {

            // FIXME: Try not to create a new array here.
            let mut new_buffers = ~[];

            // Divide up the layer into tiles.
            do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
                for tile in tiles.iter() {
                    let width = tile.screen_rect.size.width;
                    let height = tile.screen_rect.size.height;

                    let buffer = match self.buffer_map.find(tile.screen_rect.size) {
                        Some(buffer) => {
                            let mut buffer = buffer;
                            buffer.rect = tile.page_rect;
                            buffer.screen_pos = tile.screen_rect;
                            buffer.resolution = scale;
                            buffer
                        }
                        None => ~LayerBuffer {
                            draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
                                                                  self.share_gl_context,
                                                                  Size2D(width as i32, height as i32),
                                                                  B8G8R8A8),
                            rect: tile.page_rect,
                            screen_pos: tile.screen_rect,
                            resolution: scale,
                            stride: (width * 4) as uint
                        }
                    };

                    {
                        // Build the render context.
                        let ctx = RenderContext {
                            canvas: &buffer,
                            font_ctx: self.font_ctx,
                            opts: &self.opts
                        };

                        // Apply the translation to render the tile we want.
                        let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
                        let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
                        let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat,
                                                      -(buffer.rect.origin.y) as AzFloat);

                        ctx.canvas.draw_target.set_transform(&matrix);

                        // Clear the buffer.
                        ctx.clear();

                        // Draw the display list.
                        do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
                            render_layer.display_list.get().draw_into_context(&ctx);
                            ctx.canvas.draw_target.flush();
                        }
                    }

                    new_buffers.push(buffer);

                }

            }

            let layer_buffer_set = ~LayerBufferSet {
                buffers: new_buffers,
            };

            debug!("render_task: returning surface");
            if self.paint_permission {
                self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
            }
            debug!("caching paint msg");
            self.last_paint_msg = Some(layer_buffer_set);
            self.compositor.set_render_state(IdleRenderState);
        }
    }
}

<|endoftext|>


<commit_before>use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::{struct_span_err, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FileName, Span};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let dir = &self.directory;
                submod_path(self.sess, id, &attrs, dir.ownership, &dir.path)
                    .and_then(|r| eval_src_mod(self.sess, self.cfg_mods, r.path, r.ownership, id))
                    .map_err(|mut err| err.emit())
                    .unwrap_or_default()
            } else {
                Default::default()
            }
        } else {
            let old_directory = self.directory.clone();
            push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }
}

/// Reads a module from a source file.
fn eval_src_mod<'a>(
    sess: &'a ParseSess,
    cfg_mods: bool,
    path: PathBuf,
    dir_ownership: DirectoryOwnership,
    id: ast::Ident,
) -> PResult<'a, (Mod, Vec<Attribute>)> {
    let mut included_mod_stack = sess.included_mod_stack.borrow_mut();
    if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
        let mut err = String::from("circular modules: ");
        for p in &included_mod_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..]));
    }
    included_mod_stack.push(path.clone());
    drop(included_mod_stack);

    let mut p0 =
        new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span);
    p0.cfg_mods = cfg_mods;
    let mut module = p0.parse_mod(&token::Eof)?;
    module.0.inline = false;

    sess.included_mod_stack.borrow_mut().pop();
    Ok(module)
}

pub fn push_directory(
    id: Ident,
    attrs: &[Attribute],
    dir_ownership: &mut DirectoryOwnership,
    dir_path: &mut PathBuf,
) {
    if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
        dir_path.push(&*path.as_str());
        *dir_ownership = DirectoryOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirectoryOwnership::Owned { relative } = dir_ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                dir_path.push(&*ident.as_str());
            }
        }
        dir_path.push(&*id.as_str());
    }
}

fn submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    attrs: &[Attribute],
    ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(attrs, dir_path) {
        let ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { ownership, path });
    }

    let relative = match ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(sess, id, relative, dir_path);
    match ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(sess, id.span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(sess, id.span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(id_sp, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location");
    if !id_sp.is_dummy() {
        if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) {
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    id_sp,
                    &format!(
                        "maybe move this module `{}` to its own \
                                directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            id_sp,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    relative: Option<ast::Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0584,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<commit_msg>extract parse_external_module<commit_after>use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::{struct_span_err, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FileName, Span};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                let dir = &self.directory;
                parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs)
            } else {
                Default::default()
            }
        } else {
            let old_directory = self.directory.clone();
            push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }
}

fn parse_external_module(
    sess: &ParseSess,
    cfg_mods: bool,
    id: ast::Ident,
    ownership: DirectoryOwnership,
    dir_path: &Path,
    attrs: &[Attribute],
) -> (Mod, Vec<Attribute>) {
    submod_path(sess, id, &attrs, ownership, dir_path)
        .and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id))
        .map_err(|mut err| err.emit())
        .unwrap_or_default()
}

/// Reads a module from a source file.
fn eval_src_mod<'a>(
    sess: &'a ParseSess,
    cfg_mods: bool,
    path: PathBuf,
    dir_ownership: DirectoryOwnership,
    id: ast::Ident,
) -> PResult<'a, (Mod, Vec<Attribute>)> {
    let mut included_mod_stack = sess.included_mod_stack.borrow_mut();
    if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
        let mut err = String::from("circular modules: ");
        for p in &included_mod_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..]));
    }
    included_mod_stack.push(path.clone());
    drop(included_mod_stack);

    let mut p0 =
        new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span);
    p0.cfg_mods = cfg_mods;
    let mut module = p0.parse_mod(&token::Eof)?;
    module.0.inline = false;

    sess.included_mod_stack.borrow_mut().pop();
    Ok(module)
}

pub fn push_directory(
    id: Ident,
    attrs: &[Attribute],
    dir_ownership: &mut DirectoryOwnership,
    dir_path: &mut PathBuf,
) {
    if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
        dir_path.push(&*path.as_str());
        *dir_ownership = DirectoryOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirectoryOwnership::Owned { relative } = dir_ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                dir_path.push(&*ident.as_str());
            }
        }
        dir_path.push(&*id.as_str());
    }
}

fn submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    attrs: &[Attribute],
    ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(attrs, dir_path) {
        let ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { ownership, path });
    }

    let relative = match ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(sess, id, relative, dir_path);
    match ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(sess, id.span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(sess, id.span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(id_sp, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location");
    if !id_sp.is_dummy() {
        if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) {
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    id_sp,
                    &format!(
                        "maybe move this module `{}` to its own \
                                directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            id_sp,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    relative: Option<ast::Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0584,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<|endoftext|>


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

use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq};
use ast::{TTDelim};
use ast;
use codemap::{Span, Spanned, DUMMY_SP};
use ext::base::{ExtCtxt, MacResult, MacroDef};
use ext::base::{NormalTT, TTMacroExpander};
use ext::base;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_or_else};
use parse::lexer::new_tt_reader;
use parse::parser::Parser;
use parse::attr::ParserAttr;
use parse::token::{special_idents, gensym_ident};
use parse::token::{FAT_ARROW, SEMI, NtMatchers, NtTT, EOF};
use parse::token;
use print;
use util::small_vector::SmallVector;

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

struct ParserAnyMacro<'a> {
    parser: RefCell<Parser<'a>>,
}

impl<'a> ParserAnyMacro<'a> {
    /// Make sure we don't have any tokens left to parse, so we don't
    /// silently drop anything. `allow_semi` is so that "optional"
    /// semicolons at the end of normal expressions aren't complained
    /// about e.g. the semicolon in `macro_rules! kapow( () => {
    /// fail!(); } )` doesn't get picked up by .parse_expr(), but it's
    /// allowed to be there.
    fn ensure_complete_parse(&self, allow_semi: bool) {
        let mut parser = self.parser.borrow_mut();
        if allow_semi && parser.token == SEMI {
            parser.bump()
        }
        if parser.token != EOF {
            let token_str = parser.this_token_to_string();
            let msg = format!("macro expansion ignores token `{}` and any \
                               following",
                              token_str);
            let span = parser.span;
            parser.span_err(span, msg.as_slice());
        }
    }
}

impl<'a> MacResult for ParserAnyMacro<'a> {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        let ret = self.parser.borrow_mut().parse_expr();
        self.ensure_complete_parse(true);
        Some(ret)
    }
    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        let ret = self.parser.borrow_mut().parse_pat();
        self.ensure_complete_parse(false);
        Some(ret)
    }
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            // so... do outer attributes attached to the macro invocation
            // just disappear? This question applies to make_methods, as
            // well.
            match parser.parse_item_with_outer_attributes() {
                Some(item) => ret.push(item),
                None => break
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                EOF => break,
                _ => ret.push(parser.parse_method(None))
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_stmt(&self) -> Option<Gc<ast::Stmt>> {
        let attrs = self.parser.borrow_mut().parse_outer_attributes();
        let ret = self.parser.borrow_mut().parse_stmt(attrs);
        self.ensure_complete_parse(true);
        Some(ret)
    }
}

struct MacroRulesMacroExpander {
    name: Ident,
    lhses: Vec<Rc<NamedMatch>>,
    rhses: Vec<Rc<NamedMatch>>,
}

impl TTMacroExpander for MacroRulesMacroExpander {
    fn expand(&self,
              cx: &mut ExtCtxt,
              sp: Span,
              arg: &[ast::TokenTree])
              -> Box<MacResult> {
        generic_extension(cx,
                          sp,
                          self.name,
                          arg,
                          self.lhses.as_slice(),
                          self.rhses.as_slice())
    }
}

struct MacroRulesDefiner {
    def: RefCell<Option<MacroDef>>
}
impl MacResult for MacroRulesDefiner {
    fn make_def(&self) -> Option<MacroDef> {
        Some(self.def.borrow_mut().take().expect("MacroRulesDefiner expanded twice"))
    }
}

/// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension(cx: &ExtCtxt,
                     sp: Span,
                     name: Ident,
                     arg: &[ast::TokenTree],
                     lhses: &[Rc<NamedMatch>],
                     rhses: &[Rc<NamedMatch>])
                     -> Box<MacResult> {
    if cx.trace_macros() {
        println!("{}! {} {} {}",
                 token::get_ident(name),
                 "{",
                 print::pprust::tt_to_string(&TTDelim(Rc::new(arg.iter()
                                                              .map(|x| (*x).clone())
                                                              .collect()))),
                 "}");
    }

    // Which arm's failure should we report? (the one furthest along)
    let mut best_fail_spot = DUMMY_SP;
    let mut best_fail_msg = "internal error: ran no matchers".to_string();

    for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
        match **lhs {
          MatchedNonterminal(NtMatchers(ref mtcs)) => {
            // `None` is because we're not interpolating
            let arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                        None,
                                        arg.iter()
                                           .map(|x| (*x).clone())
                                           .collect());
            match parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtcs.as_slice()) {
              Success(named_matches) => {
                let rhs = match *rhses[i] {
                    // okay, what's your transcriber?
                    MatchedNonterminal(NtTT(tt)) => {
                        match *tt {
                            // cut off delimiters; don't parse 'em
                            TTDelim(ref tts) => {
                                (*tts).slice(1u,(*tts).len()-1u)
                                      .iter()
                                      .map(|x| (*x).clone())
                                      .collect()
                            }
                            _ => cx.span_fatal(
                                sp, "macro rhs must be delimited")
                        }
                    },
                    _ => cx.span_bug(sp, "bad thing in rhs")
                };
                // rhs has holes ( `$id` and `$(...)` that need filled)
                let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                           Some(named_matches),
                                           rhs);
                let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
                // Let the context choose how to interpret the result.
                // Weird, but useful for X-macros.
                return box ParserAnyMacro {
                    parser: RefCell::new(p),
                } as Box<MacResult>
              }
              Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
                best_fail_spot = sp;
                best_fail_msg = (*msg).clone();
              },
              Error(sp, ref msg) => cx.span_fatal(sp, msg.as_slice())
            }
          }
          _ => cx.bug("non-matcher found in parsed lhses")
        }
    }
    cx.span_fatal(best_fail_spot, best_fail_msg.as_slice());
}

/// This procedure performs the expansion of the
/// macro_rules! macro. It parses the RHS and adds
/// an extension to the current context.
pub fn add_new_extension(cx: &mut ExtCtxt,
                         sp: Span,
                         name: Ident,
                         arg: Vec<ast::TokenTree> )
                         -> Box<base::MacResult> {
    // these spans won't matter, anyways
    fn ms(m: Matcher_) -> Matcher {
        Spanned {
            node: m.clone(),
            span: DUMMY_SP
        }
    }

    let lhs_nm =  gensym_ident("lhs");
    let rhs_nm =  gensym_ident("rhs");

    // The pattern that macro_rules matches.
    // The grammar for macro_rules! is:
    // $( $lhs:mtcs => $rhs:tt );+
    // ...quasiquoting this would be nice.
    let argument_gram = vec!(
        ms(MatchSeq(vec!(
            ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)),
            ms(MatchTok(FAT_ARROW)),
            ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI), false, 0u, 2u)),
        //to phase into semicolon-termination instead of
        //semicolon-separation
        ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, true, 2u, 2u)));

    // Parse the macro_rules! invocation (`none` is for no interpolations):
    let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                   None,
                                   arg.clone());
    let argument_map = parse_or_else(cx.parse_sess(),
                                     cx.cfg(),
                                     arg_reader,
                                     argument_gram);

    // Extract the arguments:
    let lhses = match **argument_map.get(&lhs_nm) {
        MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
        _ => cx.span_bug(sp, "wrong-structured lhs")
    };

    let rhses = match **argument_map.get(&rhs_nm) {
        MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
        _ => cx.span_bug(sp, "wrong-structured rhs")
    };

    let exp = box MacroRulesMacroExpander {
        name: name,
        lhses: lhses,
        rhses: rhses,
    };

    box MacroRulesDefiner {
        def: RefCell::new(Some(MacroDef {
            name: token::get_ident(name).to_string(),
            ext: NormalTT(exp, Some(sp))
        }))
    } as Box<MacResult>
}
<commit_msg>comments<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq};
use ast::{TTDelim};
use ast;
use codemap::{Span, Spanned, DUMMY_SP};
use ext::base::{ExtCtxt, MacResult, MacroDef};
use ext::base::{NormalTT, TTMacroExpander};
use ext::base;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_or_else};
use parse::lexer::new_tt_reader;
use parse::parser::Parser;
use parse::attr::ParserAttr;
use parse::token::{special_idents, gensym_ident};
use parse::token::{FAT_ARROW, SEMI, NtMatchers, NtTT, EOF};
use parse::token;
use print;
use util::small_vector::SmallVector;

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

struct ParserAnyMacro<'a> {
    parser: RefCell<Parser<'a>>,
}

impl<'a> ParserAnyMacro<'a> {
    /// Make sure we don't have any tokens left to parse, so we don't
    /// silently drop anything. `allow_semi` is so that "optional"
    /// semicolons at the end of normal expressions aren't complained
    /// about e.g. the semicolon in `macro_rules! kapow( () => {
    /// fail!(); } )` doesn't get picked up by .parse_expr(), but it's
    /// allowed to be there.
    fn ensure_complete_parse(&self, allow_semi: bool) {
        let mut parser = self.parser.borrow_mut();
        if allow_semi && parser.token == SEMI {
            parser.bump()
        }
        if parser.token != EOF {
            let token_str = parser.this_token_to_string();
            let msg = format!("macro expansion ignores token `{}` and any \
                               following",
                              token_str);
            let span = parser.span;
            parser.span_err(span, msg.as_slice());
        }
    }
}

impl<'a> MacResult for ParserAnyMacro<'a> {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        let ret = self.parser.borrow_mut().parse_expr();
        self.ensure_complete_parse(true);
        Some(ret)
    }
    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        let ret = self.parser.borrow_mut().parse_pat();
        self.ensure_complete_parse(false);
        Some(ret)
    }
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            // so... do outer attributes attached to the macro invocation
            // just disappear? This question applies to make_methods, as
            // well.
            match parser.parse_item_with_outer_attributes() {
                Some(item) => ret.push(item),
                None => break
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                EOF => break,
                _ => ret.push(parser.parse_method(None))
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_stmt(&self) -> Option<Gc<ast::Stmt>> {
        let attrs = self.parser.borrow_mut().parse_outer_attributes();
        let ret = self.parser.borrow_mut().parse_stmt(attrs);
        self.ensure_complete_parse(true);
        Some(ret)
    }
}

struct MacroRulesMacroExpander {
    name: Ident,
    lhses: Vec<Rc<NamedMatch>>,
    rhses: Vec<Rc<NamedMatch>>,
}

impl TTMacroExpander for MacroRulesMacroExpander {
    fn expand(&self,
              cx: &mut ExtCtxt,
              sp: Span,
              arg: &[ast::TokenTree])
              -> Box<MacResult> {
        generic_extension(cx,
                          sp,
                          self.name,
                          arg,
                          self.lhses.as_slice(),
                          self.rhses.as_slice())
    }
}

struct MacroRulesDefiner {
    def: RefCell<Option<MacroDef>>
}
impl MacResult for MacroRulesDefiner {
    fn make_def(&self) -> Option<MacroDef> {
        Some(self.def.borrow_mut().take().expect("MacroRulesDefiner expanded twice"))
    }
}

/// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension(cx: &ExtCtxt,
                     sp: Span,
                     name: Ident,
                     arg: &[ast::TokenTree],
                     lhses: &[Rc<NamedMatch>],
                     rhses: &[Rc<NamedMatch>])
                     -> Box<MacResult> {
    if cx.trace_macros() {
        println!("{}! {} {} {}",
                 token::get_ident(name),
                 "{",
                 print::pprust::tt_to_string(&TTDelim(Rc::new(arg.iter()
                                                              .map(|x| (*x).clone())
                                                              .collect()))),
                 "}");
    }

    // Which arm's failure should we report? (the one furthest along)
    let mut best_fail_spot = DUMMY_SP;
    let mut best_fail_msg = "internal error: ran no matchers".to_string();

    for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
        match **lhs {
          MatchedNonterminal(NtMatchers(ref mtcs)) => {
            // `None` is because we're not interpolating
            let arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                        None,
                                        arg.iter()
                                           .map(|x| (*x).clone())
                                           .collect());
            match parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtcs.as_slice()) {
              Success(named_matches) => {
                let rhs = match *rhses[i] {
                    // okay, what's your transcriber?
                    MatchedNonterminal(NtTT(tt)) => {
                        match *tt {
                            // cut off delimiters; don't parse 'em
                            TTDelim(ref tts) => {
                                (*tts).slice(1u,(*tts).len()-1u)
                                      .iter()
                                      .map(|x| (*x).clone())
                                      .collect()
                            }
                            _ => cx.span_fatal(
                                sp, "macro rhs must be delimited")
                        }
                    },
                    _ => cx.span_bug(sp, "bad thing in rhs")
                };
                // rhs has holes ( `$id` and `$(...)` that need filled)
                let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                           Some(named_matches),
                                           rhs);
                let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
                // Let the context choose how to interpret the result.
                // Weird, but useful for X-macros.
                return box ParserAnyMacro {
                    parser: RefCell::new(p),
                } as Box<MacResult>
              }
              Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
                best_fail_spot = sp;
                best_fail_msg = (*msg).clone();
              },
              Error(sp, ref msg) => cx.span_fatal(sp, msg.as_slice())
            }
          }
          _ => cx.bug("non-matcher found in parsed lhses")
        }
    }
    cx.span_fatal(best_fail_spot, best_fail_msg.as_slice());
}

/// This procedure performs the expansion of the
/// macro_rules! macro. It parses the RHS and adds
/// an extension to the current context.
pub fn add_new_extension(cx: &mut ExtCtxt,
                         sp: Span,
                         name: Ident,
                         arg: Vec<ast::TokenTree> )
                         -> Box<base::MacResult> {
    // these spans won't matter, anyways
    fn ms(m: Matcher_) -> Matcher {
        Spanned {
            node: m.clone(),
            span: DUMMY_SP
        }
    }

    let lhs_nm =  gensym_ident("lhs");
    let rhs_nm =  gensym_ident("rhs");

    // The pattern that macro_rules matches.
    // The grammar for macro_rules! is:
    // $( $lhs:matchers => $rhs:tt );+
    // ...quasiquoting this would be nice.
    let argument_gram = vec!(
        ms(MatchSeq(vec!(
            ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)),
            ms(MatchTok(FAT_ARROW)),
            ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI), false, 0u, 2u)),
        //to phase into semicolon-termination instead of
        //semicolon-separation
        ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, true, 2u, 2u)));

    // Parse the macro_rules! invocation (`none` is for no interpolations):
    let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
                                   None,
                                   arg.clone());
    let argument_map = parse_or_else(cx.parse_sess(),
                                     cx.cfg(),
                                     arg_reader,
                                     argument_gram);

    // Extract the arguments:
    let lhses = match **argument_map.get(&lhs_nm) {
        MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
        _ => cx.span_bug(sp, "wrong-structured lhs")
    };

    let rhses = match **argument_map.get(&rhs_nm) {
        MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
        _ => cx.span_bug(sp, "wrong-structured rhs")
    };

    let exp = box MacroRulesMacroExpander {
        name: name,
        lhses: lhses,
        rhses: rhses,
    };

    box MacroRulesDefiner {
        def: RefCell::new(Some(MacroDef {
            name: token::get_ident(name).to_string(),
            ext: NormalTT(exp, Some(sp))
        }))
    } as Box<MacResult>
}
<|endoftext|>