<commit_before>extern crate libc;

use libc::{c_int, c_void};

use super::*;

pub enum VTermScreen {}

// Temporarily stub these in
pub enum VTermRect {}
pub enum VTermProp {}
pub enum VTermValue {}

#[repr(C)]
#[derive(PartialEq, Debug)]
pub struct VTermPos {
    pub row: c_int,
    pub col: c_int,
}

#[repr(C)]
pub struct VTermScreenCallbacks<'a> {
    damage:         &'a Fn(VTermRect, *mut c_void) -> (c_int),
    move_rect:      &'a Fn(VTermRect, VTermRect, *mut c_void) -> (c_int),
    move_cursor:    &'a Fn(VTermPos, VTermPos, c_int, *mut c_void) -> (c_int),
    set_term_prop:  &'a Fn(VTermProp, VTermValue, *mut c_void) -> (c_int),
    bell:           &'a Fn(*mut c_void) -> (c_int),
    resize:         &'a Fn(c_int, c_int, *mut c_void) -> c_int,
    sb_pushline:    &'a Fn(c_int, *const VTermScreenCell, *mut c_void) -> c_int,
    sb_popline:     &'a Fn(c_int, *const VTermScreenCell, *mut c_void) -> c_int,
}

extern {
    pub fn vterm_screen_reset(screen: *mut VTermScreen, hard: c_int);
    pub fn vterm_screen_get_cell(screen: *const VTermScreen, pos: VTermPos, cell: *mut VTermScreenCell) -> c_int;
    pub fn vterm_screen_set_callbacks(screen: *mut VTermScreen, callbacks: *const VTermScreenCallbacks, user: *mut c_void);
}

mod tests {
    extern crate libc;

    use super::super::*;
    use libc::{c_int, c_void};

    #[test]
    fn ffi_screen_can_reset() {
        unsafe {
            let vterm_ptr: *mut VTerm = vterm_new(2, 2);
            let screen_ptr = vterm_obtain_screen(vterm_ptr);
            vterm_screen_reset(screen_ptr, 1);
            vterm_free(vterm_ptr);
        }
    }

    #[test]
    fn ffi_screen_can_get_cell() {
        unsafe {
            // TODO: write something so the cell will have a known value
            let vterm_ptr: *mut VTerm = vterm_new(2, 2);
            let screen_ptr = vterm_obtain_screen(vterm_ptr);
            let pos = VTermPos { row: 1, col: 0 };
            let cell_ptr: *mut VTermScreenCell = vterm_cell_new();
            let ret = vterm_screen_get_cell(screen_ptr, pos, cell_ptr);
            assert_eq!(0, ret);

            vterm_cell_free(cell_ptr);
            vterm_free(vterm_ptr);
        }
    }

    fn handler_helper(name: String, strings: *mut Vec<String>) {
        unsafe { (*strings).push(name); }
    }
    fn damage_handler(_: VTermRect, strings: *mut c_void) -> c_int { 1 }
    fn move_rect_handler(_: VTermRect, _: VTermRect, strings: *mut c_void) -> c_int { 1 }
    fn move_cursor_handler(_: VTermPos, _: VTermPos, _: c_int, strings: *mut c_void) -> c_int { 1 }
    fn set_term_prop_handler(_: VTermProp, _: VTermValue, strings: *mut c_void) -> c_int { 1 }
    fn bell_handler(strings: *mut c_void) -> c_int { 1 }
    fn resize_handler(_: c_int, _: c_int, strings: *mut c_void) -> c_int { 1 }
    fn sb_pushline_handler(_: c_int, _: *const VTermScreenCell, strings: *mut c_void) -> c_int { 1 }
    fn sb_popline_handler(_: c_int, _: *const VTermScreenCell, strings: *mut c_void) -> c_int { 1 }

    #[test]
    fn ffi_screen_can_set_callbacks() {

        // libvterm crashes with a segfault here. It seems that in parser.c#140 its calling the
        // text callback while passing in the cbdata as the user void pointer, but the default
        // handler at state.c:222 is expected to get the state!
        unsafe {
            // TODO: write something so the cell will have a known value
            let vterm_ptr: *mut VTerm = vterm_new(5, 5);
            vterm_set_utf8(vterm_ptr, -1);
            let screen_ptr: *mut VTermScreen = vterm_obtain_screen(vterm_ptr);
            vterm_screen_reset(screen_ptr, 1);

            let callbacks = VTermScreenCallbacks {
                damage:         &damage_handler,
                move_rect:      &move_rect_handler,
                move_cursor:    &move_cursor_handler,
                set_term_prop:  &set_term_prop_handler,
                bell:           &bell_handler,
                resize:         &resize_handler,
                sb_pushline:    &sb_pushline_handler,
                sb_popline:     &sb_popline_handler,
            };

            let mut strings: Vec<String> = vec!();
            let strings_ptr: *mut c_void = &mut strings as *mut _ as *mut c_void;
            //vterm_screen_set_callbacks(screen_ptr, &callbacks, strings_ptr);

            let input_bytes = "xyz".as_bytes();
            let input_ptr = input_bytes.as_ptr();
            vterm_input_write(vterm_ptr, input_ptr, input_bytes.len() as libc::size_t);

            vterm_free(vterm_ptr);
        }
    }
}
<commit_msg>Callbacks are working.<commit_after>extern crate libc;

use libc::{c_int, c_void};

use super::*;

pub enum VTermScreen {}

// Temporarily stub these in
pub enum VTermProp {}
pub enum VTermValue {}

#[repr(C)]
#[derive(PartialEq, Debug)]
pub struct VTermPos {
    pub row: c_int,
    pub col: c_int,
}

#[repr(C)]
#[derive(PartialEq, Debug)]
pub struct VTermRect {
    pub start_row: c_int,
    pub end_row: c_int,
    pub start_col: c_int,
    pub end_col: c_int,
}

#[repr(C)]
pub struct VTermScreenCallbacks {
    damage:         extern fn(VTermRect, *mut c_void) -> (c_int),
    move_rect:      extern fn(VTermRect, VTermRect, *mut c_void) -> (c_int),
    move_cursor:    extern fn(VTermPos, VTermPos, c_int, *mut c_void) -> (c_int),
    set_term_prop:  extern fn(VTermProp, VTermValue, *mut c_void) -> (c_int),
    bell:           extern fn(*mut c_void) -> (c_int),
    resize:         extern fn(c_int, c_int, *mut c_void) -> c_int,
    sb_pushline:    extern fn(c_int, *const VTermScreenCell, *mut c_void) -> c_int,
    sb_popline:     extern fn(c_int, *const VTermScreenCell, *mut c_void) -> c_int,
}

extern {
    pub fn vterm_screen_reset(screen: *mut VTermScreen, hard: c_int);
    pub fn vterm_screen_get_cell(screen: *const VTermScreen, pos: VTermPos, cell: *mut VTermScreenCell) -> c_int;
    pub fn vterm_screen_set_callbacks(screen: *mut VTermScreen, callbacks: *const VTermScreenCallbacks, user: *mut c_void);
}

mod tests {
    extern crate libc;

    use super::super::*;
    use libc::{c_int, c_void};

    #[test]
    fn ffi_screen_can_reset() {
        unsafe {
            let vterm_ptr: *mut VTerm = vterm_new(2, 2);
            let screen_ptr = vterm_obtain_screen(vterm_ptr);
            vterm_screen_reset(screen_ptr, 1);
            vterm_free(vterm_ptr);
        }
    }

    #[test]
    fn ffi_screen_can_get_cell() {
        unsafe {
            // TODO: write something so the cell will have a known value
            let vterm_ptr: *mut VTerm = vterm_new(2, 2);
            let screen_ptr = vterm_obtain_screen(vterm_ptr);
            let pos = VTermPos { row: 1, col: 0 };
            let cell_ptr: *mut VTermScreenCell = vterm_cell_new();
            let ret = vterm_screen_get_cell(screen_ptr, pos, cell_ptr);
            assert_eq!(0, ret);

            vterm_cell_free(cell_ptr);
            vterm_free(vterm_ptr);
        }
    }

    fn handler_helper(name: String, strings: *mut c_void) {
        println!("handler helper {}", name);
        let mut strings: &mut Vec<String> = unsafe { &mut *(strings as *mut Vec<String>) };
        strings.push(name);
    }

    extern "C" fn damage_handler(_: VTermRect, strings: *mut c_void) -> c_int {
        handler_helper("damage".to_string(), strings);
        1
    }
    extern "C" fn move_rect_handler(_: VTermRect, _: VTermRect, strings: *mut c_void) -> c_int {
        handler_helper("move_rect".to_string(), strings);
        1
    }
    extern "C" fn move_cursor_handler(_: VTermPos, _: VTermPos, _: c_int, strings: *mut c_void) -> c_int {
        handler_helper("move_cursor".to_string(), strings);
        1
    }
    extern "C" fn set_term_prop_handler(_: VTermProp, _: VTermValue, strings: *mut c_void) -> c_int {
        handler_helper("set_term_prop".to_string(), strings);
        1
    }
    extern "C" fn bell_handler(strings: *mut c_void) -> c_int {
        handler_helper("bell".to_string(), strings);
        1
    }
    extern "C" fn resize_handler(_: c_int, _: c_int, strings: *mut c_void) -> c_int {
        handler_helper("resize".to_string(), strings);
        1
    }
    extern "C" fn sb_pushline_handler(_: c_int, _: *const VTermScreenCell, strings: *mut c_void) -> c_int {
        handler_helper("sb_pushline".to_string(), strings);
        1
    }
    extern "C" fn sb_popline_handler(_: c_int, _: *const VTermScreenCell, strings: *mut c_void) -> c_int {
        handler_helper("sb_popline".to_string(), strings);
        1
    }

    #[test]
    fn ffi_screen_can_set_callbacks() {

        // libvterm crashes with a segfault here. It seems that in parser.c#140 its calling the
        // text callback while passing in the cbdata as the user void pointer, but the default
        // handler at state.c:222 is expected to get the state!
        unsafe {
            // TODO: write something so the cell will have a known value
            let vterm_ptr: *mut VTerm = vterm_new(5, 5);
            vterm_set_utf8(vterm_ptr, -1);
            let screen_ptr: *mut VTermScreen = vterm_obtain_screen(vterm_ptr);
            vterm_screen_reset(screen_ptr, 1);

            let callbacks = VTermScreenCallbacks {
                damage:         damage_handler,
                move_rect:      move_rect_handler,
                move_cursor:    move_cursor_handler,
                set_term_prop:  set_term_prop_handler,
                bell:           bell_handler,
                resize:         resize_handler,
                sb_pushline:    sb_pushline_handler,
                sb_popline:     sb_popline_handler,
            };

            let mut strings: Vec<String> = vec!();
            let strings_ptr: *mut c_void = &mut strings as *mut _ as *mut c_void;
            vterm_screen_set_callbacks(screen_ptr, &callbacks, strings_ptr);

            let input_bytes = "hi".as_bytes();
            let input_ptr = input_bytes.as_ptr();
            vterm_input_write(vterm_ptr, input_ptr, input_bytes.len() as libc::size_t);

            assert_eq!("damage.damage.move_cursor", strings.connect("."));

            vterm_free(vterm_ptr);
        }
    }
}
<|endoftext|>


<commit_before>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b111111111;
static BRANCH_MARKER: u8 = 0b0;

struct BTree<'a, K> {
	segment: u64,
	manager: &'a mut buffer::BufferManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: TotalOrd + Zero> BTree<'a, K> {
	fn new<'b>(segment_id: u64, dummy: K, manager: &'b mut buffer::BufferManager) -> BTree<'b, K> {
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(1),
			next_free_page: 2,
		}
	}

	//fn locate_page

	fn insert(&mut self, key: K, value: schema::TID) {
		let node = self.tree.load(self.manager);
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = 0;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = 255;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(self, key: K) -> Option<schema::TID> {
		None
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

// TODO implement Drop to unfix page
impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: TotalOrd + Zero>(&self, manager: &mut buffer::BufferManager) -> Node<'a, K> {
		let pagelock = manager.fix_page(self.page_id).unwrap();
		let page = pagelock.read();
		LazyNode::load_node(page.get_data())
	}

	/* helper method to load a Node tepending on the page marker */
	fn load_node<'a, K: TotalOrd + Zero>(page: &[u8]) -> Node<'a, K> {
		if page[0] == 255 {
			Leaf(LeafNode::new(page))
		} else {
			Branch(BranchNode::new(page))
		}
	}
}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
}

impl<'a, K: TotalOrd + Zero> LeafNode<'a, K> {
	fn new(page: &[u8]) -> LeafNode<'a, K> {
		// first byte is a Leaf/Branch marker
		let entry_size = size_of::<LeafEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;

		let mut r: &mut[LeafEntry<K>] = unsafe {
			cast::transmute(
				Slice::<LeafEntry<K>> {
					data: page.as_ptr() as *() as *LeafEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		LeafNode {
			entries: r,
			capacity: capacity
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		if self.capacity == 0 {
			// TODO split
			fail!("Not implemented");
			return None
		}

		// find place to insert
		let location = self.find_slot(&key);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {
				found = i - 1;
				break;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// actually, this rotates right by 1 starting from index
		let last_elem = self.entries.len() - 1;
		for i in range(index, last_elem) {
			self.entries.swap(i, last_elem);
		}
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
}

impl<'a, K: TotalOrd + Zero> BranchNode<'a, K> {
	fn new(page: &[u8]) -> BranchNode<'a, K> {
		let entry_size = size_of::<BranchEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;
		let mut r: &mut [BranchEntry<K>] = unsafe {
			cast::transmute(
				Slice::<BranchEntry<K>> {
					data: page.as_ptr() as *() as *BranchEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager);
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, 42, &mut manager);
	bt.insert(42, schema::TID::new(0, 0));
	assert!(false);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(0).unwrap();
	let page = pagelock.read();
	let lp: LeafNode<u64> = LeafNode::new(page.get_data());
	println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<commit_msg>Replaced magic marker numbers<commit_after>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b111111111;
static BRANCH_MARKER: u8 = 0b0;

struct BTree<'a, K> {
	segment: u64,
	manager: &'a mut buffer::BufferManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: TotalOrd + Zero> BTree<'a, K> {
	fn new<'b>(segment_id: u64, dummy: K, manager: &'b mut buffer::BufferManager) -> BTree<'b, K> {
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(1),
			next_free_page: 2,
		}
	}

	//fn locate_page

	fn insert(&mut self, key: K, value: schema::TID) {
		let node = self.tree.load(self.manager);
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = BRANCH_MARKER;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = LEAF_MARKER;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(self, key: K) -> Option<schema::TID> {
		None
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

// TODO implement Drop to unfix page
impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: TotalOrd + Zero>(&self, manager: &mut buffer::BufferManager) -> Node<'a, K> {
		let pagelock = manager.fix_page(self.page_id).unwrap();
		let page = pagelock.read();
		LazyNode::load_node(page.get_data())
	}

	/* helper method to load a Node tepending on the page marker */
	fn load_node<'a, K: TotalOrd + Zero>(page: &[u8]) -> Node<'a, K> {
		if page[0] == LEAF_MARKER {
			Leaf(LeafNode::new(page))
		} else if page[0] == BRANCH_MARKER {
			Branch(BranchNode::new(page))
		} else {
			fail!("Trying to load unknown BTree node type")
		}
	}
}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
}

impl<'a, K: TotalOrd + Zero> LeafNode<'a, K> {
	fn new(page: &[u8]) -> LeafNode<'a, K> {
		// first byte is a Leaf/Branch marker
		let entry_size = size_of::<LeafEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;

		let mut r: &mut[LeafEntry<K>] = unsafe {
			cast::transmute(
				Slice::<LeafEntry<K>> {
					data: page.as_ptr() as *() as *LeafEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		LeafNode {
			entries: r,
			capacity: capacity
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		if self.capacity == 0 {
			// TODO split
			fail!("Not implemented");
			return None
		}

		// find place to insert
		let location = self.find_slot(&key);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {
				found = i - 1;
				break;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// actually, this rotates right by 1 starting from index
		let last_elem = self.entries.len() - 1;
		for i in range(index, last_elem) {
			self.entries.swap(i, last_elem);
		}
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
}

impl<'a, K: TotalOrd + Zero> BranchNode<'a, K> {
	fn new(page: &[u8]) -> BranchNode<'a, K> {
		let entry_size = size_of::<BranchEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;
		let mut r: &mut [BranchEntry<K>] = unsafe {
			cast::transmute(
				Slice::<BranchEntry<K>> {
					data: page.as_ptr() as *() as *BranchEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager);
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, 42, &mut manager);
	bt.insert(42, schema::TID::new(0, 0));
	assert!(false);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(0).unwrap();
	let page = pagelock.read();
	let lp: LeafNode<u64> = LeafNode::new(page.get_data());
	println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::ptr;

use class::ClassId;
use ctxt::{Context, FctId};
use dseg::DSeg;
use mem::{CodeMemory, Ptr};
use object::{Handle, Str};

pub struct JitFct {
    code: CodeMemory,

    pub fct_id: FctId,

    // pointer to beginning of function
    pub fct_start: Ptr,

    // machine code length in bytes
    fct_len: usize,

    pub framesize: i32,

    gcpoints: GcPoints,

    comments: Comments,

    linenos: LineNumberTable,

    pub exception_handlers: Vec<ExHandler>,
}

impl JitFct {
    pub fn from_buffer(fct_id: FctId, dseg: &DSeg, buffer: &[u8], gcpoints: GcPoints,
                framesize: i32, comments: Comments, linenos: LineNumberTable,
                mut exception_handlers: Vec<ExHandler>) -> JitFct {
        let size = dseg.size() as usize + buffer.len();

        let code = CodeMemory::new(size);
        let ptr = code.ptr_start();

        dseg.finish(ptr.raw());

        let fct_start;

        unsafe {
            fct_start = ptr.offset(dseg.size() as isize);
            ptr::copy_nonoverlapping(buffer.as_ptr(), fct_start.raw() as *mut u8, buffer.len());
        }

        for handler in &mut exception_handlers {
            let fct_start: usize = fct_start.raw() as usize;

            handler.try_start = fct_start + handler.try_start;
            handler.try_end = fct_start + handler.try_end;
            handler.catch = fct_start + handler.catch;
        }

        JitFct {
            fct_id: fct_id,
            code: code,
            gcpoints: gcpoints,
            comments: comments,
            framesize: framesize,
            fct_start: fct_start,
            fct_len: buffer.len(),
            linenos: linenos,
            exception_handlers: exception_handlers,
        }
    }

    pub fn lineno_for_offset(&self, offset: i32) -> i32 {
        self.linenos.get(offset)
    }

    pub fn gcpoint_for_offset(&self, offset: i32) -> Option<&GcPoint> {
        self.gcpoints.get(offset)
    }

    pub fn code(self) -> CodeMemory {
        self.code
    }

    pub fn ptr_start(&self) -> Ptr {
        self.code.ptr_start()
    }

    pub fn ptr_end(&self) -> Ptr {
        self.code.ptr_end()
    }

    pub fn fct_id(&self) -> FctId {
        self.fct_id
    }

    pub fn fct_ptr(&self) -> Ptr {
        self.fct_start
    }

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

    pub fn get_comment(&self, pos: i32) -> Option<&Comment> {
        self.comments.get(pos)
    }
}

impl fmt::Debug for JitFct {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JitFct {{ start: {:?}, end: {:?} }}",
            self.ptr_start(), self.ptr_end())
    }
}

#[derive(Debug)]
pub struct GcPoints {
    points: HashMap<i32, GcPoint>
}

impl GcPoints {
    pub fn new() -> GcPoints {
        GcPoints {
            points: HashMap::new()
        }
    }

    pub fn get(&self, offset: i32) -> Option<&GcPoint> {
        self.points.get(&offset)
    }

    pub fn insert(&mut self, offset: i32, gcpoint: GcPoint) {
        assert!(self.points.insert(offset, gcpoint).is_none());
    }
}

#[derive(Debug)]
pub struct GcPoint {
    pub offsets: Vec<i32>
}

impl GcPoint {
    pub fn new() -> GcPoint {
        GcPoint {
            offsets: Vec::new()
        }
    }

    pub fn from_offsets(offsets: Vec<i32>) -> GcPoint {
        GcPoint {
            offsets: offsets
        }
    }
}

pub struct Comments {
    comments: HashMap<i32, Comment>
}

impl Comments {
    pub fn new() -> Comments {
        Comments {
            comments: HashMap::new(),
        }
    }

    pub fn get(&self, pos: i32) -> Option<&Comment> {
        self.comments.get(&pos)
    }

    pub fn insert(&mut self, pos: i32, comment: Comment) {
        self.comments.insert(pos, comment);
    }
}

pub enum Comment {
    Lit(&'static str),
    LoadString(Handle<Str>),
    Alloc(ClassId),
    StoreVTable(ClassId),
    CallSuper(FctId),
    CallVirtual(FctId),
    CallDirect(FctId),
}

pub struct CommentFormat<'a, 'ast: 'a> {
    pub comment: &'a Comment,
    pub ctxt: &'a Context<'ast>,
}

impl<'a, 'ast> fmt::Display for CommentFormat<'a, 'ast> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.comment {
            &Comment::Lit(val) => write!(f, "{}", val),
            &Comment::LoadString(_) => write!(f, "load string"),
            &Comment::Alloc(clsid) => {
                let cls = self.ctxt.cls_by_id(clsid);
                let name = cls.name;
                let name = self.ctxt.interner.str(name);

                write!(f, "allocate object of class {}", &name)
            }

            &Comment::StoreVTable(_) => write!(f, "store vtable"),
            &Comment::CallSuper(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call super {}", &name)
            }

            &Comment::CallVirtual(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call virtual {}", &name)
            }

            &Comment::CallDirect(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call direct {}", &name)
            }
        }
    }
}

#[derive(Debug)]
pub struct LineNumberTable {
    map: HashMap<i32, i32>,
}

impl LineNumberTable {
    pub fn new() -> LineNumberTable {
        LineNumberTable {
            map: HashMap::new()
        }
    }

    pub fn insert(&mut self, offset: i32, lineno: i32) {
        assert!(self.map.insert(offset, lineno).is_none());
    }

    pub fn get(&self, offset: i32) -> i32 {
        if let Some(value) = self.map.get(&offset) {
            *value
        } else {
            0
        }
    }
}

#[derive(Debug)]
pub struct ExHandler {
    pub try_start: usize,
    pub try_end: usize,
    pub catch: usize,
    pub offset: Option<i32>,
    pub catch_type: CatchType,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CatchType {
    Any, Class(ClassId),
}
<commit_msg>better output for StoreVTable comments<commit_after>use std::collections::HashMap;
use std::fmt;
use std::ptr;

use class::ClassId;
use ctxt::{Context, FctId};
use dseg::DSeg;
use mem::{CodeMemory, Ptr};
use object::{Handle, Str};

pub struct JitFct {
    code: CodeMemory,

    pub fct_id: FctId,

    // pointer to beginning of function
    pub fct_start: Ptr,

    // machine code length in bytes
    fct_len: usize,

    pub framesize: i32,

    gcpoints: GcPoints,

    comments: Comments,

    linenos: LineNumberTable,

    pub exception_handlers: Vec<ExHandler>,
}

impl JitFct {
    pub fn from_buffer(fct_id: FctId, dseg: &DSeg, buffer: &[u8], gcpoints: GcPoints,
                framesize: i32, comments: Comments, linenos: LineNumberTable,
                mut exception_handlers: Vec<ExHandler>) -> JitFct {
        let size = dseg.size() as usize + buffer.len();

        let code = CodeMemory::new(size);
        let ptr = code.ptr_start();

        dseg.finish(ptr.raw());

        let fct_start;

        unsafe {
            fct_start = ptr.offset(dseg.size() as isize);
            ptr::copy_nonoverlapping(buffer.as_ptr(), fct_start.raw() as *mut u8, buffer.len());
        }

        for handler in &mut exception_handlers {
            let fct_start: usize = fct_start.raw() as usize;

            handler.try_start = fct_start + handler.try_start;
            handler.try_end = fct_start + handler.try_end;
            handler.catch = fct_start + handler.catch;
        }

        JitFct {
            fct_id: fct_id,
            code: code,
            gcpoints: gcpoints,
            comments: comments,
            framesize: framesize,
            fct_start: fct_start,
            fct_len: buffer.len(),
            linenos: linenos,
            exception_handlers: exception_handlers,
        }
    }

    pub fn lineno_for_offset(&self, offset: i32) -> i32 {
        self.linenos.get(offset)
    }

    pub fn gcpoint_for_offset(&self, offset: i32) -> Option<&GcPoint> {
        self.gcpoints.get(offset)
    }

    pub fn code(self) -> CodeMemory {
        self.code
    }

    pub fn ptr_start(&self) -> Ptr {
        self.code.ptr_start()
    }

    pub fn ptr_end(&self) -> Ptr {
        self.code.ptr_end()
    }

    pub fn fct_id(&self) -> FctId {
        self.fct_id
    }

    pub fn fct_ptr(&self) -> Ptr {
        self.fct_start
    }

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

    pub fn get_comment(&self, pos: i32) -> Option<&Comment> {
        self.comments.get(pos)
    }
}

impl fmt::Debug for JitFct {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JitFct {{ start: {:?}, end: {:?} }}",
            self.ptr_start(), self.ptr_end())
    }
}

#[derive(Debug)]
pub struct GcPoints {
    points: HashMap<i32, GcPoint>
}

impl GcPoints {
    pub fn new() -> GcPoints {
        GcPoints {
            points: HashMap::new()
        }
    }

    pub fn get(&self, offset: i32) -> Option<&GcPoint> {
        self.points.get(&offset)
    }

    pub fn insert(&mut self, offset: i32, gcpoint: GcPoint) {
        assert!(self.points.insert(offset, gcpoint).is_none());
    }
}

#[derive(Debug)]
pub struct GcPoint {
    pub offsets: Vec<i32>
}

impl GcPoint {
    pub fn new() -> GcPoint {
        GcPoint {
            offsets: Vec::new()
        }
    }

    pub fn from_offsets(offsets: Vec<i32>) -> GcPoint {
        GcPoint {
            offsets: offsets
        }
    }
}

pub struct Comments {
    comments: HashMap<i32, Comment>
}

impl Comments {
    pub fn new() -> Comments {
        Comments {
            comments: HashMap::new(),
        }
    }

    pub fn get(&self, pos: i32) -> Option<&Comment> {
        self.comments.get(&pos)
    }

    pub fn insert(&mut self, pos: i32, comment: Comment) {
        self.comments.insert(pos, comment);
    }
}

pub enum Comment {
    Lit(&'static str),
    LoadString(Handle<Str>),
    Alloc(ClassId),
    StoreVTable(ClassId),
    CallSuper(FctId),
    CallVirtual(FctId),
    CallDirect(FctId),
}

pub struct CommentFormat<'a, 'ast: 'a> {
    pub comment: &'a Comment,
    pub ctxt: &'a Context<'ast>,
}

impl<'a, 'ast> fmt::Display for CommentFormat<'a, 'ast> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.comment {
            &Comment::Lit(val) => write!(f, "{}", val),
            &Comment::LoadString(_) => write!(f, "load string"),
            &Comment::Alloc(clsid) => {
                let cls = self.ctxt.cls_by_id(clsid);
                let name = cls.name;
                let name = self.ctxt.interner.str(name);

                write!(f, "allocate object of class {}", &name)
            }

            &Comment::StoreVTable(clsid) => {
                let cls = self.ctxt.cls_by_id(clsid);
                let name = cls.name;
                let name = self.ctxt.interner.str(name);

                write!(f, "store vtable ptr for class {} in object", &name)
            }

            &Comment::CallSuper(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call super {}", &name)
            }

            &Comment::CallVirtual(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call virtual {}", &name)
            }

            &Comment::CallDirect(fid) => {
                let fct = self.ctxt.fct_by_id(fid);
                let name = fct.full_name(self.ctxt);

                write!(f, "call direct {}", &name)
            }
        }
    }
}

#[derive(Debug)]
pub struct LineNumberTable {
    map: HashMap<i32, i32>,
}

impl LineNumberTable {
    pub fn new() -> LineNumberTable {
        LineNumberTable {
            map: HashMap::new()
        }
    }

    pub fn insert(&mut self, offset: i32, lineno: i32) {
        assert!(self.map.insert(offset, lineno).is_none());
    }

    pub fn get(&self, offset: i32) -> i32 {
        if let Some(value) = self.map.get(&offset) {
            *value
        } else {
            0
        }
    }
}

#[derive(Debug)]
pub struct ExHandler {
    pub try_start: usize,
    pub try_end: usize,
    pub catch: usize,
    pub offset: Option<i32>,
    pub catch_type: CatchType,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CatchType {
    Any, Class(ClassId),
}
<|endoftext|>


<commit_before>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json, number, error, uri};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> Value;
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// An object representing the global variables
	global: Value,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.insert(~"console", console::_create());
		globals.insert(~"Math", math::_create());
		globals.insert(~"Object", object::_create());
		globals.insert(~"Array", array::_create());
		globals.insert(~"Function", function::_create());
		globals.insert(~"JSON", json::_create());
		globals.insert(~"Number", number::_create());
		globals.insert(~"Error", error::_create());
		let global = Gc::new(VObject(RefCell::new(globals)));
		number::init(global);
		uri::init(global);
		return ~Interpreter {global: global, scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) -> Value {
		self.global.borrow().set_field(name, val)
	}
	fn get_global(&self, name:~str) -> Value {
		self.global.borrow().get_field(name)
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					self.global.borrow().get_field(name.clone())
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let (this, func) = match **callee {
					GetConstFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						(obj, obj.borrow().get_field(field.clone()))
					},
					GetFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						let field = try!(self.run(*field));
						(obj, obj.borrow().get_field(field.borrow().to_str()))
					},
					_ => (self.global.clone(), try!(self.run(callee.clone())))
				};
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args)
					},
					_ => Err(Gc::new(VUndefined))
				}
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.get_global(~"Object").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.insert(~"__proto__", self.get_global(~"Array").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.global.borrow().set_field(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				let this = Gc::new(VObject(RefCell::new(TreeMap::new())));
				this.borrow().set_field(~"__proto__", func.borrow().get_field(~"prototype"));
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap();
						this
					},
					_ => Gc::new(VUndefined)
				})
			},
			ReturnExpr(ref ret) => {
				match *ret {
					Some(ref v) =>
						self.run(v.clone()),
					None => Ok(Gc::new(VUndefined))
				}
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.global.borrow().set_field(name.clone(), val);
					},
					GetConstFieldExpr(ref obj, ref field) => {
						let val_obj = try!(self.run(*obj));
						val_obj.borrow().set_field(field.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<commit_msg>Remove now unused float import<commit_after>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json, number, error, uri};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> Value;
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// An object representing the global variables
	global: Value,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.insert(~"console", console::_create());
		globals.insert(~"Math", math::_create());
		globals.insert(~"Object", object::_create());
		globals.insert(~"Array", array::_create());
		globals.insert(~"Function", function::_create());
		globals.insert(~"JSON", json::_create());
		globals.insert(~"Number", number::_create());
		globals.insert(~"Error", error::_create());
		let global = Gc::new(VObject(RefCell::new(globals)));
		number::init(global);
		uri::init(global);
		return ~Interpreter {global: global, scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) -> Value {
		self.global.borrow().set_field(name, val)
	}
	fn get_global(&self, name:~str) -> Value {
		self.global.borrow().get_field(name)
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					self.global.borrow().get_field(name.clone())
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let (this, func) = match **callee {
					GetConstFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						(obj, obj.borrow().get_field(field.clone()))
					},
					GetFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						let field = try!(self.run(*field));
						(obj, obj.borrow().get_field(field.borrow().to_str()))
					},
					_ => (self.global.clone(), try!(self.run(callee.clone())))
				};
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args)
					},
					_ => Err(Gc::new(VUndefined))
				}
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.get_global(~"Object").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.insert(~"__proto__", self.get_global(~"Array").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.global.borrow().set_field(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				let this = Gc::new(VObject(RefCell::new(TreeMap::new())));
				this.borrow().set_field(~"__proto__", func.borrow().get_field(~"prototype"));
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap();
						this
					},
					_ => Gc::new(VUndefined)
				})
			},
			ReturnExpr(ref ret) => {
				match *ret {
					Some(ref v) =>
						self.run(v.clone()),
					None => Ok(Gc::new(VUndefined))
				}
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.global.borrow().set_field(name.clone(), val);
					},
					GetConstFieldExpr(ref obj, ref field) => {
						let val_obj = try!(self.run(*obj));
						val_obj.borrow().set_field(field.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<|endoftext|>


<commit_before>use hir::HirDisplay;
use syntax::{ast, AstNode, TextRange, TextSize};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: add_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified. This assists is useable in a functions or closures tail expression or return type position.
//
// ```
// fn foo() { 4$02i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let (fn_type, tail_expr, builder_edit_pos) = extract_tail(ctx)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr)?.adjusted();
    if ty.is_unit() {
        return None;
    }
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("add_return_type", AssistKind::RefactorRewrite),
        match fn_type {
            FnType::Function => "Add this function's return type",
            FnType::Closure { .. } => "Add this closure's return type",
        },
        tail_expr.syntax().text_range(),
        |builder| {
            match builder_edit_pos {
                InsertOrReplace::Insert(insert_pos) => {
                    builder.insert(insert_pos, &format!("-> {} ", ty))
                }
                InsertOrReplace::Replace(text_range) => {
                    builder.replace(text_range, &format!("-> {}", ty))
                }
            }
            if let FnType::Closure { wrap_expr: true } = fn_type {
                cov_mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

enum InsertOrReplace {
    Insert(TextSize),
    Replace(TextRange),
}

/// Check the potentially already specified return type and reject it or turn it into a builder command
/// if allowed.
fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Option<InsertOrReplace> {
    match ret_ty {
        Some(ret_ty) => match ret_ty.ty() {
            Some(ast::Type::InferType(_)) | None => {
                cov_mark::hit!(existing_infer_ret_type);
                cov_mark::hit!(existing_infer_ret_type_closure);
                Some(InsertOrReplace::Replace(ret_ty.syntax().text_range()))
            }
            _ => {
                cov_mark::hit!(existing_ret_type);
                cov_mark::hit!(existing_ret_type_closure);
                None
            }
        },
        None => Some(InsertOrReplace::Insert(insert_pos + TextSize::from(1))),
    }
}

enum FnType {
    Function,
    Closure { wrap_expr: bool },
}

fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrReplace)> {
    let (fn_type, tail_expr, return_type_range, action) =
        if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
            let rpipe_pos = closure.param_list()?.syntax().last_token()?.text_range().end();
            let action = ret_ty_to_action(closure.ret_type(), rpipe_pos)?;

            let body = closure.body()?;
            let body_start = body.syntax().first_token()?.text_range().start();
            let (tail_expr, wrap_expr) = match body {
                ast::Expr::BlockExpr(block) => (block.tail_expr()?, false),
                body => (body, true),
            };

            let ret_range = TextRange::new(rpipe_pos, body_start);
            (FnType::Closure { wrap_expr }, tail_expr, ret_range, action)
        } else {
            let func = ctx.find_node_at_offset::<ast::Fn>()?;
            let rparen_pos = func.param_list()?.r_paren_token()?.text_range().end();
            let action = ret_ty_to_action(func.ret_type(), rparen_pos)?;

            let body = func.body()?;
            let stmt_list = body.stmt_list()?;
            let tail_expr = stmt_list.tail_expr()?;

            let ret_range_end = stmt_list.l_curly_token()?.text_range().start();
            let ret_range = TextRange::new(rparen_pos, ret_range_end);
            (FnType::Function, tail_expr, ret_range, action)
        };
    let range = ctx.selection_trimmed();
    if return_type_range.contains_range(range) {
        cov_mark::hit!(cursor_in_ret_position);
        cov_mark::hit!(cursor_in_ret_position_closure);
    } else if tail_expr.syntax().text_range().contains_range(range) {
        cov_mark::hit!(cursor_on_tail);
        cov_mark::hit!(cursor_on_tail_closure);
    } else {
        return None;
    }
    Some((fn_type, tail_expr, action))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn infer_return_type_specified_inferred() {
        cov_mark::check!(existing_infer_ret_type);
        check_assist(
            add_return_type,
            r#"fn foo() -> $0_ {
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_specified_inferred_closure() {
        cov_mark::check!(existing_infer_ret_type_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    || -> _ {$045};
}"#,
            r#"fn foo() {
    || -> i32 {45};
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos() {
        cov_mark::check!(cursor_in_ret_position);
        check_assist(
            add_return_type,
            r#"fn foo() $0{
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos_closure() {
        cov_mark::check!(cursor_in_ret_position_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    || $045
}"#,
            r#"fn foo() {
    || -> i32 {45}
}"#,
        );
    }

    #[test]
    fn infer_return_type() {
        cov_mark::check!(cursor_on_tail);
        check_assist(
            add_return_type,
            r#"fn foo() {
    45$0
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    if true {
        3$0
    } else {
        5
    }
}"#,
            r#"fn foo() -> i32 {
    if true {
        3
    } else {
        5
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        cov_mark::check!(existing_ret_type);
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() -> i32 {
    ( 45$0 + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    let x = $03;
    ( 45 + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    ($0)
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        cov_mark::check!(cursor_on_tail_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| {
        x$0
    };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {
        x
    };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| { x$0 };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 { x };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        cov_mark::check!(wrap_closure_non_block_expr);
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| x$0;
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {x};
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    || {
        if true {
            3$0
        } else {
            5
        }
    }
}"#,
            r#"fn foo() {
    || -> i32 {
        if true {
            3
        } else {
            5
        }
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        cov_mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    || -> i32 { 3$0 }
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    || -> i32 {
        let x = 3$0;
        6
    }
}"#,
        );
    }
}
<commit_msg>fix: add return type works when there's missing whitespace<commit_after>use hir::HirDisplay;
use syntax::{ast, AstNode, SyntaxKind, SyntaxToken, TextRange, TextSize};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: add_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified. This assists is useable in a functions or closures tail expression or return type position.
//
// ```
// fn foo() { 4$02i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let (fn_type, tail_expr, builder_edit_pos, needs_whitespace) = extract_tail(ctx)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr)?.adjusted();
    if ty.is_unit() {
        return None;
    }
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("add_return_type", AssistKind::RefactorRewrite),
        match fn_type {
            FnType::Function => "Add this function's return type",
            FnType::Closure { .. } => "Add this closure's return type",
        },
        tail_expr.syntax().text_range(),
        |builder| {
            let preceeding_whitespace = if needs_whitespace { " " } else { "" };

            match builder_edit_pos {
                InsertOrReplace::Insert(insert_pos) => {
                    builder.insert(insert_pos, &format!("{}-> {} ", preceeding_whitespace, ty))
                }
                InsertOrReplace::Replace(text_range) => {
                    builder.replace(text_range, &format!("{}-> {}", preceeding_whitespace, ty))
                }
            }
            if let FnType::Closure { wrap_expr: true } = fn_type {
                cov_mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

enum InsertOrReplace {
    Insert(TextSize),
    Replace(TextRange),
}

/// Check the potentially already specified return type and reject it or turn it into a builder command
/// if allowed.
fn ret_ty_to_action(
    ret_ty: Option<ast::RetType>,
    insert_after: SyntaxToken,
) -> Option<(InsertOrReplace, bool)> {
    match ret_ty {
        Some(ret_ty) => match ret_ty.ty() {
            Some(ast::Type::InferType(_)) | None => {
                cov_mark::hit!(existing_infer_ret_type);
                cov_mark::hit!(existing_infer_ret_type_closure);
                Some((InsertOrReplace::Replace(ret_ty.syntax().text_range()), false))
            }
            _ => {
                cov_mark::hit!(existing_ret_type);
                cov_mark::hit!(existing_ret_type_closure);
                None
            }
        },
        None => {
            let insert_after_pos = insert_after.text_range().end();
            let (insert_pos, needs_whitespace) = match insert_after.next_token() {
                Some(it) if it.kind() == SyntaxKind::WHITESPACE => {
                    (insert_after_pos + TextSize::from(1), false)
                }
                _ => (insert_after_pos, true),
            };

            Some((InsertOrReplace::Insert(insert_pos), needs_whitespace))
        }
    }
}

enum FnType {
    Function,
    Closure { wrap_expr: bool },
}

fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrReplace, bool)> {
    let (fn_type, tail_expr, return_type_range, action, needs_whitespace) =
        if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
            let rpipe = closure.param_list()?.syntax().last_token()?;
            let rpipe_pos = rpipe.text_range().end();

            let (action, needs_whitespace) = ret_ty_to_action(closure.ret_type(), rpipe)?;

            let body = closure.body()?;
            let body_start = body.syntax().first_token()?.text_range().start();
            let (tail_expr, wrap_expr) = match body {
                ast::Expr::BlockExpr(block) => (block.tail_expr()?, false),
                body => (body, true),
            };

            let ret_range = TextRange::new(rpipe_pos, body_start);
            (FnType::Closure { wrap_expr }, tail_expr, ret_range, action, needs_whitespace)
        } else {
            let func = ctx.find_node_at_offset::<ast::Fn>()?;

            let rparen = func.param_list()?.r_paren_token()?;
            let rparen_pos = rparen.text_range().end();
            let (action, needs_whitespace) = ret_ty_to_action(func.ret_type(), rparen)?;

            let body = func.body()?;
            let stmt_list = body.stmt_list()?;
            let tail_expr = stmt_list.tail_expr()?;

            let ret_range_end = stmt_list.l_curly_token()?.text_range().start();
            let ret_range = TextRange::new(rparen_pos, ret_range_end);
            (FnType::Function, tail_expr, ret_range, action, needs_whitespace)
        };
    let range = ctx.selection_trimmed();
    if return_type_range.contains_range(range) {
        cov_mark::hit!(cursor_in_ret_position);
        cov_mark::hit!(cursor_in_ret_position_closure);
    } else if tail_expr.syntax().text_range().contains_range(range) {
        cov_mark::hit!(cursor_on_tail);
        cov_mark::hit!(cursor_on_tail_closure);
    } else {
        return None;
    }
    Some((fn_type, tail_expr, action, needs_whitespace))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn infer_return_type_specified_inferred() {
        cov_mark::check!(existing_infer_ret_type);
        check_assist(
            add_return_type,
            r#"fn foo() -> $0_ {
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_specified_inferred_closure() {
        cov_mark::check!(existing_infer_ret_type_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    || -> _ {$045};
}"#,
            r#"fn foo() {
    || -> i32 {45};
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos() {
        cov_mark::check!(cursor_in_ret_position);
        check_assist(
            add_return_type,
            r#"fn foo() $0{
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos_closure() {
        cov_mark::check!(cursor_in_ret_position_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    || $045
}"#,
            r#"fn foo() {
    || -> i32 {45}
}"#,
        );
    }

    #[test]
    fn infer_return_type() {
        cov_mark::check!(cursor_on_tail);
        check_assist(
            add_return_type,
            r#"fn foo() {
    45$0
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_no_whitespace() {
        check_assist(
            add_return_type,
            r#"fn foo(){
    45$0
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    if true {
        3$0
    } else {
        5
    }
}"#,
            r#"fn foo() -> i32 {
    if true {
        3
    } else {
        5
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        cov_mark::check!(existing_ret_type);
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() -> i32 {
    ( 45$0 + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    let x = $03;
    ( 45 + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    ($0)
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        cov_mark::check!(cursor_on_tail_closure);
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| {
        x$0
    };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {
        x
    };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| { x$0 };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 { x };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_no_whitespace() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32|{ x$0 };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 { x };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        cov_mark::check!(wrap_closure_non_block_expr);
        check_assist(
            add_return_type,
            r#"fn foo() {
    |x: i32| x$0;
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {x};
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            add_return_type,
            r#"fn foo() {
    || {
        if true {
            3$0
        } else {
            5
        }
    }
}"#,
            r#"fn foo() {
    || -> i32 {
        if true {
            3
        } else {
            5
        }
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        cov_mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    || -> i32 { 3$0 }
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            add_return_type,
            r#"fn foo() {
    || -> i32 {
        let x = 3$0;
        6
    }
}"#,
        );
    }
}
<|endoftext|>


<commit_before>#![crate_id(name="comm", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::cmp::Ord;
use std::io::{BufferedReader, IoResult, print};
use std::io::fs::File;
use std::io::stdio::stdin;
use std::os;
use std::path::Path;

static NAME : &'static str = "comm";
static VERSION : &'static str = "1.0.0";

fn mkdelim(col: uint, opts: &getopts::Matches) -> String {
    let mut s = String::new();
    let delim = match opts.opt_str("output-delimiter") {
        Some(d) => d.clone(),
        None => "\t".to_string(),
    };

    if col > 1 && !opts.opt_present("1") {
        s.push_str(delim.as_slice());
    }
    if col > 2 && !opts.opt_present("2") {
        s.push_str(delim.as_slice());
    }

    s
}

fn ensure_nl(line: String) -> String {
    match line.as_slice().chars().last() {
        Some('\n') => line,
        _ => line.append("\n"),
    }
}

fn comm(a: &mut Box<Buffer>, b: &mut Box<Buffer>, opts: &getopts::Matches) {

    let delim = Vec::from_fn(4, |col| mkdelim(col, opts));

    let mut ra = a.read_line();
    let mut rb = b.read_line();

    while ra.is_ok() || rb.is_ok() {
        let ord = match (ra.clone(), rb.clone()) {
            (Err(_), Ok(_))  => Greater,
            (Ok(_) , Err(_)) => Less,
            (Ok(s0), Ok(s1)) => s0.cmp(&s1),
            _ => unreachable!(),
        };

        match ord {
            Less => {
                if !opts.opt_present("1") {
                    print!("{}{}", delim.get(1), ra.map(ensure_nl).unwrap());
                }
                ra = a.read_line();
            }
            Greater => {
                if !opts.opt_present("2") {
                    print!("{}{}", delim.get(2), rb.map(ensure_nl).unwrap());
                }
                rb = b.read_line();
            }
            Equal => {
                if !opts.opt_present("3") {
                    print!("{}{}", delim.get(3), ra.map(ensure_nl).unwrap());
                }
                ra = a.read_line();
                rb = b.read_line();
            }
        }
    }
}

fn open_file(name: &str) -> IoResult<Box<Buffer>> {
    match name {
        "-" => Ok(box stdin() as Box<Buffer>),
        _   => {
            let f = try!(File::open(&Path::new(name)));
            Ok(box BufferedReader::new(f) as Box<Buffer>)
        }
    }
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optflag("1", "", "suppress column 1 (lines uniq to FILE1)"),
        getopts::optflag("2", "", "suppress column 2 (lines uniq to FILE2)"),
        getopts::optflag("3", "", "suppress column 3 (lines that appear in both files)"),
        getopts::optopt("", "output-delimiter", "separate columns with STR", "STR"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => fail!("{}", err),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.len() != 2 {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] FILE1 FILE2", NAME);
        println!("");
        print(getopts::usage("Compare sorted files line by line.", opts.as_slice()).as_slice());
        if matches.free.len() != 2 {
            return 0;
        }
        return 0;
    }

    let mut f1 = open_file(matches.free.get(0).as_slice()).unwrap();
    let mut f2 = open_file(matches.free.get(1).as_slice()).unwrap();

    comm(&mut f1, &mut f2, &matches);

    0
}
<commit_msg>comm: exit with status 1 on invalid arguments<commit_after>#![crate_id(name="comm", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::cmp::Ord;
use std::io::{BufferedReader, IoResult, print};
use std::io::fs::File;
use std::io::stdio::stdin;
use std::os;
use std::path::Path;

static NAME : &'static str = "comm";
static VERSION : &'static str = "1.0.0";

fn mkdelim(col: uint, opts: &getopts::Matches) -> String {
    let mut s = String::new();
    let delim = match opts.opt_str("output-delimiter") {
        Some(d) => d.clone(),
        None => "\t".to_string(),
    };

    if col > 1 && !opts.opt_present("1") {
        s.push_str(delim.as_slice());
    }
    if col > 2 && !opts.opt_present("2") {
        s.push_str(delim.as_slice());
    }

    s
}

fn ensure_nl(line: String) -> String {
    match line.as_slice().chars().last() {
        Some('\n') => line,
        _ => line.append("\n"),
    }
}

fn comm(a: &mut Box<Buffer>, b: &mut Box<Buffer>, opts: &getopts::Matches) {

    let delim = Vec::from_fn(4, |col| mkdelim(col, opts));

    let mut ra = a.read_line();
    let mut rb = b.read_line();

    while ra.is_ok() || rb.is_ok() {
        let ord = match (ra.clone(), rb.clone()) {
            (Err(_), Ok(_))  => Greater,
            (Ok(_) , Err(_)) => Less,
            (Ok(s0), Ok(s1)) => s0.cmp(&s1),
            _ => unreachable!(),
        };

        match ord {
            Less => {
                if !opts.opt_present("1") {
                    print!("{}{}", delim.get(1), ra.map(ensure_nl).unwrap());
                }
                ra = a.read_line();
            }
            Greater => {
                if !opts.opt_present("2") {
                    print!("{}{}", delim.get(2), rb.map(ensure_nl).unwrap());
                }
                rb = b.read_line();
            }
            Equal => {
                if !opts.opt_present("3") {
                    print!("{}{}", delim.get(3), ra.map(ensure_nl).unwrap());
                }
                ra = a.read_line();
                rb = b.read_line();
            }
        }
    }
}

fn open_file(name: &str) -> IoResult<Box<Buffer>> {
    match name {
        "-" => Ok(box stdin() as Box<Buffer>),
        _   => {
            let f = try!(File::open(&Path::new(name)));
            Ok(box BufferedReader::new(f) as Box<Buffer>)
        }
    }
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optflag("1", "", "suppress column 1 (lines uniq to FILE1)"),
        getopts::optflag("2", "", "suppress column 2 (lines uniq to FILE2)"),
        getopts::optflag("3", "", "suppress column 3 (lines that appear in both files)"),
        getopts::optopt("", "output-delimiter", "separate columns with STR", "STR"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => fail!("{}", err),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.len() != 2 {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] FILE1 FILE2", NAME);
        println!("");
        print(getopts::usage("Compare sorted files line by line.", opts.as_slice()).as_slice());
        if matches.free.len() != 2 {
            return 1;
        }
        return 0;
    }

    let mut f1 = open_file(matches.free.get(0).as_slice()).unwrap();
    let mut f2 = open_file(matches.free.get(1).as_slice()).unwrap();

    comm(&mut f1, &mut f2, &matches);

    0
}
<|endoftext|>


<commit_before>extern crate cairo;

use std::fmt;
use std::str::FromStr;

use error::*;
use parsers::ParseError;
use parsers;

/* Keep this in sync with rsvg-private.h:RsvgViewBox */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RsvgViewBox {
    pub rect:   cairo::Rectangle,
    pub active: bool
}

impl RsvgViewBox {
    pub fn new_inactive () -> RsvgViewBox {
        RsvgViewBox {
            rect: cairo::Rectangle { x: 0.0,
                                     y: 0.0,
                                     width: 0.0,
                                     height: 0.0 },
            active: false
        }
    }
}

impl Default for RsvgViewBox {
    fn default () -> RsvgViewBox {
        RsvgViewBox::new_inactive ()
    }
}

impl FromStr for RsvgViewBox {
    type Err = AttributeError;

    fn from_str (s: &str) -> Result<RsvgViewBox, AttributeError> {
        let result = parsers::view_box (s.trim ().as_bytes ()).to_full_result ();

        match result {
            Ok ((x, y, w, h)) => {
                if w >= 0.0 && h >= 0.0 {
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: x,
                                                               y: y,
                                                               width: w,
                                                               height: h },
                                      active: true })
                } else {
                    Err (AttributeError::Value ("width and height must not be negative".to_string ()))
                }
            },

            Err (_) => {
                Err (AttributeError::Parse (ParseError::new ("string does not match 'x [,] y [,] w [,] h'")))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;
    use error::*;

    #[test]
    fn parses_valid_viewboxes () {
        assert_eq! (RsvgViewBox::from_str ("  1 2 3 4"),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: 1.0,
                                                               y: 2.0,
                                                               width: 3.0,
                                                               height: 4.0 },
                                      active: true }));

        assert_eq! (RsvgViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: -1.5,
                                                               y: -25.0,
                                                               width: 34.0,
                                                               height: 5600.0 },
                                      active: true }));
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error () {
        assert! (is_parse_error (&RsvgViewBox::from_str ("")));

        assert! (is_value_error (&RsvgViewBox::from_str (" 1,2,-3,-4 ")));

        assert! (is_parse_error (&RsvgViewBox::from_str ("qwerasdfzxcv")));

        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 3 4   5")));
    }
}
<commit_msg>Remove unused imports<commit_after>extern crate cairo;

use std::str::FromStr;

use error::*;
use parsers::ParseError;
use parsers;

/* Keep this in sync with rsvg-private.h:RsvgViewBox */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RsvgViewBox {
    pub rect:   cairo::Rectangle,
    pub active: bool
}

impl RsvgViewBox {
    pub fn new_inactive () -> RsvgViewBox {
        RsvgViewBox {
            rect: cairo::Rectangle { x: 0.0,
                                     y: 0.0,
                                     width: 0.0,
                                     height: 0.0 },
            active: false
        }
    }
}

impl Default for RsvgViewBox {
    fn default () -> RsvgViewBox {
        RsvgViewBox::new_inactive ()
    }
}

impl FromStr for RsvgViewBox {
    type Err = AttributeError;

    fn from_str (s: &str) -> Result<RsvgViewBox, AttributeError> {
        let result = parsers::view_box (s.trim ().as_bytes ()).to_full_result ();

        match result {
            Ok ((x, y, w, h)) => {
                if w >= 0.0 && h >= 0.0 {
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: x,
                                                               y: y,
                                                               width: w,
                                                               height: h },
                                      active: true })
                } else {
                    Err (AttributeError::Value ("width and height must not be negative".to_string ()))
                }
            },

            Err (_) => {
                Err (AttributeError::Parse (ParseError::new ("string does not match 'x [,] y [,] w [,] h'")))
            }
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes () {
        assert_eq! (RsvgViewBox::from_str ("  1 2 3 4"),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: 1.0,
                                                               y: 2.0,
                                                               width: 3.0,
                                                               height: 4.0 },
                                      active: true }));

        assert_eq! (RsvgViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: -1.5,
                                                               y: -25.0,
                                                               width: 34.0,
                                                               height: 5600.0 },
                                      active: true }));
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error () {
        assert! (is_parse_error (&RsvgViewBox::from_str ("")));

        assert! (is_value_error (&RsvgViewBox::from_str (" 1,2,-3,-4 ")));

        assert! (is_parse_error (&RsvgViewBox::from_str ("qwerasdfzxcv")));

        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 3 4   5")));
    }
}
<|endoftext|>