<commit_before>use light::Light;
use raytracer::compositor::{ColorRGBA, Surface, SurfaceFactory};
use raytracer::{Intersection, Ray};
use scene::{Camera, Scene};
use std::iter::range;
use std::num::Float;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::sync::TaskPool;
use vec3::Vec3;
use rand::{thread_rng, Rng, SeedableRng, Isaac64Rng};

pub static EPSILON: f64 = ::std::f64::EPSILON * 10000.0;

#[derive(Clone)]
pub struct Renderer {
    pub reflect_depth: u32,  // Maximum reflection recursions.
    pub refract_depth: u32,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub shadow_samples: u32, // Number of samples for soft shadows and area lights.
    pub pixel_samples: u32,  // The square of this is the number of samples per pixel.
    pub tasks: usize         // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, shared_scene: Arc<Scene>) -> Surface {

        let mut surface = Surface::new(camera.image_width as usize,
                                       camera.image_height as usize,
                                       ColorRGBA::new_rgb(0, 0, 0));

        let pool = TaskPool::new(self.tasks);

        let (tx, rx) = channel();

        let mut jobs = 0;

        for subsurface_factory in surface.divide(128, 8) {
            jobs += 1;

            let renderer = self.clone();
            let child_tx = tx.clone();
            let scene_local = shared_scene.clone();
            let camera_local = camera.clone();

            pool.execute(move || {
                let _ = child_tx.send(renderer.render_tile(camera_local.clone(),
                    scene_local.deref(), subsurface_factory));
            });
        }

        let start_time = ::time::get_time();

        for (i, subsurface) in rx.iter().take(jobs).enumerate() {
            surface.merge(&subsurface);
            ::util::print_progress("Tile", start_time.clone(), (i + 1) as usize, jobs);
        }
        surface
    }

    fn render_tile(&self, camera: Camera, scene: &Scene,
                   tile_factory: SurfaceFactory) -> Surface {

        let shadow_samples = self.shadow_samples;
        let pixel_samples = self.pixel_samples;
        let reflect_depth = self.reflect_depth;
        let refract_depth = self.refract_depth;

        let mut tile = tile_factory.create();

        let random_data: Vec<u64> = (0u32..64).map(|_| {
            thread_rng().next_u64()
        }).collect();
        let mut rng: Isaac64Rng = SeedableRng::from_seed(random_data.as_slice());

        for rel_y in 0usize..tile.height {
            let abs_y = camera.image_height as usize - (tile.y_off + rel_y) - 1;
            for rel_x in 0usize..tile.width {
                let abs_x = tile.x_off + rel_x;

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;
                let mut color = Vec3::zero();

                for y_subpixel in 0u32..pixel_samples {
                    for x_subpixel in 0u32..pixel_samples {
                        // Don't jitter if not antialiasing
                        let (j_x, j_y) = if pixel_samples > 1 {
                            (x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width,
                             y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width)
                        } else {
                            (0.0, 0.0)
                        };

                        let ray = camera.get_ray(abs_x as f64 + j_x, abs_y as f64 + j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples,
                                                     reflect_depth, refract_depth, false);
                        // Clamp subpixels for now to avoid intense aliasing when combined value is clamped later
                        // Should think of a better way to handle this
                        color = color + result.clamp(0.0, 1.0).scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }
                tile[(rel_x, rel_y)] = ColorRGBA::new_rgb_clamped(color.x, color.y, color.z);
            }
        }

        tile
    }

    fn trace(scene: &Scene, ray: &Ray, shadow_samples: u32,
             reflect_depth: u32, refract_depth: u32, inside: bool) -> Vec3 {

        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }

        match ray.get_nearest_hit(scene) {
            Some(hit) => {
                let n = hit.n.unit();
                let i = (-ray.direction).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let shadow = Renderer::shadow_intensity(scene, &hit, light, shadow_samples);
                    let l = (light.center() - hit.position).unit();

                    color_acc + light.color() * hit.material.sample(n, i, l, hit.u, hit.v) * shadow
                });

                if hit.material.is_reflective() || hit.material.is_refractive() {
                    let reflect_fresnel = Renderer::fresnel_reflect(hit.material.ior(), &i, &n, inside);
                    let mut refract_fresnel = 1.0 - reflect_fresnel;

                    // Global reflection
                    if hit.material.is_reflective() {
                        let r = Vec3::reflect(&i, &n);
                        let reflect_ray = Ray::new(hit.position, r);
                        let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples,
                                                         reflect_depth - 1, refract_depth, inside);

                        result = result + hit.material.global_specular(&reflection).scale(reflect_fresnel);
                    }

                    // Global refraction
                    if hit.material.is_refractive() {
                        let t = match Vec3::refract(&i, &n, hit.material.ior(), inside) {
                            Some(ref t) => *t,
                            None => {
                                refract_fresnel = 1.0; // Total internal reflection (TODO: verify)
                                Vec3::reflect(&i, &n)
                            }
                        };

                        let refract_ray = Ray::new(hit.position + t.scale(EPSILON), t);
                        let refraction = Renderer::trace(scene, &refract_ray, shadow_samples,
                                                         reflect_depth, refract_depth - 1, !inside);

                        result = result + hit.material.global_transmissive(&refraction).scale(refract_fresnel);
                    }
                }

                result
            },
            None => {
                match scene.skybox {
                    Some(ref skybox) => skybox.color(ray.direction),
                    None => scene.background
                }
            }
        }
    }

    fn shadow_intensity(scene: &Scene, hit: &Intersection,
                        light: &Box<Light+Send+Sync>, shadow_samples: u32) -> Vec3 {

        if shadow_samples <= 0 { return Vec3::one() }

        // Point light speedup (no point in sampling a point light multiple times)
        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };
        let mut shadow = Vec3::zero();

        // Take average shadow color after jittering/sampling light position
        for _ in range(0, shadow_sample_tries) {
            // L has to be a unit vector for t_max 1:1 correspondence to
            // distance to light to work. Shadow feelers only search up
            // until light source.
            let sampled_light_position = light.position();
            let shadow_l = (sampled_light_position - hit.position).unit();
            let shadow_ray = Ray::new(hit.position, shadow_l);
            let distance_to_light = (sampled_light_position - hit.position).len();

            // Check against candidate primitives in scene for occlusion
            // and multiply shadow color by occluders' shadow colors
            let candidate_nodes = scene.octree.get_intersected_objects(&shadow_ray);

            shadow = shadow + candidate_nodes.fold(Vec3::one(), |shadow_acc, prim| {
                let occlusion = prim.intersects(&shadow_ray, EPSILON, distance_to_light);
                match occlusion {
                    Some(occlusion) => shadow_acc * occlusion.material.transmission(),
                    None => shadow_acc
                }
            });
        }

        shadow.scale(1.0 / shadow_sample_tries as f64)
    }

    /// Calculates the fresnel (reflectivity) given the index of refraction and the cos_angle
    /// This uses Schlick's approximation. cos_angle is normal_dot_incoming
    /// http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
    fn fresnel_reflect(ior: f64, i: &Vec3, n: &Vec3, inside: bool) -> f64 {
        let (n1, n2) = if inside { (ior, 1.0) } else { (1.0, ior) };
        let actual_n = if inside { -*n } else { *n };

        let r0_sqrt = (n1 - n2) / (n1 + n2);
        let r0 = r0_sqrt * r0_sqrt;

        let cos_angle = if n1 <= n2 {
            i.dot(&actual_n)
        } else {
            let t = match Vec3::refract(i, &-actual_n, ior, inside) {
                Some(x) => x,
                None => return 1.0 // n1 > n2 && TIR
            };

            -actual_n.dot(&t) // n1 > n2 && !TIR
        };

        let cos_term = 1.0 - cos_angle;

        (r0 + ((1.0 - r0) * cos_term * cos_term * cos_term * cos_term * cos_term)).max(0.0).min(1.0)
    }
}

#[test]
fn it_renders_the_background_of_an_empty_scene() {
    let camera = Camera::new(
        Vec3 { x: 0.0, y: 0.0, z: 0.0 },
        Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        45.0,
        32,
        32
    );

    let test_scene = Scene {
        lights: vec!(),
        octree: ::raytracer::Octree::new_from_prims(vec!()),
        background: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        skybox: None
    };

    let shared_scene = Arc::new(test_scene);

    let renderer = Renderer {
        reflect_depth: 1,
        refract_depth: 1,
        shadow_samples: 1,
        pixel_samples: 1,
        tasks: 2
    };

    let image_data = renderer.render(camera, shared_scene);

    for color in image_data.buffer.iter() {
        assert_eq!(color.r, 255);
        assert_eq!(color.g, 0);
        assert_eq!(color.b, 0);
    }
}
<commit_msg>Use dropped TX to close job queue<commit_after>use light::Light;
use raytracer::compositor::{ColorRGBA, Surface, SurfaceFactory};
use raytracer::{Intersection, Ray};
use scene::{Camera, Scene};
use std::iter::range;
use std::num::Float;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::sync::TaskPool;
use vec3::Vec3;
use rand::{thread_rng, Rng, SeedableRng, Isaac64Rng};

pub static EPSILON: f64 = ::std::f64::EPSILON * 10000.0;

#[derive(Clone)]
pub struct Renderer {
    pub reflect_depth: u32,  // Maximum reflection recursions.
    pub refract_depth: u32,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub shadow_samples: u32, // Number of samples for soft shadows and area lights.
    pub pixel_samples: u32,  // The square of this is the number of samples per pixel.
    pub tasks: usize         // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, shared_scene: Arc<Scene>) -> Surface {

        let mut surface = Surface::new(camera.image_width as usize,
                                       camera.image_height as usize,
                                       ColorRGBA::new_rgb(0, 0, 0));

        let pool = TaskPool::new(self.tasks);

        let (tx, rx) = channel();

        let mut jobs = 0;

        for subsurface_factory in surface.divide(128, 8) {
            jobs += 1;

            let renderer = self.clone();
            let child_tx = tx.clone();
            let scene_local = shared_scene.clone();
            let camera_local = camera.clone();

            pool.execute(move || {
                let _ = child_tx.send(renderer.render_tile(camera_local.clone(),
                    scene_local.deref(), subsurface_factory));
            });
        }
        drop(tx);

        let start_time = ::time::get_time();

        for (i, subsurface) in rx.iter().enumerate() {
            surface.merge(&subsurface);
            ::util::print_progress("Tile", start_time.clone(), (i + 1) as usize, jobs);
        }
        surface
    }

    fn render_tile(&self, camera: Camera, scene: &Scene,
                   tile_factory: SurfaceFactory) -> Surface {

        let shadow_samples = self.shadow_samples;
        let pixel_samples = self.pixel_samples;
        let reflect_depth = self.reflect_depth;
        let refract_depth = self.refract_depth;

        let mut tile = tile_factory.create();

        let random_data: Vec<u64> = (0u32..64).map(|_| {
            thread_rng().next_u64()
        }).collect();
        let mut rng: Isaac64Rng = SeedableRng::from_seed(random_data.as_slice());

        for rel_y in 0usize..tile.height {
            let abs_y = camera.image_height as usize - (tile.y_off + rel_y) - 1;
            for rel_x in 0usize..tile.width {
                let abs_x = tile.x_off + rel_x;

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;
                let mut color = Vec3::zero();

                for y_subpixel in 0u32..pixel_samples {
                    for x_subpixel in 0u32..pixel_samples {
                        // Don't jitter if not antialiasing
                        let (j_x, j_y) = if pixel_samples > 1 {
                            (x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width,
                             y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width)
                        } else {
                            (0.0, 0.0)
                        };

                        let ray = camera.get_ray(abs_x as f64 + j_x, abs_y as f64 + j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples,
                                                     reflect_depth, refract_depth, false);
                        // Clamp subpixels for now to avoid intense aliasing when combined value is clamped later
                        // Should think of a better way to handle this
                        color = color + result.clamp(0.0, 1.0).scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }
                tile[(rel_x, rel_y)] = ColorRGBA::new_rgb_clamped(color.x, color.y, color.z);
            }
        }

        tile
    }

    fn trace(scene: &Scene, ray: &Ray, shadow_samples: u32,
             reflect_depth: u32, refract_depth: u32, inside: bool) -> Vec3 {

        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }

        match ray.get_nearest_hit(scene) {
            Some(hit) => {
                let n = hit.n.unit();
                let i = (-ray.direction).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let shadow = Renderer::shadow_intensity(scene, &hit, light, shadow_samples);
                    let l = (light.center() - hit.position).unit();

                    color_acc + light.color() * hit.material.sample(n, i, l, hit.u, hit.v) * shadow
                });

                if hit.material.is_reflective() || hit.material.is_refractive() {
                    let reflect_fresnel = Renderer::fresnel_reflect(hit.material.ior(), &i, &n, inside);
                    let mut refract_fresnel = 1.0 - reflect_fresnel;

                    // Global reflection
                    if hit.material.is_reflective() {
                        let r = Vec3::reflect(&i, &n);
                        let reflect_ray = Ray::new(hit.position, r);
                        let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples,
                                                         reflect_depth - 1, refract_depth, inside);

                        result = result + hit.material.global_specular(&reflection).scale(reflect_fresnel);
                    }

                    // Global refraction
                    if hit.material.is_refractive() {
                        let t = match Vec3::refract(&i, &n, hit.material.ior(), inside) {
                            Some(ref t) => *t,
                            None => {
                                refract_fresnel = 1.0; // Total internal reflection (TODO: verify)
                                Vec3::reflect(&i, &n)
                            }
                        };

                        let refract_ray = Ray::new(hit.position + t.scale(EPSILON), t);
                        let refraction = Renderer::trace(scene, &refract_ray, shadow_samples,
                                                         reflect_depth, refract_depth - 1, !inside);

                        result = result + hit.material.global_transmissive(&refraction).scale(refract_fresnel);
                    }
                }

                result
            },
            None => {
                match scene.skybox {
                    Some(ref skybox) => skybox.color(ray.direction),
                    None => scene.background
                }
            }
        }
    }

    fn shadow_intensity(scene: &Scene, hit: &Intersection,
                        light: &Box<Light+Send+Sync>, shadow_samples: u32) -> Vec3 {

        if shadow_samples <= 0 { return Vec3::one() }

        // Point light speedup (no point in sampling a point light multiple times)
        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };
        let mut shadow = Vec3::zero();

        // Take average shadow color after jittering/sampling light position
        for _ in range(0, shadow_sample_tries) {
            // L has to be a unit vector for t_max 1:1 correspondence to
            // distance to light to work. Shadow feelers only search up
            // until light source.
            let sampled_light_position = light.position();
            let shadow_l = (sampled_light_position - hit.position).unit();
            let shadow_ray = Ray::new(hit.position, shadow_l);
            let distance_to_light = (sampled_light_position - hit.position).len();

            // Check against candidate primitives in scene for occlusion
            // and multiply shadow color by occluders' shadow colors
            let candidate_nodes = scene.octree.get_intersected_objects(&shadow_ray);

            shadow = shadow + candidate_nodes.fold(Vec3::one(), |shadow_acc, prim| {
                let occlusion = prim.intersects(&shadow_ray, EPSILON, distance_to_light);
                match occlusion {
                    Some(occlusion) => shadow_acc * occlusion.material.transmission(),
                    None => shadow_acc
                }
            });
        }

        shadow.scale(1.0 / shadow_sample_tries as f64)
    }

    /// Calculates the fresnel (reflectivity) given the index of refraction and the cos_angle
    /// This uses Schlick's approximation. cos_angle is normal_dot_incoming
    /// http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
    fn fresnel_reflect(ior: f64, i: &Vec3, n: &Vec3, inside: bool) -> f64 {
        let (n1, n2) = if inside { (ior, 1.0) } else { (1.0, ior) };
        let actual_n = if inside { -*n } else { *n };

        let r0_sqrt = (n1 - n2) / (n1 + n2);
        let r0 = r0_sqrt * r0_sqrt;

        let cos_angle = if n1 <= n2 {
            i.dot(&actual_n)
        } else {
            let t = match Vec3::refract(i, &-actual_n, ior, inside) {
                Some(x) => x,
                None => return 1.0 // n1 > n2 && TIR
            };

            -actual_n.dot(&t) // n1 > n2 && !TIR
        };

        let cos_term = 1.0 - cos_angle;

        (r0 + ((1.0 - r0) * cos_term * cos_term * cos_term * cos_term * cos_term)).max(0.0).min(1.0)
    }
}

#[test]
fn it_renders_the_background_of_an_empty_scene() {
    let camera = Camera::new(
        Vec3 { x: 0.0, y: 0.0, z: 0.0 },
        Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        45.0,
        32,
        32
    );

    let test_scene = Scene {
        lights: vec!(),
        octree: ::raytracer::Octree::new_from_prims(vec!()),
        background: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        skybox: None
    };

    let shared_scene = Arc::new(test_scene);

    let renderer = Renderer {
        reflect_depth: 1,
        refract_depth: 1,
        shadow_samples: 1,
        pixel_samples: 1,
        tasks: 2
    };

    let image_data = renderer.render(camera, shared_scene);

    for color in image_data.buffer.iter() {
        assert_eq!(color.r, 255);
        assert_eq!(color.g, 0);
        assert_eq!(color.b, 0);
    }
}
<|endoftext|>


<commit_before>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

type blk = u64;
const BCNT: u8 = 5;
const BLK_BITS: u8 = 64;

const BCNT_: usize = BCNT as usize;
const VAL_BITS: u8 = BLK_BITS - 8;
const VAL_MASK: blk = (1 << VAL_BITS) - 1;

#[derive(Copy, Clone)]
struct SPart(blk);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Copy, Clone)]
pub struct VPair {
    data: [blk; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: blk,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most VAL_BITS bit, which always fit in BITS bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(BLK_BITS - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < BLK_BITS {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != BLK_BITS);
    }

    fn push(&mut self, block: blk) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != BLK_BITS);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { BLK_BITS } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { BLK_BITS } else { self. used },
        }
    }
}

#[derive(Copy, Clone)]
enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> blk {
        self.0 & VAL_MASK
    }

    fn len(&self) -> u8 {
        (self.0 >> VAL_BITS) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as blk) << VAL_BITS) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> blk {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == BLK_BITS {
            debug_assert!(self.used == BLK_BITS);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> blk {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val: blk = 0;
        let mut len: blk = 0;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= VAL_BITS as blk, "invalid input: too long");

        SPart((len << VAL_BITS) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<commit_msg>silence a warning<commit_after>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

#[allow(non_camel_case_types)]
type blk = u64;
const BCNT: u8 = 5;
const BLK_BITS: u8 = 64;

const BCNT_: usize = BCNT as usize;
const VAL_BITS: u8 = BLK_BITS - 8;
const VAL_MASK: blk = (1 << VAL_BITS) - 1;

#[derive(Copy, Clone)]
struct SPart(blk);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Copy, Clone)]
pub struct VPair {
    data: [blk; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: blk,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most VAL_BITS bit, which always fit in BITS bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(BLK_BITS - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < BLK_BITS {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != BLK_BITS);
    }

    fn push(&mut self, block: blk) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != BLK_BITS);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { BLK_BITS } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { BLK_BITS } else { self. used },
        }
    }
}

#[derive(Copy, Clone)]
enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> blk {
        self.0 & VAL_MASK
    }

    fn len(&self) -> u8 {
        (self.0 >> VAL_BITS) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as blk) << VAL_BITS) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> blk {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == BLK_BITS {
            debug_assert!(self.used == BLK_BITS);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> blk {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val: blk = 0;
        let mut len: blk = 0;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= VAL_BITS as blk, "invalid input: too long");

        SPart((len << VAL_BITS) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<|endoftext|>


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

use atomic_refcell::AtomicRefCell;
use serde::{Serialize, Serializer};
use servo_arc::Arc;
use std::fmt;
use std::ops::Deref;

pub(crate) struct ArcRefCell<T> {
    value: Arc<AtomicRefCell<T>>,
}

impl<T> ArcRefCell<T> {
    pub fn new(value: T) -> Self {
        Self {
            value: Arc::new(AtomicRefCell::new(value)),
        }
    }
}

impl<T> Clone for ArcRefCell<T> {
    fn clone(&self) -> Self {
        Self {
            value: self.value.clone(),
        }
    }
}

impl<T> Deref for ArcRefCell<T> {
    type Target = AtomicRefCell<T>;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> fmt::Debug for ArcRefCell<T>
where
    T: fmt::Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.value.fmt(formatter)
    }
}

impl<T> Serialize for ArcRefCell<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.borrow().serialize(serializer)
    }
}
<commit_msg>Implement `Default` for `ArcRefCell`<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use atomic_refcell::AtomicRefCell;
use serde::{Serialize, Serializer};
use servo_arc::Arc;
use std::fmt;
use std::ops::Deref;

pub(crate) struct ArcRefCell<T> {
    value: Arc<AtomicRefCell<T>>,
}

impl<T> ArcRefCell<T> {
    pub fn new(value: T) -> Self {
        Self {
            value: Arc::new(AtomicRefCell::new(value)),
        }
    }
}

impl<T> Clone for ArcRefCell<T> {
    fn clone(&self) -> Self {
        Self {
            value: self.value.clone(),
        }
    }
}

impl<T> Default for ArcRefCell<T>
where
    T: Default,
{
    fn default() -> Self {
        Self {
            value: Arc::new(AtomicRefCell::new(Default::default())),
        }
    }
}

impl<T> Deref for ArcRefCell<T> {
    type Target = AtomicRefCell<T>;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> fmt::Debug for ArcRefCell<T>
where
    T: fmt::Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.value.fmt(formatter)
    }
}

impl<T> Serialize for ArcRefCell<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.borrow().serialize(serializer)
    }
}
<|endoftext|>


<commit_before>use std::kinds::marker;
use std::c_str::CString;
use libc;

use {raw, Remote, Error, Signature};

/// dox
pub struct Push<'a> {
    raw: *mut raw::git_push,
    marker1: marker::ContravariantLifetime<'a>,
    marker2: marker::NoSend,
    marker3: marker::NoSync,
}

/// A status representing the result of updating a remote reference.
pub struct Status {
    /// The reference that was updated as part of a push.
    pub reference: String,
    /// If `None`, the reference was updated successfully, otherwise a message
    /// explaining why it could not be updated is provided.
    pub message: Option<String>,
}

impl<'a> Push<'a> {
    /// Create a new push from its raw component.
    ///
    /// This method is unsafe as there is no guarantee that `raw` is a valid
    /// pointer.
    pub unsafe fn from_raw<'a>(_remote: &'a Remote,
                               raw: *mut raw::git_push) -> Push<'a> {
        Push {
            raw: raw,
            marker1: marker::ContravariantLifetime,
            marker2: marker::NoSend,
            marker3: marker::NoSync,
        }
    }

    /// Get access to the underlying raw pointer.
    pub fn raw(&self) -> *mut raw::git_push { self.raw }

    /// Add a refspec to be pushed
    pub fn add_refspec(&mut self, refspec: &str) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_add_refspec(self.raw, refspec.to_c_str()));
            Ok(())
        }
    }

    /// Actually push all given refspecs
    ///
    /// To check if the push was successful (i.e. all remote references have
    /// been updated as requested), you need to call both `unpack_ok` and
    /// `statuses`. The remote repository might have refused to
    /// update some or all of the references.
    pub fn finish(&mut self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_finish(self.raw));
            Ok(())
        }
    }

    /// Check if remote side successfully unpacked
    pub fn unpack_ok(&self) -> bool {
        unsafe { raw::git_push_unpack_ok(&*self.raw) != 0 }
    }

    /// Update remote tips after a push
    pub fn update_tips(&mut self, signature: Option<&Signature>,
                       reflog_message: Option<&str>) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_update_tips(self.raw,
                                                signature.map(|s| &*s.raw()),
                                                reflog_message.map(|s| s.to_c_str())));
            Ok(())
        }
    }

    /// Return each status entry
    pub fn statuses(&mut self) -> Result<Vec<Status>, Error> {
        let mut ret: Vec<Status> = Vec::new();
        unsafe {
            try_call!(raw::git_push_status_foreach(self.raw, cb,
                                                   &mut ret as *mut _
                                                            as *mut libc::c_void));
        }
        return Ok(ret);

        extern fn cb(git_ref: *const libc::c_char,
                     msg: *const libc::c_char,
                     data: *mut libc::c_void) -> libc::c_int {
            unsafe {
                let git_ref = match CString::new(git_ref, false).as_str() {
                    Some(s) => s.to_string(),
                    None => return 0,
                };
                let msg = if !msg.is_null() {
                    match CString::new(msg, false).as_str() {
                        Some(s) => Some(s.to_string()),
                        None => return 0,
                    }
                } else {
                    None
                };

                let data = &mut *(data as *mut Vec<Status>);
                data.push(Status { reference: git_ref, message: msg });
                return 0;
            }
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Push<'a> {
    fn drop(&mut self) {
        unsafe { raw::git_push_free(self.raw) }
    }
}

#[cfg(test)]
mod tests {
    use std::io::TempDir;
    use Repository;

    #[test]
    fn smoke() {
        let td = TempDir::new("test").unwrap();
        let remote = td.path().join("remote");
        Repository::init_bare(&remote).unwrap();

        let (_td, repo) = ::test::repo_init();
        let url = format!("file://{}", remote.display());
        let mut remote = repo.remote_create("origin", url.as_slice()).unwrap();

        let mut push = remote.push().unwrap();
        push.add_refspec("refs/heads/master").unwrap();
        push.finish().unwrap();
        assert!(push.unpack_ok());
        push.update_tips(None, None).unwrap();
        let v = push.statuses().unwrap();
        assert!(v.len() > 0);
        assert_eq!(v[0].reference.as_slice(), "refs/heads/master");
        assert!(v[0].message.is_none());
    }
}
<commit_msg>Add some documentation for Push<commit_after>use std::kinds::marker;
use std::c_str::CString;
use libc;

use {raw, Remote, Error, Signature};

/// A structure to represent a pending push operation to a remote.
///
/// Remotes can create a `Push` which is then used to push data to the upstream
/// repository.
pub struct Push<'a> {
    raw: *mut raw::git_push,
    marker1: marker::ContravariantLifetime<'a>,
    marker2: marker::NoSend,
    marker3: marker::NoSync,
}

/// A status representing the result of updating a remote reference.
pub struct Status {
    /// The reference that was updated as part of a push.
    pub reference: String,
    /// If `None`, the reference was updated successfully, otherwise a message
    /// explaining why it could not be updated is provided.
    pub message: Option<String>,
}

impl<'a> Push<'a> {
    /// Create a new push from its raw component.
    ///
    /// This method is unsafe as there is no guarantee that `raw` is a valid
    /// pointer.
    pub unsafe fn from_raw<'a>(_remote: &'a Remote,
                               raw: *mut raw::git_push) -> Push<'a> {
        Push {
            raw: raw,
            marker1: marker::ContravariantLifetime,
            marker2: marker::NoSend,
            marker3: marker::NoSync,
        }
    }

    /// Get access to the underlying raw pointer.
    pub fn raw(&self) -> *mut raw::git_push { self.raw }

    /// Add a refspec to be pushed
    pub fn add_refspec(&mut self, refspec: &str) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_add_refspec(self.raw, refspec.to_c_str()));
            Ok(())
        }
    }

    /// Actually push all given refspecs
    ///
    /// To check if the push was successful (i.e. all remote references have
    /// been updated as requested), you need to call both `unpack_ok` and
    /// `statuses`. The remote repository might have refused to
    /// update some or all of the references.
    pub fn finish(&mut self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_finish(self.raw));
            Ok(())
        }
    }

    /// Check if remote side successfully unpacked
    pub fn unpack_ok(&self) -> bool {
        unsafe { raw::git_push_unpack_ok(&*self.raw) != 0 }
    }

    /// Update remote tips after a push
    pub fn update_tips(&mut self, signature: Option<&Signature>,
                       reflog_message: Option<&str>) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_push_update_tips(self.raw,
                                                signature.map(|s| &*s.raw()),
                                                reflog_message.map(|s| s.to_c_str())));
            Ok(())
        }
    }

    /// Return each status entry
    pub fn statuses(&mut self) -> Result<Vec<Status>, Error> {
        let mut ret: Vec<Status> = Vec::new();
        unsafe {
            try_call!(raw::git_push_status_foreach(self.raw, cb,
                                                   &mut ret as *mut _
                                                            as *mut libc::c_void));
        }
        return Ok(ret);

        extern fn cb(git_ref: *const libc::c_char,
                     msg: *const libc::c_char,
                     data: *mut libc::c_void) -> libc::c_int {
            unsafe {
                let git_ref = match CString::new(git_ref, false).as_str() {
                    Some(s) => s.to_string(),
                    None => return 0,
                };
                let msg = if !msg.is_null() {
                    match CString::new(msg, false).as_str() {
                        Some(s) => Some(s.to_string()),
                        None => return 0,
                    }
                } else {
                    None
                };

                let data = &mut *(data as *mut Vec<Status>);
                data.push(Status { reference: git_ref, message: msg });
                return 0;
            }
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Push<'a> {
    fn drop(&mut self) {
        unsafe { raw::git_push_free(self.raw) }
    }
}

#[cfg(test)]
mod tests {
    use std::io::TempDir;
    use Repository;

    #[test]
    fn smoke() {
        let td = TempDir::new("test").unwrap();
        let remote = td.path().join("remote");
        Repository::init_bare(&remote).unwrap();

        let (_td, repo) = ::test::repo_init();
        let url = format!("file://{}", remote.display());
        let mut remote = repo.remote_create("origin", url.as_slice()).unwrap();

        let mut push = remote.push().unwrap();
        push.add_refspec("refs/heads/master").unwrap();
        push.finish().unwrap();
        assert!(push.unpack_ok());
        push.update_tips(None, None).unwrap();
        let v = push.statuses().unwrap();
        assert!(v.len() > 0);
        assert_eq!(v[0].reference.as_slice(), "refs/heads/master");
        assert!(v[0].message.is_none());
    }
}
<|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.
//
// - Resolve variable names based on the C scope rules.
//   Local variables are resolved to offsets from the base pointer.
//   Global variables are resolved to their names.
//
// - 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.
//
// - Reject bad assignments, such as `1=2+3`.

use crate::parse::*;
use crate::util::*;
use std::collections::HashMap;
use std::mem;
use std::sync::Mutex;

lazy_static! {
    static ref STR_LABEL: Mutex<i32> = Mutex::new(0);
    static ref GLOBALS: Mutex<Vec<Var>> = Mutex::new(Vec::new());
    static ref STACKSIZE: Mutex<i32> = Mutex::new(0);
}

#[derive(Clone, Debug)]
struct Env<'a> {
    vars: HashMap<String, Var>,
    next: Option<Box<&'a Env<'a>>>,
}

fn new_env<'a>(next: Option<&'a Env>) -> Env<'a> {
    Env {
        vars: HashMap::new(),
        next: if let Some(e) = next {
            Some(Box::new(e))
        } else {
            None
        },
    }
}

fn new_int(val: i32) -> Node {
    let mut node = alloc_node();
    node.op = NodeType::NUM;
    node.ty = int_ty();
    node.val = val;
    return node;
}

impl<'a> Env<'a> {
    fn find(&self, name: & String) -> Option<&Var> {
        if let Some(v) = self.vars.get(name) {
            return Some(v);
        } else if let Some(ref next) = self.next {
            return next.find(name);
        } else {
            return None;
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Var {
    pub ty: Type,
    pub is_local: bool,

    // local
    pub offset: i32,

    // global
    pub name: String,
    pub is_extern: bool,
    pub data: String,
    pub len: usize,
}

fn alloc_var(ty: Type) -> Var {
    Var {
        ty: ty,
        is_local: false,
        offset: 0,
        name: String::new(),
        is_extern: false,
        data: String::new(),
        len: 0,
    }
}

fn new_global(ty: Type, name: String, data: String, len: usize) -> Var {
    let mut var = alloc_var(ty);
    var.is_local = false;
    //var.name = format!(".L.str{}", bump_str_label()).to_string();
    var.name = name;
    var.data = data;
    var.len = len;
    return var;
}

fn init_globals() {
    *GLOBALS.lock().unwrap() = Vec::new();
}

fn globals() -> Vec<Var> {
    GLOBALS.lock().unwrap().clone()
}

fn globals_push(var: Var) {
    let mut globals = GLOBALS.lock().unwrap();
    globals.push(var);
}

fn stacksize() -> i32 {
    *STACKSIZE.lock().unwrap()
}

fn init_stacksize() {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = 0;
}

fn set_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = i;
}

fn add_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize += i;
}

fn bump_str_label() -> i32 {
    let mut str_label = STR_LABEL.lock().unwrap();
    let ret = *str_label;
    *str_label += 1;
    return ret;
}

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.ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;
    base.ty = ptr_to(*tmp.clone().ty.ary_of.unwrap());

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

fn check_lval(node: & Node) {
    match node.op {
        NodeType::LVAR | NodeType::GVAR | NodeType::DEREF | NodeType::DOT => {
            return;
        }
        _ => {
            panic!("not an lvalue: {:?} ({})", node.op, node.name);
        }
    }
}

fn walk<'a>(node: &'a mut Node, env: &'a mut Env, decay: bool) -> &'a Node {
    match node.op {
        NodeType::NUM => {
            return node;
        }
        NodeType::STR => {
            let node_ty = node.ty.clone();
            let node_data = node.data.clone();

            let name = format!(".L.str{}", bump_str_label()).to_string();
            let var = new_global(node_ty.clone(), name, node_data, node.len);
            globals_push(var.clone());

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = node_ty;
            node.name = var.name;
            return maybe_decay(node, decay);
        }
        NodeType::IDENT => {
            let var = match env.find(&node.name) {
                None => panic!("undefined variable: {}", node.name),
                Some(var) => var,
            };

            if var.is_local {
                *node = alloc_node();
                node.op = NodeType::LVAR;
                node.ty = var.ty.clone();
                node.offset = var.offset;
                return maybe_decay(node, decay);
            }

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = var.ty.clone();
            node.name = var.name.clone();
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            set_stacksize(roundup(stacksize(), node.ty.align));
            add_stacksize(node.ty.size);
            node.offset = stacksize();

            let mut var = alloc_var(node.ty.clone());
            var.is_local = true;
            var.offset = stacksize();
            env.vars.insert(node.name.clone(), var.clone());

            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), env, true).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), env, true).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), env, true).clone()));

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

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }
            match node.rhs {
                Some(ref rhs) => {
                    if rhs.ty.ty == CType::PTR {
                        panic!("'pointer {:?} pointer' is not defined", node.op);
                    }
                }
                None => {
                }
            }

            match node.lhs {
                Some(ref lhs) => {
                    node.ty = lhs.ty.clone();
                }
                None => { }
            }

            return node;
        }
        NodeType::EQL => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), env, false).clone()));
            check_lval(& *node.lhs.clone().unwrap());

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

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

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

                node.ty = m.ty.clone();
                node.offset = m.ty.offset;
                return maybe_decay(node, decay);
            }
            panic!("member missing: {}", node.name);
        }
        NodeType::QUEST => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), env, true).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), env, true).clone()));
            node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), env, true).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(), env, true).clone()));
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), env, true).clone()));

                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(), env, true).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), env, true).clone()));
            node.ty = node.rhs.clone().unwrap().ty;
            return node;
        }
        NodeType::PRE_INC |
            NodeType::PRE_DEC |
            NodeType::POST_INC |
            NodeType::POST_DEC |
            NodeType::NEG |
            NodeType::EXCLAM => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            node.ty = node.expr.clone().unwrap().ty;
            return node;
        }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            check_lval(& *node.expr.clone().unwrap());
            node.ty = ptr_to(node.expr.clone().unwrap().ty);
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));

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

                    if expr.ty.ptr_to.clone().unwrap().ty == CType::VOID {
                        panic!("operand dereference void pointer");
                    }
                }
                None => {}
            }

            node.ty = *node.expr.clone().unwrap().ty.ptr_to.unwrap();
            return node;
        }
        NodeType::RETURN |
            NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::SIZEOF => {
            let mut nexpr = *node.expr.clone().unwrap();
            let expr = walk(&mut nexpr, env, false);
            let val = expr.ty.size;

            *node = new_int(val);
            return node;
        }
        NodeType::ALIGNOF => {
            let mut e = node.expr.clone().unwrap();
            let expr = walk(&mut e, env, false);
            *node = new_int(expr.ty.align);
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], env, true).clone();
            }
            node.ty = int_ty();
            return node;
        }
        NodeType::FUNC => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], env, true).clone();
            }
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            return node;
        }
        NodeType::COMP_STMT => {
            let mut newenv = new_env(Some(env));
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut node.stmts[i], &mut newenv, true).clone();
            }
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), env, true).clone()));
            node.ty = int_ty();
            return node;
        }
        NodeType::NULL => {
            return node;
        }
        _ => {
            panic!("unknown node type");
        }
    }
}

pub fn sema(nodes: &mut Vec<Node>) -> Vec<Var> {
    init_globals();
    let mut topenv = new_env(None);

    for node in nodes.iter_mut() {
        if node.op == NodeType::VARDEF {
            let mut var = new_global(node.ty.clone(), node.name.clone(), node.data.clone(), node.len);
            var.is_extern = node.is_extern;
            globals_push(var.clone());
            topenv.vars.insert(node.name.clone(), var);
            continue;
        }

        assert!(node.op == NodeType::FUNC);

        init_stacksize();
        walk(node, &mut topenv, true);
        node.stacksize = stacksize();
    }
    return globals();
}
<commit_msg>Make sema's env a global varaible so that we have less number of parameters.<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.
//
// - Resolve variable names based on the C scope rules.
//   Local variables are resolved to offsets from the base pointer.
//   Global variables are resolved to their names.
//
// - 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.
//
// - Reject bad assignments, such as `1=2+3`.

use crate::parse::*;
use crate::util::*;
use std::collections::HashMap;
use std::mem;
use std::sync::Mutex;

lazy_static! {
    static ref ENV: Mutex<Env> = Mutex::new(new_env(None));
    static ref STR_LABEL: Mutex<i32> = Mutex::new(0);
    static ref GLOBALS: Mutex<Vec<Var>> = Mutex::new(Vec::new());
    static ref STACKSIZE: Mutex<i32> = Mutex::new(0);
}

#[derive(Clone, Debug)]
struct Env {
    vars: HashMap<String, Var>,
    next: Option<Box<Env>>,
}

fn new_env(next: Option<Env>) -> Env {
    Env {
        vars: HashMap::new(),
        next: if let Some(e) = next {
            Some(Box::new(e))
        } else {
            None
        },
    }
}

fn env_var_put(name: String, var: Var) {
    match ENV.lock() {
        Ok(ref mut env) => {
            env.vars.insert(name, var);
        }
        Err(_) => {
            panic!();
        }
    }
}

fn env_push() {
    let mut env = ENV.lock().unwrap();
    *env = new_env(Some(env.clone()));
}

fn env_pop() {
    let mut env = ENV.lock().unwrap();
    *env = *env.next.clone().unwrap();
}

fn new_int(val: i32) -> Node {
    let mut node = alloc_node();
    node.op = NodeType::NUM;
    node.ty = int_ty();
    node.val = val;
    return node;
}

//impl<'a> Env<'a> {
impl Env {
    fn find(&self, name: & String) -> Option<&Var> {
        if let Some(v) = self.vars.get(name) {
            return Some(v);
        } else if let Some(ref next) = self.next {
            return next.find(name);
        } else {
            return None;
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Var {
    pub ty: Type,
    pub is_local: bool,

    // local
    pub offset: i32,

    // global
    pub name: String,
    pub is_extern: bool,
    pub data: String,
    pub len: usize,
}

fn alloc_var(ty: Type) -> Var {
    Var {
        ty: ty,
        is_local: false,
        offset: 0,
        name: String::new(),
        is_extern: false,
        data: String::new(),
        len: 0,
    }
}

fn new_global(ty: Type, name: String, data: String, len: usize) -> Var {
    let mut var = alloc_var(ty);
    var.is_local = false;
    //var.name = format!(".L.str{}", bump_str_label()).to_string();
    var.name = name;
    var.data = data;
    var.len = len;
    return var;
}

fn init_globals() {
    *GLOBALS.lock().unwrap() = Vec::new();
}

fn globals() -> Vec<Var> {
    GLOBALS.lock().unwrap().clone()
}

fn globals_push(var: Var) {
    let mut globals = GLOBALS.lock().unwrap();
    globals.push(var);
}

fn stacksize() -> i32 {
    *STACKSIZE.lock().unwrap()
}

fn init_stacksize() {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = 0;
}

fn set_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize = i;
}

fn add_stacksize(i: i32) {
    let mut stacksize = STACKSIZE.lock().unwrap();
    *stacksize += i;
}

fn bump_str_label() -> i32 {
    let mut str_label = STR_LABEL.lock().unwrap();
    let ret = *str_label;
    *str_label += 1;
    return ret;
}

fn find_var(name: String) -> Option<Var> {
    return match ENV.lock() {
        Ok(ref env) => {
            match env.find(&name) {
                Some(v) => Some(v.clone()),
                None => None,
            }
        }
        Err(_) => {
            panic!();
        }
    }
}

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.ty != CType::ARY {
        return base;
    }

    let tmp = base.clone();
    *base = alloc_node();
    base.op = NodeType::ADDR;
    base.ty = ptr_to(*tmp.clone().ty.ary_of.unwrap());

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

fn check_lval(node: & Node) {
    match node.op {
        NodeType::LVAR | NodeType::GVAR | NodeType::DEREF | NodeType::DOT => {
            return;
        }
        _ => {
            panic!("not an lvalue: {:?} ({})", node.op, node.name);
        }
    }
}

fn walk<'a>(node: &'a mut Node, decay: bool) -> &'a Node {
    match node.op {
        NodeType::NUM => {
            return node;
        }
        NodeType::STR => {
            let node_ty = node.ty.clone();
            let node_data = node.data.clone();

            let name = format!(".L.str{}", bump_str_label()).to_string();
            let var = new_global(node_ty.clone(), name, node_data, node.len);
            globals_push(var.clone());

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = node_ty;
            node.name = var.name;
            return maybe_decay(node, decay);
        }
        NodeType::IDENT => {
            let var = match find_var(node.name.clone()) {
                None => panic!("undefined variable: {}", node.name),
                Some(var) => var,
            };

            if var.is_local {
                *node = alloc_node();
                node.op = NodeType::LVAR;
                node.ty = var.ty.clone();
                node.offset = var.offset;
                return maybe_decay(node, decay);
            }

            *node = alloc_node();
            node.op = NodeType::GVAR;
            node.ty = var.ty.clone();
            node.name = var.name.clone();
            return maybe_decay(node, decay);
        }
        NodeType::VARDEF => {
            set_stacksize(roundup(stacksize(), node.ty.align));
            add_stacksize(node.ty.size);
            node.offset = stacksize();

            let mut var = alloc_var(node.ty.clone());
            var.is_local = true;
            var.offset = stacksize();
            env_var_put(node.name.clone(), var.clone());

            match node.init {
                Some(_) => {
                    node.init = Some(Box::new(walk(&mut *node.init.clone().unwrap(), true).clone()));
                }
                None => { }
            }
            return node;
        }
        NodeType::IF => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), true).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), true).clone()));

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

            match (&mut node.lhs, &mut node.rhs) {
                (Some(ref mut lhs), Some(ref mut rhs)) => {
                    if rhs.ty.ty == CType::PTR {
                        swap(lhs, rhs);
                    }
                }
                _ => {}
            }
            match node.rhs {
                Some(ref rhs) => {
                    if rhs.ty.ty == CType::PTR {
                        panic!("'pointer {:?} pointer' is not defined", node.op);
                    }
                }
                None => {
                }
            }

            match node.lhs {
                Some(ref lhs) => {
                    node.ty = lhs.ty.clone();
                }
                None => { }
            }

            return node;
        }
        NodeType::EQL => {
            node.lhs = Some(Box::new(walk(&mut *node.lhs.clone().unwrap(), false).clone()));
            check_lval(& *node.lhs.clone().unwrap());

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

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

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

                node.ty = m.ty.clone();
                node.offset = m.ty.offset;
                return maybe_decay(node, decay);
            }
            panic!("member missing: {}", node.name);
        }
        NodeType::QUEST => {
            node.cond = Some(Box::new(walk(&mut *node.cond.clone().unwrap(), true).clone()));
            node.then = Some(Box::new(walk(&mut *node.then.clone().unwrap(), true).clone()));
            node.els = Some(Box::new(walk(&mut *node.els.clone().unwrap(), true).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(), true).clone()));
                node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), true).clone()));

                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(), true).clone()));
            node.rhs = Some(Box::new(walk(&mut *node.rhs.clone().unwrap(), true).clone()));
            node.ty = node.rhs.clone().unwrap().ty;
            return node;
        }
        NodeType::PRE_INC |
            NodeType::PRE_DEC |
            NodeType::POST_INC |
            NodeType::POST_DEC |
            NodeType::NEG |
            NodeType::EXCLAM => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), true).clone()));
            node.ty = node.expr.clone().unwrap().ty;
            return node;
        }
        NodeType::ADDR => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), true).clone()));
            check_lval(& *node.expr.clone().unwrap());
            node.ty = ptr_to(node.expr.clone().unwrap().ty);
            return node;
        }
        NodeType::DEREF => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), true).clone()));

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

                    if expr.ty.ptr_to.clone().unwrap().ty == CType::VOID {
                        panic!("operand dereference void pointer");
                    }
                }
                None => {}
            }

            node.ty = *node.expr.clone().unwrap().ty.ptr_to.unwrap();
            return node;
        }
        NodeType::RETURN |
            NodeType::EXPR_STMT => {
            node.expr = Some(Box::new(walk(&mut *node.expr.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::SIZEOF => {
            let mut nexpr = *node.expr.clone().unwrap();
            let expr = walk(&mut nexpr, false);
            let val = expr.ty.size;

            *node = new_int(val);
            return node;
        }
        NodeType::ALIGNOF => {
            let mut e = node.expr.clone().unwrap();
            let expr = walk(&mut e, false);
            *node = new_int(expr.ty.align);
            return node;
        }
        NodeType::CALL => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], true).clone();
            }
            node.ty = int_ty();
            return node;
        }
        NodeType::FUNC => {
            for i in 0..node.args.len() {
                node.args[i] = walk(&mut node.args[i], true).clone();
            }
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), true).clone()));
            return node;
        }
        NodeType::COMP_STMT => {
            env_push();
            for i in 0..node.stmts.len() {
                node.stmts[i] = walk(&mut node.stmts[i], true).clone();
            }
            env_pop();
            return node;
        }
        NodeType::STMT_EXPR => {
            node.body = Some(Box::new(walk(&mut *node.body.clone().unwrap(), true).clone()));
            node.ty = int_ty();
            return node;
        }
        NodeType::NULL => {
            return node;
        }
        _ => {
            panic!("unknown node type");
        }
    }
}

pub fn sema(nodes: &mut Vec<Node>) -> Vec<Var> {
    init_globals();
    //let mut topenv = new_env(None);

    for node in nodes.iter_mut() {
        if node.op == NodeType::VARDEF {
            let mut var = new_global(node.ty.clone(), node.name.clone(), node.data.clone(), node.len);
            var.is_extern = node.is_extern;
            globals_push(var.clone());
            env_var_put(node.name.clone(), var);
            continue;
        }

        assert!(node.op == NodeType::FUNC);

        init_stacksize();
        walk(node, true);
        node.stacksize = stacksize();
    }
    return globals();
}
<|endoftext|>


<commit_before>#[derive(Copy, Clone, Debug)]
pub struct Rect {
    pub x: u32,
    pub y: u32,
    pub w: u32,
    pub h: u32,
}

impl Rect {
    pub fn new(x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h,
        }
    }

    pub fn new_with_points(x1: u32, y1: u32, x2: u32, y2: u32) -> Rect {
        Rect {
            x: x1,
            y: y1,
            w: x2 - x1 + 1,
            h: y2 - y1 + 1,
        }
    }

    #[inline(always)]
    pub fn top(&self) -> u32 {
        self.y
    }

    #[inline(always)]
    pub fn bottom(&self) -> u32 {
        self.y + self.h - 1
    }

    #[inline(always)]
    pub fn left(&self) -> u32 {
        self.x
    }

    #[inline(always)]
    pub fn right(&self) -> u32 {
        self.x + self.w - 1
    }

    #[inline(always)]
    pub fn area(&self) -> u32 {
        self.w * self.h
    }

    pub fn intersects(&self, other: &Rect) -> bool {
        self.left() < other.right()
            && self.right() > other.left()
            && self.top() < other.bottom()
            && self.bottom() > other.top()
    }

    pub fn contains(&self, other: &Rect) -> bool {
        self.left() <= other.left()
            && self.right() >= other.right()
            && self.top() <= other.top()
            && self.bottom() >= other.bottom()
    }

    pub fn contains_point(&self, x: u32, y: u32) -> bool {
        self.left() <= x && self.right() >= x && self.top() <= y && self.bottom() >= y
    }

    pub fn is_outline(&self, x: u32, y: u32) -> bool {
        x == self.left() || x == self.right() || y == self.top() || y == self.bottom()
    }

    pub fn crop(&self, other: &Rect) -> Vec<Rect> {
        if !self.intersects(other) {
            return vec![self.clone()];
        }

        let inside_x1 = if other.left() < self.left() {
            self.left()
        } else {
            other.left()
        };

        let inside_y1 = if other.top() < self.top() {
            self.top()
        } else {
            other.top()
        };

        let inside_x2 = if other.right() > self.right() {
            self.right()
        } else {
            other.right()
        };

        let inside_y2 = if other.bottom() > self.bottom() {
            self.bottom()
        } else {
            other.bottom()
        };

        //
        // *******************
        // *    | r3  |      *
        // *    |     |      *
        // *    +++++++      *
        // * r1 +     +      *
        // *    +     +  r2  *
        // *    +++++++      *
        // *    |     |      *
        // *    | r4  |      *
        // *******************
        //
        let mut result = Vec::new();

        let r1 = Rect::new_with_points(self.left(), self.top(), inside_x1, self.bottom());
        if r1.area() > 0 {
            result.push(r1);
        }

        let r2 = Rect::new_with_points(inside_x2, self.top(), self.right(), self.bottom());
        if r2.area() > 0 {
            result.push(r2);
        }

        let r3 = Rect::new_with_points(inside_x1, self.top(), inside_x2, inside_y1);
        if r3.area() > 0 {
            result.push(r3);
        }

        let r4 = Rect::new_with_points(inside_x1, inside_y2, inside_x2, self.bottom());
        if r4.area() > 0 {
            result.push(r4);
        }

        result
    }
}
<commit_msg>docs: Document the rect module contents<commit_after>/// Defines a rectangle in pixels with the origin at the top-left of the texture atlas.
#[derive(Copy, Clone, Debug)]
pub struct Rect {
    /// Horizontal position the rectangle begins at.
    pub x: u32,
    /// Vertical position the rectangle begins at.
    pub y: u32,
    /// Width of the rectangle.
    pub w: u32,
    /// Height of the rectangle.
    pub h: u32,
}

impl Rect {
    /// Create a new [Rect] based on a position and its width and height.
    pub fn new(x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h,
        }
    }

    /// Create a new [Rect] based on two points spanning the rectangle.
    pub fn new_with_points(x1: u32, y1: u32, x2: u32, y2: u32) -> Rect {
        Rect {
            x: x1,
            y: y1,
            w: x2 - x1 + 1,
            h: y2 - y1 + 1,
        }
    }

    /// Get the top coordinate of the rectangle.
    #[inline(always)]
    pub fn top(&self) -> u32 {
        self.y
    }

    /// Get the bottom coordinate of the rectangle.
    #[inline(always)]
    pub fn bottom(&self) -> u32 {
        self.y + self.h - 1
    }

    /// Get the left coordinate of the rectangle.
    #[inline(always)]
    pub fn left(&self) -> u32 {
        self.x
    }

    /// Get the right coordinate of the rectangle.
    #[inline(always)]
    pub fn right(&self) -> u32 {
        self.x + self.w - 1
    }

    /// Get the area of the rectangle.
    #[inline(always)]
    pub fn area(&self) -> u32 {
        self.w * self.h
    }

    /// Check if this rectangle intersects with another.
    pub fn intersects(&self, other: &Rect) -> bool {
        self.left() < other.right()
            && self.right() > other.left()
            && self.top() < other.bottom()
            && self.bottom() > other.top()
    }

    /// Check if this rectangle contains another.
    pub fn contains(&self, other: &Rect) -> bool {
        self.left() <= other.left()
            && self.right() >= other.right()
            && self.top() <= other.top()
            && self.bottom() >= other.bottom()
    }

    /// Check if this rectangle contains a point. Includes the edges of the rectangle.
    pub fn contains_point(&self, x: u32, y: u32) -> bool {
        self.left() <= x && self.right() >= x && self.top() <= y && self.bottom() >= y
    }

    /// Check if a point falls on the rectangle's boundaries.
    pub fn is_outline(&self, x: u32, y: u32) -> bool {
        x == self.left() || x == self.right() || y == self.top() || y == self.bottom()
    }

    /// Split two rectangles into non-overlapping regions.
    pub fn crop(&self, other: &Rect) -> Vec<Rect> {
        if !self.intersects(other) {
            return vec![self.clone()];
        }

        let inside_x1 = if other.left() < self.left() {
            self.left()
        } else {
            other.left()
        };

        let inside_y1 = if other.top() < self.top() {
            self.top()
        } else {
            other.top()
        };

        let inside_x2 = if other.right() > self.right() {
            self.right()
        } else {
            other.right()
        };

        let inside_y2 = if other.bottom() > self.bottom() {
            self.bottom()
        } else {
            other.bottom()
        };

        //
        // *******************
        // *    | r3  |      *
        // *    |     |      *
        // *    +++++++      *
        // * r1 +     +      *
        // *    +     +  r2  *
        // *    +++++++      *
        // *    |     |      *
        // *    | r4  |      *
        // *******************
        //
        let mut result = Vec::new();

        let r1 = Rect::new_with_points(self.left(), self.top(), inside_x1, self.bottom());
        if r1.area() > 0 {
            result.push(r1);
        }

        let r2 = Rect::new_with_points(inside_x2, self.top(), self.right(), self.bottom());
        if r2.area() > 0 {
            result.push(r2);
        }

        let r3 = Rect::new_with_points(inside_x1, self.top(), inside_x2, inside_y1);
        if r3.area() > 0 {
            result.push(r3);
        }

        let r4 = Rect::new_with_points(inside_x1, inside_y2, inside_x2, self.bottom());
        if r4.area() > 0 {
            result.push(r4);
        }

        result
    }
}
<|endoftext|>


<commit_before>use mio::*;
use mio::deprecated::{EventLoop, Handler};
use mio::udp::*;
use bytes::{Buf, MutBuf, RingBuf, SliceBuf};
use std::str;
use std::net::{SocketAddr, Ipv4Addr};
use localhost;

const LISTENER: Token = Token(0);
const SENDER: Token = Token(1);

pub struct UdpHandler {
    tx: UdpSocket,
    rx: UdpSocket,
    msg: &'static str,
    buf: SliceBuf<'static>,
    rx_buf: RingBuf
}

impl UdpHandler {
    fn new(tx: UdpSocket, rx: UdpSocket, msg: &'static str) -> UdpHandler {
        UdpHandler {
            tx: tx,
            rx: rx,
            msg: msg,
            buf: SliceBuf::wrap(msg.as_bytes()),
            rx_buf: RingBuf::new(1024)
        }
    }

    fn handle_read(&mut self, event_loop: &mut EventLoop<UdpHandler>, token: Token, _: Ready) {
        match token {
            LISTENER => {
                debug!("We are receiving a datagram now...");
                match unsafe { self.rx.recv_from(self.rx_buf.mut_bytes()) } {
                    Ok(Some((cnt, SocketAddr::V4(addr)))) => {
                        unsafe { MutBuf::advance(&mut self.rx_buf, cnt); }
                        assert_eq!(*addr.ip(), Ipv4Addr::new(127, 0, 0, 1));
                    }
                    res => panic!("unexpected result: {:?}", res),
                }
                assert!(str::from_utf8(self.rx_buf.bytes()).unwrap() == self.msg);
                event_loop.shutdown();
            },
            _ => ()
        }
    }

    fn handle_write(&mut self, _: &mut EventLoop<UdpHandler>, token: Token, _: Ready) {
        match token {
            SENDER => {
                let addr = self.rx.local_addr().unwrap();
                let cnt = self.tx.send_to(self.buf.bytes(), &addr)
                                 .unwrap().unwrap();
                self.buf.advance(cnt);
            },
            _ => ()
        }
    }
}

impl Handler for UdpHandler {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<UdpHandler>, token: Token, events: Ready) {
        if events.is_readable() {
            self.handle_read(event_loop, token, events);
        }

        if events.is_writable() {
            self.handle_write(event_loop, token, events);
        }
    }
}

#[test]
pub fn test_multicast() {
    drop(::env_logger::init());
    debug!("Starting TEST_UDP_CONNECTIONLESS");
    let mut event_loop = EventLoop::new().unwrap();

    let addr = localhost();
    let any = "0.0.0.0:0".parse().unwrap();

    let tx = UdpSocket::bind(&any).unwrap();
    let rx = UdpSocket::bind(&addr).unwrap();

    info!("Joining group 227.1.1.100");
    let any = "0.0.0.0".parse().unwrap();
    rx.join_multicast_v4(&"227.1.1.100".parse().unwrap(), &any).unwrap();

    info!("Joining group 227.1.1.101");
    rx.join_multicast_v4(&"227.1.1.101".parse().unwrap(), &any).unwrap();

    info!("Registering SENDER");
    event_loop.register(&tx, SENDER, Ready::writable(), PollOpt::edge()).unwrap();

    info!("Registering LISTENER");
    event_loop.register(&rx, LISTENER, Ready::readable(), PollOpt::edge()).unwrap();

    info!("Starting event loop to test with...");
    event_loop.run(&mut UdpHandler::new(tx, rx, "hello world")).unwrap();
}
<commit_msg>Fix test_multicast in shared-IP FreeBSD jails<commit_after>use mio::*;
use mio::deprecated::{EventLoop, Handler};
use mio::udp::*;
use bytes::{Buf, MutBuf, RingBuf, SliceBuf};
use std::str;
use std::net::IpAddr;
use localhost;

const LISTENER: Token = Token(0);
const SENDER: Token = Token(1);

pub struct UdpHandler {
    tx: UdpSocket,
    rx: UdpSocket,
    msg: &'static str,
    buf: SliceBuf<'static>,
    rx_buf: RingBuf,
    localhost: IpAddr
}

impl UdpHandler {
    fn new(tx: UdpSocket, rx: UdpSocket, msg: &'static str) -> UdpHandler {
        let sock = UdpSocket::bind(&"127.0.0.1:12345".parse().unwrap()).unwrap();
        UdpHandler {
            tx: tx,
            rx: rx,
            msg: msg,
            buf: SliceBuf::wrap(msg.as_bytes()),
            rx_buf: RingBuf::new(1024),
            localhost: sock.local_addr().unwrap().ip()
        }
    }

    fn handle_read(&mut self, event_loop: &mut EventLoop<UdpHandler>, token: Token, _: Ready) {
        match token {
            LISTENER => {
                debug!("We are receiving a datagram now...");
                match unsafe { self.rx.recv_from(self.rx_buf.mut_bytes()) } {
                    Ok(Some((cnt, addr))) => {
                        unsafe { MutBuf::advance(&mut self.rx_buf, cnt); }
                        assert_eq!(addr.ip(), self.localhost);
                    }
                    res => panic!("unexpected result: {:?}", res),
                }
                assert!(str::from_utf8(self.rx_buf.bytes()).unwrap() == self.msg);
                event_loop.shutdown();
            },
            _ => ()
        }
    }

    fn handle_write(&mut self, _: &mut EventLoop<UdpHandler>, token: Token, _: Ready) {
        match token {
            SENDER => {
                let addr = self.rx.local_addr().unwrap();
                let cnt = self.tx.send_to(self.buf.bytes(), &addr)
                                 .unwrap().unwrap();
                self.buf.advance(cnt);
            },
            _ => ()
        }
    }
}

impl Handler for UdpHandler {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<UdpHandler>, token: Token, events: Ready) {
        if events.is_readable() {
            self.handle_read(event_loop, token, events);
        }

        if events.is_writable() {
            self.handle_write(event_loop, token, events);
        }
    }
}

#[test]
pub fn test_multicast() {
    drop(::env_logger::init());
    debug!("Starting TEST_UDP_CONNECTIONLESS");
    let mut event_loop = EventLoop::new().unwrap();

    let addr = localhost();
    let any = "0.0.0.0:0".parse().unwrap();

    let tx = UdpSocket::bind(&any).unwrap();
    let rx = UdpSocket::bind(&addr).unwrap();

    info!("Joining group 227.1.1.100");
    let any = "0.0.0.0".parse().unwrap();
    rx.join_multicast_v4(&"227.1.1.100".parse().unwrap(), &any).unwrap();

    info!("Joining group 227.1.1.101");
    rx.join_multicast_v4(&"227.1.1.101".parse().unwrap(), &any).unwrap();

    info!("Registering SENDER");
    event_loop.register(&tx, SENDER, Ready::writable(), PollOpt::edge()).unwrap();

    info!("Registering LISTENER");
    event_loop.register(&rx, LISTENER, Ready::readable(), PollOpt::edge()).unwrap();

    info!("Starting event loop to test with...");
    event_loop.run(&mut UdpHandler::new(tx, rx, "hello world")).unwrap();
}
<|endoftext|>