<commit_before>//#![crate_name = "mesh"]
#![feature(old_io)]
//mod mesh;

use std::cmp::*;
use std::collections::HashMap;
use std::f32::NAN;
use std::fmt;
use std::old_io::{BufferedReader,Reader};
use std::hash::{Hash, Hasher};
use std::mem::{transmute};
use std::vec::Vec;

#[derive(PartialEq, PartialOrd, Copy)] //Show,
pub struct Vector3D {
    x: f32,
    y: f32,
    z: f32,
}

// PartialEq is derived above, but we need to impl Eq since floats don't get
// it by default. This function is just a
impl Eq for Vector3D {
    #[inline(always)]
    fn assert_receiver_is_total_eq(&self) {}
}

impl fmt::Debug for Vector3D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({},{},{})", self.x, self.y, self.z)
    }
}

impl Vector3D {
    fn read(r: &mut Reader) -> Vector3D {
        let xr = r.read_le_f32();
        let yr = r.read_le_f32();
        let zr = r.read_le_f32();
        if xr.is_ok() && yr.is_ok() && zr.is_ok() {
            let v = Vector3D { x: xr.ok().unwrap(), y: yr.ok().unwrap(), z: zr.ok().unwrap() };
            return v
        }
        return Vector3D { x: NAN, y: NAN, z: NAN };
    }
}

// Implement Hash since there is no default for f32. We'll just hash the bits
// since we know the f32s will all be canonical from reading.
impl Hash for Vector3D {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        //println!("V3D hash {:p}", self);
        let x: u32 = unsafe { transmute(self.x) };
        x.hash(state);
        let y: u32 = unsafe { transmute(self.y) };
        y.hash(state);
        let z: u32 = unsafe { transmute(self.z) };
        z.hash(state);
        //println!("V3D hash done {:p}", self);
    }
}

#[derive(PartialEq, Eq, Hash, Copy)]
pub struct StlFacet {
    n : Vector3D,
    v1: Vector3D,
    v2: Vector3D,
    v3: Vector3D,
    abc: u16,
}

impl fmt::Debug for StlFacet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?}]({:?}-{:?}-{:?})[{:X}]",
            &self.n, &self.v1, &self.v2, &self.v3, self.abc)
    }
}

impl StlFacet {
    fn read(r: &mut Reader) -> StlFacet {
        let n = Vector3D::read(r);
        let v1 = Vector3D::read(r);
        let v2 = Vector3D::read(r);
        let v3 = Vector3D::read(r);
        let abc = r.read_le_u16().unwrap();
        StlFacet { n:n, v1:v1, v2:v2, v3:v3, abc:abc }
    }
}

pub struct VertexMap {
    vertices: HashMap<Vector3D,usize>,
}

impl VertexMap {
    pub fn new() -> VertexMap {
        VertexMap {
            vertices: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.vertices.len()
    }

    pub fn get(&self, v3d: &Vector3D) -> usize {
        *self.vertices.get(v3d).unwrap()
    }

    pub fn add(&mut self, vertex: Vector3D) -> usize {
        if self.vertices.contains_key(&vertex) {
            //println!("add existing {}", vector3d_str(&vertex));
            *self.vertices.get(&vertex).unwrap()
        } else {
            //println!("add new {}", vector3d_str(&vertex));
            let idx = self.vertices.len();
            self.vertices.insert(vertex, idx);
            idx
        }
    }

    pub fn vector(&self) -> Vec<Vector3D> {
        let mut v: Vec<Vector3D> = Vec::with_capacity(self.vertices.len());
        for (v3d, idx) in self.vertices.iter() {
            v.push(*v3d);  // Funkiness just to get v expanded. Below writes the real values.
        }
        for (v3d, idx) in self.vertices.iter() {
            //println!("v3d:{:?} idx:{}", v3d, idx);
            v[*idx] = *v3d;
        }
        //for i in 0..v.len() {
        //    println!("v3d[{}]: {:?}", i, v[i]);
        //}
        v
    }
}

#[derive(PartialEq, Debug, Eq, Hash, Copy)]
pub struct Facet {
    v1: usize,
    v2: usize,
    v3: usize,
}

pub struct Mesh {
    vertices: Vec<Vector3D>,
    facets: Vec<Facet>,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertices: Vec::new(),
            facets: Vec::new(),
        }
    }

    fn indexed_vertices(fv: &Vec<StlFacet>, vm: &VertexMap) -> Vec<Facet> {
        let mut v: Vec<Facet> = Vec::with_capacity(fv.len());
        for f in fv.iter() {
            let v1 = vm.get(&f.v1);
            let v2 = vm.get(&f.v2);
            let v3 = vm.get(&f.v3);
            v.push(Facet{
                v1: v1,
                v2: v2,
                v3: v3,
            })
        }
        v
    }

    pub fn new_from_stl(fv: &Vec<StlFacet>, vm: &VertexMap) -> Mesh {
        let vs = vm.vector();
        let fs = Mesh::indexed_vertices(fv, vm);
        Mesh {
            vertices: vs,
            facets: fs,
        }
    }

    pub fn read(r: &mut Reader) -> Mesh {

        /*
        let buf = [0; 80];
        let header = match r.read(&buf) {
            Ok(nread) => {
                let hdr = String::from_utf8(&buf).unwrap();
                println!("Header: \"{}\"", hdr);
                hdr
            }
            Err(e) => {
                println!("Truncated file: {}", e);
                return Mesh{vertices: Vec::new(), facets: Vec::new()};
            }
        };

        return if header.starts_with("solid ") {
            println!("Is ASCII STL");
            Mesh::read_ascii(r)
        }
        else {
            println!("Is binary STL");
            Mesh::read_binary(r)
        }
        */
        Mesh::read_binary(r)
    }

    /*
    fn read_ascii(r: &mut Reader) -> Mesh {
        //solid vcg
        //  facet normal 7.733874e-001 -3.151335e-002 6.331499e-001
        //    outer loop
        //      vertex  2.137833e+001 5.385936e+001 1.350253e+001
        //      vertex  2.341920e+001 4.700068e+001 1.066826e+001
        //      vertex  2.859041e+001 5.985682e+001 4.991545e+000
        //    endloop
        //  endfacet
        //endsolid vcg
        for line in r.lines() {
            print!("{}", line.unwrap());
        }
        Mesh::new() // TODO
    }
    */

    fn read_binary(r: &mut Reader) -> Mesh {
        let facet_count = match r.read_le_u32() {
            Ok(c) => { println!("Facets: {}", c); c},
            Err(e) => { println!("Truncated file: {}", e); 0},
        };

        let mut facets: Vec<StlFacet> = Vec::with_capacity(facet_count as usize);
        let mut vertices = VertexMap::new();
        println!("Collections ready");

        for fi in range(0, facet_count) {
            let f = StlFacet::read(r);
            let v1i = vertices.add(f.v1);
            let v2i = vertices.add(f.v2);
            let v3i = vertices.add(f.v3);
            println!("  Facet[{}]: {:?} => {}-{}-{}", fi, f, v1i, v2i, v3i);
            facets.push(f);
        }
        println!("Vertices: {}", vertices.len());

        Mesh::new_from_stl(&facets, &vertices)
    }
}
<commit_msg>Add in normalize calculation.<commit_after>//#![crate_name = "mesh"]
#![feature(old_io)]
//mod mesh;

use std::cmp::*;
use std::collections::HashMap;
use std::f32::NAN;
use std::fmt;
use std::num::Float;
use std::old_io::{BufferedReader,Reader};
use std::hash::{Hash, Hasher};
use std::mem::{transmute};
use std::vec::Vec;

#[derive(PartialEq, PartialOrd, Copy)] //Show,
pub struct Vector3D {
    x: f32,
    y: f32,
    z: f32,
}

// PartialEq is derived above, but we need to impl Eq since floats don't get
// it by default. This function is just a
impl Eq for Vector3D {
    #[inline(always)]
    fn assert_receiver_is_total_eq(&self) {}
}

impl fmt::Debug for Vector3D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({},{},{})", self.x, self.y, self.z)
    }
}

impl Vector3D {
    fn read(r: &mut Reader) -> Vector3D {
        let xr = r.read_le_f32();
        let yr = r.read_le_f32();
        let zr = r.read_le_f32();
        if xr.is_ok() && yr.is_ok() && zr.is_ok() {
            let v = Vector3D { x: xr.ok().unwrap(), y: yr.ok().unwrap(), z: zr.ok().unwrap() };
            return v
        }
        return Vector3D { x: NAN, y: NAN, z: NAN };
    }
    fn minus(&self, o: Vector3D) -> Vector3D {
		let x = self.x - o.x;
		let y = self.y - o.y;
		let z = self.z - o.z;
		Vector3D {
			x: x,
			y: y,
			z: z
		}
	}

	fn cross(a: Vector3D, b:Vector3D) -> Vector3D {
		let cx = a.y * b.z - a.z * b.y;
		let cy = a.z * b.x - a.x * b.z;
		let cz = a.x * b.y - a.y * b.x;
		Vector3D {
		x: cx,
		y: cy,
		z: cz
		}
	}

	fn normalize(&self) -> Vector3D {
		// length = sqrt((ax * ax) + (ay * ay) + (az * az))
		let length = (self.x * self.x + self.y * self.y + self.z * self.z).sqrt();
		let x = self.x / length;
		let y = self.y / length;
		let z = self.z / length;
		Vector3D {
			x: x,
		    y: y,
		    z: z
		}
	}
}

// Implement Hash since there is no default for f32. We'll just hash the bits
// since we know the f32s will all be canonical from reading.
impl Hash for Vector3D {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        //println!("V3D hash {:p}", self);
        let x: u32 = unsafe { transmute(self.x) };
        x.hash(state);
        let y: u32 = unsafe { transmute(self.y) };
        y.hash(state);
        let z: u32 = unsafe { transmute(self.z) };
        z.hash(state);
        //println!("V3D hash done {:p}", self);
    }
}

#[derive(PartialEq, Eq, Hash, Copy)]
pub struct StlFacet {
    n : Vector3D,
    v1: Vector3D,
    v2: Vector3D,
    v3: Vector3D,
    abc: u16,
}

impl fmt::Debug for StlFacet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?}]({:?}-{:?}-{:?})[{:X}]",
            &self.n, &self.v1, &self.v2, &self.v3, self.abc)
    }
}

impl StlFacet {
    fn read(r: &mut Reader) -> StlFacet {
        let n = Vector3D::read(r);
        let v1 = Vector3D::read(r);
        let v2 = Vector3D::read(r);
        let v3 = Vector3D::read(r);
        let abc = r.read_le_u16().unwrap();
        StlFacet { n:n, v1:v1, v2:v2, v3:v3, abc:abc }
    }

    fn calculate_normal_vector(&self) -> Vector3D {
		// Dir = (B - A) x (C - A)
		// Norm = Dir / len(Dir)
        let direction = Vector3D::cross( self.v2.minus(self.v1), self.v3.minus(self.v1) );

		// Normalize is optional in our use case
		direction.normalize()
	}
}

pub struct VertexMap {
    vertices: HashMap<Vector3D,usize>,
}

impl VertexMap {
    pub fn new() -> VertexMap {
        VertexMap {
            vertices: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.vertices.len()
    }

    pub fn get(&self, v3d: &Vector3D) -> usize {
        *self.vertices.get(v3d).unwrap()
    }

    pub fn add(&mut self, vertex: Vector3D) -> usize {
        if self.vertices.contains_key(&vertex) {
            //println!("add existing {}", vector3d_str(&vertex));
            *self.vertices.get(&vertex).unwrap()
        } else {
            //println!("add new {}", vector3d_str(&vertex));
            let idx = self.vertices.len();
            self.vertices.insert(vertex, idx);
            idx
        }
    }

    pub fn vector(&self) -> Vec<Vector3D> {
        let mut v: Vec<Vector3D> = Vec::with_capacity(self.vertices.len());
        for (v3d, idx) in self.vertices.iter() {
            v.push(*v3d);  // Funkiness just to get v expanded. Below writes the real values.
        }
        for (v3d, idx) in self.vertices.iter() {
            //println!("v3d:{:?} idx:{}", v3d, idx);
            v[*idx] = *v3d;
        }
        //for i in 0..v.len() {
        //    println!("v3d[{}]: {:?}", i, v[i]);
        //}
        v
    }
}

#[derive(PartialEq, Debug, Eq, Hash, Copy)]
pub struct Facet {
    v1: usize,
    v2: usize,
    v3: usize,
}

pub struct Mesh {
    vertices: Vec<Vector3D>,
    facets: Vec<Facet>,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertices: Vec::new(),
            facets: Vec::new(),
        }
    }

    fn indexed_vertices(fv: &Vec<StlFacet>, vm: &VertexMap) -> Vec<Facet> {
        let mut v: Vec<Facet> = Vec::with_capacity(fv.len());
        for f in fv.iter() {
            let v1 = vm.get(&f.v1);
            let v2 = vm.get(&f.v2);
            let v3 = vm.get(&f.v3);
			// I wish there was a better place to put this
			let n = f.calculate_normal_vector();
            v.push(Facet{
                v1: v1,
                v2: v2,
                v3: v3,
            })
        }
        v
    }

    pub fn new_from_stl(fv: &Vec<StlFacet>, vm: &VertexMap) -> Mesh {
        let vs = vm.vector();
        let fs = Mesh::indexed_vertices(fv, vm);
        Mesh {
            vertices: vs,
            facets: fs,
        }
    }

    pub fn read(r: &mut Reader) -> Mesh {

        /*
        let buf = [0; 80];
        let header = match r.read(&buf) {
            Ok(nread) => {
                let hdr = String::from_utf8(&buf).unwrap();
                println!("Header: \"{}\"", hdr);
                hdr
            }
            Err(e) => {
                println!("Truncated file: {}", e);
                return Mesh{vertices: Vec::new(), facets: Vec::new()};
            }
        };

        return if header.starts_with("solid ") {
            println!("Is ASCII STL");
            Mesh::read_ascii(r)
        }
        else {
            println!("Is binary STL");
            Mesh::read_binary(r)
        }
        */
        Mesh::read_binary(r)
    }

    /*
    fn read_ascii(r: &mut Reader) -> Mesh {
        //solid vcg
        //  facet normal 7.733874e-001 -3.151335e-002 6.331499e-001
        //    outer loop
        //      vertex  2.137833e+001 5.385936e+001 1.350253e+001
        //      vertex  2.341920e+001 4.700068e+001 1.066826e+001
        //      vertex  2.859041e+001 5.985682e+001 4.991545e+000
        //    endloop
        //  endfacet
        //endsolid vcg
        for line in r.lines() {
            print!("{}", line.unwrap());
        }
        Mesh::new() // TODO
    }
    */

    fn read_binary(r: &mut Reader) -> Mesh {
        let facet_count = match r.read_le_u32() {
            Ok(c) => { println!("Facets: {}", c); c},
            Err(e) => { println!("Truncated file: {}", e); 0},
        };

        let mut facets: Vec<StlFacet> = Vec::with_capacity(facet_count as usize);
        let mut vertices = VertexMap::new();
        println!("Collections ready");

        for fi in range(0, facet_count) {
            let f = StlFacet::read(r);
            let v1i = vertices.add(f.v1);
            let v2i = vertices.add(f.v2);
            let v3i = vertices.add(f.v3);
            println!("  Facet[{}]: {:?} => {}-{}-{}", fi, f, v1i, v2i, v3i);
            facets.push(f);
        }
        println!("Vertices: {}", vertices.len());

        Mesh::new_from_stl(&facets, &vertices)
    }
}
<|endoftext|>


<commit_before>use super::{ParallelIterator, ParallelIteratorState, ParallelLen};
use std::marker::PhantomData;

pub struct Map<M, MAP_OP> {
    base: M,
    map_op: MAP_OP,
}

impl<M, MAP_OP> Map<M, MAP_OP> {
    pub fn new(base: M, map_op: MAP_OP) -> Map<M, MAP_OP> {
        Map { base: base, map_op: map_op }
    }
}

impl<M, MAP_OP, R> ParallelIterator for Map<M, MAP_OP>
    where M: ParallelIterator,
          MAP_OP: Fn(M::Item) -> R + Sync,
          R: Send,
{
    type Item = R;
    type Shared = MapShared<M, MAP_OP>;
    type State = MapState<M, MAP_OP>;

    fn state(self) -> (Self::Shared, Self::State) {
        let (base_shared, base_state) = self.base.state();
        (MapShared { base: base_shared, map_op: self.map_op },
         MapState { base: base_state, map_op: PhantomMap::new() })
    }
}

pub struct MapShared<M, MAP_OP>
    where M: ParallelIterator
{
    base: M::Shared,
    map_op: MAP_OP
}

pub struct MapState<M, MAP_OP>
    where M: ParallelIterator
{
    base: M::State,
    map_op: PhantomMap<MAP_OP>
}

pub struct PhantomMap<MAP_OP> {
    data: PhantomData<*const MAP_OP>
}

impl<MAP_OP> PhantomMap<MAP_OP> {
    fn new() -> PhantomMap<MAP_OP> {
        PhantomMap { data: PhantomData }
    }
}

unsafe impl<MAP_OP: Sync> Send for PhantomMap<MAP_OP> { }

impl<M, MAP_OP, R> ParallelIteratorState for MapState<M, MAP_OP>
    where M: ParallelIterator,
          MAP_OP: Fn(M::Item) -> R + Sync
{
    type Item = R;
    type Shared = MapShared<M, MAP_OP>;

    fn len(&mut self, shared: &Self::Shared) -> ParallelLen {
        self.base.len(&shared.base)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (MapState { base: left, map_op: PhantomMap::new() },
         MapState { base: right, map_op: PhantomMap::new() })
    }

    fn for_each<F>(self, shared: &Self::Shared, mut op: F)
        where F: FnMut(R)
    {
        self.base.for_each(&shared.base, |item| {
            op((shared.map_op)(item));
        });
    }
}
<commit_msg>Rename PhantomData wrapper and add comment for clarity<commit_after>use super::{ParallelIterator, ParallelIteratorState, ParallelLen};
use std::marker::PhantomData;

pub struct Map<M, MAP_OP> {
    base: M,
    map_op: MAP_OP,
}

impl<M, MAP_OP> Map<M, MAP_OP> {
    pub fn new(base: M, map_op: MAP_OP) -> Map<M, MAP_OP> {
        Map { base: base, map_op: map_op }
    }
}

impl<M, MAP_OP, R> ParallelIterator for Map<M, MAP_OP>
    where M: ParallelIterator,
          MAP_OP: Fn(M::Item) -> R + Sync,
          R: Send,
{
    type Item = R;
    type Shared = MapShared<M, MAP_OP>;
    type State = MapState<M, MAP_OP>;

    fn state(self) -> (Self::Shared, Self::State) {
        let (base_shared, base_state) = self.base.state();
        (MapShared { base: base_shared, map_op: self.map_op },
         MapState { base: base_state, map_op: PhantomMapOp::new() })
    }
}

pub struct MapShared<M, MAP_OP>
    where M: ParallelIterator,
{
    base: M::Shared,
    map_op: MAP_OP,
}

pub struct MapState<M, MAP_OP>
    where M: ParallelIterator,
{
    base: M::State,
    map_op: PhantomMapOp<MAP_OP>,
}

// Wrapper for `PhantomData` to allow `MapState` to impl `Send`
struct PhantomMapOp<MAP_OP>(PhantomData<*const MAP_OP>);

impl<MAP_OP> PhantomMapOp<MAP_OP> {
    fn new() -> PhantomMapOp<MAP_OP> {
        PhantomMapOp(PhantomData)
    }
}

unsafe impl<MAP_OP: Sync> Send for PhantomMapOp<MAP_OP> { }

impl<M, MAP_OP, R> ParallelIteratorState for MapState<M, MAP_OP>
    where M: ParallelIterator,
          MAP_OP: Fn(M::Item) -> R + Sync,
{
    type Item = R;
    type Shared = MapShared<M, MAP_OP>;

    fn len(&mut self, shared: &Self::Shared) -> ParallelLen {
        self.base.len(&shared.base)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (MapState { base: left, map_op: PhantomMapOp::new() },
         MapState { base: right, map_op: PhantomMapOp::new() })
    }

    fn for_each<F>(self, shared: &Self::Shared, mut op: F)
        where F: FnMut(R)
    {
        self.base.for_each(&shared.base, |item| {
            op((shared.map_op)(item));
        });
    }
}
<|endoftext|>


<commit_before>extern crate indy;
extern crate serde;
extern crate serde_json;
extern crate rand;

use std::path::Path;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate lazy_static;

#[macro_use]
mod utils;

pub mod api;
pub mod error;
pub mod connection;

pub fn create_path(s:&str) -> &Path {
    Path::new(s)
}

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

    #[test]
    fn txn_file_exists(){
        let p = String::from("/home/mark/genesis.txn");
        assert!(create_path(&p).exists());

    }

}
<commit_msg>Remove Erroneous Test<commit_after>extern crate indy;
extern crate serde;
extern crate serde_json;
extern crate rand;

use std::path::Path;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate lazy_static;

#[macro_use]
mod utils;

pub mod api;
pub mod error;
pub mod connection;

pub fn create_path(s:&str) -> &Path {
    Path::new(s)
}

<|endoftext|>


<commit_before>use std::char;
use std::fmt;
use parser::token;

pub struct Lexer {
	pub curr:  char,
	pub pos: uint,
	pub src: String,
	pub eof: bool
}

impl Lexer {
	pub fn new(src: &str) -> Lexer {
		let l = Lexer {
			curr: src.char_at(0),
			pos: 0,
			src: src.to_string(),
			eof: false
		};
		l
	}
	pub fn next_token(&mut self) -> token::Token {
		//println!("eof status: {}", self.eof);
		if self.eof {
			println!("EOF!!!!!");
			return token::EOF;
		}
		self.consume_whitespace();
		match self.curr {
			'(' => {self.bump(); token::LPAREN}
			')' => {self.bump(); token::RPAREN}
			c if char::is_digit(c) => {
				let start = self.pos;
				let mut end = start + 1;
				self.bump();
				while (char::is_digit(self.curr) || self.curr == '.') && !self.eof{
					//println!("digit: {}", self.eof);
					self.bump();
					end += 1;
				}
				//println!("read number: {}", self.src.as_slice().slice(start,end))
				token::NUMBER(from_str(self.src.as_slice().slice(start,end)).unwrap())
			}
			'+' => {self.bump(); token::ADD}
			'-' => {self.bump(); token::SUB}
			'*' => {self.bump(); token::MUL}
			'/' => {self.bump(); token::DIV}
			_ => { fail!("unexpected token at {}", self.pos); }
		}
	}
	pub fn bump(&mut self) {
		//println!("bumping to pos: {} of {}", self.pos+1, self.src.as_slice().len());
		self.pos += 1;
		if self.pos >= self.src.as_slice().len() {
			self.eof = true;
			return;
		}
		self.curr = self.src.as_slice().char_at(self.pos);
	}

	pub fn consume_whitespace(&mut self) {
		while is_whitespace(self.curr) {
			self.bump();
		}
	}
}
pub fn is_whitespace(c: char) -> bool {
	match c {
		' ' | '\n' | '\t' => true,
		_ => false
	}
}

impl fmt::Show for Lexer {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.src)
	}
}
<commit_msg>Fixes #1 -  behavior on  empty lines<commit_after>use std::char;
use std::fmt;
use parser::token;

pub struct Lexer {
	pub curr:  char,
	pub pos: uint,
	pub src: String,
	pub eof: bool
}

impl Lexer {
	pub fn new(src: &str) -> Lexer {
		let mut l = Lexer {
			curr: '\0',
			pos: 0,
			src: src.to_string(),
			eof: false
		};
		if l.pos >= src.len() {
			l.eof = true;
		} else {
			l.curr = src.char_at(0);
		}
		l
	}
	pub fn next_token(&mut self) -> token::Token {
		//println!("eof status: {}", self.eof);
		if self.eof {
			println!("EOF!!!!!");
			return token::EOF;
		}
		self.consume_whitespace();
		match self.curr {
			'(' => {self.bump(); token::LPAREN}
			')' => {self.bump(); token::RPAREN}
			c if char::is_digit(c) => {
				let start = self.pos;
				let mut end = start + 1;
				self.bump();
				while (char::is_digit(self.curr) || self.curr == '.') && !self.eof{
					//println!("digit: {}", self.eof);
					self.bump();
					end += 1;
				}
				//println!("read number: {}", self.src.as_slice().slice(start,end))
				token::NUMBER(from_str(self.src.as_slice().slice(start,end)).unwrap())
			}
			'+' => {self.bump(); token::ADD}
			'-' => {self.bump(); token::SUB}
			'*' => {self.bump(); token::MUL}
			'/' => {self.bump(); token::DIV}
			_ => { fail!("unexpected token at {}", self.pos); }
		}
	}
	pub fn bump(&mut self) {
		//println!("bumping to pos: {} of {}", self.pos+1, self.src.as_slice().len());
		self.pos += 1;
		if self.pos >= self.src.as_slice().len() {
			self.eof = true;
			return;
		}
		self.curr = self.src.as_slice().char_at(self.pos);

	}

	pub fn consume_whitespace(&mut self) {
		while is_whitespace(self.curr) {
			self.bump();
		}
	}
}
pub fn is_whitespace(c: char) -> bool {
	match c {
		' ' | '\n' | '\t' => true,
		_ => false
	}
}

impl fmt::Show for Lexer {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.src)
	}
}
<|endoftext|>


<commit_before>//! JIT Compiler to generate code fragments in runtime.

extern crate libc;
extern crate llvm_sys;

#[macro_use]
mod macros;
mod block;
mod buffer;
mod builder;
mod util;
mod types;
pub mod value;

use std::mem;
use std::ptr;

use llvm_sys::analysis;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMContextRef,
  LLVMModuleRef
};
use llvm_sys::bit_reader::LLVMParseBitcodeInContext;
use llvm_sys::execution_engine::{
  LLVMExecutionEngineRef,
  LLVMLinkInMCJIT,
  LLVMMCJITCompilerOptions,
  LLVMCreateMCJITCompilerForModule
};
use llvm_sys::linker;
use llvm_sys::transforms::pass_manager_builder as pass;
use llvm_sys::target::{
  LLVM_InitializeNativeTarget,
  LLVM_InitializeNativeAsmPrinter
};
use llvm_sys::target_machine::LLVMCodeModel;

use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use builder::Builder;
use value::{GlobalValue, Function, Value, ValueIter, ValueRef};
use types::Ty;
use util::chars;

pub const JIT_OPT_LVEL: usize = 2;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}

pub trait LLVMRef<T> {
  fn as_ref(&self) -> T;
}

fn new_module(ctx: LLVMContextRef, name: &str) -> LLVMModuleRef
{
  let c_name = util::chars::from_str(name);
  unsafe {
  	core::LLVMModuleCreateWithNameInContext(c_name, ctx)
  }
}
fn new_module_from_bc(ctx: LLVMContextRef, path: &str) -> Result<LLVMModuleRef, String>
{
  unsafe {
    let mut out: LLVMModuleRef = mem::uninitialized();
    let mut err: *mut c_char   = mem::uninitialized();
    let buf = try!(MemoryBuffer::from_file(path));

    let ret = LLVMParseBitcodeInContext(ctx,
                                        buf.as_ptr(),
    	                                  &mut out,
    	                                  &mut err);
    llvm_ret!(ret, out, err)
  }
}

fn new_jit_ee(m: LLVMModuleRef, opt_lv: usize) -> Result<LLVMExecutionEngineRef, String>
{
  unsafe {
    let mut ee : LLVMExecutionEngineRef = mem::uninitialized();
    let mut err: *mut c_char = mem::uninitialized();

    LLVMLinkInMCJIT();
    expect_noerr!(LLVM_InitializeNativeTarget(), "failed to initialize native target");
    expect_noerr!(LLVM_InitializeNativeAsmPrinter(), "failed to initialize native asm printer");

    let mut opts = new_mcjit_compiler_options(opt_lv);
    let opts_size = mem::size_of::<LLVMMCJITCompilerOptions>();

    let ret = LLVMCreateMCJITCompilerForModule(&mut ee,
      		                                     m,
      		                                     &mut opts,
      		                                     opts_size as u64,
      		                                     &mut err);
    llvm_ret!(ret, ee, err)
  }
}

fn new_mcjit_compiler_options(opt_lv: usize) -> LLVMMCJITCompilerOptions
{
  LLVMMCJITCompilerOptions {
    OptLevel: opt_lv as c_uint,
    CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
    NoFramePointerElim: 0,
    EnableFastISel: 1,
    MCJMM: ptr::null_mut()
  }
}

pub struct JitCompiler
{
  ctx    : LLVMContextRef,
  module : LLVMModuleRef,
  ee     : LLVMExecutionEngineRef,
  //builder: Builder // internal use
}

impl JitCompiler {

  pub fn new(module_name: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = new_module(ctx, module_name);
    JitCompiler::new_internal(ctx, module)
  }

  pub fn new_from_bc(bitcode_path: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = try!(new_module_from_bc(ctx, bitcode_path));
    JitCompiler::new_internal(ctx, module)
  }

  fn new_internal(ctx: LLVMContextRef, module: LLVMModuleRef) -> Result<JitCompiler, String>
  {
    let ee      = try!(new_jit_ee(module, JIT_OPT_LVEL));
    //let builder = Builder(unsafe { core::LLVMCreateBuilderInContext(ctx) });

    Ok(JitCompiler {
      ctx    : ctx,
      module : module,
      ee     : ee,
      //builder: builder
    })
  }

  pub fn context(&self) -> LLVMContextRef { self.ctx }
  pub fn module(&self) -> LLVMModuleRef { self.module }
  pub fn engine(&self) -> LLVMExecutionEngineRef { self.ee }

  /// Returns the target data of the base module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.module);
      chars::to_str(target)
    }
  }

  /// Get the data layout of the base module
  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.module);
  		chars::to_str(layout as *mut c_char)
  	}
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = pass::LLVMPassManagerBuilderCreate();
      pass::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      pass::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      pass::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      pass::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.module);
    }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction;
      let ret = analysis::LLVMVerifyModule(self.module, action, &mut error);

      llvm_ret!(ret, (), error)
    }
  }

  /// Dump the module to stderr (for debugging).
  pub fn dump(&self)
  {
  	unsafe { core::LLVMDumpModule(self.module); }
  }

  pub fn new_builder(&self) -> Builder
  {
    Builder(unsafe { core::LLVMCreateBuilderInContext(self.ctx) })
  }

  /// Returns the type with the name given, or `None`` if no type with that name exists.
  pub fn get_type<'a>(&'a self, name: &str) -> Option<Ty>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ty = core::LLVMGetTypeByName(self.module, c_name);
      ::util::ret_nullable_ptr(ty)
    }
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global(&self, name: &str, ty: &Ty) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobal(self.module, ty.0, c_name)
      }
    )
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space(&self,
  	                              name: &str,
  	                              ty: &Ty,
  	                              sp: AddressSpace) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobalInAddressSpace(self.module, ty.0, c_name, sp as c_uint)
      }
    )
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant(&self, name: &str, val: &Value) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        let global = core::LLVMAddGlobal(self.module, val.ty().0, c_name);
        core::LLVMSetInitializer (global, val.0);
        global
      }
    )
  }

  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global(&self, name: &str) -> Option<GlobalValue>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ptr = core::LLVMGetNamedGlobal(self.module, c_name);
      ::util::ret_nullable_ptr(ptr)
    }
  }

  /// Get an iterator of global values
  pub fn global_values(&self) -> ValueIter<GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.module) },
 			core::LLVMGetNextGlobal
 		)
  }

  /// Add a function to the module with the name given.
  pub fn add_function(&self, name: &str, sig: &Ty) -> Function
  {
    let c_name = chars::from_str(name);
    Function(unsafe { core::LLVMAddFunction(self.module, c_name, sig.0) })
  }

  /// Returns the function with the name given, or `None` if no function with that name exists.
  pub fn get_function(&self, name: &str) -> Option<Function>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ty = core::LLVMGetNamedFunction(self.module, c_name);
      ::util::ret_nullable_ptr(ty)
    }
  }
}

impl Drop for JitCompiler {
  fn drop(&mut self) {
    unsafe {
      core::LLVMDisposeModule(self.module);
      core::LLVMContextDispose(self.ctx);
    }
  }
}

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

  #[test]
  fn test_ctor() {
    let jit = JitCompiler::new("target/test-ir/test-module.bc").ok().unwrap();
  }
}<commit_msg>Add Builder member to JitCompiler and builder() to JitCompiler.<commit_after>//! JIT Compiler to generate code fragments in runtime.

extern crate libc;
extern crate llvm_sys;

#[macro_use]
mod macros;
mod block;
mod buffer;
mod builder;
mod util;
mod types;
pub mod value;

use std::mem;
use std::ptr;

use llvm_sys::analysis;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMContextRef,
  LLVMModuleRef
};
use llvm_sys::bit_reader::LLVMParseBitcodeInContext;
use llvm_sys::execution_engine::{
  LLVMExecutionEngineRef,
  LLVMLinkInMCJIT,
  LLVMMCJITCompilerOptions,
  LLVMCreateMCJITCompilerForModule
};
use llvm_sys::linker;
use llvm_sys::transforms::pass_manager_builder as pass;
use llvm_sys::target::{
  LLVM_InitializeNativeTarget,
  LLVM_InitializeNativeAsmPrinter
};
use llvm_sys::target_machine::LLVMCodeModel;

use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use builder::Builder;
use value::{GlobalValue, Function, Value, ValueIter, ValueRef};
use types::Ty;
use util::chars;

pub const JIT_OPT_LVEL: usize = 2;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}

pub trait LLVMRef<T> {
  fn as_ref(&self) -> T;
}

fn new_module(ctx: LLVMContextRef, name: &str) -> LLVMModuleRef
{
  let c_name = util::chars::from_str(name);
  unsafe {
  	core::LLVMModuleCreateWithNameInContext(c_name, ctx)
  }
}
fn new_module_from_bc(ctx: LLVMContextRef, path: &str) -> Result<LLVMModuleRef, String>
{
  unsafe {
    let mut out: LLVMModuleRef = mem::uninitialized();
    let mut err: *mut c_char   = mem::uninitialized();
    let buf = try!(MemoryBuffer::from_file(path));

    let ret = LLVMParseBitcodeInContext(ctx,
                                        buf.as_ptr(),
    	                                  &mut out,
    	                                  &mut err);
    llvm_ret!(ret, out, err)
  }
}

fn new_jit_ee(m: LLVMModuleRef, opt_lv: usize) -> Result<LLVMExecutionEngineRef, String>
{
  unsafe {
    let mut ee : LLVMExecutionEngineRef = mem::uninitialized();
    let mut err: *mut c_char = mem::uninitialized();

    LLVMLinkInMCJIT();
    expect_noerr!(LLVM_InitializeNativeTarget(), "failed to initialize native target");
    expect_noerr!(LLVM_InitializeNativeAsmPrinter(), "failed to initialize native asm printer");

    let mut opts = new_mcjit_compiler_options(opt_lv);
    let opts_size = mem::size_of::<LLVMMCJITCompilerOptions>();

    let ret = LLVMCreateMCJITCompilerForModule(&mut ee,
      		                                     m,
      		                                     &mut opts,
      		                                     opts_size as u64,
      		                                     &mut err);
    llvm_ret!(ret, ee, err)
  }
}

fn new_mcjit_compiler_options(opt_lv: usize) -> LLVMMCJITCompilerOptions
{
  LLVMMCJITCompilerOptions {
    OptLevel: opt_lv as c_uint,
    CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
    NoFramePointerElim: 0,
    EnableFastISel: 1,
    MCJMM: ptr::null_mut()
  }
}

pub struct JitCompiler
{
  ctx    : LLVMContextRef,
  module : LLVMModuleRef,
  ee     : LLVMExecutionEngineRef,
  builder: Builder
}

impl JitCompiler {

  pub fn new(module_name: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = new_module(ctx, module_name);
    JitCompiler::new_internal(ctx, module)
  }

  pub fn new_from_bc(bitcode_path: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = try!(new_module_from_bc(ctx, bitcode_path));
    JitCompiler::new_internal(ctx, module)
  }

  fn new_internal(ctx: LLVMContextRef, module: LLVMModuleRef) -> Result<JitCompiler, String>
  {
    let ee      = try!(new_jit_ee(module, JIT_OPT_LVEL));
    let builder = Builder(unsafe { core::LLVMCreateBuilderInContext(ctx) });

    Ok(JitCompiler {
      ctx    : ctx,
      module : module,
      ee     : ee,
      builder: builder
    })
  }

  pub fn context(&self) -> LLVMContextRef { self.ctx }
  pub fn module(&self) -> LLVMModuleRef { self.module }
  pub fn engine(&self) -> LLVMExecutionEngineRef { self.ee }
  pub fn builder(&self) -> &Builder { &self.builder }

  /// Returns the target data of the base module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.module);
      chars::to_str(target)
    }
  }

  /// Get the data layout of the base module
  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.module);
  		chars::to_str(layout as *mut c_char)
  	}
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = pass::LLVMPassManagerBuilderCreate();
      pass::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      pass::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      pass::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      pass::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.module);
    }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction;
      let ret = analysis::LLVMVerifyModule(self.module, action, &mut error);

      llvm_ret!(ret, (), error)
    }
  }

  /// Dump the module to stderr (for debugging).
  pub fn dump(&self)
  {
  	unsafe { core::LLVMDumpModule(self.module); }
  }

  pub fn new_builder(&self) -> Builder
  {
    Builder(unsafe { core::LLVMCreateBuilderInContext(self.ctx) })
  }

  /// Returns the type with the name given, or `None`` if no type with that name exists.
  pub fn get_type<'a>(&'a self, name: &str) -> Option<Ty>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ty = core::LLVMGetTypeByName(self.module, c_name);
      ::util::ret_nullable_ptr(ty)
    }
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global(&self, name: &str, ty: &Ty) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobal(self.module, ty.0, c_name)
      }
    )
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space(&self,
  	                              name: &str,
  	                              ty: &Ty,
  	                              sp: AddressSpace) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobalInAddressSpace(self.module, ty.0, c_name, sp as c_uint)
      }
    )
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant(&self, name: &str, val: &Value) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        let global = core::LLVMAddGlobal(self.module, val.ty().0, c_name);
        core::LLVMSetInitializer (global, val.0);
        global
      }
    )
  }

  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global(&self, name: &str) -> Option<GlobalValue>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ptr = core::LLVMGetNamedGlobal(self.module, c_name);
      ::util::ret_nullable_ptr(ptr)
    }
  }

  /// Get an iterator of global values
  pub fn global_values(&self) -> ValueIter<GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.module) },
 			core::LLVMGetNextGlobal
 		)
  }

  /// Add a function to the module with the name given.
  pub fn add_function(&self, name: &str, sig: &Ty) -> Function
  {
    let c_name = chars::from_str(name);
    Function(unsafe { core::LLVMAddFunction(self.module, c_name, sig.0) })
  }

  /// Returns the function with the name given, or `None` if no function with that name exists.
  pub fn get_function(&self, name: &str) -> Option<Function>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ty = core::LLVMGetNamedFunction(self.module, c_name);
      ::util::ret_nullable_ptr(ty)
    }
  }
}

impl Drop for JitCompiler {
  fn drop(&mut self) {
    unsafe {
      core::LLVMDisposeModule(self.module);
      core::LLVMContextDispose(self.ctx);
    }
  }
}

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

  #[test]
  fn test_ctor() {
    let jit = JitCompiler::new("target/test-ir/test-module.bc").ok().unwrap();
  }
}<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(s().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(iota().app(iota())), i());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(b().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(c().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(w().app(zero()).app(one())),
///            normalize(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(om().app(zero())), normalize(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
///
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_once();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(y().app(zero())), normalize(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<commit_msg>normalize() > beta_full() in combinators.rs<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(s().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(iota().app(iota())), i());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(b().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(c().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(w().app(zero()).app(one())),
///            beta_full(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(om().app(zero())), beta_full(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
///
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_once();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(y().app(zero())), beta_full(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;

use rustc::ty::{Ty, layout::{Size, LayoutOf}};
use rustc::mir;

use crate::*;

pub trait EvalContextExt<'tcx> {
    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>;

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool>;

    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>>;
}

impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)> {
        use rustc::mir::BinOp::*;

        trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);

        Ok(match bin_op {
            Eq | Ne => {
                // This supports fat pointers.
                let eq = match (*left, *right) {
                    (Immediate::Scalar(left), Immediate::Scalar(right)) =>
                        self.ptr_eq(left.not_undef()?, right.not_undef()?)?,
                    (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) =>
                        self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? &&
                        self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?,
                    _ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
                };
                (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool)
            }

            Lt | Le | Gt | Ge => {
                // Just compare the integers.
                // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
                let left = self.force_bits(left.to_scalar()?, left.layout.size)?;
                let right = self.force_bits(right.to_scalar()?, right.layout.size)?;
                let res = match bin_op {
                    Lt => left < right,
                    Le => left <= right,
                    Gt => left > right,
                    Ge => left >= right,
                    _ => bug!("We already established it has to be one of these operators."),
                };
                (Scalar::from_bool(res), false, self.tcx.types.bool)
            }

            Offset => {
                let pointee_ty = left.layout.ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset_inbounds(
                    left.to_scalar()?,
                    pointee_ty,
                    right.to_scalar()?.to_isize(self)?,
                )?;
                (ptr, false, left.layout.ty)
            }

            _ => bug!("Invalid operator on pointers: {:?}", bin_op)
        })
    }

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool> {
        let size = self.pointer_size();
        // Just compare the integers.
        // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
        let left = self.force_bits(left, size)?;
        let right = self.force_bits(right, size)?;
        Ok(left == right)
    }

    /// Raises an error if the offset moves the pointer outside of its allocation.
    /// For integers, we consider each of them their own tiny allocation of size 0,
    /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely.
    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
        let offset = offset
            .checked_mul(pointee_size)
            .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
        // We do this first, to rule out overflows.
        let offset_ptr = ptr.ptr_signed_offset(offset, self)?;
        // What we need to check is that starting at `ptr`,
        // we could do an access of size `offset`. Alignment does not matter.
        self.memory.check_ptr_access_align(
            ptr,
            Size::from_bytes(u64::try_from(offset).unwrap()),
            None,
            CheckInAllocMsg::InboundsTest,
        )?;
        // That's it!
        Ok(offset_ptr)
    }
}
<commit_msg>ptr_offset: handle negative offsets<commit_after>use std::convert::TryFrom;

use rustc::ty::{Ty, layout::{Size, LayoutOf}};
use rustc::mir;

use crate::*;

pub trait EvalContextExt<'tcx> {
    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>;

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool>;

    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>>;
}

impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)> {
        use rustc::mir::BinOp::*;

        trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);

        Ok(match bin_op {
            Eq | Ne => {
                // This supports fat pointers.
                let eq = match (*left, *right) {
                    (Immediate::Scalar(left), Immediate::Scalar(right)) =>
                        self.ptr_eq(left.not_undef()?, right.not_undef()?)?,
                    (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) =>
                        self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? &&
                        self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?,
                    _ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
                };
                (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool)
            }

            Lt | Le | Gt | Ge => {
                // Just compare the integers.
                // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
                let left = self.force_bits(left.to_scalar()?, left.layout.size)?;
                let right = self.force_bits(right.to_scalar()?, right.layout.size)?;
                let res = match bin_op {
                    Lt => left < right,
                    Le => left <= right,
                    Gt => left > right,
                    Ge => left >= right,
                    _ => bug!("We already established it has to be one of these operators."),
                };
                (Scalar::from_bool(res), false, self.tcx.types.bool)
            }

            Offset => {
                let pointee_ty = left.layout.ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset_inbounds(
                    left.to_scalar()?,
                    pointee_ty,
                    right.to_scalar()?.to_isize(self)?,
                )?;
                (ptr, false, left.layout.ty)
            }

            _ => bug!("Invalid operator on pointers: {:?}", bin_op)
        })
    }

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool> {
        let size = self.pointer_size();
        // Just compare the integers.
        // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
        let left = self.force_bits(left, size)?;
        let right = self.force_bits(right, size)?;
        Ok(left == right)
    }

    /// Raises an error if the offset moves the pointer outside of its allocation.
    /// For integers, we consider each of them their own tiny allocation of size 0,
    /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely.
    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
        let offset = offset
            .checked_mul(pointee_size)
            .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
        // We do this first, to rule out overflows.
        let offset_ptr = ptr.ptr_signed_offset(offset, self)?;
        // What we need to check is that starting at `min(ptr, offset_ptr)`,
        // we could do an access of size `abs(offset)`. Alignment does not matter.
        let (min_ptr, abs_offset) = if offset >= 0 {
            (ptr, u64::try_from(offset).unwrap())
        } else {
            // Negative offset.
            // If the negation overflows, the result will be negative so the try_from will fail.
            (offset_ptr, u64::try_from(-offset).unwrap())
        };
        self.memory.check_ptr_access_align(
            min_ptr,
            Size::from_bytes(abs_offset),
            None,
            CheckInAllocMsg::InboundsTest,
        )?;
        // That's it!
        Ok(offset_ptr)
    }
}
<|endoftext|>


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

use compiler;
use parser::{Size};

use syntax::ext::build::AstBuilder;
use syntax::ext::base::ExtCtxt;
use syntax::ast;
use syntax::ptr::P;
use syntax::parse::token::intern;
use syntax::codemap::{Span, Spanned};

pub fn serialize(ecx: &mut ExtCtxt, name: P<ast::Expr>, stmts: compiler::StmtBuffer) -> Vec<ast::Stmt> {
    let mut buffer = Vec::new();

    // construction for `op.push(expr)` is as follows
    // op = Path::from_ident(name)
    // push = Ident::with_empty_ctxt(intern("push"))
    // expr = expr_lit(span, LitKind::Byte)
    // expr_method_call(span, op, Vec![expr])

    let mut stmts = stmts.into_iter().peekable();

    while let Some(stmt) = stmts.next() {
        use compiler::Stmt::*;

        let (method, args) = match stmt {
            Const(byte)            => {
                let mut bytes = vec![byte];
                while let Some(&Const(byte)) = stmts.peek() {
                    bytes.push(byte);
                    stmts.next();
                    if stmts.len() == 32 {
                        break;
                    }
                }

                if bytes.len() == 1 {
                    ("push",   vec![ecx.expr_lit(ecx.call_site(), ast::LitKind::Byte(bytes[0]))])
                } else {
                    ("extend", vec![ecx.expr_lit(ecx.call_site(), ast::LitKind::ByteStr(Rc::new(bytes)))])
                }
            },
            ExprConst(expr)        => ("push",    vec![expr]),

            Var(expr, Size::BYTE)  => ("push_i8",  vec![expr]),
            Var(expr, Size::WORD)  => ("push_i16", vec![expr]),
            Var(expr, Size::DWORD) => ("push_i32", vec![expr]),
            Var(expr, Size::QWORD) => ("push_i64", vec![expr]),
            Var(_, _)           => panic!("immediate serializaiton of this size is not supported yet"),

            Extend(expr)           => ("extend", vec![expr]),

            DynScale(scale, rest)  => {
                let temp = ast::Ident::with_empty_ctxt(intern("temp"));
                buffer.push(ecx.stmt_let(ecx.call_site(), false, temp, encoded_size(ecx, &name, scale)));
                ("push", vec![or_mask_shift_expr(ecx, rest, ecx.expr_ident(ecx.call_site(), temp), 3, 6)])
            },

            Align(expr)            => ("align",   vec![expr]),

            GlobalLabel(ident)     => ("global_label", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            )]),
            LocalLabel(ident)      => ("local_label", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            )]),
            DynamicLabel(expr)     => ("dynamic_label", vec![expr]),

            GlobalJumpTarget(ident, size) => ("global_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            ForwardJumpTarget(ident, size) => ("forward_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            BackwardJumpTarget(ident, size) => ("backward_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            DynamicJumpTarget(expr, size) => {
                let span = expr.span;
                ("dynamic_reloc", vec![expr, ecx.expr_u8(span, size.in_bytes())])
            },
            Stmt(stmt) => {
                buffer.push(stmt);
                continue;
            }
        };

        let op = name.clone();
        let method = ast::Ident::with_empty_ctxt(intern(method));
        let expr = ecx.expr_method_call(ecx.call_site(), op, method, args);

        buffer.push(ecx.stmt_semi(expr));
    }

    buffer
}

pub fn add_exprs<T: Iterator<Item=P<ast::Expr>>>(ecx: &ExtCtxt, span: Span, mut exprs: T) -> Option<P<ast::Expr>> {
    exprs.next().map(|mut accum| {
        for next in exprs {
            accum = ecx.expr_binary(span, ast::BinOpKind::Add, accum, next);
        }
        accum
    })
}

pub fn size_of_scale_expr(ecx: &ExtCtxt, ty: ast::Path, value: P<ast::Expr>) -> P<ast::Expr> {
    let span = value.span;
    ecx.expr_binary(span,
        ast::BinOpKind::Mul,
        ecx.expr_cast(span,
            size_of(ecx, ty),
            ecx.ty_ident(span, ast::Ident::with_empty_ctxt(intern("i32")))
        ),
        value
    )
}

pub fn or_mask_shift_expr(ecx: &ExtCtxt, orig: P<ast::Expr>, mut expr: P<ast::Expr>, mask: u64, shift: i8) -> P<ast::Expr> {
    let span = expr.span;
    // take expr and return !((expr & mask) << shift)

    expr = ecx.expr_binary(span, ast::BinOpKind::BitAnd, expr, ecx.expr_lit(
        span, ast::LitKind::Int(mask as u64, ast::LitIntType::Unsuffixed)
    ));

    if shift < 0 {
        expr = ecx.expr_binary(span, ast::BinOpKind::Shr, expr, ecx.expr_lit(
            span, ast::LitKind::Int((-shift) as u64, ast::LitIntType::Unsuffixed)
        ));
    } else if shift > 0 {
        expr = ecx.expr_binary(span, ast::BinOpKind::Shl, expr, ecx.expr_lit(
            span, ast::LitKind::Int(shift as u64, ast::LitIntType::Unsuffixed)
        ));
    }

    ecx.expr_binary(span, ast::BinOpKind::BitOr, orig, expr)
}

pub fn offset_of(ecx: &ExtCtxt, path: ast::Path, attr: ast::Ident) -> P<ast::Expr> {
    // generate a P<Expr> that resolves into the offset of an attribute to a type.
    // this is somewhat ridiculously complex because we can't expand macros here

    let span = path.span;

    let structpat = ecx.pat_struct(span, path.clone(), vec![
        Spanned {span: span, node: ast::FieldPat {
            ident: attr,
            pat: ecx.pat_wild(span),
            is_shorthand: false
        }},
    ]).map(|mut pat| {
        if let ast::PatKind::Struct(_, _, ref mut dotdot) = pat.node {
            *dotdot = true;
        }
        pat
    });

    // there's no default constructor function for let pattern;
    let validation_stmt = ast::Stmt {
        id: ast::DUMMY_NODE_ID,
        span: span,
        node: ast::StmtKind::Local(P(ast::Local {
            pat: structpat,
            ty: None,
            init: None,
            id: ast::DUMMY_NODE_ID,
            span: span,
            attrs: ast::ThinVec::new()
        }))
    };

    let temp     = ast::Ident::with_empty_ctxt(intern("temp"));
    let rv       = ast::Ident::with_empty_ctxt(intern("rv"));
    let usize_id = ast::Ident::with_empty_ctxt(intern("usize"));
    let i32_id   = ast::Ident::with_empty_ctxt(intern("i32"));
    let uninitialized = ["std", "mem", "uninitialized"].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();
    let forget        = ["std", "mem", "forget"       ].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();

    // unsafe {
    let block = ecx.block(span, vec![
        // let path { attr: _, ..};
        validation_stmt,
        // let temp: path = ::std::mem::uninitialized();
        ecx.stmt_let_typed(span, false, temp, ecx.ty_path(path),
            ecx.expr_call_global(span, uninitialized, Vec::new())
        ).unwrap(),
        // let rv = &temp.attr as *const _ as usize - &temp as *const _ as usize;
        ecx.stmt_let(span,
            false,
            rv,
            ecx.expr_binary(span, ast::BinOpKind::Sub,
                ecx.expr_cast(span,
                    ecx.expr_cast(span,
                        ecx.expr_addr_of(span,
                            ecx.expr_field_access(span,
                                ecx.expr_ident(span, temp),
                                attr
                            )
                        ), ecx.ty_ptr(span, ecx.ty_infer(span), ast::Mutability::Immutable)
                    ), ecx.ty_ident(span, usize_id)
                ),
                ecx.expr_cast(span,
                    ecx.expr_cast(span,
                        ecx.expr_addr_of(span, ecx.expr_ident(span, temp)),
                        ecx.ty_ptr(span, ecx.ty_infer(span), ast::Mutability::Immutable)
                    ), ecx.ty_ident(span, usize_id)
                )
            )
        ),
        // ::std::mem::forget(temp);
        ecx.stmt_semi(ecx.expr_call_global(span, forget, vec![ecx.expr_ident(span, temp)])),
        // rv as i32
        ecx.stmt_expr(ecx.expr_cast(span, ecx.expr_ident(span, rv), ecx.ty_ident(span, i32_id)))
    ]).map(|mut b| {
        b.rules = ast::BlockCheckMode::Unsafe(ast::UnsafeSource::CompilerGenerated);
        b
    });

    ecx.expr_block(block)
}

pub fn size_of(ecx: &ExtCtxt, path: ast::Path) -> P<ast::Expr> {
    // generate a P<Expr> that returns the size of type at path
    let span = path.span;

    let ty = ecx.ty_path(path);
    let idents = ["std", "mem", "size_of"].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();
    let size_of = ecx.path_all(span, true, idents, Vec::new(), vec![ty], Vec::new());
    ecx.expr_call(span, ecx.expr_path(size_of), Vec::new())
}

pub fn encoded_size(ecx: &ExtCtxt, name: &P<ast::Expr>, size: P<ast::Expr>) -> P<ast::Expr> {
    let span = size.span;

    ecx.expr_match(span, size, vec![
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 8))], ecx.expr_u8(span, 3)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 4))], ecx.expr_u8(span, 2)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 2))], ecx.expr_u8(span, 1)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 1))], ecx.expr_u8(span, 0)),
        ecx.arm(span, vec![ecx.pat_wild(span)], ecx.expr_method_call(span,
            name.clone(),
            ast::Ident::with_empty_ctxt(intern("runtime_error")),
            vec![ecx.expr_str(span,
                intern("Type size not representable as scale").as_str()
            )]
        ))
    ])
}
<commit_msg>ExtCtxt.stmt_let_typed return type was changed, correct for this to build on recent nightlies<commit_after>use std::rc::Rc;

use compiler;
use parser::{Size};

use syntax::ext::build::AstBuilder;
use syntax::ext::base::ExtCtxt;
use syntax::ast;
use syntax::ptr::P;
use syntax::parse::token::intern;
use syntax::codemap::{Span, Spanned};

pub fn serialize(ecx: &mut ExtCtxt, name: P<ast::Expr>, stmts: compiler::StmtBuffer) -> Vec<ast::Stmt> {
    let mut buffer = Vec::new();

    // construction for `op.push(expr)` is as follows
    // op = Path::from_ident(name)
    // push = Ident::with_empty_ctxt(intern("push"))
    // expr = expr_lit(span, LitKind::Byte)
    // expr_method_call(span, op, Vec![expr])

    let mut stmts = stmts.into_iter().peekable();

    while let Some(stmt) = stmts.next() {
        use compiler::Stmt::*;

        let (method, args) = match stmt {
            Const(byte)            => {
                let mut bytes = vec![byte];
                while let Some(&Const(byte)) = stmts.peek() {
                    bytes.push(byte);
                    stmts.next();
                    if stmts.len() == 32 {
                        break;
                    }
                }

                if bytes.len() == 1 {
                    ("push",   vec![ecx.expr_lit(ecx.call_site(), ast::LitKind::Byte(bytes[0]))])
                } else {
                    ("extend", vec![ecx.expr_lit(ecx.call_site(), ast::LitKind::ByteStr(Rc::new(bytes)))])
                }
            },
            ExprConst(expr)        => ("push",    vec![expr]),

            Var(expr, Size::BYTE)  => ("push_i8",  vec![expr]),
            Var(expr, Size::WORD)  => ("push_i16", vec![expr]),
            Var(expr, Size::DWORD) => ("push_i32", vec![expr]),
            Var(expr, Size::QWORD) => ("push_i64", vec![expr]),
            Var(_, _)           => panic!("immediate serializaiton of this size is not supported yet"),

            Extend(expr)           => ("extend", vec![expr]),

            DynScale(scale, rest)  => {
                let temp = ast::Ident::with_empty_ctxt(intern("temp"));
                buffer.push(ecx.stmt_let(ecx.call_site(), false, temp, encoded_size(ecx, &name, scale)));
                ("push", vec![or_mask_shift_expr(ecx, rest, ecx.expr_ident(ecx.call_site(), temp), 3, 6)])
            },

            Align(expr)            => ("align",   vec![expr]),

            GlobalLabel(ident)     => ("global_label", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            )]),
            LocalLabel(ident)      => ("local_label", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            )]),
            DynamicLabel(expr)     => ("dynamic_label", vec![expr]),

            GlobalJumpTarget(ident, size) => ("global_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            ForwardJumpTarget(ident, size) => ("forward_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            BackwardJumpTarget(ident, size) => ("backward_reloc", vec![ecx.expr_lit(
                ident.span,
                ast::LitKind::Str(ident.node.name.as_str(), ast::StrStyle::Cooked)
            ), ecx.expr_u8(ident.span, size.in_bytes())]),
            DynamicJumpTarget(expr, size) => {
                let span = expr.span;
                ("dynamic_reloc", vec![expr, ecx.expr_u8(span, size.in_bytes())])
            },
            Stmt(stmt) => {
                buffer.push(stmt);
                continue;
            }
        };

        let op = name.clone();
        let method = ast::Ident::with_empty_ctxt(intern(method));
        let expr = ecx.expr_method_call(ecx.call_site(), op, method, args);

        buffer.push(ecx.stmt_semi(expr));
    }

    buffer
}

pub fn add_exprs<T: Iterator<Item=P<ast::Expr>>>(ecx: &ExtCtxt, span: Span, mut exprs: T) -> Option<P<ast::Expr>> {
    exprs.next().map(|mut accum| {
        for next in exprs {
            accum = ecx.expr_binary(span, ast::BinOpKind::Add, accum, next);
        }
        accum
    })
}

pub fn size_of_scale_expr(ecx: &ExtCtxt, ty: ast::Path, value: P<ast::Expr>) -> P<ast::Expr> {
    let span = value.span;
    ecx.expr_binary(span,
        ast::BinOpKind::Mul,
        ecx.expr_cast(span,
            size_of(ecx, ty),
            ecx.ty_ident(span, ast::Ident::with_empty_ctxt(intern("i32")))
        ),
        value
    )
}

pub fn or_mask_shift_expr(ecx: &ExtCtxt, orig: P<ast::Expr>, mut expr: P<ast::Expr>, mask: u64, shift: i8) -> P<ast::Expr> {
    let span = expr.span;
    // take expr and return !((expr & mask) << shift)

    expr = ecx.expr_binary(span, ast::BinOpKind::BitAnd, expr, ecx.expr_lit(
        span, ast::LitKind::Int(mask as u64, ast::LitIntType::Unsuffixed)
    ));

    if shift < 0 {
        expr = ecx.expr_binary(span, ast::BinOpKind::Shr, expr, ecx.expr_lit(
            span, ast::LitKind::Int((-shift) as u64, ast::LitIntType::Unsuffixed)
        ));
    } else if shift > 0 {
        expr = ecx.expr_binary(span, ast::BinOpKind::Shl, expr, ecx.expr_lit(
            span, ast::LitKind::Int(shift as u64, ast::LitIntType::Unsuffixed)
        ));
    }

    ecx.expr_binary(span, ast::BinOpKind::BitOr, orig, expr)
}

pub fn offset_of(ecx: &ExtCtxt, path: ast::Path, attr: ast::Ident) -> P<ast::Expr> {
    // generate a P<Expr> that resolves into the offset of an attribute to a type.
    // this is somewhat ridiculously complex because we can't expand macros here

    let span = path.span;

    let structpat = ecx.pat_struct(span, path.clone(), vec![
        Spanned {span: span, node: ast::FieldPat {
            ident: attr,
            pat: ecx.pat_wild(span),
            is_shorthand: false
        }},
    ]).map(|mut pat| {
        if let ast::PatKind::Struct(_, _, ref mut dotdot) = pat.node {
            *dotdot = true;
        }
        pat
    });

    // there's no default constructor function for let pattern;
    let validation_stmt = ast::Stmt {
        id: ast::DUMMY_NODE_ID,
        span: span,
        node: ast::StmtKind::Local(P(ast::Local {
            pat: structpat,
            ty: None,
            init: None,
            id: ast::DUMMY_NODE_ID,
            span: span,
            attrs: ast::ThinVec::new()
        }))
    };

    let temp     = ast::Ident::with_empty_ctxt(intern("temp"));
    let rv       = ast::Ident::with_empty_ctxt(intern("rv"));
    let usize_id = ast::Ident::with_empty_ctxt(intern("usize"));
    let i32_id   = ast::Ident::with_empty_ctxt(intern("i32"));
    let uninitialized = ["std", "mem", "uninitialized"].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();
    let forget        = ["std", "mem", "forget"       ].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();

    // unsafe {
    let block = ecx.block(span, vec![
        // let path { attr: _, ..};
        validation_stmt,
        // let temp: path = ::std::mem::uninitialized();
        ecx.stmt_let_typed(span, false, temp, ecx.ty_path(path),
            ecx.expr_call_global(span, uninitialized, Vec::new())
        ),
        // let rv = &temp.attr as *const _ as usize - &temp as *const _ as usize;
        ecx.stmt_let(span,
            false,
            rv,
            ecx.expr_binary(span, ast::BinOpKind::Sub,
                ecx.expr_cast(span,
                    ecx.expr_cast(span,
                        ecx.expr_addr_of(span,
                            ecx.expr_field_access(span,
                                ecx.expr_ident(span, temp),
                                attr
                            )
                        ), ecx.ty_ptr(span, ecx.ty_infer(span), ast::Mutability::Immutable)
                    ), ecx.ty_ident(span, usize_id)
                ),
                ecx.expr_cast(span,
                    ecx.expr_cast(span,
                        ecx.expr_addr_of(span, ecx.expr_ident(span, temp)),
                        ecx.ty_ptr(span, ecx.ty_infer(span), ast::Mutability::Immutable)
                    ), ecx.ty_ident(span, usize_id)
                )
            )
        ),
        // ::std::mem::forget(temp);
        ecx.stmt_semi(ecx.expr_call_global(span, forget, vec![ecx.expr_ident(span, temp)])),
        // rv as i32
        ecx.stmt_expr(ecx.expr_cast(span, ecx.expr_ident(span, rv), ecx.ty_ident(span, i32_id)))
    ]).map(|mut b| {
        b.rules = ast::BlockCheckMode::Unsafe(ast::UnsafeSource::CompilerGenerated);
        b
    });

    ecx.expr_block(block)
}

pub fn size_of(ecx: &ExtCtxt, path: ast::Path) -> P<ast::Expr> {
    // generate a P<Expr> that returns the size of type at path
    let span = path.span;

    let ty = ecx.ty_path(path);
    let idents = ["std", "mem", "size_of"].iter().cloned().map(intern).map(ast::Ident::with_empty_ctxt).collect();
    let size_of = ecx.path_all(span, true, idents, Vec::new(), vec![ty], Vec::new());
    ecx.expr_call(span, ecx.expr_path(size_of), Vec::new())
}

pub fn encoded_size(ecx: &ExtCtxt, name: &P<ast::Expr>, size: P<ast::Expr>) -> P<ast::Expr> {
    let span = size.span;

    ecx.expr_match(span, size, vec![
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 8))], ecx.expr_u8(span, 3)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 4))], ecx.expr_u8(span, 2)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 2))], ecx.expr_u8(span, 1)),
        ecx.arm(span, vec![ecx.pat_lit(span, ecx.expr_usize(span, 1))], ecx.expr_u8(span, 0)),
        ecx.arm(span, vec![ecx.pat_wild(span)], ecx.expr_method_call(span,
            name.clone(),
            ast::Ident::with_empty_ctxt(intern("runtime_error")),
            vec![ecx.expr_str(span,
                intern("Type size not representable as scale").as_str()
            )]
        ))
    ])
}
<|endoftext|>


<commit_before><commit_msg>Fix typo<commit_after><|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::HashMap;
use request::Request;
use urlencoded;
use http::server::request::RequestUri;
use http::server::request::RequestUri::{Star, AbsoluteUri, AbsolutePath, Authority};
use url::UrlParser;
use plugin::{Phantom, PluginFor, GetCached};
use typemap::Assoc;

type QueryStore = HashMap<String, Vec<String>>;

// Plugin boilerplate
struct QueryStringParser;
impl Assoc<QueryStore> for QueryStringParser {}
impl<'a, 'b> PluginFor<Request<'a, 'b>, QueryStore> for QueryStringParser {
    fn eval(req: &mut Request, _: Phantom<QueryStringParser>) -> Option<QueryStore> {
        Some(QueryStringParser::parse(&req.origin.request_uri))
    }
}

pub trait QueryString {
    // FIXME: This would probably be better to return Cow<Vec<String>, [String]>
    // but ToOwned isn't implemented for that combination yet.
    fn query(&mut self, key: &str, default: &str) -> Cow<Vec<String>, Vec<String>>;
}

impl<'a, 'b> QueryString for Request<'a, 'b> {
    fn query(&mut self, key: &str, default: &str) -> Cow<Vec<String>, Vec<String>> {
        let store = self.get_ref::<QueryStringParser>()
                        .expect("Bug: QueryStringParser returned None");

        match store.get(key) {
            Some(result) => Cow::Borrowed(result),
            _ => Cow::Owned(vec![default.to_string()])
        }
    }
}

impl QueryStringParser {
    fn parse(origin: &RequestUri) -> QueryStore {
        match *origin {
            AbsoluteUri(ref url) => {
                for query in url.query.iter() {
                    return urlencoded::parse(query.as_slice())
                }
            },
            AbsolutePath(ref s) => {
                match UrlParser::new().parse_path(s.as_slice()) {
                    Ok((_, Some(query), _)) => {
                        return urlencoded::parse(query.as_slice())
                    }
                    Ok(..) => {}
                    // FIXME: If this fails to parse, then it really shouldn't
                    // have reached here.
                    Err(..) => {}
                }
            },
            Star | Authority(..) => {}
        }

        HashMap::new()
    }
}

#[test]
fn splits_and_parses_an_url() {
    use url::Url;
    let t = |url|{
        let store = QueryStringParser::parse(&url);
        assert_eq!(store["foo".to_string()], vec!["bar".to_string()]);
        assert_eq!(store["message".to_string()],
                        vec!["hello".to_string(), "world".to_string()]);
    };

    let raw = "http://www.foo.bar/query/test?foo=bar&message=hello&message=world";
    t(AbsoluteUri(Url::parse(raw).unwrap()));

    t(AbsolutePath("/query/test?foo=bar&message=hello&message=world".to_string()));

    assert_eq!(QueryStringParser::parse(&Star), HashMap::new());

    let store = QueryStringParser::parse(&Authority("host.com".to_string()));
    assert_eq!(store, HashMap::new());
}
<commit_msg>refactor(query_string): simplify query_string::parse<commit_after>use std::borrow::Cow;
use std::collections::HashMap;
use request::Request;
use urlencoded;
use http::server::request::RequestUri;
use http::server::request::RequestUri::{Star, AbsoluteUri, AbsolutePath, Authority};
use url::UrlParser;
use plugin::{Phantom, PluginFor, GetCached};
use typemap::Assoc;

type QueryStore = HashMap<String, Vec<String>>;

// Plugin boilerplate
struct QueryStringParser;
impl Assoc<QueryStore> for QueryStringParser {}
impl<'a, 'b> PluginFor<Request<'a, 'b>, QueryStore> for QueryStringParser {
    fn eval(req: &mut Request, _: Phantom<QueryStringParser>) -> Option<QueryStore> {
        Some(parse(&req.origin.request_uri))
    }
}

pub trait QueryString {
    // FIXME: This would probably be better to return Cow<Vec<String>, [String]>
    // but ToOwned isn't implemented for that combination yet.
    fn query(&mut self, key: &str, default: &str) -> Cow<Vec<String>, Vec<String>>;
}

impl<'a, 'b> QueryString for Request<'a, 'b> {
    fn query(&mut self, key: &str, default: &str) -> Cow<Vec<String>, Vec<String>> {
        let store = self.get_ref::<QueryStringParser>()
                        .expect("Bug: QueryStringParser returned None");

        match store.get(key) {
            Some(result) => Cow::Borrowed(result),
            _ => Cow::Owned(vec![default.to_string()])
        }
    }
}

fn parse(origin: &RequestUri) -> QueryStore {
    let f = |query: Option<&String>| query.map(|q| urlencoded::parse(q.as_slice()));

    let result = match *origin {
        AbsoluteUri(ref url) => f(url.query.as_ref()),
        AbsolutePath(ref s) => UrlParser::new().parse_path(s.as_slice())
                                                // FIXME: If this fails to parse,
                                                // then it really shouldn't have
                                                // reached here.
                                               .ok()
                                               .and_then(|(_, query, _)| f(query.as_ref())),
        Star | Authority(..) => None
    };

    result.unwrap_or_else(|| HashMap::new())
}

#[test]
fn splits_and_parses_an_url() {
    use url::Url;
    let t = |url|{
        let store = parse(&url);
        assert_eq!(store["foo".to_string()], vec!["bar".to_string()]);
        assert_eq!(store["message".to_string()],
                        vec!["hello".to_string(), "world".to_string()]);
    };

    let raw = "http://www.foo.bar/query/test?foo=bar&message=hello&message=world";
    t(AbsoluteUri(Url::parse(raw).unwrap()));

    t(AbsolutePath("/query/test?foo=bar&message=hello&message=world".to_string()));

    assert_eq!(parse(&Star), HashMap::new());

    let store = parse(&Authority("host.com".to_string()));
    assert_eq!(store, HashMap::new());
}
<|endoftext|>