<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell, Ref, RefMut};
use std::ops::{Deref, DerefMut};
use std::intrinsics;
use std::mem;
use std::raw::TraitObject;
use std::marker::PhantomData;

use bs_audio::AudioSource;

use ecs::{Entity, EntityManager, ComponentManager};
use input::Input;
use component::{TransformManager, CameraManager, MeshManager, LightManager, AudioSourceManager,
                AlarmManager, ColliderManager};
use resource::ResourceManager;

#[cfg(not(feature = "hotloading"))]
type ManagerId = ::std::any::TypeId;

#[cfg(feature = "hotloading")]
type ManagerId = &'static str;

/// Contains all the data that defines the current state of the world.
///
/// This is passed into systems in System::update(). It can be used access component
/// managers and input.
#[derive(Debug)]
pub struct Scene {
    entity_manager: RefCell<EntityManager>,
    component_managers: HashMap<ManagerId, RefCell<Box<ComponentManager>>>,
    pub input: Input,
    pub audio_source: AudioSource,
    resource_manager: Rc<ResourceManager>,
}

impl Scene {
    pub fn new(resource_manager: &Rc<ResourceManager>, audio_source: AudioSource) -> Scene {
        let mut scene = Scene {
            entity_manager: RefCell::new(EntityManager::new()),
            component_managers: HashMap::new(),
            input: Input::new(),
            audio_source: audio_source,
            resource_manager: resource_manager.clone(),
        };

        scene.register_manager(TransformManager::new());
        scene.register_manager(CameraManager::new());
        scene.register_manager(LightManager::new());
        scene.register_manager(MeshManager::new(resource_manager.clone()));
        scene.register_manager(AudioSourceManager::new(resource_manager.clone()));
        scene.register_manager(AlarmManager::new());
        scene.register_manager(ColliderManager::new());

        scene
    }

    pub fn clone(&self, resource_manager: &Rc<ResourceManager>) -> Scene {
        let mut scene = Scene {
            entity_manager: RefCell::new(self.entity_manager.borrow().clone()),
            component_managers: HashMap::new(),
            input: self.input.clone(),
            audio_source: self.audio_source.clone(),
            resource_manager: resource_manager.clone(),
        };

        // Reload internal component managers.
        scene.reload_manager::<TransformManager>(self);
        scene.reload_manager::<CameraManager>(self);
        scene.reload_manager::<LightManager>(self);
        scene.reload_manager::<AlarmManager>(self);
        scene.reload_manager::<ColliderManager>(self);
        scene.register_manager(self.get_manager::<MeshManager>().clone(resource_manager.clone()));
        scene.register_manager(self.get_manager::<AudioSourceManager>().clone(resource_manager.clone()));

        scene
    }

    pub fn register_manager<T: ComponentManager>(&mut self, manager: T) {
        let manager_id = manager_id::<T>();
        assert!(!self.component_managers.contains_key(&manager_id),
                "Manager {} with ID {:?} already registered", type_name::<T>(), manager_id);

        self.component_managers.insert(manager_id, RefCell::new(Box::new(manager)));
    }

    pub fn get_manager<T: ComponentManager>(&self) -> ManagerRef<T> {
        let manager_id = manager_id::<T>();
        let manager = match self.component_managers.get(&manager_id) {
            Some(manager) => manager,
            None => panic!("Tried to retrieve manager {} with ID {:?} but none exists",
                           type_name::<T>(),
                           manager_id),
        };

        ManagerRef {
            manager: manager.borrow(),
            _phantom: PhantomData,
        }
    }

    pub fn get_manager_mut<T: ComponentManager>(&self) -> ManagerRefMut<T> {
        let manager_id = manager_id::<T>();
        let manager = match self.component_managers.get(&manager_id) {
            Some(manager) => manager,
            None => panic!("Tried to retrieve manager {} with ID {:?} but none exists",
                           type_name::<T>(),
                           manager_id),
        };

        ManagerRefMut {
            manager: manager.borrow_mut(),
            _phantom: PhantomData,
        }
    }

    pub fn reload_manager<T: ComponentManager + Clone>(&mut self, old_scene: &Scene) {
        self.register_manager(old_scene.get_manager::<T>().clone());
    }

    pub fn create_entity(&self) -> Entity {
        self.entity_manager.borrow_mut().create()
    }

    pub fn resource_manager(&self) -> &ResourceManager {
        &*self.resource_manager
    }

    /// Instantiates an instance of the model in the scene, returning the root entity.
    pub fn instantiate_model(&self, resource: &str) -> Entity {
        self.resource_manager.clone().instantiate_model(resource, self).unwrap()
    }

    pub fn destroy_entity(&self, entity: Entity) {
        for (_, manager) in self.component_managers.iter() {
            manager.borrow().destroy_all(entity);
        }

        let transform_manager = self.get_manager::<TransformManager>();
        transform_manager.walk_children(entity, &mut |entity| {
            for (_, manager) in self.component_managers.iter() {
                manager.borrow().destroy_all(entity);
            }
        });

        self.entity_manager.borrow_mut().mark_for_destroy(entity);
    }

    pub fn destroy_marked(&self) {
        for (_, manager) in self.component_managers.iter() {
            manager.borrow_mut().destroy_marked();
        }

        self.entity_manager.borrow_mut().destroy_marked();
    }
}

#[cfg(not(feature = "hotloading"))]
fn manager_id<T: ComponentManager>() -> ManagerId {
    ::std::any::TypeId::of::<T>()
}

/// Two cases:
///
/// - No template (e.g. `foo::bar::TransformManager`) just remove path (becomes `TransformManager`).
/// - Template (e.g. `foo::bar::Manager<foo::bar::Foo>`) innermost type without leading path
///   (becomes `Foo`).
#[cfg(feature = "hotloading")]
fn manager_id<T: ComponentManager>() -> ManagerId {
    let full_name = type_name::<T>();

    // Find first occurrence of '<' character since we know the start of the proper name has to
    // be before that.
    let sub_str = match full_name.find('<') {
        Some(index) => &full_name[index + 1..full_name.len() - 1], // foo::Foo<foo::Bar> => foo::Bar
        None => full_name,                                         // foo::Foo => foo::Foo
    };

    let slice_index = match sub_str.rfind("::") {
        Some(last_index) => last_index + 2,
        None => 0,
    };

    &sub_str[slice_index..]
}

fn type_name<T>() -> &'static str {
    unsafe {
        intrinsics::type_name::<T>()
    }
}

pub struct ManagerRef<'a, T: ComponentManager> {
    manager: Ref<'a, Box<ComponentManager>>,
    _phantom: PhantomData<T>,
}

impl<'a, T: ComponentManager> Deref for ManagerRef<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        unsafe { downcast_manager(self.manager.deref().deref()) }
    }
}

pub struct ManagerRefMut<'a, T: ComponentManager> {
    manager: RefMut<'a, Box<ComponentManager>>,
    _phantom: PhantomData<T>,
}

impl<'a, T: ComponentManager> Deref for ManagerRefMut<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        unsafe { downcast_manager(self.manager.deref().deref()) }
    }
}

impl<'a, T: ComponentManager> DerefMut for ManagerRefMut<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut T {
        let manager = self.manager.deref_mut().deref_mut();
        unsafe { downcast_manager_mut(manager) }
    }
}

/// Performs an unchecked downcast from the `ComponentManager` trait object to the concrete type.
unsafe fn downcast_manager<'a, T: ComponentManager>(manager: &'a ComponentManager) -> &'a T {
    // Get the raw representation of the trait object.
    let to: TraitObject = mem::transmute(manager);

    // Extract the data pointer.
    mem::transmute(to.data)
}

unsafe fn downcast_manager_mut<'a, T: ComponentManager>(manager: &'a mut ComponentManager) -> &'a mut T {
    // Get the raw representation of the trait object.
    let to: TraitObject = mem::transmute(manager);

    // Extract the data pointer.
    mem::transmute(to.data)
}
<commit_msg>feature(hotloading): add Scene::reload_manager_or_default()<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell, Ref, RefMut};
use std::ops::{Deref, DerefMut};
use std::intrinsics;
use std::mem;
use std::raw::TraitObject;
use std::marker::PhantomData;

use bs_audio::AudioSource;

use ecs::{Entity, EntityManager, ComponentManager};
use input::Input;
use component::{TransformManager, CameraManager, MeshManager, LightManager, AudioSourceManager,
                AlarmManager, ColliderManager};
use resource::ResourceManager;

#[cfg(not(feature = "hotloading"))]
type ManagerId = ::std::any::TypeId;

#[cfg(feature = "hotloading")]
type ManagerId = &'static str;

/// Contains all the data that defines the current state of the world.
///
/// This is passed into systems in System::update(). It can be used access component
/// managers and input.
#[derive(Debug)]
pub struct Scene {
    entity_manager: RefCell<EntityManager>,
    component_managers: HashMap<ManagerId, RefCell<Box<ComponentManager>>>,
    pub input: Input,
    pub audio_source: AudioSource,
    resource_manager: Rc<ResourceManager>,
}

impl Scene {
    pub fn new(resource_manager: &Rc<ResourceManager>, audio_source: AudioSource) -> Scene {
        let mut scene = Scene {
            entity_manager: RefCell::new(EntityManager::new()),
            component_managers: HashMap::new(),
            input: Input::new(),
            audio_source: audio_source,
            resource_manager: resource_manager.clone(),
        };

        scene.register_manager(TransformManager::new());
        scene.register_manager(CameraManager::new());
        scene.register_manager(LightManager::new());
        scene.register_manager(MeshManager::new(resource_manager.clone()));
        scene.register_manager(AudioSourceManager::new(resource_manager.clone()));
        scene.register_manager(AlarmManager::new());
        scene.register_manager(ColliderManager::new());

        scene
    }

    pub fn clone(&self, resource_manager: &Rc<ResourceManager>) -> Scene {
        let mut scene = Scene {
            entity_manager: RefCell::new(self.entity_manager.borrow().clone()),
            component_managers: HashMap::new(),
            input: self.input.clone(),
            audio_source: self.audio_source.clone(),
            resource_manager: resource_manager.clone(),
        };

        // Reload internal component managers.
        scene.reload_manager::<TransformManager>(self);
        scene.reload_manager::<CameraManager>(self);
        scene.reload_manager::<LightManager>(self);
        scene.reload_manager::<AlarmManager>(self);
        scene.reload_manager::<ColliderManager>(self);
        scene.register_manager(self.get_manager::<MeshManager>().clone(resource_manager.clone()));
        scene.register_manager(self.get_manager::<AudioSourceManager>().clone(resource_manager.clone()));

        scene
    }

    pub fn register_manager<T: ComponentManager>(&mut self, manager: T) {
        let manager_id = manager_id::<T>();
        assert!(!self.component_managers.contains_key(&manager_id),
                "Manager {} with ID {:?} already registered", type_name::<T>(), manager_id);

        self.component_managers.insert(manager_id, RefCell::new(Box::new(manager)));
    }

    pub fn get_manager<T: ComponentManager>(&self) -> ManagerRef<T> {
        let manager_id = manager_id::<T>();
        let manager = match self.component_managers.get(&manager_id) {
            Some(manager) => manager,
            None => panic!("Tried to retrieve manager {} with ID {:?} but none exists",
                           type_name::<T>(),
                           manager_id),
        };

        ManagerRef {
            manager: manager.borrow(),
            _phantom: PhantomData,
        }
    }

    pub fn get_manager_mut<T: ComponentManager>(&self) -> ManagerRefMut<T> {
        let manager_id = manager_id::<T>();
        let manager = match self.component_managers.get(&manager_id) {
            Some(manager) => manager,
            None => panic!("Tried to retrieve manager {} with ID {:?} but none exists",
                           type_name::<T>(),
                           manager_id),
        };

        ManagerRefMut {
            manager: manager.borrow_mut(),
            _phantom: PhantomData,
        }
    }

    pub fn has_manager<T: ComponentManager>(&self) -> bool {
        let manager_id = manager_id::<T>();
        self.component_managers.get(&manager_id).is_some()
    }

    /// Reload a component manager for hotloading purposes.
    ///
    /// Clones the component manager from the old scene into the new scene.
    ///
    /// ## Panics
    ///
    /// Panics if the component manager isn't present in the old scene.
    pub fn reload_manager<T: ComponentManager + Clone>(&mut self, old_scene: &Scene) {
        self.register_manager(old_scene.get_manager::<T>().clone());
    }

    /// Reload a component manager or use a default if one was not previously registered.
    ///
    /// Checks the old scene if it has a component manager of the specified type registered. If so
    /// this method behaves identically to `reload_manager()`, otherwise it registers the default
    /// manager with the scene.
    pub fn reload_manager_or_default<T: ComponentManager + Clone>(&mut self, old_scene: &Scene, default: T) {
        if old_scene.has_manager::<T>() {
            self.reload_manager::<T>(old_scene);
        } else {
            self.register_manager(default);
        }
    }

    pub fn create_entity(&self) -> Entity {
        self.entity_manager.borrow_mut().create()
    }

    pub fn resource_manager(&self) -> &ResourceManager {
        &*self.resource_manager
    }

    /// Instantiates an instance of the model in the scene, returning the root entity.
    pub fn instantiate_model(&self, resource: &str) -> Entity {
        self.resource_manager.clone().instantiate_model(resource, self).unwrap()
    }

    pub fn destroy_entity(&self, entity: Entity) {
        for (_, manager) in self.component_managers.iter() {
            manager.borrow().destroy_all(entity);
        }

        let transform_manager = self.get_manager::<TransformManager>();
        transform_manager.walk_children(entity, &mut |entity| {
            for (_, manager) in self.component_managers.iter() {
                manager.borrow().destroy_all(entity);
            }
        });

        self.entity_manager.borrow_mut().mark_for_destroy(entity);
    }

    pub fn destroy_marked(&self) {
        for (_, manager) in self.component_managers.iter() {
            manager.borrow_mut().destroy_marked();
        }

        self.entity_manager.borrow_mut().destroy_marked();
    }
}

#[cfg(not(feature = "hotloading"))]
fn manager_id<T: ComponentManager>() -> ManagerId {
    ::std::any::TypeId::of::<T>()
}

/// Two cases:
///
/// - No template (e.g. `foo::bar::TransformManager`) just remove path (becomes `TransformManager`).
/// - Template (e.g. `foo::bar::Manager<foo::bar::Foo>`) innermost type without leading path
///   (becomes `Foo`).
#[cfg(feature = "hotloading")]
fn manager_id<T: ComponentManager>() -> ManagerId {
    let full_name = type_name::<T>();

    // Find first occurrence of '<' character since we know the start of the proper name has to
    // be before that.
    let sub_str = match full_name.find('<') {
        Some(index) => &full_name[index + 1..full_name.len() - 1], // foo::Foo<foo::Bar> => foo::Bar
        None => full_name,                                         // foo::Foo => foo::Foo
    };

    let slice_index = match sub_str.rfind("::") {
        Some(last_index) => last_index + 2,
        None => 0,
    };

    &sub_str[slice_index..]
}

fn type_name<T>() -> &'static str {
    unsafe {
        intrinsics::type_name::<T>()
    }
}

pub struct ManagerRef<'a, T: ComponentManager> {
    manager: Ref<'a, Box<ComponentManager>>,
    _phantom: PhantomData<T>,
}

impl<'a, T: ComponentManager> Deref for ManagerRef<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        unsafe { downcast_manager(self.manager.deref().deref()) }
    }
}

pub struct ManagerRefMut<'a, T: ComponentManager> {
    manager: RefMut<'a, Box<ComponentManager>>,
    _phantom: PhantomData<T>,
}

impl<'a, T: ComponentManager> Deref for ManagerRefMut<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        unsafe { downcast_manager(self.manager.deref().deref()) }
    }
}

impl<'a, T: ComponentManager> DerefMut for ManagerRefMut<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut T {
        let manager = self.manager.deref_mut().deref_mut();
        unsafe { downcast_manager_mut(manager) }
    }
}

/// Performs an unchecked downcast from the `ComponentManager` trait object to the concrete type.
unsafe fn downcast_manager<'a, T: ComponentManager>(manager: &'a ComponentManager) -> &'a T {
    // Get the raw representation of the trait object.
    let to: TraitObject = mem::transmute(manager);

    // Extract the data pointer.
    mem::transmute(to.data)
}

unsafe fn downcast_manager_mut<'a, T: ComponentManager>(manager: &'a mut ComponentManager) -> &'a mut T {
    // Get the raw representation of the trait object.
    let to: TraitObject = mem::transmute(manager);

    // Extract the data pointer.
    mem::transmute(to.data)
}
<|endoftext|>


<commit_before>///
/// Description: Parse soruce code, returning a vector of bytes representing the compiled program
///

use std::hashmap::HashMap;
use parser::trans::MarkerId;
use parser::trans::VarId;

mod lexer;
mod trans;
mod asm;

#[deriving(Eq)]
enum BlockType {
    IfBlock,
    LoopBlock,
    FunctionBlock,
}

struct MarkerStack {
    priv markers: ~[(BlockType, MarkerId)],
    last_marker: MarkerId
}

impl MarkerStack {
    fn new() -> MarkerStack {
        MarkerStack {
            markers: ~[],
            last_marker: 0
        }
    }

    /// Add a new marker to the marker stack
    fn push(&mut self, block_type: BlockType) {
        self.markers.push((block_type, self.last_marker));
        self.last_marker += 1;
    }

    /// Pop the last marker added
    fn pop(&mut self) -> (BlockType, MarkerId) {
        self.markers.pop()
    }

    /// Find the top most marker of the specified type
    fn find_type(&mut self, block_type: BlockType) -> Option<MarkerId> {
        self.markers.rev_iter().find(|& &(btype, _)| btype == block_type).map(|&(_, id)| id)
    }
}

static SYSTEM_CALLS: [&'static str, ..8] = [
    "__clear", "__draw_pos", "__set_addr", "__draw", "__random", "__set_delay",
    "__get_font", "__key_wait"
];

struct Parser {
    variables: HashMap<~str, VarId>,
    var_index: VarId,
    marker_stack: MarkerStack,
    code: ~[lexer::Token],
    pos: uint,
}

pub fn parse(source_code: &str) -> ~[u8] {
    let mut parser = Parser {
        variables: HashMap::new(),
        var_index: 0,
        marker_stack: MarkerStack::new(),
        code: lexer::Lexer::new(source_code).collect(),
        pos: 0,
    };
    println!("{:?}\n", parser.code);
    let ops = trans::block_to_asm(parser.parse_block(FunctionBlock));
    for op in ops.iter() {
        println!("{:?}", op);
    }
    println!("");
    asm::compile(ops, parser.marker_stack.last_marker)
}

impl Parser {
    fn parse_block(&mut self, block_type: BlockType) -> trans::Block {
        let mut statements = ~[];
        self.marker_stack.push(block_type);
        self.marker_stack.push(block_type);
        // Parse the block
        match self.code[self.pos].clone() {
            lexer::LeftBrace => {
                self.pos += 1;
                // Loop through all the statements in the block
                loop {
                    match self.code[self.pos].clone() {
                        lexer::RightBrace => break,
                        _ => statements.push(self.parse_statement()),
                    }
                }
            },
            xx => fail!("Error: expected `LeftBrace` but found `{:?}`", xx)
        }
        // Get the block markers
        let (_, end_id) = self.marker_stack.pop();
        let (_, start_id) = self.marker_stack.pop();
        trans::Block {
            statements: statements,
            start_id: start_id,
            end_id: end_id,
        }
    }

    fn parse_statement(&mut self) -> trans::Statement {
        match self.code[self.pos].clone() {
            lexer::Let => self.parse_let(),
            lexer::If => self.parse_if(),
            lexer::For => fail!("ICE: Unimplemented"),
            lexer::While => fail!("ICE: Unimplemented"),
            lexer::Fn => fail!("ICE: Unimplemented"),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Ident(ref s) => self.parse_ident_statement(s),
            xx => fail!("Unexpected token found: `{:?}`", xx)
        }
    }

    fn parse_let(&mut self) -> trans::Statement {
        self.pos += 1;
        // Determine the variables name
        let var_name = match self.code[self.pos].clone() {
            lexer::Ident(ref s) => s.clone(),
            xx => fail!("Error: expected `Ident` but found `{:?}`", xx)
        };
        // Check if variable is already defined
        if SYSTEM_CALLS.iter().any(|&x| x == var_name) {
            fail!("Error: `{}` is a system command");
        }
        if self.variables.contains_key(&var_name) {
            fail!("Error: Shadowing is unsupported. (`{}` was already defined)", var_name);
        }
        // Add the variable to the variable list
        self.variables.insert(var_name.clone(), self.var_index);
        self.var_index += 1;
        self.pos += 1;
        // Check if we are assigning to the variable
        match self.code[self.pos].clone() {
            lexer::Assignment => {
                self.pos += 1;
                // Parse the assignment
                self.parse_assignment(self.var_index-1)
            },
            lexer::StatementEnd => {
                self.pos += 1;
                // Variable declaration without assignment is a NOP
                trans::Nop
            },
            xx => fail!("Error: expected `Assignment` or `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_assignment(&mut self, var_id: VarId) -> trans::Statement {
        // Parse the rhs expression
        let expr = self.parse_expression();
        // Check for statement end
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {},
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx)
        }
        self.pos += 1;
        trans::Assignment(var_id, expr)
    }

    fn parse_if(&mut self) -> trans::Statement {
        self.pos += 1;
        // Parse the condition
        let condition_expr = self.parse_expression();
        // Parse the if block
        let if_block = self.parse_block(IfBlock);
        // Parse the else block
        let else_block = match self.code[self.pos].clone() {
            lexer::Else => {
                self.pos += 1;
                self.parse_block(IfBlock)
            },
            _ => {
                // Create a blank block if the else block was not specified
                self.marker_stack.last_marker += 2;
                trans::Block {
                    statements: ~[],
                    start_id: self.marker_stack.last_marker-2,
                    end_id: self.marker_stack.last_marker-1,
                }
            }
        };
        trans::If(condition_expr, if_block, else_block)
    }

    fn parse_loop(&mut self) -> trans::Statement {
        self.pos += 1;
        let mut loop_block = self.parse_block(LoopBlock);
        // Add the jump back to the start of the loop
        loop_block.statements.push(trans::Jump(loop_block.start_id));
        trans::Loop(loop_block)
    }

    fn parse_break(&mut self) -> trans::Statement {
        let jump_id = match self.marker_stack.find_type(LoopBlock) {
            Some(id) => id,
            None => fail!("Error: `Break` is not valid here.")
        };

        self.pos += 1;
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {
                self.pos += 1;
                trans::Jump(jump_id)
            },
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_expression(&mut self) -> trans::Expression {
        let mut current_expr = None;
        loop {
            current_expr = match self.code[self.pos].clone() {
                lexer::Ident(ref s) => {
                    Some(trans::Variable(self.get_variable(s)))
                },
                lexer::LitNum(n) => {
                    self.pos += 1;
                    Some(trans::LitNum(n as u8))
                },
                lexer::Plus => Some(self.parse_operator(current_expr, trans::Plus)),
                lexer::Minus => Some(self.parse_operator(current_expr, trans::Minus)),
                _ => break,
            };
        }
        // Return the expression if there was one
        match current_expr {
            Some(expr) => expr,
            None => fail!("Error: expected expression")
        }
    }

    fn parse_operator(&mut self,
            lhs: Option<trans::Expression>,
            operator: trans::Operator) -> trans::Expression {
        // Check that there is a valid lhs expression
        let lhs = match lhs {
            Some(expr) => expr,
            None => fail!("Error: invalid LHS operand"),
        };
        self.pos += 1;
        // Parse the rhs expression
        let rhs = self.parse_expression();
        trans::OperatorExpr(~rhs, operator, ~lhs)
    }

    fn parse_ident_statement(&mut self, name: &~str) -> trans::Statement {
        // Check if the identifier was a system call
        match SYSTEM_CALLS.iter().find(|& &x| x == *name) {
            Some(&n) => {
                self.pos += 1;
                return trans::CallSys(match n {
                    "__clear"     => self.parse_syscall_clear(),
                    "__draw_pos"  => self.parse_syscall_draw_pos(),
                    "__set_addr"  => fail!("Unimplemented"),
                    "__draw"      => self.parse_syscall_draw(),
                    "__random"    => fail!("Unimplemented"),
                    "__set_delay" => fail!("Unimplemented"),
                    "__get_font"  => self.parse_syscall_get_font(),
                    "__key_wait"  => self.parse_syscall_key_wait(),

                    _ => fail!("Unreachable")
                });
            },
            None => {}
        }

        // Check if the identifier is a variable
        match self.variables.find(name) {
            Some(&var_id) => {
                self.pos += 1;
                match self.code[self.pos].clone() {
                    // If the identifier was a variable, then there should be an assignment
                    lexer::Assignment => {
                        self.pos += 1;
                        return self.parse_assignment(var_id);
                    },
                    xx => fail!("Error: expected `Assignment` but found `{:?}`", xx)
                }
            },
            None => {}
        }

        fail!("Error: `{}` is undefined", *name);
    }

    fn parse_syscall_clear(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::Clear
    }

    fn parse_syscall_draw_pos(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let x_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::Comma {
            fail!("Expected `Comma` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let y_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        trans::DrawPos(x_expr, y_expr)
    }

    fn parse_syscall_draw(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let command = match self.code[self.pos].clone() {
            lexer::LitNum(n) => {
                assert!(n < 0x10);
                trans::Draw(n as u8)
            },
            xx => fail!("Expected `LitNum` but found `{:?}`", xx)
        };
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        command
    }

    fn parse_syscall_get_font(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::GetFont(expr)
    }

    fn parse_syscall_key_wait(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::KeyWait(expr)
    }

    /// Returns the id of a variable name
    fn get_variable(&mut self, var_name: &~str) -> VarId {
        let var_id = match self.variables.find(var_name) {
            Some(id) => id,
            None => fail!("Error: `{}` is undefined", *var_name)
        };
        self.pos += 1;
        *var_id
    }
}
<commit_msg>Fix bug where the first `}` ends all blocks<commit_after>///
/// Description: Parse soruce code, returning a vector of bytes representing the compiled program
///

use std::hashmap::HashMap;
use parser::trans::MarkerId;
use parser::trans::VarId;

mod lexer;
mod trans;
mod asm;

#[deriving(Eq)]
enum BlockType {
    IfBlock,
    LoopBlock,
    FunctionBlock,
}

struct MarkerStack {
    priv markers: ~[(BlockType, MarkerId)],
    last_marker: MarkerId
}

impl MarkerStack {
    fn new() -> MarkerStack {
        MarkerStack {
            markers: ~[],
            last_marker: 0
        }
    }

    /// Add a new marker to the marker stack
    fn push(&mut self, block_type: BlockType) {
        self.markers.push((block_type, self.last_marker));
        self.last_marker += 1;
    }

    /// Pop the last marker added
    fn pop(&mut self) -> (BlockType, MarkerId) {
        self.markers.pop()
    }

    /// Find the top most marker of the specified type
    fn find_type(&mut self, block_type: BlockType) -> Option<MarkerId> {
        self.markers.rev_iter().find(|& &(btype, _)| btype == block_type).map(|&(_, id)| id)
    }
}

static SYSTEM_CALLS: [&'static str, ..8] = [
    "__clear", "__draw_pos", "__set_addr", "__draw", "__random", "__set_delay",
    "__get_font", "__key_wait"
];

struct Parser {
    variables: HashMap<~str, VarId>,
    var_index: VarId,
    marker_stack: MarkerStack,
    code: ~[lexer::Token],
    pos: uint,
}

pub fn parse(source_code: &str) -> ~[u8] {
    let mut parser = Parser {
        variables: HashMap::new(),
        var_index: 0,
        marker_stack: MarkerStack::new(),
        code: lexer::Lexer::new(source_code).collect(),
        pos: 0,
    };
    println!("{:?}\n", parser.code);
    let ops = trans::block_to_asm(parser.parse_block(FunctionBlock));
    for op in ops.iter() {
        println!("{:?}", op);
    }
    println!("");
    asm::compile(ops, parser.marker_stack.last_marker)
}

impl Parser {
    fn parse_block(&mut self, block_type: BlockType) -> trans::Block {
        let mut statements = ~[];
        self.marker_stack.push(block_type);
        self.marker_stack.push(block_type);
        // Parse the block
        match self.code[self.pos].clone() {
            lexer::LeftBrace => {
                self.pos += 1;
                // Loop through all the statements in the block
                loop {
                    match self.code[self.pos].clone() {
                        lexer::RightBrace => break,
                        _ => statements.push(self.parse_statement()),
                    }
                }
            },
            xx => fail!("Error: expected `LeftBrace` but found `{:?}`", xx)
        }
        self.pos += 1;
        // Get the block markers
        let (_, end_id) = self.marker_stack.pop();
        let (_, start_id) = self.marker_stack.pop();
        trans::Block {
            statements: statements,
            start_id: start_id,
            end_id: end_id,
        }
    }

    fn parse_statement(&mut self) -> trans::Statement {
        match self.code[self.pos].clone() {
            lexer::Let => self.parse_let(),
            lexer::If => self.parse_if(),
            lexer::For => fail!("ICE: Unimplemented"),
            lexer::While => fail!("ICE: Unimplemented"),
            lexer::Fn => fail!("ICE: Unimplemented"),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Ident(ref s) => self.parse_ident_statement(s),
            xx => fail!("Unexpected token found: `{:?}`", xx)
        }
    }

    fn parse_let(&mut self) -> trans::Statement {
        self.pos += 1;
        // Determine the variables name
        let var_name = match self.code[self.pos].clone() {
            lexer::Ident(ref s) => s.clone(),
            xx => fail!("Error: expected `Ident` but found `{:?}`", xx)
        };
        // Check if variable is already defined
        if SYSTEM_CALLS.iter().any(|&x| x == var_name) {
            fail!("Error: `{}` is a system command");
        }
        if self.variables.contains_key(&var_name) {
            fail!("Error: Shadowing is unsupported. (`{}` was already defined)", var_name);
        }
        // Add the variable to the variable list
        self.variables.insert(var_name.clone(), self.var_index);
        self.var_index += 1;
        self.pos += 1;
        // Check if we are assigning to the variable
        match self.code[self.pos].clone() {
            lexer::Assignment => {
                self.pos += 1;
                // Parse the assignment
                self.parse_assignment(self.var_index-1)
            },
            lexer::StatementEnd => {
                self.pos += 1;
                // Variable declaration without assignment is a NOP
                trans::Nop
            },
            xx => fail!("Error: expected `Assignment` or `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_assignment(&mut self, var_id: VarId) -> trans::Statement {
        // Parse the rhs expression
        let expr = self.parse_expression();
        // Check for statement end
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {},
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx)
        }
        self.pos += 1;
        trans::Assignment(var_id, expr)
    }

    fn parse_if(&mut self) -> trans::Statement {
        self.pos += 1;
        // Parse the condition
        let condition_expr = self.parse_expression();
        // Parse the if block
        let if_block = self.parse_block(IfBlock);
        // Parse the else block
        let else_block = match self.code[self.pos].clone() {
            lexer::Else => {
                self.pos += 1;
                self.parse_block(IfBlock)
            },
            _ => {
                // Create a blank block if the else block was not specified
                self.marker_stack.last_marker += 2;
                trans::Block {
                    statements: ~[],
                    start_id: self.marker_stack.last_marker-2,
                    end_id: self.marker_stack.last_marker-1,
                }
            }
        };
        trans::If(condition_expr, if_block, else_block)
    }

    fn parse_loop(&mut self) -> trans::Statement {
        self.pos += 1;
        let mut loop_block = self.parse_block(LoopBlock);
        // Add the jump back to the start of the loop
        loop_block.statements.push(trans::Jump(loop_block.start_id));
        trans::Loop(loop_block)
    }

    fn parse_break(&mut self) -> trans::Statement {
        let jump_id = match self.marker_stack.find_type(LoopBlock) {
            Some(id) => id,
            None => fail!("Error: `Break` is not valid here.")
        };

        self.pos += 1;
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {
                self.pos += 1;
                trans::Jump(jump_id)
            },
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_expression(&mut self) -> trans::Expression {
        let mut current_expr = None;
        loop {
            current_expr = match self.code[self.pos].clone() {
                lexer::Ident(ref s) => {
                    Some(trans::Variable(self.get_variable(s)))
                },
                lexer::LitNum(n) => {
                    self.pos += 1;
                    Some(trans::LitNum(n as u8))
                },
                lexer::Plus => Some(self.parse_operator(current_expr, trans::Plus)),
                lexer::Minus => Some(self.parse_operator(current_expr, trans::Minus)),
                _ => break,
            };
        }
        // Return the expression if there was one
        match current_expr {
            Some(expr) => expr,
            None => fail!("Error: expected expression")
        }
    }

    fn parse_operator(&mut self,
            lhs: Option<trans::Expression>,
            operator: trans::Operator) -> trans::Expression {
        // Check that there is a valid lhs expression
        let lhs = match lhs {
            Some(expr) => expr,
            None => fail!("Error: invalid LHS operand"),
        };
        self.pos += 1;
        // Parse the rhs expression
        let rhs = self.parse_expression();
        trans::OperatorExpr(~rhs, operator, ~lhs)
    }

    fn parse_ident_statement(&mut self, name: &~str) -> trans::Statement {
        // Check if the identifier was a system call
        match SYSTEM_CALLS.iter().find(|& &x| x == *name) {
            Some(&n) => {
                self.pos += 1;
                return trans::CallSys(match n {
                    "__clear"     => self.parse_syscall_clear(),
                    "__draw_pos"  => self.parse_syscall_draw_pos(),
                    "__set_addr"  => fail!("Unimplemented"),
                    "__draw"      => self.parse_syscall_draw(),
                    "__random"    => fail!("Unimplemented"),
                    "__set_delay" => fail!("Unimplemented"),
                    "__get_font"  => self.parse_syscall_get_font(),
                    "__key_wait"  => self.parse_syscall_key_wait(),

                    _ => fail!("Unreachable")
                });
            },
            None => {}
        }

        // Check if the identifier is a variable
        match self.variables.find(name) {
            Some(&var_id) => {
                self.pos += 1;
                match self.code[self.pos].clone() {
                    // If the identifier was a variable, then there should be an assignment
                    lexer::Assignment => {
                        self.pos += 1;
                        return self.parse_assignment(var_id);
                    },
                    xx => fail!("Error: expected `Assignment` but found `{:?}`", xx)
                }
            },
            None => {}
        }

        fail!("Error: `{}` is undefined", *name);
    }

    fn parse_syscall_clear(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::Clear
    }

    fn parse_syscall_draw_pos(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let x_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::Comma {
            fail!("Expected `Comma` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let y_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        trans::DrawPos(x_expr, y_expr)
    }

    fn parse_syscall_draw(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let command = match self.code[self.pos].clone() {
            lexer::LitNum(n) => {
                assert!(n < 0x10);
                trans::Draw(n as u8)
            },
            xx => fail!("Expected `LitNum` but found `{:?}`", xx)
        };
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        command
    }

    fn parse_syscall_get_font(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::GetFont(expr)
    }

    fn parse_syscall_key_wait(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::KeyWait(expr)
    }

    /// Returns the id of a variable name
    fn get_variable(&mut self, var_name: &~str) -> VarId {
        let var_id = match self.variables.find(var_name) {
            Some(id) => id,
            None => fail!("Error: `{}` is undefined", *var_name)
        };
        self.pos += 1;
        *var_id
    }
}
<|endoftext|>


<commit_before>use std::mem;

use lexer::Lexer;
use lexer::token::{TokenType,Token};
use lexer::position::Position;
use lexer::reader::{CodeReader,StrReader,FileReader};
use error::ParseError;
use error::ErrorCode;

use ast::BinOp;
use ast::Expr;

pub struct Parser<T: CodeReader> {
    lexer: Lexer<T>,
    token: Token
}

impl Parser<StrReader> {
    pub fn from_str(code: &'static str) -> Parser<StrReader> {
        Parser::new(Lexer::from_str(code))
    }
}

impl Parser<FileReader> {
    pub fn from_file(filename: &'static str) -> Parser<FileReader> {
        Parser::new(Lexer::from_file(filename))
    }
}

type AstErr = Result<Box<Expr>,ParseError>;

impl<T: CodeReader> Parser<T> {
    pub fn new( lexer: Lexer<T> ) -> Parser<T> {
        let token = Token::new(TokenType::End, Position::new(1,1));
        let mut parser = Parser { lexer: lexer, token: token };

        parser
    }

    pub fn parse(&mut self) -> AstErr {
        // initialize parser
        try!(self.read_token());

        self.parse_expression()
    }

    fn parse_expression(&mut self) -> AstErr {
        self.parse_factor()
    }

    fn parse_expression_l0(&mut self) -> AstErr {
        let left = try!(self.parse_expression_l1());

        if self.token.is(TokenType::Assign) {
            try!(self.read_token());
            let right = try!(self.parse_expression_l0());

            Ok(box Expr::ExprAssign(left, right))
        } else {
            Ok(left)
        }
    }

    fn parse_expression_l1(&mut self) -> AstErr {
        let left = try!(self.parse_expression_l2());

        if self.token.is(TokenType::Eq) || self.token.is(TokenType::NEq) {
            let op = try!(self.read_token());
            let right = try!(self.parse_expression_l2());

            Ok(box Expr::ExprBin(BinOp::Add, left, right))
        } else {
            Ok(left)
        }
    }

    fn parse_expression_l2(&mut self) -> AstErr {
        self.parse_factor()
    }

    fn parse_expression_l3(&mut self) -> AstErr {
        self.parse_factor()
    }

    fn parse_expression_l4(&mut self) -> AstErr {
        self.parse_factor()
    }

    fn parse_expression_l5(&mut self) -> AstErr {
        self.parse_factor()
    }

    fn parse_factor(&mut self) -> AstErr {
        match self.token.token_type {
            TokenType::Number => self.parse_number(),
            TokenType::String => self.parse_string(),
            TokenType::Identifier => self.parse_identifier(),
            _ => Err(ParseError {
                filename: self.lexer.filename().to_string(),
                position: self.token.position,
                code: ErrorCode::UnknownFactor,
                message: format!("factor expected but got {}", self.token)
            })
        }
    }

    fn parse_number(&mut self) -> AstErr {
        let num = try!(self.read_token());

        match num.value.parse::<i64>() {
            Some(num) => Ok(box Expr::ExprLitInt(num)),
            None => Err(ParseError {
                filename: self.lexer.filename().to_string(),
                position: self.token.position,
                message: format!("number {} does not fit into range", num),
                code: ErrorCode::NumberOverflow
            } )
        }
    }

    fn parse_string(&mut self) -> AstErr {
        let string = try!(self.read_token());

        Ok(box Expr::ExprLitStr(string.value))
    }

    fn parse_identifier(&mut self) -> AstErr {
        let ident = try!(self.read_token());

        Ok(box Expr::ExprIdent(ident.value))
    }

    fn read_token(&mut self) -> Result<Token,ParseError> {
        let tok = try!(self.lexer.read_token());

        Ok(mem::replace(&mut self.token, tok))
    }
}

#[test]
fn test_number() {
    let mut parser = Parser::from_str("10");

    assert_eq!(Expr::ExprLitInt(10), *parser.parse().unwrap());
}

#[test]
fn test_string() {
    let mut parser = Parser::from_str("\"abc\"");

    assert_eq!(Expr::ExprLitStr("abc".to_string()), *parser.parse().unwrap());
}
<commit_msg>renamed AstErr to AstResult<commit_after>use std::mem;

use lexer::Lexer;
use lexer::token::{TokenType,Token};
use lexer::position::Position;
use lexer::reader::{CodeReader,StrReader,FileReader};
use error::ParseError;
use error::ErrorCode;

use ast::BinOp;
use ast::Expr;

pub struct Parser<T: CodeReader> {
    lexer: Lexer<T>,
    token: Token
}

impl Parser<StrReader> {
    pub fn from_str(code: &'static str) -> Parser<StrReader> {
        Parser::new(Lexer::from_str(code))
    }
}

impl Parser<FileReader> {
    pub fn from_file(filename: &'static str) -> Parser<FileReader> {
        Parser::new(Lexer::from_file(filename))
    }
}

type AstResult = Result<Box<Expr>,ParseError>;

impl<T: CodeReader> Parser<T> {
    pub fn new( lexer: Lexer<T> ) -> Parser<T> {
        let token = Token::new(TokenType::End, Position::new(1,1));
        let mut parser = Parser { lexer: lexer, token: token };

        parser
    }

    pub fn parse(&mut self) -> AstResult {
        // initialize parser
        try!(self.read_token());

        self.parse_expression()
    }

    fn parse_expression(&mut self) -> AstResult {
        self.parse_factor()
    }

    fn parse_expression_l0(&mut self) -> AstResult {
        let left = try!(self.parse_expression_l1());

        if self.token.is(TokenType::Assign) {
            try!(self.read_token());
            let right = try!(self.parse_expression_l0());

            Ok(box Expr::ExprAssign(left, right))
        } else {
            Ok(left)
        }
    }

    fn parse_expression_l1(&mut self) -> AstResult {
        let left = try!(self.parse_expression_l2());

        if self.token.is(TokenType::Eq) || self.token.is(TokenType::NEq) {
            let op = try!(self.read_token());
            let right = try!(self.parse_expression_l2());

            Ok(box Expr::ExprBin(BinOp::Add, left, right))
        } else {
            Ok(left)
        }
    }

    fn parse_expression_l2(&mut self) -> AstResult {
        self.parse_factor()
    }

    fn parse_expression_l3(&mut self) -> AstResult {
        self.parse_factor()
    }

    fn parse_expression_l4(&mut self) -> AstResult {
        self.parse_factor()
    }

    fn parse_expression_l5(&mut self) -> AstResult {
        self.parse_factor()
    }

    fn parse_factor(&mut self) -> AstResult {
        match self.token.token_type {
            TokenType::Number => self.parse_number(),
            TokenType::String => self.parse_string(),
            TokenType::Identifier => self.parse_identifier(),
            _ => Err(ParseError {
                filename: self.lexer.filename().to_string(),
                position: self.token.position,
                code: ErrorCode::UnknownFactor,
                message: format!("factor expected but got {}", self.token)
            })
        }
    }

    fn parse_number(&mut self) -> AstResult {
        let num = try!(self.read_token());

        match num.value.parse::<i64>() {
            Some(num) => Ok(box Expr::ExprLitInt(num)),
            None => Err(ParseError {
                filename: self.lexer.filename().to_string(),
                position: self.token.position,
                message: format!("number {} does not fit into range", num),
                code: ErrorCode::NumberOverflow
            } )
        }
    }

    fn parse_string(&mut self) -> AstResult {
        let string = try!(self.read_token());

        Ok(box Expr::ExprLitStr(string.value))
    }

    fn parse_identifier(&mut self) -> AstResult {
        let ident = try!(self.read_token());

        Ok(box Expr::ExprIdent(ident.value))
    }

    fn read_token(&mut self) -> Result<Token,ParseError> {
        let tok = try!(self.lexer.read_token());

        Ok(mem::replace(&mut self.token, tok))
    }
}

#[test]
fn test_number() {
    let mut parser = Parser::from_str("10");

    assert_eq!(Expr::ExprLitInt(10), *parser.parse().unwrap());
}

#[test]
fn test_string() {
    let mut parser = Parser::from_str("\"abc\"");

    assert_eq!(Expr::ExprLitStr("abc".to_string()), *parser.parse().unwrap());
}
<|endoftext|>


<commit_before>//! Operation result structures and helpers.
//!
//! Most LDAP operations return an [`LdapResult`](struct.LdapResult.html). This module
//! contains its definition, as well as that of a number of wrapper structs and
//! helper methods, which adapt LDAP result and error handling to be a closer
//! match to Rust conventions.

use std::error::Error;
use std::fmt;
use std::io;
use std::result::Result as StdResult;

use crate::controls::Control;
use crate::exop::Exop;
use crate::protocol::{LdapOp, MaybeControls, ResultSender};
use crate::search::parse_refs;
use crate::search::ResultEntry;
use crate::RequestId;

use lber::common::TagClass;
use lber::parse::parse_uint;
use lber::structures::Tag;
use lber::universal::Types;
use lber::IResult;

use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
use tokio::time;

/// Type alias for the standard `Result` with the fixed `LdapError` error part.
pub type Result<T> = std::result::Result<T, LdapError>;

/// Error variants recognized by the library.
#[derive(Debug, Error)]
pub enum LdapError {
    /// No path given for a `ldapi://` URL.
    #[error("empty Unix domain socket path")]
    EmptyUnixPath,

    /// A `ldapi://` URL contains a port spec, which it shouldn't.
    #[error("the port must be empty in the ldapi scheme")]
    PortInUnixPath,

    /// Encapsulated I/O error.
    #[error("I/O error: {source}")]
    Io {
        #[from]
        source: io::Error,
    },

    /// Error while sending an operation to the connection handler.
    #[error("op send error: {source}")]
    OpSend {
        #[from]
        source: mpsc::error::SendError<(RequestId, LdapOp, Tag, MaybeControls, ResultSender)>,
    },

    /// Error while receiving operation results from the connection handler.
    #[error("result recv error: {source}")]
    ResultRecv {
        #[from]
        source: oneshot::error::RecvError,
    },

    /// Error while sending an internal ID scrubbing request to the connection handler.
    #[error("id scrub send error: {source}")]
    IdScrubSend {
        #[from]
        source: mpsc::error::SendError<RequestId>,
    },

    /// Operation or connection timeout.
    #[error("timeout: {elapsed}")]
    Timeout {
        #[from]
        elapsed: time::Elapsed,
    },

    /// Error parsing the string representation of a search filter.
    #[error("filter parse error")]
    FilterParsing,

    /// Premature end of a search stream.
    #[error("premature end of search stream")]
    EndOfStream,

    /// URL parsing error.
    #[error("url parse error: {source}")]
    UrlParsing {
        #[from]
        source: url::ParseError,
    },

    /// Unknown LDAP URL scheme.
    #[error("unknown LDAP URL scheme: {0}")]
    UnknownScheme(String),

    #[cfg(feature = "tls-native")]
    /// Native TLS library error.
    #[error("native TLS error: {source}")]
    NativeTLS {
        #[from]
        source: native_tls::Error,
    },

    #[cfg(feature = "tls-rustls")]
    /// rustls library error.
    #[error("rustls error: {source}")]
    TLS {
        #[from]
        source: rustls::TLSError,
    },

    /// LDAP operation result with an error return code.
    #[error("LDAP operation result: {result}")]
    LdapResult {
        #[from]
        result: LdapResult,
    },

    /// No values provided for the Add operation.
    #[error("empty value set for Add")]
    AddNoValues,

    /// No values provided for the Add operation.
    #[error("adapter init error: {0}")]
    AdapterInit(String),
}

impl From<LdapError> for io::Error {
    fn from(le: LdapError) -> io::Error {
        match le {
            LdapError::Io { source, .. } => source,
            _ => io::Error::new(io::ErrorKind::Other, format!("{}", le)),
        }
    }
}

/// Common components of an LDAP operation result.
///
/// This structure faithfully replicates the components dictated by the standard,
/// and is distinctly C-like with its reliance on numeric codes for the indication
/// of outcome. It would be tempting to hide it behind an automatic `Result`-like
/// interface, but there are scenarios where this would preclude intentional
/// incorporation of error conditions into query design. Instead, the struct
/// implements helper methods, [`success()`](#method.success) and
/// [`non_error()`](#method.non_error), which may be used for ergonomic error
/// handling when simple condition checking suffices.
#[derive(Clone, Debug)]
pub struct LdapResult {
    /// Result code.
    ///
    /// Generally, the value of zero indicates successful completion, but there's
    /// a number of other non-error codes arising as a result of various operations.
    /// See [Section A.1 of RFC 4511](https://tools.ietf.org/html/rfc4511#appendix-A.1).
    pub rc: u32,
    /// Matched component DN, where applicable.
    pub matched: String,
    /// Additional diagnostic text.
    pub text: String,
    /// Referrals.
    ///
    /// Absence of referrals is represented by an empty vector.
    pub refs: Vec<String>,
    /// Response controls.
    ///
    /// Missing and empty controls are both represented by an empty vector.
    pub ctrls: Vec<Control>,
}

#[doc(hidden)]
impl From<Tag> for LdapResult {
    fn from(t: Tag) -> LdapResult {
        <LdapResultExt as From<Tag>>::from(t).0
    }
}

impl Error for LdapResult {}

impl fmt::Display for LdapResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        fn description(this: &LdapResult) -> &'static str {
            match this.rc {
                0 => "success",
                1 => "operationsError",
                2 => "protocolError",
                3 => "timeLimitExceeded",
                4 => "sizeLimitExceeded",
                5 => "compareFalse",
                6 => "compareTrue",
                7 => "authMethodNotSupported",
                8 => "strongerAuthRequired",
                10 => "referral",
                11 => "adminLimitExceeded",
                12 => "unavailableCriticalExtension",
                13 => "confidentialityRequired",
                14 => "saslBindInProgress",
                16 => "noSuchAttribute",
                17 => "undefinedAttributeType",
                18 => "inappropriateMatching",
                19 => "constraintViolation",
                20 => "attributeOrValueExists",
                21 => "invalidAttributeSyntax",
                32 => "noSuchObject",
                33 => "aliasProblem",
                34 => "invalidDNSyntax",
                36 => "aliasDereferencingProblem",
                48 => "inappropriateAuthentication",
                49 => "invalidCredentials",
                50 => "insufficientAccessRights",
                51 => "busy",
                52 => "unavailable",
                53 => "unwillingToPerform",
                54 => "loopDetect",
                64 => "namingViolation",
                65 => "objectClassViolation",
                66 => "notAllowedOnNonLeaf",
                67 => "notAllowedOnRDN",
                68 => "entryAlreadyExists",
                69 => "objectClassModsProhibited",
                71 => "affectsMultipleDSAs",
                80 => "other",
                88 => "abandoned",
                122 => "assertionFailed",
                _ => "unknown",
            }
        }

        write!(
            f,
            "rc={} ({}), dn: \"{}\", text: \"{}\"",
            self.rc,
            description(self),
            self.matched,
            self.text
        )
    }
}

impl LdapResult {
    /// If the result code is zero, return the instance itself wrapped
    /// in `Ok()`, otherwise wrap the instance in an `LdapError`.
    pub fn success(self) -> Result<Self> {
        if self.rc == 0 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }

    /// If the result code is 0 or 10 (referral), return the instance
    /// itself wrapped in `Ok()`, otherwise wrap the instance in an
    /// `LdapError`.
    pub fn non_error(self) -> Result<Self> {
        if self.rc == 0 || self.rc == 10 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct LdapResultExt(pub LdapResult, pub Exop);

impl From<Tag> for LdapResultExt {
    fn from(t: Tag) -> LdapResultExt {
        let t = match t {
            Tag::StructureTag(t) => t,
            Tag::Null(_) => {
                return LdapResultExt(
                    LdapResult {
                        rc: 0,
                        matched: String::from(""),
                        text: String::from(""),
                        refs: vec![],
                        ctrls: vec![],
                    },
                    Exop {
                        name: None,
                        val: None,
                    },
                )
            }
            _ => unimplemented!(),
        };
        let mut tags = t.expect_constructed().expect("result sequence").into_iter();
        let rc = match parse_uint(
            tags.next()
                .expect("element")
                .match_class(TagClass::Universal)
                .and_then(|t| t.match_id(Types::Enumerated as u64))
                .and_then(|t| t.expect_primitive())
                .expect("result code")
                .as_slice(),
        ) {
            IResult::Done(_, rc) => rc as u32,
            _ => panic!("failed to parse result code"),
        };
        let matched = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("matched dn");
        let text = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("diagnostic message");
        let mut refs = Vec::new();
        let mut exop_name = None;
        let mut exop_val = None;
        loop {
            match tags.next() {
                None => break,
                Some(comp) => match comp.id {
                    3 => {
                        refs.extend(parse_refs(comp));
                    }
                    10 => {
                        exop_name = Some(
                            String::from_utf8(comp.expect_primitive().expect("octet string"))
                                .expect("exop name"),
                        );
                    }
                    11 => {
                        exop_val = Some(comp.expect_primitive().expect("octet string"));
                    }
                    _ => (),
                },
            }
        }
        LdapResultExt(
            LdapResult {
                rc,
                matched,
                text,
                refs,
                ctrls: vec![],
            },
            Exop {
                name: exop_name,
                val: exop_val,
            },
        )
    }
}

/// Wrapper for results of a Search operation which returns all entries at once.
///
/// The wrapper exists so that methods [`success()`](#method.success) and
/// [`non_error()`](#method.non_error) can be called on an instance. Those methods
/// destructure the wrapper and return its components as elements of an anonymous
/// tuple.
#[derive(Clone, Debug)]
pub struct SearchResult(pub Vec<ResultEntry>, pub LdapResult);

impl SearchResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}

/// Wrapper for the result of a Compare operation.
///
/// Compare uniquely has two non-zero return codes to indicate the outcome of a successful
/// comparison, while other return codes indicate errors, as usual (except 10 for referral).
/// The [`equal()`](#method.equal) method optimizes for the expected case of ignoring
/// referrals; [`non_error()`](#method.non_error) can be used when that's not possible.
#[derive(Clone, Debug)]
pub struct CompareResult(pub LdapResult);

impl CompareResult {
    /// If the result code is 5 (compareFalse) or 6 (compareTrue), return the corresponding
    /// boolean value wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn equal(self) -> Result<bool> {
        match self.0.rc {
            5 => Ok(false),
            6 => Ok(true),
            _ => Err(LdapError::from(self.0)),
        }
    }

    /// If the result code is 5 (compareFalse), 6 (compareTrue),  or 10 (referral), return
    /// the inner `LdapResult`, otherwise rewrap `LdapResult` in an `LdapError`.
    pub fn non_error(self) -> Result<LdapResult> {
        if self.0.rc == 5 || self.0.rc == 6 || self.0.rc == 10 {
            Ok(self.0)
        } else {
            Err(LdapError::from(self.0))
        }
    }
}

/// Wrapper for the result of an Extended operation.
///
/// Similarly to [`SearchResult`](struct.SearchResult.html), methods
/// [`success()`](#method.success) and [`non_error()`](#method.non_error) can be
/// called on an instance, and will destructure the wrapper into an anonymous
/// tuple of its components.
#[derive(Clone, Debug)]
pub struct ExopResult(pub Exop, pub LdapResult);

impl ExopResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}
<commit_msg>Update Rustls error enum variant<commit_after>//! Operation result structures and helpers.
//!
//! Most LDAP operations return an [`LdapResult`](struct.LdapResult.html). This module
//! contains its definition, as well as that of a number of wrapper structs and
//! helper methods, which adapt LDAP result and error handling to be a closer
//! match to Rust conventions.

use std::error::Error;
use std::fmt;
use std::io;
use std::result::Result as StdResult;

use crate::controls::Control;
use crate::exop::Exop;
use crate::protocol::{LdapOp, MaybeControls, ResultSender};
use crate::search::parse_refs;
use crate::search::ResultEntry;
use crate::RequestId;

use lber::common::TagClass;
use lber::parse::parse_uint;
use lber::structures::Tag;
use lber::universal::Types;
use lber::IResult;

use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
use tokio::time;

/// Type alias for the standard `Result` with the fixed `LdapError` error part.
pub type Result<T> = std::result::Result<T, LdapError>;

/// Error variants recognized by the library.
#[derive(Debug, Error)]
pub enum LdapError {
    /// No path given for a `ldapi://` URL.
    #[error("empty Unix domain socket path")]
    EmptyUnixPath,

    /// A `ldapi://` URL contains a port spec, which it shouldn't.
    #[error("the port must be empty in the ldapi scheme")]
    PortInUnixPath,

    /// Encapsulated I/O error.
    #[error("I/O error: {source}")]
    Io {
        #[from]
        source: io::Error,
    },

    /// Error while sending an operation to the connection handler.
    #[error("op send error: {source}")]
    OpSend {
        #[from]
        source: mpsc::error::SendError<(RequestId, LdapOp, Tag, MaybeControls, ResultSender)>,
    },

    /// Error while receiving operation results from the connection handler.
    #[error("result recv error: {source}")]
    ResultRecv {
        #[from]
        source: oneshot::error::RecvError,
    },

    /// Error while sending an internal ID scrubbing request to the connection handler.
    #[error("id scrub send error: {source}")]
    IdScrubSend {
        #[from]
        source: mpsc::error::SendError<RequestId>,
    },

    /// Operation or connection timeout.
    #[error("timeout: {elapsed}")]
    Timeout {
        #[from]
        elapsed: time::Elapsed,
    },

    /// Error parsing the string representation of a search filter.
    #[error("filter parse error")]
    FilterParsing,

    /// Premature end of a search stream.
    #[error("premature end of search stream")]
    EndOfStream,

    /// URL parsing error.
    #[error("url parse error: {source}")]
    UrlParsing {
        #[from]
        source: url::ParseError,
    },

    /// Unknown LDAP URL scheme.
    #[error("unknown LDAP URL scheme: {0}")]
    UnknownScheme(String),

    #[cfg(feature = "tls-native")]
    /// Native TLS library error.
    #[error("native TLS error: {source}")]
    NativeTLS {
        #[from]
        source: native_tls::Error,
    },

    #[cfg(feature = "tls-rustls")]
    /// Rustls library error.
    #[error("rustls error: {source}")]
    Rustls {
        #[from]
        source: rustls::TLSError,
    },

    /// LDAP operation result with an error return code.
    #[error("LDAP operation result: {result}")]
    LdapResult {
        #[from]
        result: LdapResult,
    },

    /// No values provided for the Add operation.
    #[error("empty value set for Add")]
    AddNoValues,

    /// No values provided for the Add operation.
    #[error("adapter init error: {0}")]
    AdapterInit(String),
}

impl From<LdapError> for io::Error {
    fn from(le: LdapError) -> io::Error {
        match le {
            LdapError::Io { source, .. } => source,
            _ => io::Error::new(io::ErrorKind::Other, format!("{}", le)),
        }
    }
}

/// Common components of an LDAP operation result.
///
/// This structure faithfully replicates the components dictated by the standard,
/// and is distinctly C-like with its reliance on numeric codes for the indication
/// of outcome. It would be tempting to hide it behind an automatic `Result`-like
/// interface, but there are scenarios where this would preclude intentional
/// incorporation of error conditions into query design. Instead, the struct
/// implements helper methods, [`success()`](#method.success) and
/// [`non_error()`](#method.non_error), which may be used for ergonomic error
/// handling when simple condition checking suffices.
#[derive(Clone, Debug)]
pub struct LdapResult {
    /// Result code.
    ///
    /// Generally, the value of zero indicates successful completion, but there's
    /// a number of other non-error codes arising as a result of various operations.
    /// See [Section A.1 of RFC 4511](https://tools.ietf.org/html/rfc4511#appendix-A.1).
    pub rc: u32,
    /// Matched component DN, where applicable.
    pub matched: String,
    /// Additional diagnostic text.
    pub text: String,
    /// Referrals.
    ///
    /// Absence of referrals is represented by an empty vector.
    pub refs: Vec<String>,
    /// Response controls.
    ///
    /// Missing and empty controls are both represented by an empty vector.
    pub ctrls: Vec<Control>,
}

#[doc(hidden)]
impl From<Tag> for LdapResult {
    fn from(t: Tag) -> LdapResult {
        <LdapResultExt as From<Tag>>::from(t).0
    }
}

impl Error for LdapResult {}

impl fmt::Display for LdapResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        fn description(this: &LdapResult) -> &'static str {
            match this.rc {
                0 => "success",
                1 => "operationsError",
                2 => "protocolError",
                3 => "timeLimitExceeded",
                4 => "sizeLimitExceeded",
                5 => "compareFalse",
                6 => "compareTrue",
                7 => "authMethodNotSupported",
                8 => "strongerAuthRequired",
                10 => "referral",
                11 => "adminLimitExceeded",
                12 => "unavailableCriticalExtension",
                13 => "confidentialityRequired",
                14 => "saslBindInProgress",
                16 => "noSuchAttribute",
                17 => "undefinedAttributeType",
                18 => "inappropriateMatching",
                19 => "constraintViolation",
                20 => "attributeOrValueExists",
                21 => "invalidAttributeSyntax",
                32 => "noSuchObject",
                33 => "aliasProblem",
                34 => "invalidDNSyntax",
                36 => "aliasDereferencingProblem",
                48 => "inappropriateAuthentication",
                49 => "invalidCredentials",
                50 => "insufficientAccessRights",
                51 => "busy",
                52 => "unavailable",
                53 => "unwillingToPerform",
                54 => "loopDetect",
                64 => "namingViolation",
                65 => "objectClassViolation",
                66 => "notAllowedOnNonLeaf",
                67 => "notAllowedOnRDN",
                68 => "entryAlreadyExists",
                69 => "objectClassModsProhibited",
                71 => "affectsMultipleDSAs",
                80 => "other",
                88 => "abandoned",
                122 => "assertionFailed",
                _ => "unknown",
            }
        }

        write!(
            f,
            "rc={} ({}), dn: \"{}\", text: \"{}\"",
            self.rc,
            description(self),
            self.matched,
            self.text
        )
    }
}

impl LdapResult {
    /// If the result code is zero, return the instance itself wrapped
    /// in `Ok()`, otherwise wrap the instance in an `LdapError`.
    pub fn success(self) -> Result<Self> {
        if self.rc == 0 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }

    /// If the result code is 0 or 10 (referral), return the instance
    /// itself wrapped in `Ok()`, otherwise wrap the instance in an
    /// `LdapError`.
    pub fn non_error(self) -> Result<Self> {
        if self.rc == 0 || self.rc == 10 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct LdapResultExt(pub LdapResult, pub Exop);

impl From<Tag> for LdapResultExt {
    fn from(t: Tag) -> LdapResultExt {
        let t = match t {
            Tag::StructureTag(t) => t,
            Tag::Null(_) => {
                return LdapResultExt(
                    LdapResult {
                        rc: 0,
                        matched: String::from(""),
                        text: String::from(""),
                        refs: vec![],
                        ctrls: vec![],
                    },
                    Exop {
                        name: None,
                        val: None,
                    },
                )
            }
            _ => unimplemented!(),
        };
        let mut tags = t.expect_constructed().expect("result sequence").into_iter();
        let rc = match parse_uint(
            tags.next()
                .expect("element")
                .match_class(TagClass::Universal)
                .and_then(|t| t.match_id(Types::Enumerated as u64))
                .and_then(|t| t.expect_primitive())
                .expect("result code")
                .as_slice(),
        ) {
            IResult::Done(_, rc) => rc as u32,
            _ => panic!("failed to parse result code"),
        };
        let matched = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("matched dn");
        let text = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("diagnostic message");
        let mut refs = Vec::new();
        let mut exop_name = None;
        let mut exop_val = None;
        loop {
            match tags.next() {
                None => break,
                Some(comp) => match comp.id {
                    3 => {
                        refs.extend(parse_refs(comp));
                    }
                    10 => {
                        exop_name = Some(
                            String::from_utf8(comp.expect_primitive().expect("octet string"))
                                .expect("exop name"),
                        );
                    }
                    11 => {
                        exop_val = Some(comp.expect_primitive().expect("octet string"));
                    }
                    _ => (),
                },
            }
        }
        LdapResultExt(
            LdapResult {
                rc,
                matched,
                text,
                refs,
                ctrls: vec![],
            },
            Exop {
                name: exop_name,
                val: exop_val,
            },
        )
    }
}

/// Wrapper for results of a Search operation which returns all entries at once.
///
/// The wrapper exists so that methods [`success()`](#method.success) and
/// [`non_error()`](#method.non_error) can be called on an instance. Those methods
/// destructure the wrapper and return its components as elements of an anonymous
/// tuple.
#[derive(Clone, Debug)]
pub struct SearchResult(pub Vec<ResultEntry>, pub LdapResult);

impl SearchResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}

/// Wrapper for the result of a Compare operation.
///
/// Compare uniquely has two non-zero return codes to indicate the outcome of a successful
/// comparison, while other return codes indicate errors, as usual (except 10 for referral).
/// The [`equal()`](#method.equal) method optimizes for the expected case of ignoring
/// referrals; [`non_error()`](#method.non_error) can be used when that's not possible.
#[derive(Clone, Debug)]
pub struct CompareResult(pub LdapResult);

impl CompareResult {
    /// If the result code is 5 (compareFalse) or 6 (compareTrue), return the corresponding
    /// boolean value wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn equal(self) -> Result<bool> {
        match self.0.rc {
            5 => Ok(false),
            6 => Ok(true),
            _ => Err(LdapError::from(self.0)),
        }
    }

    /// If the result code is 5 (compareFalse), 6 (compareTrue),  or 10 (referral), return
    /// the inner `LdapResult`, otherwise rewrap `LdapResult` in an `LdapError`.
    pub fn non_error(self) -> Result<LdapResult> {
        if self.0.rc == 5 || self.0.rc == 6 || self.0.rc == 10 {
            Ok(self.0)
        } else {
            Err(LdapError::from(self.0))
        }
    }
}

/// Wrapper for the result of an Extended operation.
///
/// Similarly to [`SearchResult`](struct.SearchResult.html), methods
/// [`success()`](#method.success) and [`non_error()`](#method.non_error) can be
/// called on an instance, and will destructure the wrapper into an anonymous
/// tuple of its components.
#[derive(Clone, Debug)]
pub struct ExopResult(pub Exop, pub LdapResult);

impl ExopResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}
<|endoftext|>


<commit_before>use regex::{Captures, Regex};
use term::{self, Terminal};

/// Finds all matches for the given pattern on the given subject and prints out
/// the subject with matches highlighted.
pub fn print_matches(pattern: &str, subject: &str) {
    // Attempt to compile the given regex pattern.
    let regex = match Regex::new(&pattern) {
        Ok(result) => { result },
        Err(_) => {
            println!("Invalid regular expression pattern '{}'.", pattern);
            return;
        }
    };

    // Loop over each match in the subject and pretty-print the match as well as
    // any trailing, non-matching text preceding the match.
    let mut last_index = 0;
    for captures in regex.captures_iter(subject) {
        let positions = captures.pos(0).unwrap();

        print!("{}", &subject[last_index .. positions.0]);
        print_captures(captures);
        last_index = positions.1;
    }

    // Print trailing unmatched text if there is any.
    if last_index < subject.len() {
        print!("{}", &subject[last_index ..]);
    }
}

/// Prints out a capture group using color formatting.
fn print_captures(captures: Captures) {
    // Grab a terminal object to write formatted output with.
    let mut terminal = term::stdout().unwrap();

    terminal.bg(term::color::BLUE).unwrap();
    print!("{}", captures.at(0).unwrap());
    terminal.reset().unwrap();
}
<commit_msg>First attempt at submatch highlighting<commit_after>use regex::{Captures, Regex};
use term::{self, color, Terminal};

/// Finds all matches for the given pattern on the given subject and prints out
/// the subject with matches highlighted.
pub fn print_matches(pattern: &str, subject: &str) {
    // Attempt to compile the given regex pattern.
    let regex = match Regex::new(&pattern) {
        Ok(result) => { result },
        Err(_) => {
            println!("Invalid regular expression pattern '{}'.", pattern);
            return;
        }
    };

    // Loop over each match in the subject and pretty-print the match as well as
    // any trailing, non-matching text preceding the match.
    let mut last_index = 0;
    for captures in regex.captures_iter(subject) {
        let positions = captures.pos(0).unwrap();

        print!("{}", &subject[last_index .. positions.0]);
        print_captures(captures);
        last_index = positions.1;
    }

    // Print trailing unmatched text if there is any.
    if last_index < subject.len() {
        print!("{}", &subject[last_index ..]);
    }
}

/// Prints out a capture group using color formatting.
fn print_captures(captures: Captures) {
    let mut terminal = term::stdout().unwrap();
    let color_cycle = [color::BLUE, color::GREEN, color::MAGENTA, color::YELLOW];

    // Get the string of the entire match. We will use this to print substrings
    // as we traverse the capture tree.
    let string = captures.at(0).unwrap();
    let offsets = captures.pos(0).unwrap();

    let mut stack: Vec<(usize, usize)> = Vec::new();
    stack.push(offsets);

    let mut left_bound = 0;

    for i in 1..captures.len() {
        let pos = captures.pos(i).unwrap();

        if pos.1 <= stack.last().unwrap().1 {
            // Inside parent
            terminal.bg(color_cycle[(stack.len() % 4) - 1]).unwrap();
            print!("{}", &string[stack.last().unwrap().0 - offsets.0 .. pos.0 - offsets.0]);
            stack.push(pos);
        } else {
            left_bound = stack.last().unwrap().0;
            let right_bound = stack.last().unwrap().1;

            // Unwind stack until we find the correct parent.
            while pos.1 > stack.last().unwrap().1 {
                stack.pop().unwrap();
                terminal.bg(color_cycle[stack.len() % 4]).unwrap();
                print!("{}", &string[left_bound - offsets.0 .. right_bound - offsets.0]);
                left_bound = right_bound;
            }

            terminal.bg(color_cycle[(stack.len() % 4) - 1]).unwrap();
            print!("{}", &string[right_bound - offsets.0 .. pos.0 - offsets.0]);
            stack.push(pos);
            left_bound = pos.0;
        }
    }

    terminal.bg(color_cycle[0]).unwrap();
    print!("{}", &string[left_bound - offsets.0 .. offsets.1]);

    // Reset coloring to normal.
    terminal.reset().unwrap();
}
<|endoftext|>


<commit_before>//! CSS funciri values.

use cssparser::Parser;

use crate::allowed_url::{Fragment, Href};
use crate::error::*;
use crate::parsers::Parse;

/// Used where style properties take a funciri or "none"
///
/// This is not to be used for values which don't come from properties.
/// For example, the `xlink:href` attribute in the `<image>` element
/// does not take a funciri value (which looks like `url(...)`), but rather
/// it takes a plain URL.  Use the `Href` type in that case.
#[derive(Debug, Clone, PartialEq)]
pub enum IRI {
    None,
    Resource(Fragment),
}

impl Default for IRI {
    fn default() -> IRI {
        IRI::None
    }
}

impl IRI {
    /// Returns the contents of an `IRI::Resource`, or `None`
    pub fn get(&self) -> Option<&Fragment> {
        match *self {
            IRI::None => None,
            IRI::Resource(ref f) => Some(f),
        }
    }
}

impl Parse for IRI {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<IRI, ParseError<'i>> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(IRI::None)
        } else {
            let loc = parser.current_source_location();

            let url = parser.expect_url()?;
            parser.expect_exhausted()?;

            let href =
                Href::parse(&url).map_err(|e| loc.new_custom_error(ValueErrorKind::from(e)))?;

            match href {
                Href::PlainUrl(_) => Err(loc.new_custom_error(ValueErrorKind::parse_error(
                    "href requires a fragment identifier",
                ))),
                Href::WithFragment(f) => Ok(IRI::Resource(f)),
            }
        }
    }
}

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

    #[test]
    fn parses_none() {
        assert_eq!(IRI::parse_str("none"), Ok(IRI::None));
    }

    #[test]
    fn parses_url() {
        assert_eq!(
            IRI::parse_str("url(#bar)"),
            Ok(IRI::Resource(Fragment::new(None, "bar".to_string())))
        );

        assert_eq!(
            IRI::parse_str("url(foo#bar)"),
            Ok(IRI::Resource(Fragment::new(
                Some("foo".to_string()),
                "bar".to_string()
            )))
        );

        // be permissive if the closing ) is missing
        assert_eq!(
            IRI::parse_str("url(#bar"),
            Ok(IRI::Resource(Fragment::new(None, "bar".to_string())))
        );
        assert_eq!(
            IRI::parse_str("url(foo#bar"),
            Ok(IRI::Resource(Fragment::new(
                Some("foo".to_string()),
                "bar".to_string()
            )))
        );

        assert!(IRI::parse_str("").is_err());
        assert!(IRI::parse_str("foo").is_err());
        assert!(IRI::parse_str("url(foo)bar").is_err());
    }
}
<commit_msg>IRI.parse: don't expect_exhausted<commit_after>//! CSS funciri values.

use cssparser::Parser;

use crate::allowed_url::{Fragment, Href};
use crate::error::*;
use crate::parsers::Parse;

/// Used where style properties take a funciri or "none"
///
/// This is not to be used for values which don't come from properties.
/// For example, the `xlink:href` attribute in the `<image>` element
/// does not take a funciri value (which looks like `url(...)`), but rather
/// it takes a plain URL.  Use the `Href` type in that case.
#[derive(Debug, Clone, PartialEq)]
pub enum IRI {
    None,
    Resource(Fragment),
}

impl Default for IRI {
    fn default() -> IRI {
        IRI::None
    }
}

impl IRI {
    /// Returns the contents of an `IRI::Resource`, or `None`
    pub fn get(&self) -> Option<&Fragment> {
        match *self {
            IRI::None => None,
            IRI::Resource(ref f) => Some(f),
        }
    }
}

impl Parse for IRI {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<IRI, ParseError<'i>> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(IRI::None)
        } else {
            let loc = parser.current_source_location();

            let url = parser.expect_url()?;

            let href =
                Href::parse(&url).map_err(|e| loc.new_custom_error(ValueErrorKind::from(e)))?;

            match href {
                Href::PlainUrl(_) => Err(loc.new_custom_error(ValueErrorKind::parse_error(
                    "href requires a fragment identifier",
                ))),
                Href::WithFragment(f) => Ok(IRI::Resource(f)),
            }
        }
    }
}

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

    #[test]
    fn parses_none() {
        assert_eq!(IRI::parse_str("none"), Ok(IRI::None));
    }

    #[test]
    fn parses_url() {
        assert_eq!(
            IRI::parse_str("url(#bar)"),
            Ok(IRI::Resource(Fragment::new(None, "bar".to_string())))
        );

        assert_eq!(
            IRI::parse_str("url(foo#bar)"),
            Ok(IRI::Resource(Fragment::new(
                Some("foo".to_string()),
                "bar".to_string()
            )))
        );

        // be permissive if the closing ) is missing
        assert_eq!(
            IRI::parse_str("url(#bar"),
            Ok(IRI::Resource(Fragment::new(None, "bar".to_string())))
        );
        assert_eq!(
            IRI::parse_str("url(foo#bar"),
            Ok(IRI::Resource(Fragment::new(
                Some("foo".to_string()),
                "bar".to_string()
            )))
        );

        assert!(IRI::parse_str("").is_err());
        assert!(IRI::parse_str("foo").is_err());
        assert!(IRI::parse_str("url(foo)bar").is_err());
    }
}
<|endoftext|>


<commit_before>use regex::Regex;

#[derive(Debug, PartialEq)]
pub struct Message {
    pub data: String,
}

impl Message {
    pub fn new(data: &str) -> Message {
        Message { data: data.to_string() }
    }

    pub fn decompress_v1(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompressed_string_length_v1(&self.data, marker_finder)
    }

    pub fn decompress_v2(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompress_string_v2(&self.data, &marker_finder)
    }
}

fn decompressed_string_length_v1(message: &str, marker_regex: Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: usize = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length += (number_of_repeats * number_of_chars) as u64;
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

fn decompress_string_v2(message: &str, marker_regex: &Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: u64 = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length =
            number_of_repeats *
            decompress_string_v2(&message[(str_index - number_of_chars)..str_index], marker_regex);
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

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

    #[test]
    fn test_decompress_v1() {
        let test_data = vec![Message::new("ADVENT").decompress_v1(),
                             Message::new("A(1x5)BC").decompress_v1(),
                             Message::new("(3x3)XYZ").decompress_v1(),
                             Message::new("A(2x2)BCD(2x2)EFG").decompress_v1(),
                             Message::new("(6x1)(1x3)A").decompress_v1(),
                             Message::new("X(8x2)(3x3)ABCY").decompress_v1()];

        assert_eq!(test_data, vec![6, 7, 9, 11, 6, 18]);
    }

    #[test]
    fn test_decompress_v2() {
        let test_data = vec![Message::new("(3X3)XYZ").decompress_v2(),
                 Message::new("X(8x2)(3x3)ABCY").decompress_v2(),
                 Message::new("(27x12)(20x12)(13x14)(7x10)(1x12)A").decompress_v2(),
                 Message::new("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN")
                     .decompress_v2()];

        assert_eq!(test_data, vec![9, 20, 241920, 445]);
    }
}<commit_msg>Clean it up.<commit_after>use regex::Regex;

#[derive(Debug, PartialEq)]
pub struct Message {
    pub data: String,
}

impl Message {
    pub fn new(data: &str) -> Message {
        Message { data: data.to_string() }
    }

    pub fn decompress_v1(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompressed_string_length_v1(&self.data, marker_finder)
    }

    pub fn decompress_v2(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompress_string_v2(&self.data, &marker_finder)
    }
}

fn decompressed_string_length_v1(message: &str, marker_regex: Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: usize = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length += (number_of_repeats * number_of_chars) as u64;
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

fn decompress_string_v2(message: &str, marker_regex: &Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: u64 = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length +=
            number_of_repeats *
            decompress_string_v2(&message[(str_index - number_of_chars)..str_index], marker_regex);
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

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

    #[test]
    fn test_decompress_v1() {
        let test_data = vec![Message::new("ADVENT").decompress_v1(),
                             Message::new("A(1x5)BC").decompress_v1(),
                             Message::new("(3x3)XYZ").decompress_v1(),
                             Message::new("A(2x2)BCD(2x2)EFG").decompress_v1(),
                             Message::new("(6x1)(1x3)A").decompress_v1(),
                             Message::new("X(8x2)(3x3)ABCY").decompress_v1()];

        assert_eq!(test_data, vec![6, 7, 9, 11, 6, 18]);
    }

    #[test]
    fn test_decompress_v2() {
        let test_data = vec![Message::new("(3X3)XYZ").decompress_v2(),
                 Message::new("X(8x2)(3x3)ABCY").decompress_v2(),
                 Message::new("(27x12)(20x12)(13x14)(7x10)(1x12)A").decompress_v2(),
                 Message::new("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN")
                     .decompress_v2()];

        assert_eq!(test_data, vec![9, 20, 241920, 445]);
    }
}<|endoftext|>