<commit_before>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
//! Compile
//!
//! This module contains code for compiling Mnemosyne ASTs into LLVM IR.

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult = Result<TypeRef, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
    ///   - An `Err` with a positional error message in the event of
    ///     a type error.
    ///
    /// # Panics:
    ///   - In the event of an internal compiler error (i.e. if a well-formed
    ///     type could not be gotten from LLVM correctly).
    fn translate_type(&self, context: LLVMContext) -> TypeResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name =
            CString::new(module_name)
                .expect_ice(
                    &format!( "Could not create C string for module name: {:?}"
                            , module_name));
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod:  not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: NamedValues::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    /// Get any existing declarations for a given function name.
    ///
    /// # Returns:
    ///   - `Some` if there is an existing previous declaration
    ///     for this function.
    ///   - `None` if the function has not been declared previously.
    ///
    /// # Panics:
    ///   - If the C string representation for the function name could
    ///     not be created.
    pub fn existing_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect_ice(&format!(
                         "Could not create C string for function name: {:?}"
                        , name
                        ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.existing_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the pattern binds an equivalent number of arguments
        // as the function signature (minus one, which is the return type).
        for e in &self.equations {
            match e.pattern_length()
                   .cmp(&self.arity()) {
                // the equation's pattern is shorter than the function's arity
                // eventually, we'll autocurry this, but for now, we error.
                // TODO: maybe there should be a warning as well?
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
                // the equation's pattern is longer than the function's arity
                // this is super wrong and always an error.
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);

        // Get the function's parameter types
        let mut param_types = self.sig.param_types().iter()
                                  .map(|ty| ty.translate_type(context));
        unimplemented!()
    }

}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        Ok(match *self { Primitive::IntSize => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)  => context.int_type(bits as usize)
                    , Primitive::Uint(bits) => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }
            .expect_ice( &format!( "Could not get {:?} type from LLVM"
                                 , *self)
                       )
            )
    }
}
<commit_msg>LLVM context now passed by ref<commit_after>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
//! Compile
//!
//! This module contains code for compiling Mnemosyne ASTs into LLVM IR.

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult = Result<TypeRef, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: &LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
    ///   - An `Err` with a positional error message in the event of
    ///     a type error.
    ///
    /// # Panics:
    ///   - In the event of an internal compiler error (i.e. if a well-formed
    ///     type could not be gotten from LLVM correctly).
    fn translate_type(&self, context: &LLVMContext) -> TypeResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name =
            CString::new(module_name)
                .expect_ice(
                    &format!( "Could not create C string for module name: {:?}"
                            , module_name));
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod:  not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: NamedValues::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    /// Get any existing declarations for a given function name.
    ///
    /// # Returns:
    ///   - `Some` if there is an existing previous declaration
    ///     for this function.
    ///   - `None` if the function has not been declared previously.
    ///
    /// # Panics:
    ///   - If the C string representation for the function name could
    ///     not be created.
    pub fn existing_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect_ice(&format!(
                         "Could not create C string for function name: {:?}"
                        , name
                        ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: &LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: &LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.existing_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: &LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the pattern binds an equivalent number of arguments
        // as the function signature (minus one, which is the return type).
        for e in &self.equations {
            match e.pattern_length()
                   .cmp(&self.arity()) {
                // the equation's pattern is shorter than the function's arity
                // eventually, we'll autocurry this, but for now, we error.
                // TODO: maybe there should be a warning as well?
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
                // the equation's pattern is longer than the function's arity
                // this is super wrong and always an error.
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);

        // Get the function's parameter types
        let mut param_types = self.sig.param_types().iter()
                                  .map(|ty| ty.translate_type(&context));
        unimplemented!()
    }

}

impl TranslateType for Type {
    fn translate_type(&self, context: &LLVMContext) -> TypeResult {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: &LLVMContext) -> TypeResult {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: &LLVMContext) -> TypeResult {
        Ok(match *self { Primitive::IntSize => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)  => context.int_type(bits as usize)
                    , Primitive::Uint(bits) => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }
            .expect_ice( &format!( "Could not get {:?} type from LLVM"
                                 , *self)
                       )
            )
    }
}
<|endoftext|>


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

use super::*;

/// Error structure containing the available information on a COM error.
#[derive(Debug)]
pub struct ComError {

    /// `HRESULT` that triggered the error.
    pub hresult : HRESULT,

    /// Possible detailed error info.
    pub error_info : Option<ErrorInfo>,
}

impl ComError {

    /// Constructs a new `ComError` from a `HRESULT` code.
    pub fn new_hr( hresult : HRESULT ) -> ComError
    {
        ComError { hresult, error_info: None }
    }

    /// Construts a new `ComError` with a given message.
    pub fn new_message(
        hresult: HRESULT,
        description: String
    ) -> ComError
    {
        ComError {
            hresult,
            error_info: Some( ErrorInfo::new( description ) )
        }
    }

    /// Gets the description if it's available.
    pub fn description( &self ) -> Option< &str >
    {
        self.error_info.as_ref().map( |e| e.description.as_str() )
    }
}

impl From<ComError> for std::io::Error {

    fn from( com_error : ComError ) -> std::io::Error {

        let error_kind = match com_error.hresult {

            ::STG_E_FILENOTFOUND => std::io::ErrorKind::NotFound,
            ::E_ACCESSDENIED => std::io::ErrorKind::PermissionDenied,
            ::RPC_E_CALL_REJECTED => std::io::ErrorKind::ConnectionRefused,
            ::RPC_E_DISCONNECTED => std::io::ErrorKind::ConnectionReset,
            ::RPC_E_CALL_CANCELED => std::io::ErrorKind::ConnectionAborted,
            ::RPC_E_TIMEOUT => std::io::ErrorKind::TimedOut,
            ::E_INVALIDARG => std::io::ErrorKind::InvalidInput,
            _ => std::io::ErrorKind::Other,
        };

        std::io::Error::new(
                error_kind,
                com_error.description().unwrap_or( "Unknown error" ) )
    }
}

impl From<std::io::Error> for ComError {

    fn from( io_error : std::io::Error ) -> ComError {

        let hresult = match io_error.kind() {

            std::io::ErrorKind::NotFound => ::STG_E_FILENOTFOUND,
            std::io::ErrorKind::PermissionDenied => ::E_ACCESSDENIED,
            std::io::ErrorKind::ConnectionRefused => ::RPC_E_CALL_REJECTED,
            std::io::ErrorKind::ConnectionReset => ::RPC_E_DISCONNECTED,
            std::io::ErrorKind::ConnectionAborted => ::RPC_E_CALL_CANCELED,
            std::io::ErrorKind::TimedOut => ::RPC_E_TIMEOUT,
            std::io::ErrorKind::InvalidInput => ::E_INVALIDARG,
            _ => ::E_FAIL,
        };

        ComError::new_message( hresult, io_error.description().to_owned() )
    }
}

impl From<::HRESULT> for ComError {
    fn from( hresult : ::HRESULT ) -> ComError {
        ComError::new_hr( hresult )
    }
}

impl From<ComError> for ::HRESULT {
    fn from( error : ComError ) -> ::HRESULT {
        error.hresult
    }
}

#[cfg(windows)]
#[allow(non_snake_case)]
mod error_store {

    use super::*;

    #[link(name = "oleaut32")]
    extern "system" {
        pub(super) fn SetErrorInfo(
            dw_reserved: u32,
            errorinfo: raw::InterfacePtr<IErrorInfo>,
        ) -> ::HRESULT;

        #[allow(private_in_public)]
        pub(super) fn GetErrorInfo(
            dw_reserved: u32,
            errorinfo: *mut raw::InterfacePtr<IErrorInfo>,
        ) -> ::HRESULT;
    }
}

#[cfg(not(windows))]
#[allow(non_snake_case)]
mod error_store {

    pub unsafe fn SetErrorInfo(
        _dw_reserved: u32,
        _errorinfo: raw::InterfacePtr<IErrorInfo>,
    ) -> ::HRESULT { ::S_OK }

    pub unsafe fn GetErrorInfo(
        _dw_reserved: u32,
        _errorinfo: *mut raw::InterfacePtr<IErrorInfo>,
    ) -> ::HRESULT { ::S_OK }
}

/// Error info COM object data.
#[com_class( clsid = None, IErrorInfo )]
#[derive(Debug)]
pub struct ErrorInfo {
    guid : GUID,
    source : String,
    description : String,
    help_file: String,
    help_context: u32,
}

impl ErrorInfo {
    pub fn new( description : String ) -> ErrorInfo {
        ErrorInfo {
            description,
            guid: GUID::zero_guid(),
            source: String::new(),
            help_file: String::new(),
            help_context: 0,
        }
    }

    pub fn guid( &self ) -> &GUID { &self.guid }
    pub fn source( &self ) -> &str { &self.source }
    pub fn description( &self ) -> &str { &self.description }
    pub fn help_file( &self ) -> &str { &self.help_file }
    pub fn help_context( &self ) -> u32 { self.help_context }
}

impl<'a> TryFrom<&'a IErrorInfo> for ErrorInfo {

    type Error = ::HRESULT;

    fn try_from( source : &'a IErrorInfo ) -> Result<Self, Self::Error> {

        Ok( ErrorInfo {
            guid: source.get_guid()?,
            source: source.get_source()?.to_owned(),
            description: source.get_description()?.to_owned(),
            help_file: source.get_help_file()?.to_owned(),
            help_context: source.get_help_context()?,
        } )
    }
}

#[com_interface( com_iid = "1CF2B120-547D-101B-8E65-08002B2BD119" )]
trait IErrorInfo
{
    fn get_guid( &self ) -> ComResult< GUID >;
    fn get_source( &self ) -> ComResult< String >;
    fn get_description( &self ) -> ComResult< String >;
    fn get_help_file( &self ) -> ComResult< String >;
    fn get_help_context( &self ) -> ComResult< u32 >;
}

#[com_impl]
impl IErrorInfo for ErrorInfo
{
    fn get_guid( &self ) -> ComResult< GUID > { Ok( self.guid.clone() ) }
    fn get_source( &self ) -> ComResult< String > { Ok( self.source.clone() ) }
    fn get_description( &self ) -> ComResult< String > { Ok( self.description.clone() ) }
    fn get_help_file( &self ) -> ComResult< String > { Ok( self.help_file.clone() ) }
    fn get_help_context( &self ) -> ComResult< u32 > { Ok( self.help_context ) }
}

/// Extracts the HRESULT from the error result and stores the extended error
/// information in thread memory so it can be fetched by the COM client.
pub fn return_hresult< E >( error : E ) -> HRESULT
    where E : Into< ComError >
{
    // Convet the error.
    let com_error = error.into();

    match com_error.error_info {

        Some( error_info ) => {

            // ComError contains ErrorInfo. We need to set this in the OS error
            // store.

            // Construct the COM class used for IErrorInfo. The class contains the
            // description in memory.
            let mut info = ComStruct::< ErrorInfo >::new( error_info );

            // Get the IErrorInfo interface and set it in thread memory.
            let mut error_ptr : RawComPtr = std::ptr::null_mut();
            unsafe {

                // We are intentionally ignoring the HRESULT codes here. We don't
                // want to override the original error HRESULT with these codes.
                ComBox::query_interface(
                        info.as_mut(),
                        &IID_IErrorInfo,
                        &mut error_ptr );
                error_store::SetErrorInfo( 0, raw::InterfacePtr::new( error_ptr ) );
            }
        },
        None => {
            // No error info in the ComError.
            unsafe { error_store::SetErrorInfo( 0, raw::InterfacePtr::null() ); }
        }
    }

    // Return the HRESULT of the original error.
    com_error.hresult
}

/// Gets the last COM error that occurred on the current thread.
pub fn get_last_error< E >( last_hr : HRESULT ) -> E
    where E : From< ComError >
{
    let com_error = ComError {
        hresult: last_hr,
        error_info: unsafe {

            // Get the last error COM interface.
            let mut error_ptr : raw::InterfacePtr<IErrorInfo>
                    = raw::InterfacePtr::null();
            let hr = error_store::GetErrorInfo( 0, &mut error_ptr );

            if hr == S_OK && ! error_ptr.is_null(){

                let ierrorinfo = ComItf::< IErrorInfo >::wrap(
                        error_ptr,
                        TypeSystem::Automation );

                // Construct a proper ErrorInfo struct from the COM interface.
                let error_info = ErrorInfo::try_from( &*ierrorinfo ).ok();

                // Release the interface.
                let iunk : &ComItf<IUnknown> = ierrorinfo.as_ref();
                iunk.release();

                error_info

            } else {

                // GetErrorInfo didn't return proper error. Don't provide one
                // in the ComError.
                None
            }
        },
    };

    E::from( com_error )
}

/// Defines a way to handle errors based on the method return value type.
///
/// The default implementation will terminate the process on the basis that
/// errors must not silently leak. The specialization for `HRESULT` will return
/// the `HRESULT`.
///
/// The user is free to implement this trait for their own types to handle
/// custom status codes gracefully.
pub trait ErrorValue {

    /// Attempts to convert a COM error into a custom status code.
    fn from_error( HRESULT ) -> Self;
}

impl<T> ErrorValue for T {
    default fn from_error( _ : HRESULT ) -> Self {
        panic!( "Function does not support error values" )
    }
}

impl ErrorValue for HRESULT {
    fn from_error( hr : HRESULT ) -> Self { hr }
}
<commit_msg>Further non-windows fixes<commit_after>
use std::error::Error;
use std::convert::TryFrom;

use super::*;

/// Error structure containing the available information on a COM error.
#[derive(Debug)]
pub struct ComError {

    /// `HRESULT` that triggered the error.
    pub hresult : HRESULT,

    /// Possible detailed error info.
    pub error_info : Option<ErrorInfo>,
}

impl ComError {

    /// Constructs a new `ComError` from a `HRESULT` code.
    pub fn new_hr( hresult : HRESULT ) -> ComError
    {
        ComError { hresult, error_info: None }
    }

    /// Construts a new `ComError` with a given message.
    pub fn new_message(
        hresult: HRESULT,
        description: String
    ) -> ComError
    {
        ComError {
            hresult,
            error_info: Some( ErrorInfo::new( description ) )
        }
    }

    /// Gets the description if it's available.
    pub fn description( &self ) -> Option< &str >
    {
        self.error_info.as_ref().map( |e| e.description.as_str() )
    }
}

impl From<ComError> for std::io::Error {

    fn from( com_error : ComError ) -> std::io::Error {

        let error_kind = match com_error.hresult {

            ::STG_E_FILENOTFOUND => std::io::ErrorKind::NotFound,
            ::E_ACCESSDENIED => std::io::ErrorKind::PermissionDenied,
            ::RPC_E_CALL_REJECTED => std::io::ErrorKind::ConnectionRefused,
            ::RPC_E_DISCONNECTED => std::io::ErrorKind::ConnectionReset,
            ::RPC_E_CALL_CANCELED => std::io::ErrorKind::ConnectionAborted,
            ::RPC_E_TIMEOUT => std::io::ErrorKind::TimedOut,
            ::E_INVALIDARG => std::io::ErrorKind::InvalidInput,
            _ => std::io::ErrorKind::Other,
        };

        std::io::Error::new(
                error_kind,
                com_error.description().unwrap_or( "Unknown error" ) )
    }
}

impl From<std::io::Error> for ComError {

    fn from( io_error : std::io::Error ) -> ComError {

        let hresult = match io_error.kind() {

            std::io::ErrorKind::NotFound => ::STG_E_FILENOTFOUND,
            std::io::ErrorKind::PermissionDenied => ::E_ACCESSDENIED,
            std::io::ErrorKind::ConnectionRefused => ::RPC_E_CALL_REJECTED,
            std::io::ErrorKind::ConnectionReset => ::RPC_E_DISCONNECTED,
            std::io::ErrorKind::ConnectionAborted => ::RPC_E_CALL_CANCELED,
            std::io::ErrorKind::TimedOut => ::RPC_E_TIMEOUT,
            std::io::ErrorKind::InvalidInput => ::E_INVALIDARG,
            _ => ::E_FAIL,
        };

        ComError::new_message( hresult, io_error.description().to_owned() )
    }
}

impl From<::HRESULT> for ComError {
    fn from( hresult : ::HRESULT ) -> ComError {
        ComError::new_hr( hresult )
    }
}

impl From<ComError> for ::HRESULT {
    fn from( error : ComError ) -> ::HRESULT {
        error.hresult
    }
}

#[cfg(windows)]
#[allow(non_snake_case)]
mod error_store {

    use super::*;

    #[link(name = "oleaut32")]
    extern "system" {
        pub(super) fn SetErrorInfo(
            dw_reserved: u32,
            errorinfo: raw::InterfacePtr<IErrorInfo>,
        ) -> ::HRESULT;

        #[allow(private_in_public)]
        pub(super) fn GetErrorInfo(
            dw_reserved: u32,
            errorinfo: *mut raw::InterfacePtr<IErrorInfo>,
        ) -> ::HRESULT;
    }
}

#[cfg(not(windows))]
#[allow(non_snake_case)]
mod error_store {

    use super::*;

    pub(super) unsafe fn SetErrorInfo(
        _dw_reserved: u32,
        _errorinfo: raw::InterfacePtr<IErrorInfo>,
    ) -> ::HRESULT { ::S_OK }

    pub(super) unsafe fn GetErrorInfo(
        _dw_reserved: u32,
        _errorinfo: *mut raw::InterfacePtr<IErrorInfo>,
    ) -> ::HRESULT { ::S_OK }
}

/// Error info COM object data.
#[com_class( clsid = None, IErrorInfo )]
#[derive(Debug)]
pub struct ErrorInfo {
    guid : GUID,
    source : String,
    description : String,
    help_file: String,
    help_context: u32,
}

impl ErrorInfo {
    pub fn new( description : String ) -> ErrorInfo {
        ErrorInfo {
            description,
            guid: GUID::zero_guid(),
            source: String::new(),
            help_file: String::new(),
            help_context: 0,
        }
    }

    pub fn guid( &self ) -> &GUID { &self.guid }
    pub fn source( &self ) -> &str { &self.source }
    pub fn description( &self ) -> &str { &self.description }
    pub fn help_file( &self ) -> &str { &self.help_file }
    pub fn help_context( &self ) -> u32 { self.help_context }
}

impl<'a> TryFrom<&'a IErrorInfo> for ErrorInfo {

    type Error = ::HRESULT;

    fn try_from( source : &'a IErrorInfo ) -> Result<Self, Self::Error> {

        Ok( ErrorInfo {
            guid: source.get_guid()?,
            source: source.get_source()?.to_owned(),
            description: source.get_description()?.to_owned(),
            help_file: source.get_help_file()?.to_owned(),
            help_context: source.get_help_context()?,
        } )
    }
}

#[com_interface( com_iid = "1CF2B120-547D-101B-8E65-08002B2BD119" )]
trait IErrorInfo
{
    fn get_guid( &self ) -> ComResult< GUID >;
    fn get_source( &self ) -> ComResult< String >;
    fn get_description( &self ) -> ComResult< String >;
    fn get_help_file( &self ) -> ComResult< String >;
    fn get_help_context( &self ) -> ComResult< u32 >;
}

#[com_impl]
impl IErrorInfo for ErrorInfo
{
    fn get_guid( &self ) -> ComResult< GUID > { Ok( self.guid.clone() ) }
    fn get_source( &self ) -> ComResult< String > { Ok( self.source.clone() ) }
    fn get_description( &self ) -> ComResult< String > { Ok( self.description.clone() ) }
    fn get_help_file( &self ) -> ComResult< String > { Ok( self.help_file.clone() ) }
    fn get_help_context( &self ) -> ComResult< u32 > { Ok( self.help_context ) }
}

/// Extracts the HRESULT from the error result and stores the extended error
/// information in thread memory so it can be fetched by the COM client.
pub fn return_hresult< E >( error : E ) -> HRESULT
    where E : Into< ComError >
{
    // Convet the error.
    let com_error = error.into();

    match com_error.error_info {

        Some( error_info ) => {

            // ComError contains ErrorInfo. We need to set this in the OS error
            // store.

            // Construct the COM class used for IErrorInfo. The class contains the
            // description in memory.
            let mut info = ComStruct::< ErrorInfo >::new( error_info );

            // Get the IErrorInfo interface and set it in thread memory.
            let mut error_ptr : RawComPtr = std::ptr::null_mut();
            unsafe {

                // We are intentionally ignoring the HRESULT codes here. We don't
                // want to override the original error HRESULT with these codes.
                ComBox::query_interface(
                        info.as_mut(),
                        &IID_IErrorInfo,
                        &mut error_ptr );
                error_store::SetErrorInfo( 0, raw::InterfacePtr::new( error_ptr ) );
            }
        },
        None => {
            // No error info in the ComError.
            unsafe { error_store::SetErrorInfo( 0, raw::InterfacePtr::null() ); }
        }
    }

    // Return the HRESULT of the original error.
    com_error.hresult
}

/// Gets the last COM error that occurred on the current thread.
pub fn get_last_error< E >( last_hr : HRESULT ) -> E
    where E : From< ComError >
{
    let com_error = ComError {
        hresult: last_hr,
        error_info: unsafe {

            // Get the last error COM interface.
            let mut error_ptr : raw::InterfacePtr<IErrorInfo>
                    = raw::InterfacePtr::null();
            let hr = error_store::GetErrorInfo( 0, &mut error_ptr );

            if hr == S_OK && ! error_ptr.is_null(){

                let ierrorinfo = ComItf::< IErrorInfo >::wrap(
                        error_ptr,
                        TypeSystem::Automation );

                // Construct a proper ErrorInfo struct from the COM interface.
                let error_info = ErrorInfo::try_from( &*ierrorinfo ).ok();

                // Release the interface.
                let iunk : &ComItf<IUnknown> = ierrorinfo.as_ref();
                iunk.release();

                error_info

            } else {

                // GetErrorInfo didn't return proper error. Don't provide one
                // in the ComError.
                None
            }
        },
    };

    E::from( com_error )
}

/// Defines a way to handle errors based on the method return value type.
///
/// The default implementation will terminate the process on the basis that
/// errors must not silently leak. The specialization for `HRESULT` will return
/// the `HRESULT`.
///
/// The user is free to implement this trait for their own types to handle
/// custom status codes gracefully.
pub trait ErrorValue {

    /// Attempts to convert a COM error into a custom status code.
    fn from_error( HRESULT ) -> Self;
}

impl<T> ErrorValue for T {
    default fn from_error( _ : HRESULT ) -> Self {
        panic!( "Function does not support error values" )
    }
}

impl ErrorValue for HRESULT {
    fn from_error( hr : HRESULT ) -> Self { hr }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use collections::String;
use collections::Vec;

use common::event::{self, Event, EventOption};

use core::{cmp, mem};

use drivers::io::{Io, Pio};

use graphics::color::Color;
use graphics::display::Display;

use sync::WaitQueue;

fn ansi_color(value: u8) -> Color {
    match value {
        0 => Color::new(0x00, 0x00, 0x00),
        1 => Color::new(0x80, 0x00, 0x00),
        2 => Color::new(0x00, 0x80, 0x00),
        3 => Color::new(0x80, 0x80, 0x00),
        4 => Color::new(0x00, 0x00, 0x80),
        5 => Color::new(0x80, 0x00, 0x80),
        6 => Color::new(0x00, 0x80, 0x80),
        7 => Color::new(0xc0, 0xc0, 0xc0),
        8 => Color::new(0x80, 0x80, 0x80),
        9 => Color::new(0xff, 0x00, 0x00),
        10 => Color::new(0x00, 0xff, 0x00),
        11 => Color::new(0xff, 0xff, 0x00),
        12 => Color::new(0x00, 0x00, 0xff),
        13 => Color::new(0xff, 0x00, 0xff),
        14 => Color::new(0x00, 0xff, 0xff),
        15 => Color::new(0xff, 0xff, 0xff),
        16 ... 231 => {
            let convert = |value: u8| -> u8 {
                match value {
                    0 => 0,
                    _ => value * 0x28 + 0x28
                }
            };

            let r = convert((value - 16)/36 % 6);
            let g = convert((value - 16)/6 % 6);
            let b = convert((value - 16) % 6);
            Color::new(r, g, b)
        },
        232 ... 255 => {
            let gray = (value - 232) * 10 + 8;
            Color::new(gray, gray, gray)
        },
        _ => Color::new(0, 0, 0)
    }
}

pub struct Console {
    pub display: Option<Box<Display>>,
    pub point_x: usize,
    pub point_y: usize,
    pub foreground: Color,
    pub background: Color,
    pub draw: bool,
    pub redraw: bool,
    pub command: String,
    pub commands: WaitQueue<String>,
    pub escape: bool,
    pub escape_sequence: bool,
    pub sequence: Vec<String>,
    pub raw_mode: bool,
}

impl Console {
    pub fn new() -> Console {
        Console {
            display: Display::root(),
            point_x: 0,
            point_y: 0,
            foreground: ansi_color(7),
            background: ansi_color(0),
            draw: false,
            redraw: true,
            command: String::new(),
            commands: WaitQueue::new(),
            escape: false,
            escape_sequence: false,
            sequence: Vec::new(),
            raw_mode: false,
        }
    }

    pub fn code(&mut self, c: char) {
        if self.escape_sequence {
            match c {
                '0' ... '9' => {
                    // Add a number to the sequence list
                    if let Some(mut value) = self.sequence.last_mut() {
                        value.push(c);
                    }
                },
                ';' => {
                    // Split sequence into list
                    self.sequence.push(String::new());
                },
                'm' => {
                    // Display attributes
                    let mut value_iter = self.sequence.iter();
                    while let Some(value_str) = value_iter.next() {
                        let value = value_str.parse::<u8>().unwrap_or(0);
                        match value {
                            0 => {
                                self.foreground = ansi_color(7);
                                self.background = ansi_color(0);
                            },
                            30 ... 37 => self.foreground = ansi_color(value - 30),
                            38 => match value_iter.next().map_or("", |s| &s).parse::<usize>().unwrap_or(0) {
                                2 => {
                                    //True color
                                    let r = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let g = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let b = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.foreground = Color::new(r, g, b);
                                },
                                5 => {
                                    //256 color
                                    let color_value = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.foreground = ansi_color(color_value);
                                },
                                _ => {}
                            },
                            40 ... 47 => self.background = ansi_color(value - 40),
                            48 => match value_iter.next().map_or("", |s| &s).parse::<usize>().unwrap_or(0) {
                                2 => {
                                    //True color
                                    let r = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let g = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let b = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.background = Color::new(r, g, b);
                                },
                                5 => {
                                    //256 color
                                    let color_value = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.background = ansi_color(color_value);
                                },
                                _ => {}
                            },
                            _ => {},
                        }
                    }

                    self.escape_sequence = false;
                },
                'J' => {
                    match self.sequence.get(0).map_or("", |p| &p).parse::<usize>().unwrap_or(0) {
                        0 => {
                            //TODO: Erase down
                        },
                        1 => {
                            //TODO: Erase up
                        },
                        2 => {
                            // Erase all
                            self.point_x = 0;
                            self.point_y = 0;
                            if let Some(ref mut display) = self.display {
                                display.set(self.background);
                            }
                            self.redraw = true;
                        },
                        _ => {}
                    }

                    self.escape_sequence = false;
                },
                'H' | 'f' => {
                    if let Some(ref mut display) = self.display {
                        display.rect(self.point_x, self.point_y, 8, 16, self.background);
                    }

                    let row = self.sequence.get(0).map_or("", |p| &p).parse::<isize>().unwrap_or(1);
                    self.point_y = cmp::max(0, row - 1) as usize * 16;

                    let col = self.sequence.get(1).map_or("", |p| &p).parse::<isize>().unwrap_or(1);
                    self.point_x = cmp::max(0, col - 1) as usize * 8;

                    if let Some(ref mut display) = self.display {
                        display.rect(self.point_x, self.point_y, 8, 16, self.foreground);
                    }
                    self.redraw = true;

                    self.escape_sequence = false;
                },
/*
@MANSTART{terminal-raw-mode}
INTRODUCTION
    Since Redox has no ioctl syscall, it uses escape codes for switching to raw mode.

ENTERING AND EXITING RAW MODE
    Entering raw mode is done using CSI-r (^[r). Unsetting raw mode is done by CSI-R (^[R).

RAW MODE
    Raw mode means that the stdin must be handled solely by the program itself. It will not automatically be printed nor will it be modified in any way (modulo escape codes).

    This means that:
        - stdin is not printed.
        - newlines are interpreted as carriage returns in stdin.
        - stdin is not buffered, meaning that the stream of bytes goes directly to the program, without the user having to press enter.
@MANEND
*/
                'r' => {
                    self.raw_mode = true;
                    self.escape_sequence = false;
                },
                'R' => {
                    self.raw_mode = false;
                    self.escape_sequence = false;
                },
                _ => self.escape_sequence = false,
            }

            if !self.escape_sequence {
                self.sequence.clear();
                self.escape = false;
            }
        } else {
            match c {
                '[' => {
                    // Control sequence initiator

                    self.escape_sequence = true;
                    self.sequence.push(String::new());
                },
                'c' => {
                    // Reset
                    self.point_x = 0;
                    self.point_y = 0;
                    self.raw_mode = false;
                    self.foreground = ansi_color(7);
                    self.background = ansi_color(0);
                    if let Some(ref mut display) = self.display {
                        display.set(self.background);
                    }
                    self.redraw = true;

                    self.escape = false;
                }
                _ => self.escape = false,
            }
        }
    }

    pub fn character(&mut self, c: char) {
        let (width, height) = if let Some(ref mut display) = self.display {
            (display.width, display.height)
        } else {
            (80, 30)
        };

        if let Some(ref mut display) = self.display {
            display.rect(self.point_x, self.point_y, 8, 16, self.background);
        }

        match c {
            '\0' => {},
            '\x1B' => self.escape = true,
            '\n' => {
                self.point_x = 0;
                self.point_y += 16;
                self.redraw = true;
            },
            '\t' => self.point_x = ((self.point_x / 64) + 1) * 64,
            '\r' => self.point_x = 0,
            '\x08' => {
                if self.point_x >= 8 {
                    self.point_x -= 8;
                }

                if let Some(ref mut display) = self.display {
                    display.rect(self.point_x, self.point_y, 8, 16, self.background);
                }
            },
            _ => {
                if let Some(ref mut display) = self.display {
                    display.char(self.point_x, self.point_y, c, self.foreground);
                }

                self.point_x += 8;
            }
        }

        if self.point_x >= width {
            self.point_x = 0;
            self.point_y += 16;
        }

        while self.point_y + 16 > height {
            if let Some(ref mut display) = self.display {
                display.scroll(16, self.background);
            }
            self.point_y -= 16;
        }

        if let Some(ref mut display) = self.display {
            display.rect(self.point_x, self.point_y, 8, 16, self.foreground);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed {
                    if self.raw_mode {
                        match key_event.scancode {
                            event::K_BKSP => self.command.push_str("\x08"),
                            event::K_UP => self.command.push_str("\x1B[A"),
                            event::K_DOWN => self.command.push_str("\x1B[B"),
                            event::K_RIGHT => self.command.push_str("\x1B[C"),
                            event::K_LEFT => self.command.push_str("\x1B[D"),
                            _ => match key_event.character {
                                '\0' => {},
                                c => {
                                    self.command.push(c);
                                }
                            },
                        }

                        if ! self.command.is_empty() {
                            let mut command = String::new();
                            mem::swap(&mut self.command, &mut command);
                            self.commands.send(command);
                        }
                    } else {
                        match key_event.scancode {
                            event::K_BKSP => if ! self.command.is_empty() {
                                self.redraw = true;

                                self.write(&[8]);
                                self.command.pop();
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                c => {
                                    self.redraw = true;

                                    self.write(&[c as u8]);
                                    self.command.push(c);

                                    if c == '\n' {
                                        let mut command = String::new();
                                        mem::swap(&mut self.command, &mut command);
                                        self.commands.send(command);
                                    }
                                }
                            },
                        }
                    }
                }
            }
            _ => (),
        }
    }

    pub fn write(&mut self, bytes: &[u8]) {
        for byte in bytes.iter() {
            let c = *byte as char;

            if self.escape {
                self.code(c);
            } else {
                self.character(c);
            }

            //if self.display.is_none()
            {
                let serial_status = Pio::<u8>::new(0x3F8 + 5);
                let mut serial_data = Pio::<u8>::new(0x3F8);

                while !serial_status.readf(0x20) {}
                serial_data.write(*byte);

                if *byte == 8 {
                    while !serial_status.readf(0x20) {}
                    serial_data.write(0x20);

                    while !serial_status.readf(0x20) {}
                    serial_data.write(8);
                }
            }
        }

        if self.draw && self.redraw {
            self.redraw = false;
            if let Some(ref mut display) = self.display {
                display.flip();
            }
        }
    }
}
<commit_msg>Faster screen draws in raw mode<commit_after>use alloc::boxed::Box;

use collections::String;
use collections::Vec;

use common::event::{self, Event, EventOption};

use core::{cmp, mem};

use drivers::io::{Io, Pio};

use graphics::color::Color;
use graphics::display::Display;

use sync::WaitQueue;

fn ansi_color(value: u8) -> Color {
    match value {
        0 => Color::new(0x00, 0x00, 0x00),
        1 => Color::new(0x80, 0x00, 0x00),
        2 => Color::new(0x00, 0x80, 0x00),
        3 => Color::new(0x80, 0x80, 0x00),
        4 => Color::new(0x00, 0x00, 0x80),
        5 => Color::new(0x80, 0x00, 0x80),
        6 => Color::new(0x00, 0x80, 0x80),
        7 => Color::new(0xc0, 0xc0, 0xc0),
        8 => Color::new(0x80, 0x80, 0x80),
        9 => Color::new(0xff, 0x00, 0x00),
        10 => Color::new(0x00, 0xff, 0x00),
        11 => Color::new(0xff, 0xff, 0x00),
        12 => Color::new(0x00, 0x00, 0xff),
        13 => Color::new(0xff, 0x00, 0xff),
        14 => Color::new(0x00, 0xff, 0xff),
        15 => Color::new(0xff, 0xff, 0xff),
        16 ... 231 => {
            let convert = |value: u8| -> u8 {
                match value {
                    0 => 0,
                    _ => value * 0x28 + 0x28
                }
            };

            let r = convert((value - 16)/36 % 6);
            let g = convert((value - 16)/6 % 6);
            let b = convert((value - 16) % 6);
            Color::new(r, g, b)
        },
        232 ... 255 => {
            let gray = (value - 232) * 10 + 8;
            Color::new(gray, gray, gray)
        },
        _ => Color::new(0, 0, 0)
    }
}

pub struct Console {
    pub display: Option<Box<Display>>,
    pub point_x: usize,
    pub point_y: usize,
    pub foreground: Color,
    pub background: Color,
    pub draw: bool,
    pub redraw: bool,
    pub command: String,
    pub commands: WaitQueue<String>,
    pub escape: bool,
    pub escape_sequence: bool,
    pub sequence: Vec<String>,
    pub raw_mode: bool,
}

impl Console {
    pub fn new() -> Console {
        Console {
            display: Display::root(),
            point_x: 0,
            point_y: 0,
            foreground: ansi_color(7),
            background: ansi_color(0),
            draw: false,
            redraw: true,
            command: String::new(),
            commands: WaitQueue::new(),
            escape: false,
            escape_sequence: false,
            sequence: Vec::new(),
            raw_mode: false,
        }
    }

    pub fn code(&mut self, c: char) {
        if self.escape_sequence {
            match c {
                '0' ... '9' => {
                    // Add a number to the sequence list
                    if let Some(mut value) = self.sequence.last_mut() {
                        value.push(c);
                    }
                },
                ';' => {
                    // Split sequence into list
                    self.sequence.push(String::new());
                },
                'm' => {
                    // Display attributes
                    let mut value_iter = self.sequence.iter();
                    while let Some(value_str) = value_iter.next() {
                        let value = value_str.parse::<u8>().unwrap_or(0);
                        match value {
                            0 => {
                                self.foreground = ansi_color(7);
                                self.background = ansi_color(0);
                            },
                            30 ... 37 => self.foreground = ansi_color(value - 30),
                            38 => match value_iter.next().map_or("", |s| &s).parse::<usize>().unwrap_or(0) {
                                2 => {
                                    //True color
                                    let r = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let g = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let b = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.foreground = Color::new(r, g, b);
                                },
                                5 => {
                                    //256 color
                                    let color_value = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.foreground = ansi_color(color_value);
                                },
                                _ => {}
                            },
                            40 ... 47 => self.background = ansi_color(value - 40),
                            48 => match value_iter.next().map_or("", |s| &s).parse::<usize>().unwrap_or(0) {
                                2 => {
                                    //True color
                                    let r = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let g = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    let b = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.background = Color::new(r, g, b);
                                },
                                5 => {
                                    //256 color
                                    let color_value = value_iter.next().map_or("", |s| &s).parse::<u8>().unwrap_or(0);
                                    self.background = ansi_color(color_value);
                                },
                                _ => {}
                            },
                            _ => {},
                        }
                    }

                    self.escape_sequence = false;
                },
                'J' => {
                    match self.sequence.get(0).map_or("", |p| &p).parse::<usize>().unwrap_or(0) {
                        0 => {
                            //TODO: Erase down
                        },
                        1 => {
                            //TODO: Erase up
                        },
                        2 => {
                            // Erase all
                            self.point_x = 0;
                            self.point_y = 0;
                            if let Some(ref mut display) = self.display {
                                display.set(self.background);
                            }
                            if ! self.raw_mode {
                                self.redraw = true;
                            }
                        },
                        _ => {}
                    }

                    self.escape_sequence = false;
                },
                'H' | 'f' => {
                    if let Some(ref mut display) = self.display {
                        display.rect(self.point_x, self.point_y, 8, 16, self.background);
                    }

                    let row = self.sequence.get(0).map_or("", |p| &p).parse::<isize>().unwrap_or(1);
                    self.point_y = cmp::max(0, row - 1) as usize * 16;

                    let col = self.sequence.get(1).map_or("", |p| &p).parse::<isize>().unwrap_or(1);
                    self.point_x = cmp::max(0, col - 1) as usize * 8;

                    if let Some(ref mut display) = self.display {
                        display.rect(self.point_x, self.point_y, 8, 16, self.foreground);
                    }

                    self.escape_sequence = false;
                },
/*
@MANSTART{terminal-raw-mode}
INTRODUCTION
    Since Redox has no ioctl syscall, it uses escape codes for switching to raw mode.

ENTERING AND EXITING RAW MODE
    Entering raw mode is done using CSI-r (^[r). Unsetting raw mode is done by CSI-R (^[R).

RAW MODE
    Raw mode means that the stdin must be handled solely by the program itself. It will not automatically be printed nor will it be modified in any way (modulo escape codes).

    This means that:
        - stdin is not printed.
        - newlines are interpreted as carriage returns in stdin.
        - stdin is not buffered, meaning that the stream of bytes goes directly to the program, without the user having to press enter.
@MANEND
*/
                'r' => {
                    self.raw_mode = true;
                    self.escape_sequence = false;
                },
                'R' => {
                    self.raw_mode = false;
                    self.escape_sequence = false;
                },
                _ => self.escape_sequence = false,
            }

            if !self.escape_sequence {
                self.sequence.clear();
                self.escape = false;
            }
        } else {
            match c {
                '[' => {
                    // Control sequence initiator

                    self.escape_sequence = true;
                    self.sequence.push(String::new());
                },
                'c' => {
                    // Reset
                    self.point_x = 0;
                    self.point_y = 0;
                    self.raw_mode = false;
                    self.foreground = ansi_color(7);
                    self.background = ansi_color(0);
                    if let Some(ref mut display) = self.display {
                        display.set(self.background);
                    }
                    self.redraw = true;

                    self.escape = false;
                }
                _ => self.escape = false,
            }
        }
    }

    pub fn character(&mut self, c: char) {
        let (width, height) = if let Some(ref mut display) = self.display {
            (display.width, display.height)
        } else {
            (80, 30)
        };

        if let Some(ref mut display) = self.display {
            display.rect(self.point_x, self.point_y, 8, 16, self.background);
        }

        match c {
            '\0' => {},
            '\x1B' => self.escape = true,
            '\n' => {
                self.point_x = 0;
                self.point_y += 16;
                if ! self.raw_mode {
                    self.redraw = true;
                }
            },
            '\t' => self.point_x = ((self.point_x / 64) + 1) * 64,
            '\r' => self.point_x = 0,
            '\x08' => {
                if self.point_x >= 8 {
                    self.point_x -= 8;
                }

                if let Some(ref mut display) = self.display {
                    display.rect(self.point_x, self.point_y, 8, 16, self.background);
                }
            },
            _ => {
                if let Some(ref mut display) = self.display {
                    display.char(self.point_x, self.point_y, c, self.foreground);
                }

                self.point_x += 8;
            }
        }

        if self.point_x >= width {
            self.point_x = 0;
            self.point_y += 16;
        }

        while self.point_y + 16 > height {
            if let Some(ref mut display) = self.display {
                display.scroll(16, self.background);
            }
            self.point_y -= 16;
        }

        if let Some(ref mut display) = self.display {
            display.rect(self.point_x, self.point_y, 8, 16, self.foreground);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed {
                    if self.raw_mode {
                        match key_event.scancode {
                            event::K_BKSP => self.command.push_str("\x08"),
                            event::K_UP => self.command.push_str("\x1B[A"),
                            event::K_DOWN => self.command.push_str("\x1B[B"),
                            event::K_RIGHT => self.command.push_str("\x1B[C"),
                            event::K_LEFT => self.command.push_str("\x1B[D"),
                            _ => match key_event.character {
                                '\0' => {},
                                c => {
                                    self.command.push(c);
                                }
                            },
                        }

                        if ! self.command.is_empty() {
                            let mut command = String::new();
                            mem::swap(&mut self.command, &mut command);
                            self.commands.send(command);
                        }
                    } else {
                        match key_event.scancode {
                            event::K_BKSP => if ! self.command.is_empty() {
                                self.redraw = true;

                                self.write(&[8]);
                                self.command.pop();
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                c => {
                                    self.redraw = true;

                                    self.write(&[c as u8]);
                                    self.command.push(c);

                                    if c == '\n' {
                                        let mut command = String::new();
                                        mem::swap(&mut self.command, &mut command);
                                        self.commands.send(command);
                                    }
                                }
                            },
                        }
                    }
                }
            }
            _ => (),
        }
    }

    pub fn write(&mut self, bytes: &[u8]) {
        for byte in bytes.iter() {
            let c = *byte as char;

            if self.escape {
                self.code(c);
            } else {
                self.character(c);
            }

            if self.display.is_none() {
                let serial_status = Pio::<u8>::new(0x3F8 + 5);
                let mut serial_data = Pio::<u8>::new(0x3F8);

                while !serial_status.readf(0x20) {}
                serial_data.write(*byte);

                if *byte == 8 {
                    while !serial_status.readf(0x20) {}
                    serial_data.write(0x20);

                    while !serial_status.readf(0x20) {}
                    serial_data.write(8);
                }
            }
        }

        if self.draw && self.redraw {
            self.redraw = false;
            if let Some(ref mut display) = self.display {
                display.flip();
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Implementation of incremental re-parsing.
//!
//! We use two simple strategies for this:
//!   - if the edit modifies only a single token (like changing an identifier's
//!     letter), we replace only this token.
//!   - otherwise, we search for the nearest `{}` block which contains the edit
//!     and try to parse only this block.

use ra_parser::Reparser;
use ra_text_edit::AtomTextEdit;

use crate::{
    algo,
    parsing::{
        lexer::{lex_single_syntax_kind, tokenize, Token},
        text_token_source::TextTokenSource,
        text_tree_sink::TextTreeSink,
    },
    syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
    SyntaxError,
    SyntaxKind::*,
    TextRange, TextUnit, T,
};

pub(crate) fn incremental_reparse(
    node: &SyntaxNode,
    edit: &AtomTextEdit,
    errors: Vec<SyntaxError>,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    if let Some((green, old_range)) = reparse_token(node, &edit) {
        return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range));
    }

    if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
    }
    None
}

fn reparse_token<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, TextRange)> {
    let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
    let prev_token_kind = prev_token.kind();
    match prev_token_kind {
        WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
            if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                // removing a new line may extends previous token
                let deleted_range = edit.delete - prev_token.text_range().start();
                if prev_token.text()[deleted_range].contains('\n') {
                    return None;
                }
            }

            let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
            let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?;

            if new_token_kind != prev_token_kind
                || (new_token_kind == IDENT && is_contextual_kw(&new_text))
            {
                return None;
            }

            // Check that edited token is not a part of the bigger token.
            // E.g. if for source code `bruh"str"` the user removed `ruh`, then
            // `b` no longer remains an identifier, but becomes a part of byte string literal
            if let Some(next_char) = root.text().char_at(prev_token.text_range().end()) {
                new_text.push(next_char);
                let token_with_next_char = lex_single_syntax_kind(&new_text);
                if let Some((_kind, _error)) = token_with_next_char {
                    return None;
                }
                new_text.pop();
            }

            let new_token =
                GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
            Some((prev_token.replace_with(new_token), prev_token.text_range()))
        }
        _ => None,
    }
}

fn reparse_block<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
    let text = get_text_after_edit(node.clone().into(), edit);

    let (tokens, new_lexer_errors) = tokenize(&text);
    if !is_balanced(&tokens) {
        return None;
    }

    let mut token_source = TextTokenSource::new(&text, &tokens);
    let mut tree_sink = TextTreeSink::new(&text, &tokens);
    reparser.parse(&mut token_source, &mut tree_sink);

    let (green, mut new_parser_errors) = tree_sink.finish();
    new_parser_errors.extend(new_lexer_errors);

    Some((node.replace_with(green), new_parser_errors, node.text_range()))
}

fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
    let edit =
        AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());

    let text = match element {
        NodeOrToken::Token(token) => token.text().to_string(),
        NodeOrToken::Node(node) => node.text().to_string(),
    };
    edit.apply(text)
}

fn is_contextual_kw(text: &str) -> bool {
    match text {
        "auto" | "default" | "union" => true,
        _ => false,
    }
}

fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
    let node = algo::find_covering_element(node, range);

    let mut ancestors = match node {
        NodeOrToken::Token(it) => it.parent().ancestors(),
        NodeOrToken::Node(it) => it.ancestors(),
    };
    ancestors.find_map(|node| {
        let first_child = node.first_child_or_token().map(|it| it.kind());
        let parent = node.parent().map(|it| it.kind());
        Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
    })
}

fn is_balanced(tokens: &[Token]) -> bool {
    if tokens.is_empty()
        || tokens.first().unwrap().kind != T!['{']
        || tokens.last().unwrap().kind != T!['}']
    {
        return false;
    }
    let mut balance = 0usize;
    for t in &tokens[1..tokens.len() - 1] {
        match t.kind {
            T!['{'] => balance += 1,
            T!['}'] => {
                balance = match balance.checked_sub(1) {
                    Some(b) => b,
                    None => return false,
                }
            }
            _ => (),
        }
    }
    balance == 0
}

fn merge_errors(
    old_errors: Vec<SyntaxError>,
    new_errors: Vec<SyntaxError>,
    range_before_reparse: TextRange,
    edit: &AtomTextEdit,
) -> Vec<SyntaxError> {
    let mut res = Vec::new();

    for old_err in old_errors {
        let old_err_range = old_err.range();
        // FIXME: make sure that .start() was here previously by a mistake
        if old_err_range.end() <= range_before_reparse.start() {
            res.push(old_err);
        } else if old_err_range.start() >= range_before_reparse.end() {
            let inserted_len = TextUnit::of_str(&edit.insert);
            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
            // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
        }
    }
    res.extend(new_errors.into_iter().map(|new_err| {
        // fighting borrow checker with a variable ;)
        let offseted_range = new_err.range() + range_before_reparse.start();
        new_err.with_range(offseted_range)
    }));
    res
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_range};

    use super::*;
    use crate::{AstNode, Parse, SourceFile};

    fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
        let (range, before) = extract_range(before);
        let edit = AtomTextEdit::replace(range, replace_with.to_owned());
        let after = edit.apply(before.clone());

        let fully_reparsed = SourceFile::parse(&after);
        let incrementally_reparsed: Parse<SourceFile> = {
            let f = SourceFile::parse(&before);
            let (green, new_errors, range) =
                incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap();
            assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
            Parse::new(green, new_errors)
        };

        assert_eq_text!(
            &format!("{:#?}", fully_reparsed.tree().syntax()),
            &format!("{:#?}", incrementally_reparsed.tree().syntax()),
        );
    }

    #[test] // FIXME: some test here actually test token reparsing
    fn reparse_block_tests() {
        do_check(
            r"
fn foo() {
    let x = foo + <|>bar<|>
}
",
            "baz",
            3,
        );
        do_check(
            r"
fn foo() {
    let x = foo<|> + bar<|>
}
",
            "baz",
            25,
        );
        do_check(
            r"
struct Foo {
    f: foo<|><|>
}
",
            ",\n    g: (),",
            14,
        );
        do_check(
            r"
fn foo {
    let;
    1 + 1;
    <|>92<|>;
}
",
            "62",
            31, // FIXME: reparse only int literal here
        );
        do_check(
            r"
mod foo {
    fn <|><|>
}
",
            "bar",
            11,
        );

        do_check(
            r"
trait Foo {
    type <|>Foo<|>;
}
",
            "Output",
            3,
        );
        do_check(
            r"
impl IntoIterator<Item=i32> for Foo {
    f<|><|>
}
",
            "n next(",
            9,
        );
        do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10);
        do_check(
            r"
pub enum A {
    Foo<|><|>
}
",
            "\nBar;\n",
            11,
        );
        do_check(
            r"
foo!{a, b<|><|> d}
",
            ", c[3]",
            8,
        );
        do_check(
            r"
fn foo() {
    vec![<|><|>]
}
",
            "123",
            14,
        );
        do_check(
            r"
extern {
    fn<|>;<|>
}
",
            " exit(code: c_int)",
            11,
        );
    }

    #[test]
    fn reparse_token_tests() {
        do_check(
            r"<|><|>
fn foo() -> i32 { 1 }
",
            "\n\n\n   \n",
            1,
        );
        do_check(
            r"
fn foo() -> <|><|> {}
",
            "  \n",
            2,
        );
        do_check(
            r"
fn <|>foo<|>() -> i32 { 1 }
",
            "bar",
            3,
        );
        do_check(
            r"
fn foo<|><|>foo() {  }
",
            "bar",
            6,
        );
        do_check(
            r"
fn foo /* <|><|> */ () {}
",
            "some comment",
            6,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
/// foo <|><|>omment
mod { }
",
            "c",
            14,
        );
        do_check(
            r#"
fn -> &str { "Hello<|><|>" }
"#,
            ", world",
            7,
        );
        do_check(
            r#"
fn -> &str { // "Hello<|><|>"
"#,
            ", world",
            10,
        );
        do_check(
            r##"
fn -> &str { r#"Hello<|><|>"#
"##,
            ", world",
            10,
        );
        do_check(
            r"
#[derive(<|>Copy<|>)]
enum Foo {

}
",
            "Clone",
            4,
        );
    }
}
<commit_msg>ra_syntax: fix reparsing merging errors, also now reparse_token() reports errors<commit_after>//! Implementation of incremental re-parsing.
//!
//! We use two simple strategies for this:
//!   - if the edit modifies only a single token (like changing an identifier's
//!     letter), we replace only this token.
//!   - otherwise, we search for the nearest `{}` block which contains the edit
//!     and try to parse only this block.

use ra_parser::Reparser;
use ra_text_edit::AtomTextEdit;

use crate::{
    algo,
    parsing::{
        lexer::{lex_single_syntax_kind, tokenize, Token},
        text_token_source::TextTokenSource,
        text_tree_sink::TextTreeSink,
    },
    syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
    SyntaxError,
    SyntaxKind::*,
    TextRange, TextUnit, T,
};

pub(crate) fn incremental_reparse(
    node: &SyntaxNode,
    edit: &AtomTextEdit,
    errors: Vec<SyntaxError>,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) {
        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
    }

    if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
    }
    None
}

fn reparse_token<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
    let prev_token_kind = prev_token.kind();
    match prev_token_kind {
        WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
            if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                // removing a new line may extends previous token
                let deleted_range = edit.delete - prev_token.text_range().start();
                if prev_token.text()[deleted_range].contains('\n') {
                    return None;
                }
            }

            let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
            let (new_token_kind, new_err) = lex_single_syntax_kind(&new_text)?;

            if new_token_kind != prev_token_kind
                || (new_token_kind == IDENT && is_contextual_kw(&new_text))
            {
                return None;
            }

            // Check that edited token is not a part of the bigger token.
            // E.g. if for source code `bruh"str"` the user removed `ruh`, then
            // `b` no longer remains an identifier, but becomes a part of byte string literal
            if let Some(next_char) = root.text().char_at(prev_token.text_range().end()) {
                new_text.push(next_char);
                let token_with_next_char = lex_single_syntax_kind(&new_text);
                if let Some((_kind, _error)) = token_with_next_char {
                    return None;
                }
                new_text.pop();
            }

            let new_token =
                GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
            Some((
                prev_token.replace_with(new_token),
                new_err.into_iter().collect(),
                prev_token.text_range(),
            ))
        }
        _ => None,
    }
}

fn reparse_block<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
    let text = get_text_after_edit(node.clone().into(), edit);

    let (tokens, new_lexer_errors) = tokenize(&text);
    if !is_balanced(&tokens) {
        return None;
    }

    let mut token_source = TextTokenSource::new(&text, &tokens);
    let mut tree_sink = TextTreeSink::new(&text, &tokens);
    reparser.parse(&mut token_source, &mut tree_sink);

    let (green, mut new_parser_errors) = tree_sink.finish();
    new_parser_errors.extend(new_lexer_errors);

    Some((node.replace_with(green), new_parser_errors, node.text_range()))
}

fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
    let edit =
        AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());

    let text = match element {
        NodeOrToken::Token(token) => token.text().to_string(),
        NodeOrToken::Node(node) => node.text().to_string(),
    };
    edit.apply(text)
}

fn is_contextual_kw(text: &str) -> bool {
    match text {
        "auto" | "default" | "union" => true,
        _ => false,
    }
}

fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
    let node = algo::find_covering_element(node, range);

    let mut ancestors = match node {
        NodeOrToken::Token(it) => it.parent().ancestors(),
        NodeOrToken::Node(it) => it.ancestors(),
    };
    ancestors.find_map(|node| {
        let first_child = node.first_child_or_token().map(|it| it.kind());
        let parent = node.parent().map(|it| it.kind());
        Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
    })
}

fn is_balanced(tokens: &[Token]) -> bool {
    if tokens.is_empty()
        || tokens.first().unwrap().kind != T!['{']
        || tokens.last().unwrap().kind != T!['}']
    {
        return false;
    }
    let mut balance = 0usize;
    for t in &tokens[1..tokens.len() - 1] {
        match t.kind {
            T!['{'] => balance += 1,
            T!['}'] => {
                balance = match balance.checked_sub(1) {
                    Some(b) => b,
                    None => return false,
                }
            }
            _ => (),
        }
    }
    balance == 0
}

fn merge_errors(
    old_errors: Vec<SyntaxError>,
    new_errors: Vec<SyntaxError>,
    range_before_reparse: TextRange,
    edit: &AtomTextEdit,
) -> Vec<SyntaxError> {
    let mut res = Vec::new();

    for old_err in old_errors {
        let old_err_range = old_err.range();
        // FIXME: make sure that .start() was here previously by a mistake
        if old_err_range.end() <= range_before_reparse.start() {
            res.push(old_err);
        } else if old_err_range.start() >= range_before_reparse.end() {
            let inserted_len = TextUnit::of_str(&edit.insert);
            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
            // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
        }
    }
    res.extend(new_errors.into_iter().map(|new_err| {
        // fighting borrow checker with a variable ;)
        let offseted_range = new_err.range() + range_before_reparse.start();
        new_err.with_range(offseted_range)
    }));
    res
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_range};

    use super::*;
    use crate::{AstNode, Parse, SourceFile};

    fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
        let (range, before) = extract_range(before);
        let edit = AtomTextEdit::replace(range, replace_with.to_owned());
        let after = edit.apply(before.clone());

        let fully_reparsed = SourceFile::parse(&after);
        let incrementally_reparsed: Parse<SourceFile> = {
            let before = SourceFile::parse(&before);
            let (green, new_errors, range) =
                incremental_reparse(before.tree().syntax(), &edit, before.errors.to_vec()).unwrap();
            assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
            Parse::new(green, new_errors)
        };

        assert_eq_text!(
            &format!("{:#?}", fully_reparsed.tree().syntax()),
            &format!("{:#?}", incrementally_reparsed.tree().syntax()),
        );
        assert_eq!(fully_reparsed.errors(), incrementally_reparsed.errors());
    }

    #[test] // FIXME: some test here actually test token reparsing
    fn reparse_block_tests() {
        do_check(
            r"
fn foo() {
    let x = foo + <|>bar<|>
}
",
            "baz",
            3,
        );
        do_check(
            r"
fn foo() {
    let x = foo<|> + bar<|>
}
",
            "baz",
            25,
        );
        do_check(
            r"
struct Foo {
    f: foo<|><|>
}
",
            ",\n    g: (),",
            14,
        );
        do_check(
            r"
fn foo {
    let;
    1 + 1;
    <|>92<|>;
}
",
            "62",
            31, // FIXME: reparse only int literal here
        );
        do_check(
            r"
mod foo {
    fn <|><|>
}
",
            "bar",
            11,
        );

        do_check(
            r"
trait Foo {
    type <|>Foo<|>;
}
",
            "Output",
            3,
        );
        do_check(
            r"
impl IntoIterator<Item=i32> for Foo {
    f<|><|>
}
",
            "n next(",
            9,
        );
        do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10);
        do_check(
            r"
pub enum A {
    Foo<|><|>
}
",
            "\nBar;\n",
            11,
        );
        do_check(
            r"
foo!{a, b<|><|> d}
",
            ", c[3]",
            8,
        );
        do_check(
            r"
fn foo() {
    vec![<|><|>]
}
",
            "123",
            14,
        );
        do_check(
            r"
extern {
    fn<|>;<|>
}
",
            " exit(code: c_int)",
            11,
        );
    }

    #[test]
    fn reparse_token_tests() {
        do_check(
            r"<|><|>
fn foo() -> i32 { 1 }
",
            "\n\n\n   \n",
            1,
        );
        do_check(
            r"
fn foo() -> <|><|> {}
",
            "  \n",
            2,
        );
        do_check(
            r"
fn <|>foo<|>() -> i32 { 1 }
",
            "bar",
            3,
        );
        do_check(
            r"
fn foo<|><|>foo() {  }
",
            "bar",
            6,
        );
        do_check(
            r"
fn foo /* <|><|> */ () {}
",
            "some comment",
            6,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
/// foo <|><|>omment
mod { }
",
            "c",
            14,
        );
        do_check(
            r#"
fn -> &str { "Hello<|><|>" }
"#,
            ", world",
            7,
        );
        do_check(
            r#"
fn -> &str { // "Hello<|><|>"
"#,
            ", world",
            10,
        );
        do_check(
            r##"
fn -> &str { r#"Hello<|><|>"#
"##,
            ", world",
            10,
        );
        do_check(
            r"
#[derive(<|>Copy<|>)]
enum Foo {

}
",
            "Clone",
            4,
        );
    }

    #[test]
    fn reparse_str_token_with_error_unchanged() {
        do_check(r#""<|>Unclosed<|> string literal"#, "Still unclosed", 24);
    }

    #[test]
    fn reparse_str_token_with_error_fixed() {
        do_check(r#""unterinated<|><|>"#, "\"", 12);
    }

    #[test]
    fn reparse_block_with_error_in_middle_unchanged() {
        do_check(
            r#"fn main() {
                if {}
                32 + 4<|><|>
                return
                if {}
            }"#,
            "23",
            105,
        )
    }

    #[test]
    fn reparse_block_with_error_in_middle_fixed() {
        do_check(
            r#"fn main() {
                if {}
                32 + 4<|><|>
                return
                if {}
            }"#,
            ";",
            105,
        )
    }
}
<|endoftext|>


<commit_before>use std::fmt;
pub use self::DecodeError::*;

const BASE: u64 = 62;
const ALPHABET: [u8; BASE as usize] =
[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I',
b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b',
b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u',
b'v', b'w', b'x', b'y', b'z'];

pub fn encode(mut num: u64) -> String {
    if num == 0 { return "0".to_owned() }
    let mut bytes = Vec::new();

    while num > 0 {
        bytes.push(ALPHABET[(num % BASE) as usize]);
        num /= BASE
    }
    bytes.reverse();

    String::from_utf8(bytes).unwrap()
}

pub enum DecodeError { InvalidBase62Byte(char, usize) }

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase62Byte(ch, idx) =>
                write!(f, "Invalid character '{}' at position {}", ch, idx)
        }
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

pub fn decode(string: &str) -> Result<u64, DecodeError> {
    let mut result = 0;

    for (i, c) in string.as_bytes().iter().rev().enumerate() {
        let num = BASE.pow(i as u32);
        match ALPHABET.binary_search(&c) {
            Ok(v) => { result += v as u64 * num },
            Err(_e) => {
                return Err(InvalidBase62Byte(c.to_owned() as char, string.len() - i))
            }
        }
    }

    Ok(result)
}

#[cfg(test)]
mod tests {
    use base62;

    #[test]
    fn test_encode() {
        assert_eq!(base62::encode(1337), "LZ");
    }

    #[test]
    fn test_decode() {
        assert_eq!(base62::decode("LZ").unwrap(), 1337);
    }

    #[test]
    fn test_decode_invalid_char() {
        assert!(base62::decode("{").is_err());
    }
}
<commit_msg>Complexify strings in tests<commit_after>use std::fmt;
pub use self::DecodeError::*;

const BASE: u64 = 62;
const ALPHABET: [u8; BASE as usize] =
[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I',
b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b',
b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u',
b'v', b'w', b'x', b'y', b'z'];

pub fn encode(mut num: u64) -> String {
    if num == 0 { return "0".to_owned() }
    let mut bytes = Vec::new();

    while num > 0 {
        bytes.push(ALPHABET[(num % BASE) as usize]);
        num /= BASE
    }
    bytes.reverse();

    String::from_utf8(bytes).unwrap()
}

pub enum DecodeError { InvalidBase62Byte(char, usize) }

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase62Byte(ch, idx) =>
                write!(f, "Invalid character '{}' at position {}", ch, idx)
        }
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

pub fn decode(string: &str) -> Result<u64, DecodeError> {
    let mut result = 0;

    for (i, c) in string.as_bytes().iter().rev().enumerate() {
        let num = BASE.pow(i as u32);
        match ALPHABET.binary_search(&c) {
            Ok(v) => { result += v as u64 * num },
            Err(_e) => {
                return Err(InvalidBase62Byte(c.to_owned() as char, string.len() - i))
            }
        }
    }

    Ok(result)
}

#[cfg(test)]
mod tests {
    use base62;

    #[test]
    fn test_encode() {
        assert_eq!(base62::encode(852751187393), "F0ob4rZ");
    }

    #[test]
    fn test_decode() {
        assert_eq!(base62::decode("F0ob4rZ").unwrap(), 852751187393);
    }

    #[test]
    fn test_decode_invalid_char() {
        assert!(base62::decode("ds{Z455f").is_err());
    }
}
<|endoftext|>


<commit_before><commit_msg>Added LCDC register<commit_after><|endoftext|>


<commit_before><commit_msg>Pass by reference is not really needed for [f64;2]<commit_after><|endoftext|>


<commit_before><commit_msg>Add forgotten logging piece to dumper<commit_after><|endoftext|>