<commit_before>/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `NotReady` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::Async::Ready(t)) => t,
        Ok($crate::Async::NotReady) => return Ok($crate::Async::NotReady),
        Err(e) => return Err(From::from(e)),
    })
}

/// Return type of the `Future::poll` method, indicates whether a future's value
/// is ready or not.
///
/// * `Ok(Async::Ready(t))` means that a future has successfully resolved
/// * `Ok(Async::NotReady)` means that a future is not ready to complete yet
/// * `Err(e)` means that a future has completed with the given failure
pub type Poll<T, E> = Result<Async<T>, E>;

/// Return type of future, indicating whether a value is ready or not.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Async<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet, but may be so later.
    NotReady,
}

impl<T> Async<T> {
    /// Change the success type of this `Async` value with the closure provided
    pub fn map<F, U>(self, f: F) -> Async<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Async::NotReady => Async::NotReady,
            Async::Ready(t) => Async::Ready(f(t)),
        }
    }

    /// Returns whether this is `Async::NotReady`
    pub fn is_not_ready(&self) -> bool {
        match *self {
            Async::NotReady => true,
            Async::Ready(_) => false,
        }
    }

    /// Returns whether this is `Async::Ready`
    pub fn is_ready(&self) -> bool {
        !self.is_not_ready()
    }
}

impl<T> From<T> for Async<T> {
    fn from(t: T) -> Async<T> {
        Async::Ready(t)
    }
}

/// The result of an asynchronous attempt to send a value to a sink.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AsyncSink<T> {
    /// The `start_send` attempt succeeded, so the sending process has
    /// *started*; you muse use `Sink::poll_complete` to drive the send
    /// to completion.
    Ready,

    /// The `start_send` attempt failed due to the sink being full. The value
    /// being sent is returned, and the current `Task` will be autoamtically
    /// notified again once the sink has room.
    NotReady(T),
}

impl<T> AsyncSink<T> {
    /// Returns whether this is `AsyncSink::NotReady`
    pub fn is_not_ready(&self) -> bool {
        match *self {
            AsyncSink::NotReady(_) => true,
            AsyncSink::Ready => false,
        }
    }

    /// Returns whether this is `AsyncSink::Ready`
    pub fn is_ready(&self) -> bool {
        !self.is_not_ready()
    }
}

/// Return type of the `Sink::start_send` method, indicating the outcome of a
/// send attempt. See `AsyncSink` for more details.
pub type StartSend<T, E> = Result<AsyncSink<T>, E>;
<commit_msg>Refactors logic of poll::Async::is_[not_]ready()<commit_after>/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `NotReady` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::Async::Ready(t)) => t,
        Ok($crate::Async::NotReady) => return Ok($crate::Async::NotReady),
        Err(e) => return Err(From::from(e)),
    })
}

/// Return type of the `Future::poll` method, indicates whether a future's value
/// is ready or not.
///
/// * `Ok(Async::Ready(t))` means that a future has successfully resolved
/// * `Ok(Async::NotReady)` means that a future is not ready to complete yet
/// * `Err(e)` means that a future has completed with the given failure
pub type Poll<T, E> = Result<Async<T>, E>;

/// Return type of future, indicating whether a value is ready or not.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Async<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet, but may be so later.
    NotReady,
}

impl<T> Async<T> {
    /// Change the success type of this `Async` value with the closure provided
    pub fn map<F, U>(self, f: F) -> Async<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Async::NotReady => Async::NotReady,
            Async::Ready(t) => Async::Ready(f(t)),
        }
    }

    /// Returns whether this is `Async::Ready`
    pub fn is_ready(&self) -> bool {
        match *self {
            Async::Ready(_) => true,
            Async::NotReady => false,
        }
    }

    /// Returns whether this is `Async::NotReady`
    pub fn is_not_ready(&self) -> bool {
        !self.is_ready()
    }
}

impl<T> From<T> for Async<T> {
    fn from(t: T) -> Async<T> {
        Async::Ready(t)
    }
}

/// The result of an asynchronous attempt to send a value to a sink.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AsyncSink<T> {
    /// The `start_send` attempt succeeded, so the sending process has
    /// *started*; you muse use `Sink::poll_complete` to drive the send
    /// to completion.
    Ready,

    /// The `start_send` attempt failed due to the sink being full. The value
    /// being sent is returned, and the current `Task` will be autoamtically
    /// notified again once the sink has room.
    NotReady(T),
}

impl<T> AsyncSink<T> {
    /// Returns whether this is `AsyncSink::NotReady`
    pub fn is_not_ready(&self) -> bool {
        match *self {
            AsyncSink::NotReady(_) => true,
            AsyncSink::Ready => false,
        }
    }

    /// Returns whether this is `AsyncSink::Ready`
    pub fn is_ready(&self) -> bool {
        !self.is_not_ready()
    }
}

/// Return type of the `Sink::start_send` method, indicating the outcome of a
/// send attempt. See `AsyncSink` for more details.
pub type StartSend<T, E> = Result<AsyncSink<T>, E>;
<|endoftext|>


<commit_before>//   Copyright Colin Sherratt 2014
//
//   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.

use std::marker::PhantomData;
use std::collections::VecDeque;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Line<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Line{x, y} = self;
        emit(x);
        emit(y);
    }
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: VecDeque<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U> {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> Self::Output where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_vertex<F>(self, mut map: F) -> Line<U> where F: FnMut(T) -> U {
        let Line{x, y} = self;
        Line {
            x: map(x),
            y: map(y),
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U>: Sized {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;

    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, Output=P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    type Output = P;

    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map,
            phantom_t: PhantomData,
            phantom_u: PhantomData
        }
    }
}

struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>
}

impl<'a, P,
         POut: MapVertex<T, U, Output=P>,
         SRC: Iterator<Item=POut>,
         T, U, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.src.size_hint()
    }

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}

/// Represents a line
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)]
pub struct Line<T> {
    /// the first point
    pub x: T,
    /// The second point
    pub y: T
}

impl<T> Line<T> {
    /// Create a new line using point x and y
    pub fn new(x: T, y: T) -> Line<T> {
        Line{x: x, y: y}
    }
}

/// Convert a Polygon into it's fragments
pub trait EmitLines {
    /// The Vertex defines the corners of a Polygon
    type Vertex;

    /// convert a polygon into lines, each line is emitted via
    /// calling of the callback of `emit` This allow for
    /// a variable amount of lines to be returned
    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<Self::Vertex>);
}

impl<T: Clone> EmitLines for Triangle<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Quad<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.w.clone()));
        emit(Line::new(self.w        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Polygon<T> {
    type Vertex = T;

    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<T>)
    {
        match self {
            Polygon::PolyTri(x) => x.emit_lines(emit),
            Polygon::PolyQuad(x) => x.emit_lines(emit)
        }
    }
}

/// Creates an LinesIterator from another Iterator
pub trait Lines: Sized {
    /// The type of each point in the lines
    type Vertex;

    /// Convert the iterator into a LinesIterator
    fn lines(self) -> LinesIterator<Self, Self::Vertex>;
}

impl<T, P, V> Lines for T
    where T: Iterator<Item=P>,
          P: EmitLines<Vertex=V>
{
    type Vertex = V;

    fn lines(self) -> LinesIterator<T, V> {
        LinesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// An iterator that turns Polygons into an Iterator of Lines
pub struct LinesIterator<I, V> {
    source: I,
    buffer: VecDeque<Line<V>>,
}

impl<I, P, V> Iterator for LinesIterator<I, V>
    where I: Iterator<Item=P>,
          P: EmitLines<Vertex=V>

{
    type Item = Line<V>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (n, _) = self.source.size_hint();
        (n, None)
    }

    fn next(&mut self) -> Option<Line<V>> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_lines(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}
<commit_msg>Fix a private-in-public error<commit_after>//   Copyright Colin Sherratt 2014
//
//   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.

use std::marker::PhantomData;
use std::collections::VecDeque;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Line<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Line{x, y} = self;
        emit(x);
        emit(y);
    }
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: VecDeque<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U> {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> Self::Output where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_vertex<F>(self, mut map: F) -> Line<U> where F: FnMut(T) -> U {
        let Line{x, y} = self;
        Line {
            x: map(x),
            y: map(y),
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U>: Sized {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;

    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, Output=P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    type Output = P;

    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map,
            phantom_t: PhantomData,
            phantom_u: PhantomData
        }
    }
}

pub struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>
}

impl<'a, P,
         POut: MapVertex<T, U, Output=P>,
         SRC: Iterator<Item=POut>,
         T, U, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.src.size_hint()
    }

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}

/// Represents a line
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)]
pub struct Line<T> {
    /// the first point
    pub x: T,
    /// The second point
    pub y: T
}

impl<T> Line<T> {
    /// Create a new line using point x and y
    pub fn new(x: T, y: T) -> Line<T> {
        Line{x: x, y: y}
    }
}

/// Convert a Polygon into it's fragments
pub trait EmitLines {
    /// The Vertex defines the corners of a Polygon
    type Vertex;

    /// convert a polygon into lines, each line is emitted via
    /// calling of the callback of `emit` This allow for
    /// a variable amount of lines to be returned
    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<Self::Vertex>);
}

impl<T: Clone> EmitLines for Triangle<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Quad<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.w.clone()));
        emit(Line::new(self.w        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Polygon<T> {
    type Vertex = T;

    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<T>)
    {
        match self {
            Polygon::PolyTri(x) => x.emit_lines(emit),
            Polygon::PolyQuad(x) => x.emit_lines(emit)
        }
    }
}

/// Creates an LinesIterator from another Iterator
pub trait Lines: Sized {
    /// The type of each point in the lines
    type Vertex;

    /// Convert the iterator into a LinesIterator
    fn lines(self) -> LinesIterator<Self, Self::Vertex>;
}

impl<T, P, V> Lines for T
    where T: Iterator<Item=P>,
          P: EmitLines<Vertex=V>
{
    type Vertex = V;

    fn lines(self) -> LinesIterator<T, V> {
        LinesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// An iterator that turns Polygons into an Iterator of Lines
pub struct LinesIterator<I, V> {
    source: I,
    buffer: VecDeque<Line<V>>,
}

impl<I, P, V> Iterator for LinesIterator<I, V>
    where I: Iterator<Item=P>,
          P: EmitLines<Vertex=V>

{
    type Item = Line<V>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (n, _) = self.source.size_hint();
        (n, None)
    }

    fn next(&mut self) -> Option<Line<V>> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_lines(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}
<|endoftext|>


<commit_before>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 250.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let p1_rect = [0.0, 0.0, self.p1.size[0], self.p1.size[1]];
        let p2_rect = [0.0, 0.0, self.p2.size[0], self.p2.size[1]];
        let ball_rect = [0.0, 0.0, self.ball.size[0], self.ball.size[1]];
        let ball = &mut self.ball;
        let p1 = &mut self.p1;
        let p2 = &mut self.p2;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            let transform = c.transform.trans(ball.pos[0], ball.pos[1])
                .trans(-ball.size[0]/2.0, -ball.size[1]/2.0);
            rectangle(WHITE, ball_rect, transform, gl);

            let transform = c.transform.trans(p1.pos[0], p1.pos[1])
                .trans(-p1.size[0]/2.0, -p1.size[1]/2.0);
            rectangle(WHITE, p1_rect, transform, gl);

            let transform = c.transform.trans(p2.pos[0], p2.pos[1])
                .trans(-p2.size[0]/2.0, -p2.size[1]/2.0);
            rectangle(WHITE, p2_rect, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            let t = (self.p2.pos[0] - self.ball.pos[0]) / self.ball.vel[0];
            let target_y = self.ball.pos[1] + self.ball.vel[1] * t;

            if target_y > self.p2.pos[1] { ai_down = true; }
            else if target_y < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
            }

            Player::Right => {
                self.server = Player::Left;
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<commit_msg>Ball speeds up after each paddle hit<commit_after>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 200.0;
static BALL_SPEED_INCREMENT: f64 = 25.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let p1_rect = [0.0, 0.0, self.p1.size[0], self.p1.size[1]];
        let p2_rect = [0.0, 0.0, self.p2.size[0], self.p2.size[1]];
        let ball_rect = [0.0, 0.0, self.ball.size[0], self.ball.size[1]];
        let ball = &mut self.ball;
        let p1 = &mut self.p1;
        let p2 = &mut self.p2;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            let transform = c.transform.trans(ball.pos[0], ball.pos[1])
                .trans(-ball.size[0]/2.0, -ball.size[1]/2.0);
            rectangle(WHITE, ball_rect, transform, gl);

            let transform = c.transform.trans(p1.pos[0], p1.pos[1])
                .trans(-p1.size[0]/2.0, -p1.size[1]/2.0);
            rectangle(WHITE, p1_rect, transform, gl);

            let transform = c.transform.trans(p2.pos[0], p2.pos[1])
                .trans(-p2.size[0]/2.0, -p2.size[1]/2.0);
            rectangle(WHITE, p2_rect, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            let t = (self.p2.pos[0] - self.ball.pos[0]) / self.ball.vel[0];
            let target_y = self.ball.pos[1] + self.ball.vel[1] * t;

            if target_y > self.p2.pos[1] { ai_down = true; }
            else if target_y < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle y velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    // increment ball x velocity a bit
                    self.ball.vel[0] += BALL_SPEED_INCREMENT *
                        self.ball.vel[0].signum();

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
            }

            Player::Right => {
                self.server = Player::Left;
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<|endoftext|>


<commit_before>extern mod linenoise;

fn handle_input(line: ~str) {
    linenoise::history_add(line);
    linenoise::history_save("history.txt");
    let split_line = str::split_char(line, ' ');
    let command = split_line.head();
    let args = split_line.tail();
    core::run::run_program(*command, args);
}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        handle_input(line);
    }
}
<commit_msg>Working multiple processes<commit_after>extern mod linenoise;

fn run_command(command: &~str) -> core::os::Pipe {
    io::println(*command);
    let pipe = core::os::pipe();
    let command_split = str::split_char(*command, ' ');
    let command_name = command_split.head();
    let command_args = command_split.tail();
    core::run::spawn_process(*command_name, command_args, ~None, ~None, pipe.in, pipe.out, pipe.out);
    pipe
}

fn handle_input(line: &str) {
    linenoise::history_add(line);
    linenoise::history_save("history.txt");
    let mut pipes = ~[];
    let commands = str::split_char(line, '|');
    for commands.each |command| {
        pipes.push(run_command(command));
    }
}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        handle_input(line);
    }
}
<|endoftext|>


<commit_before>// Semantics analyzer. This pass plays a few important roles as shown
// below:
//
// - Add types to nodes. For example, a tree that represents "1+2" is
//   typed as INT because the result type of an addition of two
//   integers is integer.
//
// - Insert nodes to make array-to-pointer conversion explicit.
//   Recall that, in C, "array of T" is automatically converted to
//   "pointer to T" in most contexts.
//
// - Scales operands for pointer arithmetic. E.g. ptr+1 becomes ptr+4
//   for integer and becomes ptr+8 for pointer.
//
// - Reject bad assignments, such as `1=2+3`.

use crate::parse::*;
use crate::token::*;
use crate::util::*;
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

fn swap(p: &mut Node, q: &mut Node) {
    mem::swap(p, q);
}

fn maybe_decay(base: & mut Node, decay: bool) -> & mut Node {
    if !decay || base.ty.borrow().ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;

    let node_ty = tmp.clone().ty;
    let ty_tmp = *node_ty.borrow().clone().ary_of.unwrap();
    base.ty = Rc::new(RefCell::new(ptr_to(Rc::new(RefCell::new(ty_tmp)))));

    base.expr = Some(Box::new(tmp));
    return base;
}

macro_rules! bad_node {
    ($node:expr, $msg:expr) => {
        bad_token(&*$node.token.clone().unwrap(), $msg.to_string());
        panic!();
    };
}

fn check_lval(node: Box<Node>) {
    match node.op {
        NodeType::VAR | NodeType::DEREF | NodeType::DOT => { }
        _ => {
            bad_node!(node, "not an lvalue");
        }
    }
}

fn scale_ptr(op: NodeType, node: Node, ty: Type) -> Node {
    let mut e = alloc_node();
    e.op = op;
    e.lhs = Some(Box::new(node.clone()));
    let ptr = ty.ptr_to.unwrap();
    e.rhs = Some(Box::new(new_int_node(ptr.borrow().size, node.token)));
    return e;
}

fn check_int(node: & Node) {
    if node.ty.borrow().ty != CType::INT {
        if node.ty.borrow().ty != CType::CHAR {
            bad_node!(node, "not an integer");
        }
    }
}

fn walk<'a>(node: &'a mut Node, prog: &'a mut Program) -> &'a Node {
    return do_walk(node, true, prog);
}

fn walk_noconv<'a>(node: &'a mut Node, prog: &'a mut Program) -> &'a Node {
    return do_walk(node, false, prog);
}

fn do_walk<'a>(node: &'a mut Node, decay: bool, prog: &'a mut Program) -> &'a Node {
    match node.op {
        NodeType::NUM |
            NodeType::NULL |
            NodeType::BREAK => {
            return node;
        }
        NodeType::VAR => {
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), prog).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), prog).clone()));

            if node.els.is_some() {
                node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), prog).clone()));
            }
            return node;
        }
        NodeType::FOR => {
            node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), prog).clone()));
            if let Some(mut cond) = node.cond.clone() {
                node.cond = Some(Box::new(walk(&mut cond, prog).clone()));
            }
            if let Some(mut inc) = node.inc.clone() {
                node.inc = Some(Box::new(walk(&mut inc, prog).clone()));
            }
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::DO_WHILE => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::ADD => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.borrow().ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }

            if let Some(ref rhs) = node.rhs {
                check_int(rhs);
            }

            if let Some(ref lhs) = node.lhs {
                if lhs.ty.borrow().ty == CType::PTR {
                    node.rhs = Some(Box::new(scale_ptr(NodeType::MUL, *node.rhs.clone().unwrap(), lhs.ty.borrow().clone())));
                }
            }

            if let Some(ref lhs) = node.lhs {
                node.ty = lhs.ty.clone();
            }
            return node;
        }
        NodeType::SUB => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

            let l = &node.rhs.clone().unwrap().ty;
            let r = &node.lhs.clone().unwrap().ty;
            if l.borrow().ty == CType::PTR && r.borrow().ty == CType::PTR {
                if !same_type(r.clone(), l.clone()) {
                    bad_node!(node, "incompatible pointer");
                }
                *node = scale_ptr(NodeType::DIV, node.clone(), l.borrow().clone());
            }

            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::ADD_EQ |
            NodeType::SUB_EQ => {
                node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
                check_lval(node.lhs.clone().unwrap());
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
                if let Some(ref lhs) = node.lhs {
                    node.ty = lhs.ty.clone();
                }

                if let Some(ref lhs) = node.lhs {
                    if lhs.ty.borrow().ty == CType::PTR {
                        node.rhs = Some(Box::new(scale_ptr(NodeType::MUL, *node.rhs.clone().unwrap(), lhs.ty.borrow().clone())));
                    }
                }
                return node;
        }

        NodeType::EQL |
            NodeType::MUL_EQ |
            NodeType::DIV_EQ |
            NodeType::MOD_EQ |
            NodeType::SHL_EQ |
            NodeType::SHR_EQ |
            NodeType::BITAND_EQ |
            NodeType::XOR_EQ |
            NodeType::BITOR_EQ => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            check_lval(node.lhs.clone().unwrap());

            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::DOT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            let node_ty = node.expr.clone().unwrap().ty;
            if node_ty.borrow().ty != CType::STRUCT {
                bad_node!(node, "struct expected before '.'");
            }

            let ty = node.expr.clone().unwrap().ty;
            if ty.borrow().members == None {
                bad_node!(node, format!("incomplete type: {:?}", node.expr));
            }

            for m in ty.borrow().clone().members.unwrap().iter() {
                if m.name != node.name {
                    continue;
                }

                node.ty = m.ty.clone();
                return maybe_decay(node, decay);
            }
            bad_node!(node, format!("member missing: {}", node.name));
        }
        NodeType::QUEST => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), prog).clone()));
            node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), prog).clone()));
            node.ty = node.then.clone().unwrap().ty;
            return node;
        }
        NodeType::MUL |
            NodeType::DIV |
            NodeType::MOD |
            NodeType::LT |
            NodeType::OR |
            NodeType::XOR |
            NodeType::AND |
            NodeType::EQ |
            NodeType::NE |
            NodeType::LE |
            NodeType::SHL |
            NodeType::SHR |
            NodeType::LOGAND |
            NodeType::LOGOR => {
                node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

                check_int(&*node.lhs.clone().unwrap());
                check_int(&*node.rhs.clone().unwrap());

                match node.lhs {
                    Some(ref lhs) => {
                        node.ty = lhs.ty.clone();
                    }
                    None => { }
                }
                return node;
            }
        NodeType::COMMA => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
            node.ty = node.rhs.clone().unwrap().ty;
            return node;
        }
        NodeType::POST_INC |
            NodeType::POST_DEC |
            NodeType::NEG |
            NodeType::EXCLAM |
            NodeType::NOT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            node.ty = node.expr.clone().unwrap().ty;
            return node;
        }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            check_lval(node.expr.clone().unwrap());
            node.ty = Rc::new(RefCell::new(ptr_to(node.expr.clone().unwrap().ty)));
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));

            match &mut node.expr {
                Some(ref expr) => {
                    if expr.ty.borrow().ty != CType::PTR {
                        bad_node!(node, format!("operand must be a pointer: {:?}", expr));
                    }

                    let ptr = expr.ty.borrow().ptr_to.clone().unwrap();
                    if ptr.borrow().ty == CType::VOID {
                        bad_node!(node, "operand dereference void pointer");
                    }
                }
                None => {}
            }

            let ty_tmp = node.expr.clone().unwrap().ty;
            node.ty = ty_tmp.borrow().clone().ptr_to.unwrap();
            return maybe_decay(node, decay);
        }
        NodeType::RETURN |
            NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], prog).clone();
            }
            let node_ty = *node.ty.borrow().clone().returning.unwrap();
            node.ty = Rc::new(RefCell::new(node_ty));
            return node;
        }
        NodeType::COMP_STMT => {
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut node.stmts[i], prog).clone();
            }
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            node.ty = Rc::new(RefCell::new(int_ty()));
            return node;
        }
        _ => {
            panic!("unknown node type: {:?}", node);
        }
    }
}

fn sema_funcdef(node: Rc<RefCell<Node>>, prog: &mut Program) {
    let mut args = Vec::new();
    for a in node.borrow_mut().args.iter_mut() {
        args.push(walk(&mut a.clone(), prog).clone());
    }
    node.borrow_mut().args = args;
    let mut body = node.borrow_mut().body.clone().unwrap();
    node.borrow_mut().body = Some(Box::new(walk(&mut body, prog).clone()));

    let mut off = 0;
    for v in node.borrow_mut().lvars.iter_mut() {
        off = roundup(off, v.borrow().ty.align);
        off += v.borrow().ty.size;
        v.borrow_mut().offset = off;
    }
    node.borrow_mut().stacksize = off;
}

pub fn get_type(node: &mut Node) -> Type {
    let mut prog = new_program();
    return walk_noconv(node, &mut prog).ty.borrow().clone();
}

pub fn sema(prog: &mut Program) {
    let nodes = prog.nodes.clone();

    for node in nodes.iter() {
        if node.borrow().op == NodeType::DECL {
            continue;
        }

        assert!(node.borrow().op == NodeType::FUNC);
        sema_funcdef(node.clone(), prog);
    }

    prog.nodes = nodes;
}
<commit_msg>More error checks.<commit_after>// Semantics analyzer. This pass plays a few important roles as shown
// below:
//
// - Add types to nodes. For example, a tree that represents "1+2" is
//   typed as INT because the result type of an addition of two
//   integers is integer.
//
// - Insert nodes to make array-to-pointer conversion explicit.
//   Recall that, in C, "array of T" is automatically converted to
//   "pointer to T" in most contexts.
//
// - Scales operands for pointer arithmetic. E.g. ptr+1 becomes ptr+4
//   for integer and becomes ptr+8 for pointer.
//
// - Reject bad assignments, such as `1=2+3`.

use crate::parse::*;
use crate::token::*;
use crate::util::*;
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

fn swap(p: &mut Node, q: &mut Node) {
    mem::swap(p, q);
}

fn maybe_decay(base: & mut Node, decay: bool) -> & mut Node {
    if !decay || base.ty.borrow().ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;

    let node_ty = tmp.clone().ty;
    let ty_tmp = *node_ty.borrow().clone().ary_of.unwrap();
    base.ty = Rc::new(RefCell::new(ptr_to(Rc::new(RefCell::new(ty_tmp)))));

    base.expr = Some(Box::new(tmp.clone()));
    base.token = tmp.token.clone();
    return base;
}

macro_rules! bad_node {
    ($node:expr, $msg:expr) => {
        bad_token(&*$node.token.clone().unwrap(), $msg.to_string());
        panic!();
    };
}

fn check_lval(node: Box<Node>) {
    match node.op {
        NodeType::VAR | NodeType::DEREF | NodeType::DOT => { }
        _ => {
            bad_node!(node, "not an lvalue");
        }
    }
}

fn scale_ptr(op: NodeType, base: Node, ty: Type) -> Node {
    let mut node = alloc_node();
    node.op = op;
    node.lhs = Some(Box::new(base.clone()));
    let ptr = ty.ptr_to.unwrap();
    node.rhs = Some(Box::new(new_int_node(ptr.borrow().size, base.token.clone())));
    node.token = base.token.clone();
    return node;
}

fn check_int(node: & Node) {
    if node.ty.borrow().ty != CType::INT {
        if node.ty.borrow().ty != CType::CHAR {
            bad_node!(node, "not an integer");
        }
    }
}

fn walk<'a>(node: &'a mut Node, prog: &'a mut Program) -> &'a Node {
    return do_walk(node, true, prog);
}

fn walk_noconv<'a>(node: &'a mut Node, prog: &'a mut Program) -> &'a Node {
    return do_walk(node, false, prog);
}

fn do_walk<'a>(node: &'a mut Node, decay: bool, prog: &'a mut Program) -> &'a Node {
    match node.op {
        NodeType::NUM |
            NodeType::NULL |
            NodeType::BREAK => {
            return node;
        }
        NodeType::VAR => {
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), prog).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), prog).clone()));

            if node.els.is_some() {
                node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), prog).clone()));
            }
            return node;
        }
        NodeType::FOR => {
            node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), prog).clone()));
            if let Some(mut cond) = node.cond.clone() {
                node.cond = Some(Box::new(walk(&mut cond, prog).clone()));
            }
            if let Some(mut inc) = node.inc.clone() {
                node.inc = Some(Box::new(walk(&mut inc, prog).clone()));
            }
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::DO_WHILE => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::ADD => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.borrow().ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }

            if let Some(ref rhs) = node.rhs {
                check_int(rhs);
            }

            if let Some(ref lhs) = node.lhs {
                if lhs.ty.borrow().ty == CType::PTR {
                    node.rhs = Some(Box::new(scale_ptr(NodeType::MUL, *node.rhs.clone().unwrap(), lhs.ty.borrow().clone())));
                }
            }

            if let Some(ref lhs) = node.lhs {
                node.ty = lhs.ty.clone();
            }
            return node;
        }
        NodeType::SUB => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

            let l = &node.rhs.clone().unwrap().ty;
            let r = &node.lhs.clone().unwrap().ty;
            if l.borrow().ty == CType::PTR && r.borrow().ty == CType::PTR {
                if !same_type(r.clone(), l.clone()) {
                    bad_node!(node, "incompatible pointer");
                }
                *node = scale_ptr(NodeType::DIV, node.clone(), l.borrow().clone());
            }

            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::ADD_EQ |
            NodeType::SUB_EQ => {
                node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
                check_lval(node.lhs.clone().unwrap());
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
                if let Some(ref lhs) = node.lhs {
                    node.ty = lhs.ty.clone();
                }

                if let Some(ref lhs) = node.lhs {
                    if lhs.ty.borrow().ty == CType::PTR {
                        node.rhs = Some(Box::new(scale_ptr(NodeType::MUL, *node.rhs.clone().unwrap(), lhs.ty.borrow().clone())));
                    }
                }
                return node;
        }

        NodeType::EQL |
            NodeType::MUL_EQ |
            NodeType::DIV_EQ |
            NodeType::MOD_EQ |
            NodeType::SHL_EQ |
            NodeType::SHR_EQ |
            NodeType::BITAND_EQ |
            NodeType::XOR_EQ |
            NodeType::BITOR_EQ => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            check_lval(node.lhs.clone().unwrap());

            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
            node.ty = node.lhs.clone().unwrap().ty;
            return node;
        }
        NodeType::DOT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            let node_ty = node.expr.clone().unwrap().ty;
            if node_ty.borrow().ty != CType::STRUCT {
                bad_node!(node, "struct expected before '.'");
            }

            let ty = node.expr.clone().unwrap().ty;
            if ty.borrow().members == None {
                bad_node!(node, format!("incomplete type: {:?}", node.expr));
            }

            for m in ty.borrow().clone().members.unwrap().iter() {
                if m.name != node.name {
                    continue;
                }

                node.ty = m.ty.clone();
                return maybe_decay(node, decay);
            }
            bad_node!(node, format!("member missing: {}", node.name));
        }
        NodeType::QUEST => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), prog).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), prog).clone()));
            node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), prog).clone()));
            node.ty = node.then.clone().unwrap().ty;
            return node;
        }
        NodeType::MUL |
            NodeType::DIV |
            NodeType::MOD |
            NodeType::LT |
            NodeType::OR |
            NodeType::XOR |
            NodeType::AND |
            NodeType::EQ |
            NodeType::NE |
            NodeType::LE |
            NodeType::SHL |
            NodeType::SHR |
            NodeType::LOGAND |
            NodeType::LOGOR => {
                node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));

                check_int(&*node.lhs.clone().unwrap());
                check_int(&*node.rhs.clone().unwrap());

                match node.lhs {
                    Some(ref lhs) => {
                        node.ty = lhs.ty.clone();
                    }
                    None => { }
                }
                node.ty = Rc::new(RefCell::new(int_ty()));
                return node;
            }
        NodeType::COMMA => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), prog).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), prog).clone()));
            node.ty = node.rhs.clone().unwrap().ty;
            return node;
        }
        NodeType::POST_INC | NodeType::POST_DEC | NodeType::NEG => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            node.ty = node.expr.clone().unwrap().ty;
            return node;
        }
        NodeType::EXCLAM | NodeType::NOT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            check_int(&*node.expr.clone().unwrap());
            node.ty = node.expr.clone().unwrap().ty;
            return node;
        }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            check_lval(node.expr.clone().unwrap());
            node.ty = Rc::new(RefCell::new(ptr_to(node.expr.clone().unwrap().ty)));
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));

            match &mut node.expr {
                Some(ref expr) => {
                    if expr.ty.borrow().ty != CType::PTR {
                        bad_node!(node, format!("operand must be a pointer: {:?}", expr));
                    }

                    let ptr = expr.ty.borrow().ptr_to.clone().unwrap();
                    if ptr.borrow().ty == CType::VOID {
                        bad_node!(node, "operand dereference void pointer");
                    }
                }
                None => {}
            }

            let ty_tmp = node.expr.clone().unwrap().ty;
            node.ty = ty_tmp.borrow().clone().ptr_to.unwrap();
            return maybe_decay(node, decay);
        }
        NodeType::RETURN |
            NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), prog).clone()));
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], prog).clone();
            }
            let node_ty = *node.ty.borrow().clone().returning.unwrap();
            node.ty = Rc::new(RefCell::new(node_ty));
            return node;
        }
        NodeType::COMP_STMT => {
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut node.stmts[i], prog).clone();
            }
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), prog).clone()));
            node.ty = Rc::new(RefCell::new(int_ty()));
            return node;
        }
        _ => {
            panic!("unknown node type: {:?}", node);
        }
    }
}

fn sema_funcdef(node: Rc<RefCell<Node>>, prog: &mut Program) {
    let mut args = Vec::new();
    for a in node.borrow_mut().args.iter_mut() {
        args.push(walk(&mut a.clone(), prog).clone());
    }
    node.borrow_mut().args = args;
    let mut body = node.borrow_mut().body.clone().unwrap();
    node.borrow_mut().body = Some(Box::new(walk(&mut body, prog).clone()));

    let mut off = 0;
    for v in node.borrow_mut().lvars.iter_mut() {
        off = roundup(off, v.borrow().ty.align);
        off += v.borrow().ty.size;
        v.borrow_mut().offset = off;
    }
    node.borrow_mut().stacksize = off;
}

pub fn get_type(node: &mut Node) -> Type {
    let mut prog = new_program();
    return walk_noconv(node, &mut prog).ty.borrow().clone();
}

pub fn sema(prog: &mut Program) {
    let nodes = prog.nodes.clone();

    for node in nodes.iter() {
        if node.borrow().op == NodeType::DECL {
            continue;
        }

        assert!(node.borrow().op == NodeType::FUNC);
        sema_funcdef(node.clone(), prog);
    }

    prog.nodes = nodes;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Cesar Eduardo Barros
//
// 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.

#[cfg(feature = "simd")]
use std::mem::transmute;

#[cfg(feature = "simd")]
pub use simdty::{u32x4, u64x4};

#[cfg(not(feature = "simd"))]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[cfg(not(feature = "simd"))]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub struct u64x4(pub u64, pub u64, pub u64, pub u64);

#[cfg(not(feature = "simd"))]
use std::ops::BitXor;

macro_rules! impl_bitxor {
    ($vec:ident) => {
        #[cfg(not(feature = "simd"))]
        impl BitXor for $vec {
            type Output = Self;

            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                $vec(self.0 ^ rhs.0,
                     self.1 ^ rhs.1,
                     self.2 ^ rhs.2,
                     self.3 ^ rhs.3)
            }
        }
    }
}

impl_bitxor!(u32x4);
impl_bitxor!(u64x4);

pub trait Vector: Copy {
    fn from_le(self) -> Self;
    fn to_le(self) -> Self;

    fn wrapping_add(self, rhs: Self) -> Self;

    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self { self.rotate_right_any(n) }
    fn rotate_right_any(self, n: u32) -> Self;

    fn shuffle_left_1(self) -> Self;
    fn shuffle_left_2(self) -> Self;
    fn shuffle_left_3(self) -> Self;

    #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() }
    #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() }
    #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() }
}

macro_rules! impl_vector_common {
    ($vec:ident, $word:ident, $bits:expr) => {
        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn from_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn from_le(self) -> Self {
            $vec($word::from_le(self.0),
                 $word::from_le(self.1),
                 $word::from_le(self.2),
                 $word::from_le(self.3))
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn to_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn to_le(self) -> Self {
            $vec(self.0.to_le(),
                 self.1.to_le(),
                 self.2.to_le(),
                 self.3.to_le())
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self { self + rhs }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self {
            $vec(self.0.wrapping_add(rhs.0),
                 self.1.wrapping_add(rhs.1),
                 self.2.wrapping_add(rhs.2),
                 self.3.wrapping_add(rhs.3))
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            let r = n as $word;
            let l = $bits - r;

            (self >> $vec(r, r, r, r)) | (self << $vec(l, l, l, l))
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            $vec(self.0.rotate_right(n),
                 self.1.rotate_right(n),
                 self.2.rotate_right(n),
                 self.3.rotate_right(n))
        }

        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            $vec(self.1, self.2, self.3, self.0)
        }

        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            $vec(self.2, self.3, self.0, self.1)
        }

        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            $vec(self.3, self.0, self.1, self.2)
        }
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u32x4_rotate_right_16(vec: u32x4) -> u32x4 {
    use simdty::u16x8;
    unsafe {
        let tmp: u16x8 = transmute(vec);
        transmute(u16x8(tmp.1, tmp.0,
                        tmp.3, tmp.2,
                        tmp.5, tmp.4,
                        tmp.7, tmp.6))
    }
}

impl Vector for u32x4 {
    impl_vector_common!(u32x4, u32, 32);

    #[cfg(feature = "simd")]
    #[cfg(any(target_arch = "arm", target_arch = "aarch64",
              target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            16 => u32x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_32(vec: u64x4) -> u64x4 {
    use simdty::u32x8;
    unsafe {
        let tmp: u32x8 = transmute(vec);
        transmute(u32x8(tmp.1, tmp.0,
                        tmp.3, tmp.2,
                        tmp.5, tmp.4,
                        tmp.7, tmp.6))
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_16(vec: u64x4) -> u64x4 {
    use simdty::u16x16;
    unsafe {
        let tmp: u16x16 = transmute(vec);
        transmute(u16x16(tmp.1,  tmp.2,  tmp.3,  tmp.0,
                         tmp.5,  tmp.6,  tmp.7,  tmp.4,
                         tmp.9,  tmp.10, tmp.11, tmp.8,
                         tmp.13, tmp.14, tmp.15, tmp.12))
    }
}

impl Vector for u64x4 {
    impl_vector_common!(u64x4, u64, 64);

    #[cfg(feature = "simd")]
    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd")]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            16 => u64x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}
<commit_msg>Use inline assembly for VEXT on NEON<commit_after>// Copyright (c) 2015 Cesar Eduardo Barros
//
// 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.

#[cfg(feature = "simd")]
use std::mem::transmute;

#[cfg(feature = "simd")]
pub use simdty::{u32x4, u64x4};

#[cfg(not(feature = "simd"))]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[cfg(not(feature = "simd"))]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub struct u64x4(pub u64, pub u64, pub u64, pub u64);

#[cfg(not(feature = "simd"))]
use std::ops::BitXor;

macro_rules! impl_bitxor {
    ($vec:ident) => {
        #[cfg(not(feature = "simd"))]
        impl BitXor for $vec {
            type Output = Self;

            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                $vec(self.0 ^ rhs.0,
                     self.1 ^ rhs.1,
                     self.2 ^ rhs.2,
                     self.3 ^ rhs.3)
            }
        }
    }
}

impl_bitxor!(u32x4);
impl_bitxor!(u64x4);

pub trait Vector: Copy {
    fn from_le(self) -> Self;
    fn to_le(self) -> Self;

    fn wrapping_add(self, rhs: Self) -> Self;

    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self { self.rotate_right_any(n) }
    fn rotate_right_any(self, n: u32) -> Self;

    fn shuffle_left_1(self) -> Self;
    fn shuffle_left_2(self) -> Self;
    fn shuffle_left_3(self) -> Self;

    #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() }
    #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() }
    #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() }
}

macro_rules! impl_vector_common {
    ($vec:ident, $word:ident, $bits:expr) => {
        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn from_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn from_le(self) -> Self {
            $vec($word::from_le(self.0),
                 $word::from_le(self.1),
                 $word::from_le(self.2),
                 $word::from_le(self.3))
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn to_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn to_le(self) -> Self {
            $vec(self.0.to_le(),
                 self.1.to_le(),
                 self.2.to_le(),
                 self.3.to_le())
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self { self + rhs }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self {
            $vec(self.0.wrapping_add(rhs.0),
                 self.1.wrapping_add(rhs.1),
                 self.2.wrapping_add(rhs.2),
                 self.3.wrapping_add(rhs.3))
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            let r = n as $word;
            let l = $bits - r;

            (self >> $vec(r, r, r, r)) | (self << $vec(l, l, l, l))
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            $vec(self.0.rotate_right(n),
                 self.1.rotate_right(n),
                 self.2.rotate_right(n),
                 self.3.rotate_right(n))
        }

        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            $vec(self.1, self.2, self.3, self.0)
        }

        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            $vec(self.2, self.3, self.0, self.1)
        }

        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            $vec(self.3, self.0, self.1, self.2)
        }
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u32x4_rotate_right_16(vec: u32x4) -> u32x4 {
    use simdty::u16x8;
    unsafe {
        let tmp: u16x8 = transmute(vec);
        transmute(u16x8(tmp.1, tmp.0,
                        tmp.3, tmp.2,
                        tmp.5, tmp.4,
                        tmp.7, tmp.6))
    }
}

impl Vector for u32x4 {
    impl_vector_common!(u32x4, u32, 32);

    #[cfg(feature = "simd")]
    #[cfg(any(target_arch = "arm", target_arch = "aarch64",
              target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            16 => u32x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_32(vec: u64x4) -> u64x4 {
    use simdty::u32x8;
    unsafe {
        let tmp: u32x8 = transmute(vec);
        transmute(u32x8(tmp.1, tmp.0,
                        tmp.3, tmp.2,
                        tmp.5, tmp.4,
                        tmp.7, tmp.6))
    }
}

#[cfg(feature = "simd")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_16(vec: u64x4) -> u64x4 {
    use simdty::u16x16;
    unsafe {
        let tmp: u16x16 = transmute(vec);
        transmute(u16x16(tmp.1,  tmp.2,  tmp.3,  tmp.0,
                         tmp.5,  tmp.6,  tmp.7,  tmp.4,
                         tmp.9,  tmp.10, tmp.11, tmp.8,
                         tmp.13, tmp.14, tmp.15, tmp.12))
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
use simdty::u64x2;

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn vext_u64_u8(a: u64x2, b: u8) -> u64x2 {
    unsafe {
        let result: u64x2;
        asm!("vext.8 ${0:e}, ${1:e}, ${1:e}, $2\nvext.8 ${0:f}, ${1:f}, ${1:f}, $2"
           : "=w" (result)
           : "w" (a), "n" (b));
        result
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn u64x4_rotate_right_u8(vec: u64x4, n: u8) -> u64x4 {
    let tmp0 = vext_u64_u8(u64x2(vec.0, vec.1), n);
    let tmp1 = vext_u64_u8(u64x2(vec.2, vec.3), n);
    u64x4(tmp0.0, tmp0.1, tmp1.0, tmp1.1)
}

impl Vector for u64x4 {
    impl_vector_common!(u64x4, u64, 64);

    #[cfg(feature = "simd")]
    #[cfg(any(all(target_arch = "arm", not(feature = "simd_asm")),
              target_arch = "aarch64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd_asm")]
    #[cfg(target_arch = "arm")]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            24 => u64x4_rotate_right_u8(self, 3),
            16 => u64x4_rotate_right_u8(self, 2),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd")]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            16 => u64x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}
<|endoftext|>