<commit_before>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbimage;
extern crate orbfont;

use std::env;
use std::fs::File;
use std::path::Path;
use std::process::Command;

use orbclient::{Color, EventOption, Window};
use orbimage::Image;
use orbfont::Font;

use package::Package;

pub mod package;

const BAR_COLOR: Color = Color::rgb(40, 45, 57);
const BAR_HIGHLIGHT_COLOR: Color = Color::rgb(80, 86, 102);
const TEXT_COLOR: Color = Color::rgb(204, 210, 224);
const TEXT_HIGHLIGHT_COLOR: Color = Color::rgb(235, 241, 255);

//TODO: Implement display size in orbclient
#[cfg(target_os = "redox")]
fn get_display_size() -> (i32, i32) {
    match File::open("display:") {
        Ok(display) => {
            let path = display.path().map(|path| path.into_os_string().into_string().unwrap_or(String::new())).unwrap_or(String::new());
            let res = path.split(":").nth(1).unwrap_or("");
            let width = res.split("/").nth(0).unwrap_or("").parse::<i32>().unwrap_or(0);
            let height = res.split("/").nth(1).unwrap_or("").parse::<i32>().unwrap_or(0);
            (width, height)
        },
        Err(err) => panic!("launcher: failed to get display size: {}", err)
    }
}

#[cfg(not(target_os = "redox"))]
fn get_display_size() -> (i32, i32) {
    panic!("launcher: failed to get display size")
}

fn get_packages() -> Vec<Package> {
    let read_dir = Path::new("/apps/").read_dir().expect("failed to read_dir on /apps/");

    let mut entries = vec![];
    for dir in read_dir {
        let dir = match dir {
            Ok(x) => x,
            Err(_) => continue,
        };
        let file_name = dir.file_name().to_string_lossy().into_owned();
        if dir.file_type().expect("failed to get file_type").is_dir() {
            entries.push(file_name);
        }
    }

    entries.sort();

    let mut packages: Vec<Package> = Vec::new();
    for entry in entries.iter() {
        packages.push(Package::from_path(&format!("/apps/{}", entry)));
    }

    packages
}

fn draw(window: &mut Window, packages: &Vec<Package>, start: &Image, shutdown: &Image, selected: i32){
    let w = window.width();
    let h = window.height();
    window.set(BAR_COLOR);

    let mut x = 0;
    let mut i = 0;

    {
        let y = h as isize - start.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              start.width() as u32, start.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        start.draw(window, x as i32, y as i32);

        x += start.width() as i32;
        i += 1;
    }

    for package in packages.iter() {
        let y = h as isize - package.icon.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              package.icon.width() as u32, package.icon.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, x as i32, y as i32);

        x += package.icon.width() as i32;
        i += 1;
    }

    {
        x = w as i32 - shutdown.width() as i32;
        let y = h as isize - shutdown.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              shutdown.width() as u32, shutdown.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        shutdown.draw(window, x as i32, y as i32);
    }

    window.sync();
}

fn draw_chooser(window: &mut Window, font: &Font, packages: &Vec<Package>, _mouse_x: i32, mouse_y: i32){
    let w = window.width();

    window.set(BAR_COLOR);

    let mut y = 0;
    for package in packages.iter() {
        let highlight = mouse_y >= y as i32 && mouse_y < y + 32;

        if highlight {
            window.rect(0, y, w, 32, BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, 0, y);

        let mut c_x = 40;
        for c in package.name.chars() {
            font.render(&c.to_string(), 16.0).draw(window, c_x as i32, y + 8, if highlight { TEXT_HIGHLIGHT_COLOR } else { TEXT_COLOR });
            c_x += 8;
        }

        y += 32;
    }

    window.sync();
}

fn main() {
    let paths = env::args().skip(1);
    if paths.len() > 0 {
        for ref path in paths {
            let mut packages = get_packages();

            packages.retain(|package| -> bool {
                for accept in package.accepts.iter() {
                    if (accept.starts_with('*') && path.ends_with(&accept[1 ..])) ||
                       (accept.ends_with('*') && path.starts_with(&accept[.. accept.len() - 1])) {
                        return true;
                    }
                }
                false
            });

            if packages.len() > 1 {
                let mut window = Window::new(-1, -1, 400, packages.len() as u32 * 32, path).unwrap();
                let font = Font::find(None, None, None).unwrap();

                draw_chooser(&mut window, &font, &packages, -1, -1);
                'choosing: loop {
                    for event in window.events() {
                        match event.to_option() {
                            EventOption::Mouse(mouse_event) => {
                                draw_chooser(&mut window, &font, &packages, mouse_event.x, mouse_event.y);

                                if mouse_event.left_button {
                                    let mut y = 0;
                                    for package in packages.iter() {
                                        if mouse_event.y >= y && mouse_event.y < y + 32 {
                                            if let Err(err) = Command::new(&package.binary).arg(path).spawn() {
                                                println!("{}: Failed to launch: {}", package.binary, err);
                                            }
                                            break 'choosing;
                                        }
                                        y += 32;
                                    }
                                }
                            },
                            EventOption::Quit(_) => break 'choosing,
                            _ => ()
                        }
                    }
                }
            } else if let Some(package) = packages.get(0) {
                if let Err(err) = Command::new(&package.binary).arg(&path).spawn() {
                    println!("launcher: failed to launch '{}': {}", package.binary, err);
                }
            } else {
                println!("launcher: no application found for '{}'", path);
            }
        }
    } else {
        let packages = get_packages();

        let start = Image::from_path("/ui/apps/kde.bmp").unwrap_or(Image::default());

        let shutdown = Image::from_path("/ui/actions/system-shutdown.bmp").unwrap_or(Image::default());

        let (width, height) = get_display_size();
        let mut window = Window::new(0, height - 32, width as u32, 32, "").unwrap();

        let mut selected = -1;

        draw(&mut window, &packages, &start, &shutdown, selected);
        'running: loop {
            for event in window.events() {
                match event.to_option() {
                    EventOption::Mouse(mouse_event) => {
                        let mut now_selected = -1;

                        {
                            let mut x = 0;
                            let mut i = 0;

                            {
                                let y = window.height() as i32 - start.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + start.width() as i32 {
                                       now_selected = i;
                                }
                                x += start.width() as i32;
                                i += 1;
                            }

                            for package in packages.iter() {
                                let y = window.height() as i32 - package.icon.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + package.icon.width() as i32 {
                                    now_selected = i;
                                }
                                x += package.icon.width() as i32;
                                i += 1;
                            }

                            {
                                x = window.width() as i32 - shutdown.width() as i32;
                                let y = window.height() as i32 - shutdown.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + shutdown.width() as i32 {
                                       now_selected = i;
                                }
                            }
                        }

                        if now_selected != selected {
                            selected = now_selected;
                            draw(&mut window, &packages, &start, &shutdown, selected);
                        }

                        if mouse_event.left_button {
                            let mut i = 0;

                            if i == selected {
                                let start_h = packages.len() as u32 * 32;
                                let mut start_window = Window::new(0, height - 32 - start_h as i32, 400, start_h, "Start").unwrap();
                                let font = Font::find(None, None, None).unwrap();

                                draw_chooser(&mut start_window, &font, &packages, -1, -1);
                                'start_choosing: loop {
                                    for event in start_window.events() {
                                        match event.to_option() {
                                            EventOption::Mouse(mouse_event) => {
                                                draw_chooser(&mut start_window, &font, &packages, mouse_event.x, mouse_event.y);

                                                if mouse_event.left_button {
                                                    let mut y = 0;
                                                    for package in packages.iter() {
                                                        if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                            if let Err(err) = Command::new(&package.binary).spawn() {
                                                                println!("{}: Failed to launch: {}", package.binary, err);
                                                            }
                                                            break 'start_choosing;
                                                        }
                                                        y += 32;
                                                    }
                                                }
                                            },
                                            EventOption::Quit(_) => break 'start_choosing,
                                            _ => ()
                                        }
                                    }
                                }
                            }
                            i += 1;

                            for package in packages.iter() {
                                if i == selected {
                                    if let Err(err) = Command::new(&package.binary).spawn() {
                                        println!("{}: Failed to launch: {}", package.binary, err);
                                    }
                                }
                                i += 1;
                            }

                            if i == selected {
                                   File::create("acpi:off").unwrap();
                            }
                        }
                    },
                    EventOption::Quit(_) => break 'running,
                    _ => ()
                }
            }
        }
    }
}
<commit_msg>Update start icon<commit_after>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbimage;
extern crate orbfont;

use std::env;
use std::fs::File;
use std::path::Path;
use std::process::Command;

use orbclient::{Color, EventOption, Window};
use orbimage::Image;
use orbfont::Font;

use package::Package;

pub mod package;

const BAR_COLOR: Color = Color::rgb(40, 45, 57);
const BAR_HIGHLIGHT_COLOR: Color = Color::rgb(80, 86, 102);
const TEXT_COLOR: Color = Color::rgb(204, 210, 224);
const TEXT_HIGHLIGHT_COLOR: Color = Color::rgb(235, 241, 255);

//TODO: Implement display size in orbclient
#[cfg(target_os = "redox")]
fn get_display_size() -> (i32, i32) {
    match File::open("display:") {
        Ok(display) => {
            let path = display.path().map(|path| path.into_os_string().into_string().unwrap_or(String::new())).unwrap_or(String::new());
            let res = path.split(":").nth(1).unwrap_or("");
            let width = res.split("/").nth(0).unwrap_or("").parse::<i32>().unwrap_or(0);
            let height = res.split("/").nth(1).unwrap_or("").parse::<i32>().unwrap_or(0);
            (width, height)
        },
        Err(err) => panic!("launcher: failed to get display size: {}", err)
    }
}

#[cfg(not(target_os = "redox"))]
fn get_display_size() -> (i32, i32) {
    panic!("launcher: failed to get display size")
}

fn get_packages() -> Vec<Package> {
    let read_dir = Path::new("/apps/").read_dir().expect("failed to read_dir on /apps/");

    let mut entries = vec![];
    for dir in read_dir {
        let dir = match dir {
            Ok(x) => x,
            Err(_) => continue,
        };
        let file_name = dir.file_name().to_string_lossy().into_owned();
        if dir.file_type().expect("failed to get file_type").is_dir() {
            entries.push(file_name);
        }
    }

    entries.sort();

    let mut packages: Vec<Package> = Vec::new();
    for entry in entries.iter() {
        packages.push(Package::from_path(&format!("/apps/{}", entry)));
    }

    packages
}

fn draw(window: &mut Window, packages: &Vec<Package>, start: &Image, shutdown: &Image, selected: i32){
    let w = window.width();
    let h = window.height();
    window.set(BAR_COLOR);

    let mut x = 0;
    let mut i = 0;

    {
        let y = h as isize - start.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              start.width() as u32, start.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        start.draw(window, x as i32, y as i32);

        x += start.width() as i32;
        i += 1;
    }

    for package in packages.iter() {
        let y = h as isize - package.icon.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              package.icon.width() as u32, package.icon.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, x as i32, y as i32);

        x += package.icon.width() as i32;
        i += 1;
    }

    {
        x = w as i32 - shutdown.width() as i32;
        let y = h as isize - shutdown.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              shutdown.width() as u32, shutdown.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        shutdown.draw(window, x as i32, y as i32);
    }

    window.sync();
}

fn draw_chooser(window: &mut Window, font: &Font, packages: &Vec<Package>, _mouse_x: i32, mouse_y: i32){
    let w = window.width();

    window.set(BAR_COLOR);

    let mut y = 0;
    for package in packages.iter() {
        let highlight = mouse_y >= y as i32 && mouse_y < y + 32;

        if highlight {
            window.rect(0, y, w, 32, BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, 0, y);

        let mut c_x = 40;
        for c in package.name.chars() {
            font.render(&c.to_string(), 16.0).draw(window, c_x as i32, y + 8, if highlight { TEXT_HIGHLIGHT_COLOR } else { TEXT_COLOR });
            c_x += 8;
        }

        y += 32;
    }

    window.sync();
}

fn main() {
    let paths = env::args().skip(1);
    if paths.len() > 0 {
        for ref path in paths {
            let mut packages = get_packages();

            packages.retain(|package| -> bool {
                for accept in package.accepts.iter() {
                    if (accept.starts_with('*') && path.ends_with(&accept[1 ..])) ||
                       (accept.ends_with('*') && path.starts_with(&accept[.. accept.len() - 1])) {
                        return true;
                    }
                }
                false
            });

            if packages.len() > 1 {
                let mut window = Window::new(-1, -1, 400, packages.len() as u32 * 32, path).unwrap();
                let font = Font::find(None, None, None).unwrap();

                draw_chooser(&mut window, &font, &packages, -1, -1);
                'choosing: loop {
                    for event in window.events() {
                        match event.to_option() {
                            EventOption::Mouse(mouse_event) => {
                                draw_chooser(&mut window, &font, &packages, mouse_event.x, mouse_event.y);

                                if mouse_event.left_button {
                                    let mut y = 0;
                                    for package in packages.iter() {
                                        if mouse_event.y >= y && mouse_event.y < y + 32 {
                                            if let Err(err) = Command::new(&package.binary).arg(path).spawn() {
                                                println!("{}: Failed to launch: {}", package.binary, err);
                                            }
                                            break 'choosing;
                                        }
                                        y += 32;
                                    }
                                }
                            },
                            EventOption::Quit(_) => break 'choosing,
                            _ => ()
                        }
                    }
                }
            } else if let Some(package) = packages.get(0) {
                if let Err(err) = Command::new(&package.binary).arg(&path).spawn() {
                    println!("launcher: failed to launch '{}': {}", package.binary, err);
                }
            } else {
                println!("launcher: no application found for '{}'", path);
            }
        }
    } else {
        let packages = get_packages();

        let start = Image::from_path("/ui/start.png").unwrap_or(Image::default());

        let shutdown = Image::from_path("/ui/actions/system-shutdown.bmp").unwrap_or(Image::default());

        let (width, height) = get_display_size();
        let mut window = Window::new(0, height - 32, width as u32, 32, "").unwrap();

        let mut selected = -1;

        draw(&mut window, &packages, &start, &shutdown, selected);
        'running: loop {
            for event in window.events() {
                match event.to_option() {
                    EventOption::Mouse(mouse_event) => {
                        let mut now_selected = -1;

                        {
                            let mut x = 0;
                            let mut i = 0;

                            {
                                let y = window.height() as i32 - start.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + start.width() as i32 {
                                       now_selected = i;
                                }
                                x += start.width() as i32;
                                i += 1;
                            }

                            for package in packages.iter() {
                                let y = window.height() as i32 - package.icon.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + package.icon.width() as i32 {
                                    now_selected = i;
                                }
                                x += package.icon.width() as i32;
                                i += 1;
                            }

                            {
                                x = window.width() as i32 - shutdown.width() as i32;
                                let y = window.height() as i32 - shutdown.height() as i32;
                                if mouse_event.y >= y && mouse_event.x >= x &&
                                   mouse_event.x < x + shutdown.width() as i32 {
                                       now_selected = i;
                                }
                            }
                        }

                        if now_selected != selected {
                            selected = now_selected;
                            draw(&mut window, &packages, &start, &shutdown, selected);
                        }

                        if mouse_event.left_button {
                            let mut i = 0;

                            if i == selected {
                                let start_h = packages.len() as u32 * 32;
                                let mut start_window = Window::new(0, height - 32 - start_h as i32, 400, start_h, "Start").unwrap();
                                let font = Font::find(None, None, None).unwrap();

                                draw_chooser(&mut start_window, &font, &packages, -1, -1);
                                'start_choosing: loop {
                                    for event in start_window.events() {
                                        match event.to_option() {
                                            EventOption::Mouse(mouse_event) => {
                                                draw_chooser(&mut start_window, &font, &packages, mouse_event.x, mouse_event.y);

                                                if mouse_event.left_button {
                                                    let mut y = 0;
                                                    for package in packages.iter() {
                                                        if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                            if let Err(err) = Command::new(&package.binary).spawn() {
                                                                println!("{}: Failed to launch: {}", package.binary, err);
                                                            }
                                                            break 'start_choosing;
                                                        }
                                                        y += 32;
                                                    }
                                                }
                                            },
                                            EventOption::Quit(_) => break 'start_choosing,
                                            _ => ()
                                        }
                                    }
                                }
                            }
                            i += 1;

                            for package in packages.iter() {
                                if i == selected {
                                    if let Err(err) = Command::new(&package.binary).spawn() {
                                        println!("{}: Failed to launch: {}", package.binary, err);
                                    }
                                }
                                i += 1;
                            }

                            if i == selected {
                                   File::create("acpi:off").unwrap();
                            }
                        }
                    },
                    EventOption::Quit(_) => break 'running,
                    _ => ()
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};

use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
use rustc_mir::interpret::Memory;
use rustc_target::abi::Size;

use crate::stacked_borrows::Tag;
use crate::Evaluator;

pub type MemoryExtra = RefCell<GlobalState>;

#[derive(Clone, Debug, Default)]
pub struct AllocExtra {
    base_addr: Cell<Option<u64>>
}

#[derive(Clone, Debug)]
pub struct GlobalState {
    /// This is used as a map between the address of each allocation and its `AllocId`.
    /// It is always sorted
    pub int_to_ptr_map: Vec<(u64, AllocId)>,
    /// This is used as a memory address when a new pointer is casted to an integer. It
    /// is always larger than any address that was previously made part of a block.
    pub next_base_addr: u64,
}

impl Default for GlobalState {
    // FIXME: Query the page size in the future
    fn default() -> Self {
        GlobalState {
            int_to_ptr_map: Vec::default(),
            next_base_addr: 2u64.pow(16)
        }
    }
}

impl<'mir, 'tcx> GlobalState {
    pub fn int_to_ptr(
        int: u64,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<Tag>> {
        let global_state = memory.extra.intptrcast.borrow();

        match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) {
            Ok(pos) => {
                let (_, alloc_id) = global_state.int_to_ptr_map[pos];
                // `int` is equal to the starting address for an allocation, the offset should be
                // zero. The pointer is untagged because it was created from a cast
                Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
            },
            Err(0) => err!(DanglingPointerDeref),
            Err(pos) => {
                // This is the largest of the adresses smaller than `int`,
                // i.e. the greatest lower bound (glb)
                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
                // This never overflows because `int >= glb`
                let offset = int - glb;
                // If the offset exceeds the size of the allocation, this access is illegal
                if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
                    // This pointer is untagged because it was created from a cast
                    Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
                } else {
                    err!(DanglingPointerDeref)
                }
            }
        }
    }

    pub fn ptr_to_int(
        ptr: Pointer<Tag>,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, u64> {
        let mut global_state = memory.extra.intptrcast.borrow_mut();

        let alloc = memory.get(ptr.alloc_id)?;

        let base_addr = match alloc.extra.intptrcast.base_addr.get() {
            Some(base_addr) => base_addr,
            None => {
                // This allocation does not have a base address yet, pick one.
                let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes());
                global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
                alloc.extra.intptrcast.base_addr.set(Some(base_addr));
                // Given that `next_base_addr` increases in each allocation, pushing the
                // corresponding tuple keeps `int_to_ptr_map` sorted
                global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));

                base_addr
            }
        };

        Ok(base_addr + ptr.offset.bytes())
    }

    /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
    /// of `align` that is strictly larger to `addr`
    fn align_addr(addr: u64, align: u64) -> u64 {
        addr + align - addr % align
    }
}
<commit_msg>Auto merge of #794 - RalfJung:alignment-sanity, r=oli-obk<commit_after>use std::cell::{Cell, RefCell};

use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
use rustc_mir::interpret::Memory;
use rustc_target::abi::Size;

use crate::stacked_borrows::Tag;
use crate::Evaluator;

pub type MemoryExtra = RefCell<GlobalState>;

#[derive(Clone, Debug, Default)]
pub struct AllocExtra {
    base_addr: Cell<Option<u64>>
}

#[derive(Clone, Debug)]
pub struct GlobalState {
    /// This is used as a map between the address of each allocation and its `AllocId`.
    /// It is always sorted
    pub int_to_ptr_map: Vec<(u64, AllocId)>,
    /// This is used as a memory address when a new pointer is casted to an integer. It
    /// is always larger than any address that was previously made part of a block.
    pub next_base_addr: u64,
}

impl Default for GlobalState {
    // FIXME: Query the page size in the future
    fn default() -> Self {
        GlobalState {
            int_to_ptr_map: Vec::default(),
            next_base_addr: 2u64.pow(16)
        }
    }
}

impl<'mir, 'tcx> GlobalState {
    pub fn int_to_ptr(
        int: u64,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<Tag>> {
        let global_state = memory.extra.intptrcast.borrow();

        match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) {
            Ok(pos) => {
                let (_, alloc_id) = global_state.int_to_ptr_map[pos];
                // `int` is equal to the starting address for an allocation, the offset should be
                // zero. The pointer is untagged because it was created from a cast
                Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
            },
            Err(0) => err!(DanglingPointerDeref),
            Err(pos) => {
                // This is the largest of the adresses smaller than `int`,
                // i.e. the greatest lower bound (glb)
                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
                // This never overflows because `int >= glb`
                let offset = int - glb;
                // If the offset exceeds the size of the allocation, this access is illegal
                if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
                    // This pointer is untagged because it was created from a cast
                    Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
                } else {
                    err!(DanglingPointerDeref)
                }
            }
        }
    }

    pub fn ptr_to_int(
        ptr: Pointer<Tag>,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, u64> {
        let mut global_state = memory.extra.intptrcast.borrow_mut();

        let alloc = memory.get(ptr.alloc_id)?;

        let base_addr = match alloc.extra.intptrcast.base_addr.get() {
            Some(base_addr) => base_addr,
            None => {
                // This allocation does not have a base address yet, pick one.
                let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes());
                global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
                alloc.extra.intptrcast.base_addr.set(Some(base_addr));
                // Given that `next_base_addr` increases in each allocation, pushing the
                // corresponding tuple keeps `int_to_ptr_map` sorted
                global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));

                base_addr
            }
        };

        debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check
        Ok(base_addr + ptr.offset.bytes())
    }

    /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
    /// of `align` that is strictly larger to `addr`
    fn align_addr(addr: u64, align: u64) -> u64 {
        addr + align - addr % align
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use range::Range;
use super::piston_meta::MetaData;
use super::piston_meta::bootstrap::Convert;
use super::lt::{arg_lifetime, Lifetime};
use super::kind::Kind;
use super::ArgNames;
use ast::AssignOp;
use Lt;
use Type;

#[derive(Debug)]
pub struct Node {
    /// The kind of node.
    pub kind: Kind,
    /// The names associated with a node.
    pub names: Vec<Arc<String>>,
    /// The type.
    pub ty: Option<Type>,
    /// Whether the argument or call argument is mutable.
    pub mutable: bool,
    /// Whether there is a `?` operator used on the node.
    pub try: bool,
    /// The range in source.
    pub source: Range,
    /// The parent index.
    pub parent: Option<usize>,
    /// The children.
    pub children: Vec<usize>,
    /// The start index in meta data.
    pub start: usize,
    /// The end index in meta data.
    pub end: usize,
    /// The lifetime.
    pub lifetime: Option<Arc<String>>,
    /// The declaration.
    pub declaration: Option<usize>,
    /// Operation.
    pub op: Option<AssignOp>,
    /// Number of ids.
    /// Used to determine declaration of locals.
    pub ids: u32,
    /// The argument lifetime constraints, one for each argument to a function.
    /// Just using an empty vector for nodes that are not functions.
    pub lts: Vec<Lt>,
}

impl Node {
    pub fn name(&self) -> Option<&Arc<String>> {
        if self.names.len() == 0 { None }
        else { Some(&self.names[0]) }
    }

    pub fn print(&self, nodes: &[Node], indent: u32) {
        for _ in 0..indent { print!(" ") }
        println!("kind: {:?}, name: {:?}, type: {:?} {{", self.kind, self.name(), self.ty);
        for &c in &self.children {
            nodes[c].print(nodes, indent + 1);
        }
        for _ in 0..indent { print!(" ") }
        println!("}}")
    }

    pub fn find_child_by_kind(&self, nodes: &[Node], kind: Kind) -> Option<usize> {
        for &ch in &self.children {
            if nodes[ch].kind == kind { return Some(ch); }
        }
        return None
    }

    pub fn item_ids(&self) -> bool {
        if self.kind == Kind::Item && self.children.len() > 0 { true }
        else { false }
    }

    pub fn inner_type(&self, ty: &Type) -> Type {
        if self.try {
            match ty {
                &Type::Option(ref ty) => (**ty).clone(),
                &Type::Result(ref ty) => (**ty).clone(),
                x => x.clone()
            }
        } else {
            ty.clone()
        }
    }

    pub fn has_lifetime(&self) -> bool {
        use super::kind::Kind::*;

        match self.kind {
            Pow | Sum | SumVec4 | Min | Max | Any | All |
            Vec4 | Vec4UnLoop | Swizzle |
            Assign | For | ForN | Link => false,
            Add | Mul | Compare => self.children.len() == 1,
            _ => true
        }
    }

    pub fn lifetime(
        &self,
        nodes: &[Node],
        arg_names: &ArgNames
    ) -> Option<Lifetime> {
        if !self.has_lifetime() { return None; }
        if let Some(declaration) = self.declaration {
            if self.kind == Kind::Item {
                let arg = &nodes[declaration];
                if arg.kind == Kind::Arg {
                    return arg_lifetime(declaration, &arg, nodes, arg_names);
                } else if arg.kind == Kind::Current {
                    return Some(Lifetime::Current(declaration));
                } else {
                    return Some(Lifetime::Local(declaration));
                }
            }
        } else {
            // Intrinsic functions copies argument constraints to the call.
            if self.kind == Kind::Call && self.lts.len() > 0 {
                let mut returns_static = true;
                'args: for (_, lt) in self.children.iter().map(|&i| &nodes[i])
                        .filter(|&n| n.kind == Kind::CallArg)
                        .zip(self.lts.iter()) {
                    let mut lt = *lt;
                    loop {
                        match lt {
                            Lt::Default => {
                                continue 'args;
                            }
                            Lt::Return => {
                                returns_static = false;
                                break 'args;
                            }
                            x => {
                                lt = x;
                                continue;
                            }
                        }
                    }
                }

                if returns_static {
                    return None;
                }
            } else if self.kind == Kind::Item
                && self.name().map(|n| &**n == "return") == Some(true) {
                return Some(Lifetime::Return(vec![]));
            }
        }

        // Pick the smallest lifetime among children.
        let mut min: Option<Lifetime> = None;
        // TODO: Filter by kind of children.
        let mut call_arg_ind = 0;
        for &c in &self.children {
            match (self.kind, nodes[c].kind) {
                (_, Kind::Link) => {}
                (_, Kind::LinkItem) => {}
                (_, Kind::ReturnVoid) => {}
                (_, Kind::Swizzle) => {}
                (_, Kind::Loop) => {}
                (_, Kind::Go) => {}
                (_, Kind::For) => {}
                (_, Kind::ForN) => {}
                (_, Kind::Break) => {}
                (_, Kind::Continue) => {}
                (_, Kind::Sift) => {}
                (_, Kind::SumVec4) => {}
                (_, Kind::Sum) => {}
                (_, Kind::Min) => {}
                (_, Kind::Max) => {}
                (_, Kind::Any) => {}
                (_, Kind::All) => {}
                (_, Kind::Vec4UnLoop) => {}
                (_, Kind::Vec4) => {}
                (_, Kind::Start) => { continue }
                (_, Kind::End) => { continue }
                (_, Kind::Assign) => {}
                (_, Kind::Object) => {}
                (_, Kind::KeyValue) => {}
                (_, Kind::Val) => {}
                (_, Kind::Add) => {}
                (_, Kind::Mul) => {}
                (_, Kind::Call) => {}
                (_, Kind::Item) => {}
                (_, Kind::UnOp) => {
                    // The result of all unary operators does not depend
                    // on the lifetime of the argument.
                    continue
                }
                (_, Kind::Compare) => {
                    // The result of all compare operators does not depend
                    // on the lifetime of the arguments.
                    continue
                }
                (_, Kind::Left) => {}
                (_, Kind::Right) => {}
                (_, Kind::Expr) => {}
                (_, Kind::Return) => {}
                (_, Kind::Array) => {}
                (_, Kind::ArrayItem) => {}
                (_, Kind::ArrayFill) => {}
                (_, Kind::Pow) => {}
                (_, Kind::Base) => {}
                (_, Kind::Exp) => {}
                (_, Kind::Block) => {}
                (_, Kind::If) => {}
                (_, Kind::TrueBlock) => {}
                (_, Kind::ElseIfBlock) => {}
                (_, Kind::ElseBlock) => {}
                (_, Kind::Cond) => {
                    // A condition controls the flow, but the result does not
                    // depend on its lifetime.
                    continue
                }
                (_, Kind::ElseIfCond) => {
                    // A condition controls the flow, but the result does not
                    // depend on its lifetime.
                    continue
                }
                (_, Kind::Fill) => {}
                (_, Kind::N) => {
                    // The result of array fill does not depend on `n`.
                    continue
                }
                (Kind::Call, Kind::CallArg) => {
                    // If there is no return lifetime on the declared argument,
                    // there is no need to check it, because the computed value
                    // does not depend on the lifetime of that argument.
                    if let Some(declaration) = self.declaration {
                        if let Some(&arg) = nodes[declaration].children.iter()
                            .filter(|&&i| nodes[i].kind == Kind::Arg)
                            .nth(call_arg_ind) {
                            match arg_lifetime(arg, &nodes[arg],
                                               nodes, arg_names) {
                                Some(Lifetime::Return(_)) => {}
                                _ => {
                                    call_arg_ind += 1;
                                    continue;
                                }
                            }
                        }
                    }
                    call_arg_ind += 1;
                }
                x => panic!("Unimplemented `{:?}`. \
                        Perhaps you need add something to `Node::has_lifetime`?", x),
            }
            let lifetime = match nodes[c].lifetime(nodes, arg_names) {
                Some(lifetime) => lifetime,
                None => { continue; }
            };
            if min.is_none() || min.as_ref().map(|l| l < &lifetime) == Some(true) {
                min = Some(lifetime);
            }
        }
        min
    }
}

pub fn convert_meta_data(
    nodes: &mut Vec<Node>,
    data: &[Range<MetaData>]
) -> Result<(), Range<String>> {
    let mut parents: Vec<usize> = vec![];
    let ref mut ignored = vec![];
    let mut skip: Option<usize> = None;
    for (i, d) in data.iter().enumerate() {
        if let Some(j) = skip {
            if j > i { continue; }
        }
        match d.data {
            MetaData::StartNode(ref kind_name) => {
                let kind = match Kind::new(kind_name) {
                    Some(kind) => kind,
                    None => return Err(d.range().wrap(format!("Unknown kind `{}`", kind_name)))
                };

                // Parse type information and put it in parent node.
                if kind == Kind::Type || kind == Kind::RetType {
                    let convert = Convert::new(&data[i..]);
                    if let Ok((range, val)) = Type::from_meta_data(kind_name, convert, ignored) {
                        let parent = *parents.last().unwrap();
                        nodes[parent].ty = Some(val);
                        skip = Some(range.next_offset() + i);
                        continue;
                    }
                }

                let ty = match kind {
                    Kind::Array | Kind::ArrayFill => Some(Type::array()),
                    Kind::Vec4 | Kind::Vec4UnLoop => Some(Type::Vec4),
                    Kind::Object => Some(Type::object()),
                    Kind::Sum => Some(Type::F64),
                    Kind::Swizzle => Some(Type::F64),
                    Kind::Compare => Some(Type::Bool),
                    Kind::Link => Some(Type::Link),
                    Kind::Any | Kind::All => Some(Type::Bool),
                    _ => None
                };

                let parent = parents.last().map(|i| *i);
                parents.push(nodes.len());
                nodes.push(Node {
                    kind: kind,
                    names: vec![],
                    ty: ty,
                    mutable: false,
                    try: false,
                    source: Range::empty(0),
                    parent: parent,
                    children: vec![],
                    start: i,
                    end: 0,
                    lifetime: None,
                    declaration: None,
                    op: None,
                    ids: 0,
                    lts: vec![]
                });
            }
            MetaData::EndNode(_) => {
                let ind = parents.pop().unwrap();
                {
                    let node = &mut nodes[ind];
                    node.source = d.range();
                    node.end = i + 1;
                }
                match parents.last() {
                    Some(&parent) => {
                        nodes[parent].children.push(ind);
                    }
                    None => {}
                }
            }
            MetaData::String(ref n, ref val) => {
                match &***n {
                    "name" => {
                        let i = *parents.last().unwrap();
                        nodes[i].names.push(val.clone());
                    }
                    "word" => {
                        // Put words together to name.
                        let i = *parents.last().unwrap();
                        if nodes[i].names.len() == 0 {
                            let mut name = val.clone();
                            Arc::make_mut(&mut name).push('_');
                            nodes[i].names.push(name);
                        } else if let Some(ref mut name) = nodes[i].names.get_mut(0) {
                            let name = Arc::make_mut(name);
                            name.push('_');
                            name.push_str(val);
                        }
                    }
                    "lifetime" => {
                        let i = *parents.last().unwrap();
                        nodes[i].lifetime = Some(val.clone());
                    }
                    "id" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ids += 1;
                    }
                    "text" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::Text);
                    }
                    _ => {}
                }
            }
            MetaData::Bool(ref n, _val) => {
                match &***n {
                    ":=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Assign);
                    }
                    "=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Set);
                    }
                    "+=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Add);
                    }
                    "-=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Sub);
                    }
                    "*=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Mul);
                    }
                    "/=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Div);
                    }
                    "%=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Rem);
                    }
                    "^=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Pow);
                    }
                    "mut" => {
                        let i = *parents.last().unwrap();
                        nodes[i].mutable = _val;
                    }
                    "try" | "try_item" => {
                        let i = *parents.last().unwrap();
                        nodes[i].try = _val;
                    }
                    "bool" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::Bool);
                    }
                    "returns" => {
                        // Assuming this will be overwritten when
                        // type is parsed or inferred.
                        let i = *parents.last().unwrap();
                        if _val {
                            nodes[i].ty = Some(Type::Any);
                        } else {
                            nodes[i].ty = Some(Type::Void);
                        }
                    }
                    "return_void" => {
                        // There is no sub node, so we need change kind of parent.
                        // This should always be an expression.
                        let i = *parents.last().unwrap();
                        nodes[i].kind = Kind::ReturnVoid;
                    }
                    _ => {}
                }
            }
            MetaData::F64(ref n, _) => {
                match &***n {
                    "num" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::F64);
                    }
                    _ => {}
                }
            }
        }
    }
    Ok(())
}
<commit_msg>Infer type from sift loops<commit_after>use std::sync::Arc;
use range::Range;
use super::piston_meta::MetaData;
use super::piston_meta::bootstrap::Convert;
use super::lt::{arg_lifetime, Lifetime};
use super::kind::Kind;
use super::ArgNames;
use ast::AssignOp;
use Lt;
use Type;

#[derive(Debug)]
pub struct Node {
    /// The kind of node.
    pub kind: Kind,
    /// The names associated with a node.
    pub names: Vec<Arc<String>>,
    /// The type.
    pub ty: Option<Type>,
    /// Whether the argument or call argument is mutable.
    pub mutable: bool,
    /// Whether there is a `?` operator used on the node.
    pub try: bool,
    /// The range in source.
    pub source: Range,
    /// The parent index.
    pub parent: Option<usize>,
    /// The children.
    pub children: Vec<usize>,
    /// The start index in meta data.
    pub start: usize,
    /// The end index in meta data.
    pub end: usize,
    /// The lifetime.
    pub lifetime: Option<Arc<String>>,
    /// The declaration.
    pub declaration: Option<usize>,
    /// Operation.
    pub op: Option<AssignOp>,
    /// Number of ids.
    /// Used to determine declaration of locals.
    pub ids: u32,
    /// The argument lifetime constraints, one for each argument to a function.
    /// Just using an empty vector for nodes that are not functions.
    pub lts: Vec<Lt>,
}

impl Node {
    pub fn name(&self) -> Option<&Arc<String>> {
        if self.names.len() == 0 { None }
        else { Some(&self.names[0]) }
    }

    pub fn print(&self, nodes: &[Node], indent: u32) {
        for _ in 0..indent { print!(" ") }
        println!("kind: {:?}, name: {:?}, type: {:?} {{", self.kind, self.name(), self.ty);
        for &c in &self.children {
            nodes[c].print(nodes, indent + 1);
        }
        for _ in 0..indent { print!(" ") }
        println!("}}")
    }

    pub fn find_child_by_kind(&self, nodes: &[Node], kind: Kind) -> Option<usize> {
        for &ch in &self.children {
            if nodes[ch].kind == kind { return Some(ch); }
        }
        return None
    }

    pub fn item_ids(&self) -> bool {
        if self.kind == Kind::Item && self.children.len() > 0 { true }
        else { false }
    }

    pub fn inner_type(&self, ty: &Type) -> Type {
        if self.try {
            match ty {
                &Type::Option(ref ty) => (**ty).clone(),
                &Type::Result(ref ty) => (**ty).clone(),
                x => x.clone()
            }
        } else {
            ty.clone()
        }
    }

    pub fn has_lifetime(&self) -> bool {
        use super::kind::Kind::*;

        match self.kind {
            Pow | Sum | SumVec4 | Min | Max | Any | All |
            Vec4 | Vec4UnLoop | Swizzle |
            Assign | For | ForN | Link => false,
            Add | Mul | Compare => self.children.len() == 1,
            _ => true
        }
    }

    pub fn lifetime(
        &self,
        nodes: &[Node],
        arg_names: &ArgNames
    ) -> Option<Lifetime> {
        if !self.has_lifetime() { return None; }
        if let Some(declaration) = self.declaration {
            if self.kind == Kind::Item {
                let arg = &nodes[declaration];
                if arg.kind == Kind::Arg {
                    return arg_lifetime(declaration, &arg, nodes, arg_names);
                } else if arg.kind == Kind::Current {
                    return Some(Lifetime::Current(declaration));
                } else {
                    return Some(Lifetime::Local(declaration));
                }
            }
        } else {
            // Intrinsic functions copies argument constraints to the call.
            if self.kind == Kind::Call && self.lts.len() > 0 {
                let mut returns_static = true;
                'args: for (_, lt) in self.children.iter().map(|&i| &nodes[i])
                        .filter(|&n| n.kind == Kind::CallArg)
                        .zip(self.lts.iter()) {
                    let mut lt = *lt;
                    loop {
                        match lt {
                            Lt::Default => {
                                continue 'args;
                            }
                            Lt::Return => {
                                returns_static = false;
                                break 'args;
                            }
                            x => {
                                lt = x;
                                continue;
                            }
                        }
                    }
                }

                if returns_static {
                    return None;
                }
            } else if self.kind == Kind::Item
                && self.name().map(|n| &**n == "return") == Some(true) {
                return Some(Lifetime::Return(vec![]));
            }
        }

        // Pick the smallest lifetime among children.
        let mut min: Option<Lifetime> = None;
        // TODO: Filter by kind of children.
        let mut call_arg_ind = 0;
        for &c in &self.children {
            match (self.kind, nodes[c].kind) {
                (_, Kind::Link) => {}
                (_, Kind::LinkItem) => {}
                (_, Kind::ReturnVoid) => {}
                (_, Kind::Swizzle) => {}
                (_, Kind::Loop) => {}
                (_, Kind::Go) => {}
                (_, Kind::For) => {}
                (_, Kind::ForN) => {}
                (_, Kind::Break) => {}
                (_, Kind::Continue) => {}
                (_, Kind::Sift) => {}
                (_, Kind::SumVec4) => {}
                (_, Kind::Sum) => {}
                (_, Kind::Min) => {}
                (_, Kind::Max) => {}
                (_, Kind::Any) => {}
                (_, Kind::All) => {}
                (_, Kind::Vec4UnLoop) => {}
                (_, Kind::Vec4) => {}
                (_, Kind::Start) => { continue }
                (_, Kind::End) => { continue }
                (_, Kind::Assign) => {}
                (_, Kind::Object) => {}
                (_, Kind::KeyValue) => {}
                (_, Kind::Val) => {}
                (_, Kind::Add) => {}
                (_, Kind::Mul) => {}
                (_, Kind::Call) => {}
                (_, Kind::Item) => {}
                (_, Kind::UnOp) => {
                    // The result of all unary operators does not depend
                    // on the lifetime of the argument.
                    continue
                }
                (_, Kind::Compare) => {
                    // The result of all compare operators does not depend
                    // on the lifetime of the arguments.
                    continue
                }
                (_, Kind::Left) => {}
                (_, Kind::Right) => {}
                (_, Kind::Expr) => {}
                (_, Kind::Return) => {}
                (_, Kind::Array) => {}
                (_, Kind::ArrayItem) => {}
                (_, Kind::ArrayFill) => {}
                (_, Kind::Pow) => {}
                (_, Kind::Base) => {}
                (_, Kind::Exp) => {}
                (_, Kind::Block) => {}
                (_, Kind::If) => {}
                (_, Kind::TrueBlock) => {}
                (_, Kind::ElseIfBlock) => {}
                (_, Kind::ElseBlock) => {}
                (_, Kind::Cond) => {
                    // A condition controls the flow, but the result does not
                    // depend on its lifetime.
                    continue
                }
                (_, Kind::ElseIfCond) => {
                    // A condition controls the flow, but the result does not
                    // depend on its lifetime.
                    continue
                }
                (_, Kind::Fill) => {}
                (_, Kind::N) => {
                    // The result of array fill does not depend on `n`.
                    continue
                }
                (Kind::Call, Kind::CallArg) => {
                    // If there is no return lifetime on the declared argument,
                    // there is no need to check it, because the computed value
                    // does not depend on the lifetime of that argument.
                    if let Some(declaration) = self.declaration {
                        if let Some(&arg) = nodes[declaration].children.iter()
                            .filter(|&&i| nodes[i].kind == Kind::Arg)
                            .nth(call_arg_ind) {
                            match arg_lifetime(arg, &nodes[arg],
                                               nodes, arg_names) {
                                Some(Lifetime::Return(_)) => {}
                                _ => {
                                    call_arg_ind += 1;
                                    continue;
                                }
                            }
                        }
                    }
                    call_arg_ind += 1;
                }
                x => panic!("Unimplemented `{:?}`. \
                        Perhaps you need add something to `Node::has_lifetime`?", x),
            }
            let lifetime = match nodes[c].lifetime(nodes, arg_names) {
                Some(lifetime) => lifetime,
                None => { continue; }
            };
            if min.is_none() || min.as_ref().map(|l| l < &lifetime) == Some(true) {
                min = Some(lifetime);
            }
        }
        min
    }
}

pub fn convert_meta_data(
    nodes: &mut Vec<Node>,
    data: &[Range<MetaData>]
) -> Result<(), Range<String>> {
    let mut parents: Vec<usize> = vec![];
    let ref mut ignored = vec![];
    let mut skip: Option<usize> = None;
    for (i, d) in data.iter().enumerate() {
        if let Some(j) = skip {
            if j > i { continue; }
        }
        match d.data {
            MetaData::StartNode(ref kind_name) => {
                let kind = match Kind::new(kind_name) {
                    Some(kind) => kind,
                    None => return Err(d.range().wrap(format!("Unknown kind `{}`", kind_name)))
                };

                // Parse type information and put it in parent node.
                if kind == Kind::Type || kind == Kind::RetType {
                    let convert = Convert::new(&data[i..]);
                    if let Ok((range, val)) = Type::from_meta_data(kind_name, convert, ignored) {
                        let parent = *parents.last().unwrap();
                        nodes[parent].ty = Some(val);
                        skip = Some(range.next_offset() + i);
                        continue;
                    }
                }

                let ty = match kind {
                    Kind::Array | Kind::ArrayFill => Some(Type::array()),
                    Kind::Vec4 | Kind::Vec4UnLoop => Some(Type::Vec4),
                    Kind::Object => Some(Type::object()),
                    Kind::Sift => Some(Type::array()),
                    Kind::Sum => Some(Type::F64),
                    Kind::Swizzle => Some(Type::F64),
                    Kind::Compare => Some(Type::Bool),
                    Kind::Link => Some(Type::Link),
                    Kind::Any | Kind::All => Some(Type::Bool),
                    _ => None
                };

                let parent = parents.last().map(|i| *i);
                parents.push(nodes.len());
                nodes.push(Node {
                    kind: kind,
                    names: vec![],
                    ty: ty,
                    mutable: false,
                    try: false,
                    source: Range::empty(0),
                    parent: parent,
                    children: vec![],
                    start: i,
                    end: 0,
                    lifetime: None,
                    declaration: None,
                    op: None,
                    ids: 0,
                    lts: vec![]
                });
            }
            MetaData::EndNode(_) => {
                let ind = parents.pop().unwrap();
                {
                    let node = &mut nodes[ind];
                    node.source = d.range();
                    node.end = i + 1;
                }
                match parents.last() {
                    Some(&parent) => {
                        nodes[parent].children.push(ind);
                    }
                    None => {}
                }
            }
            MetaData::String(ref n, ref val) => {
                match &***n {
                    "name" => {
                        let i = *parents.last().unwrap();
                        nodes[i].names.push(val.clone());
                    }
                    "word" => {
                        // Put words together to name.
                        let i = *parents.last().unwrap();
                        if nodes[i].names.len() == 0 {
                            let mut name = val.clone();
                            Arc::make_mut(&mut name).push('_');
                            nodes[i].names.push(name);
                        } else if let Some(ref mut name) = nodes[i].names.get_mut(0) {
                            let name = Arc::make_mut(name);
                            name.push('_');
                            name.push_str(val);
                        }
                    }
                    "lifetime" => {
                        let i = *parents.last().unwrap();
                        nodes[i].lifetime = Some(val.clone());
                    }
                    "id" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ids += 1;
                    }
                    "text" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::Text);
                    }
                    _ => {}
                }
            }
            MetaData::Bool(ref n, _val) => {
                match &***n {
                    ":=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Assign);
                    }
                    "=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Set);
                    }
                    "+=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Add);
                    }
                    "-=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Sub);
                    }
                    "*=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Mul);
                    }
                    "/=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Div);
                    }
                    "%=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Rem);
                    }
                    "^=" => {
                        let i = *parents.last().unwrap();
                        nodes[i].op = Some(AssignOp::Pow);
                    }
                    "mut" => {
                        let i = *parents.last().unwrap();
                        nodes[i].mutable = _val;
                    }
                    "try" | "try_item" => {
                        let i = *parents.last().unwrap();
                        nodes[i].try = _val;
                    }
                    "bool" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::Bool);
                    }
                    "returns" => {
                        // Assuming this will be overwritten when
                        // type is parsed or inferred.
                        let i = *parents.last().unwrap();
                        if _val {
                            nodes[i].ty = Some(Type::Any);
                        } else {
                            nodes[i].ty = Some(Type::Void);
                        }
                    }
                    "return_void" => {
                        // There is no sub node, so we need change kind of parent.
                        // This should always be an expression.
                        let i = *parents.last().unwrap();
                        nodes[i].kind = Kind::ReturnVoid;
                    }
                    _ => {}
                }
            }
            MetaData::F64(ref n, _) => {
                match &***n {
                    "num" => {
                        let i = *parents.last().unwrap();
                        nodes[i].ty = Some(Type::F64);
                    }
                    _ => {}
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate unicode_names;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Emoji;
impl Emoji {
    pub fn new() -> Emoji {
        Emoji {}
    }

    fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> {

        let mut names: Vec<String> = Vec::new();
        for emoji in self.return_emojis(content) {

            let name = match unicode_names::name(emoji) {
                Some(v) => format!("{}", v).to_lowercase(),
                None => "UNKNOWN".to_string(),
            };

            names.push(name);
        }

        server.send_privmsg(target, &names.join(", "))
    }

    fn return_emojis(&self, string: &str) -> Vec<char> {

        let mut emojis: Vec<char> = Vec::new();

        for c in string.chars() {
            if self.is_emoji(&c) {
                emojis.push(c);
            }
        }

        emojis
    }

    fn is_emoji(&self, c: &char) -> bool {
        match *c { '\u{1F600}'...'\u{1F64F}'     // Emoticons
            | '\u{1F300}'...'\u{1F5FF}'          // Misc Symbols and Pictographs
            | '\u{1F680}'...'\u{1F6FF}'          // Transport and Map
            | '\u{2600}' ...'\u{26FF}'           // Misc symbols
            | '\u{2700}' ...'\u{27BF}'           // Dingbats
            | '\u{FE00}' ...'\u{FE0F}'           // Variation Selectors
            | '\u{1F900}'...'\u{1F9FF}'          // Supplemental Symbols and Pictographs
            | '\u{20D0}' ...'\u{20FF}' => true,  // Combining Diacritical Marks for Symbols
            _ => false,
        }
    }
}

impl Plugin for Emoji {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, _) => true,
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(ref target, ref content) => self.emoji(server, content, target),
            _ => Ok(()),
        }
    }

    fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Mention emoji range source<commit_after>extern crate unicode_names;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Emoji;
impl Emoji {
    pub fn new() -> Emoji {
        Emoji {}
    }

    fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> {

        let mut names: Vec<String> = Vec::new();
        for emoji in self.return_emojis(content) {

            let name = match unicode_names::name(emoji) {
                Some(v) => format!("{}", v).to_lowercase(),
                None => "UNKNOWN".to_string(),
            };

            names.push(name);
        }

        server.send_privmsg(target, &names.join(", "))
    }

    fn return_emojis(&self, string: &str) -> Vec<char> {

        let mut emojis: Vec<char> = Vec::new();

        for c in string.chars() {
            if self.is_emoji(&c) {
                emojis.push(c);
            }
        }

        emojis
    }

    fn is_emoji(&self, c: &char) -> bool {
        // Emoji ranges from stackoverflow:
        // https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji
        match *c { '\u{1F600}'...'\u{1F64F}'     // Emoticons
            | '\u{1F300}'...'\u{1F5FF}'          // Misc Symbols and Pictographs
            | '\u{1F680}'...'\u{1F6FF}'          // Transport and Map
            | '\u{2600}' ...'\u{26FF}'           // Misc symbols
            | '\u{2700}' ...'\u{27BF}'           // Dingbats
            | '\u{FE00}' ...'\u{FE0F}'           // Variation Selectors
            | '\u{1F900}'...'\u{1F9FF}'          // Supplemental Symbols and Pictographs
            | '\u{20D0}' ...'\u{20FF}' => true,  // Combining Diacritical Marks for Symbols
            _ => false,
        }
    }
}

impl Plugin for Emoji {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, _) => true,
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(ref target, ref content) => self.emoji(server, content, target),
            _ => Ok(()),
        }
    }

    fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>