<commit_before>use llvm_sys::analysis::{LLVMVerifyModule, LLVMVerifierFailureAction};
use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffer, LLVMWriteBitcodeToFD};
use llvm_sys::core::{LLVMAddFunction, LLVMAddGlobal, LLVMCreateFunctionPassManagerForModule, LLVMDisposeMessage, LLVMDumpModule, LLVMGetNamedFunction, LLVMGetTypeByName, LLVMSetDataLayout, LLVMSetInitializer, LLVMSetTarget, LLVMCloneModule, LLVMDisposeModule, LLVMGetTarget, LLVMGetDataLayout, LLVMModuleCreateWithName, LLVMGetModuleContext, LLVMGetFirstFunction, LLVMGetLastFunction};
use llvm_sys::execution_engine::{LLVMCreateExecutionEngineForModule, LLVMLinkInInterpreter, LLVMLinkInMCJIT};
use llvm_sys::prelude::LLVMModuleRef;
use llvm_sys::target::{LLVM_InitializeNativeTarget, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeDisassembler};

use std::ffi::{CString, CStr};
use std::fs::File;
use std::mem::{uninitialized, zeroed};
use std::path::Path;
use std::os::unix::io::AsRawFd;

use context::{Context, ContextRef};
use data_layout::DataLayout;
use execution_engine::ExecutionEngine;
use memory_buffer::MemoryBuffer;
use pass_manager::PassManager;
use types::{AsTypeRef, BasicType, FunctionType, BasicTypeEnum};
use values::{BasicValue, FunctionValue, PointerValue};

pub struct Module {
    pub(crate) module: LLVMModuleRef,
}

impl Module {
    pub(crate) fn new(module: LLVMModuleRef) -> Self {
        assert!(!module.is_null());

        Module {
            module: module
        }
    }

    pub fn create(name: &str) -> Self {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let module = unsafe {
            LLVMModuleCreateWithName(c_string.as_ptr())
        };

        Module::new(module)
    }

    pub fn add_function(&self, name: &str, return_type: &FunctionType) -> FunctionValue {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMAddFunction(self.module, c_string.as_ptr(), return_type.as_type_ref())
        };

        // unsafe {
        //     LLVMSetLinkage(value, LLVMCommonLinkage);
        // }

        FunctionValue::new(value)
    }

    pub fn get_context(&self) -> ContextRef {
        let context = unsafe {
            LLVMGetModuleContext(self.module)
        };

        ContextRef::new(Context::new(context))
    }

    pub fn get_first_function(&self) -> Option<FunctionValue> {
        let function = unsafe {
            LLVMGetFirstFunction(self.module)
        };

        if function.is_null() {
            return None;
        }

        Some(FunctionValue::new(function))
    }

    pub fn get_last_function(&self) -> Option<FunctionValue> {
        let function = unsafe {
            LLVMGetLastFunction(self.module)
        };

        if function.is_null() {
            return None;
        }

        Some(FunctionValue::new(function))
    }

    pub fn get_function(&self, name: &str) -> Option<FunctionValue> {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMGetNamedFunction(self.module, c_string.as_ptr())
        };

        if value.is_null() {
            return None;
        }

        Some(FunctionValue::new(value))
    }

    pub fn get_type(&self, name: &str) -> Option<BasicTypeEnum> {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let type_ = unsafe {
            LLVMGetTypeByName(self.module, c_string.as_ptr())
        };

        if type_.is_null() {
            return None;
        }

        Some(BasicTypeEnum::new(type_))
    }

    // TODO: Make this take a targets::Target object by ref and call get_name
    pub fn set_target(&self, target_triple: &str) {
        let c_string = CString::new(target_triple).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMSetTarget(self.module, c_string.as_ptr())
        }
    }

    pub fn get_target(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetTarget(self.module))
        }
    }

    pub fn create_execution_engine(&self, jit_mode: bool) -> Result<ExecutionEngine, String> {
        let mut execution_engine = unsafe { uninitialized() };
        let mut err_str = unsafe { zeroed() };

        if jit_mode {
            unsafe {
                LLVMLinkInMCJIT();
            }
        }

        unsafe {
            LLVMLinkInInterpreter();
        }

        let code = unsafe {
            LLVMCreateExecutionEngineForModule(&mut execution_engine, self.module, &mut err_str) // Should take ownership of module
        };

        if code == 1 {
            let rust_str = unsafe {
                let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

                LLVMDisposeMessage(err_str);

                rust_str
            };

            return Err(rust_str);
        }

        Ok(ExecutionEngine::new(execution_engine, jit_mode))
    }

    pub fn create_function_pass_manager(&self) -> PassManager {
        let pass_manager = unsafe {
            LLVMCreateFunctionPassManagerForModule(self.module)
        };

        PassManager::new(pass_manager)
    }

    // REVIEW: Is this really always a pointer? It would make sense...
    pub fn add_global(&self, type_: &BasicType, init_value: Option<&BasicValue>, name: &str) -> PointerValue {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMAddGlobal(self.module, type_.as_type_ref(), c_string.as_ptr())
        };

        if let Some(init_val) = init_value {
            unsafe {
                LLVMSetInitializer(value, init_val.as_value_ref())
            }
        }

        PointerValue::new(value)
    }

    pub fn write_bitcode_to_path(&self, path: &Path) -> bool {
        let path_str = path.to_str().expect("Did not find a valid Unicode path string");
        let c_string = CString::new(path_str).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMWriteBitcodeToFile(self.module, c_string.as_ptr()) == 0
        }
    }

    // See GH issue #6
    fn write_bitcode_to_file(&self, file: &File, should_close: bool, unbuffered: bool) -> bool {
        // REVIEW: as_raw_fd docs suggest it only works in *nix
        // Also, should_close should maybe be hardcoded to true?
        unsafe {
            LLVMWriteBitcodeToFD(self.module, file.as_raw_fd(), should_close as i32, unbuffered as i32) == 0
        }
    }

    // REVIEW: Untested
    pub fn write_bitcode_to_memory(&self) -> MemoryBuffer {
        let memory_buffer = unsafe {
            LLVMWriteBitcodeToMemoryBuffer(self.module)
        };

        MemoryBuffer::new(memory_buffer)
    }

    pub fn verify(&self, print: bool) -> bool {
        let err_str: *mut *mut i8 = unsafe { zeroed() };

        let action = if print {
            LLVMVerifierFailureAction::LLVMPrintMessageAction
        } else {
            LLVMVerifierFailureAction::LLVMReturnStatusAction
        };

        let code = unsafe {
            LLVMVerifyModule(self.module, action, err_str)
        };

        if code == 1 && !err_str.is_null() {
            unsafe {
                if print {
                    let rust_str = CStr::from_ptr(*err_str).to_str().unwrap();

                    println!("{}", rust_str); // FIXME: Should probably be stderr?
                }

                LLVMDisposeMessage(*err_str);
            }
        }

        code == 0
    }

    pub fn get_data_layout(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetDataLayout(self.module))
        }
    }

    pub fn set_data_layout(&self, data_layout: DataLayout) {
        unsafe {
            LLVMSetDataLayout(self.module, data_layout.data_layout)
        }
    }

    pub fn print_to_stderr(&self) {
        unsafe {
            LLVMDumpModule(self.module);
        }
    }
}

impl Clone for Module {
    fn clone(&self) -> Self {
        let module = unsafe {
            LLVMCloneModule(self.module)
        };

        Module::new(module)
    }
}

// FIXME: Causes segfault in test(s)
// impl Drop for Module {
//     fn drop(&mut self) {
//         unsafe {
//             LLVMDisposeModule(self.module)
//         }
//     }
// }

#[test]
fn test_write_bitcode_to_path() {
    use context::Context;
    use std::env::temp_dir;
    use std::fs::{File, remove_file};
    use std::io::Read;

    let mut path = temp_dir();

    path.push("temp.bc");

    let context = Context::create();
    let module = context.create_module("my_module");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    module.add_function("my_fn", &fn_type);
    module.write_bitcode_to_path(&path);

    let mut contents = Vec::new();
    let mut file = File::open(&path).expect("Could not open temp file");

    file.read_to_end(&mut contents).expect("Unable to verify written file");

    assert!(contents.len() > 0);

    remove_file(&path).unwrap();
}

// REVIEW: This test infrequently fails. Seems to happen more often on travis.
// Possibly a LLVM bug? Wrapper is really straightforward. See issue #6 on GH
// #[test]
// fn test_write_bitcode_to_file() {
//     use context::Context;
//     use std::env::temp_dir;
//     use std::fs::{File, remove_file};
//     use std::io::{Read, Seek, SeekFrom};

//     let mut path = temp_dir();

//     path.push("temp2.bc");

//     let mut file = File::create(&path).unwrap();

//     let context = Context::create();
//     let module = context.create_module("my_module");
//     let void_type = context.void_type();
//     let fn_type = void_type.fn_type(&[], false);

//     module.add_function("my_fn", &fn_type);
//     module.write_bitcode_to_file(&file, true, false);

//     let mut contents = Vec::new();
//     let mut file2 = File::open(&path).expect("Could not open temp file");

//     file.read_to_end(&mut contents).expect("Unable to verify written file");

//     assert!(contents.len() > 0);

//     remove_file(&path).unwrap();
// }
<commit_msg>Codecov change test<commit_after>use llvm_sys::analysis::{LLVMVerifyModule, LLVMVerifierFailureAction};
use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffer, LLVMWriteBitcodeToFD};
use llvm_sys::core::{LLVMAddFunction, LLVMAddGlobal, LLVMCreateFunctionPassManagerForModule, LLVMDisposeMessage, LLVMDumpModule, LLVMGetNamedFunction, LLVMGetTypeByName, LLVMSetDataLayout, LLVMSetInitializer, LLVMSetTarget, LLVMCloneModule, LLVMDisposeModule, LLVMGetTarget, LLVMGetDataLayout, LLVMModuleCreateWithName, LLVMGetModuleContext, LLVMGetFirstFunction, LLVMGetLastFunction};
use llvm_sys::execution_engine::{LLVMCreateExecutionEngineForModule, LLVMLinkInInterpreter, LLVMLinkInMCJIT};
use llvm_sys::prelude::LLVMModuleRef;

use std::ffi::{CString, CStr};
use std::fs::File;
use std::mem::{uninitialized, zeroed};
use std::path::Path;
use std::os::unix::io::AsRawFd;

use context::{Context, ContextRef};
use data_layout::DataLayout;
use execution_engine::ExecutionEngine;
use memory_buffer::MemoryBuffer;
use pass_manager::PassManager;
use types::{AsTypeRef, BasicType, FunctionType, BasicTypeEnum};
use values::{BasicValue, FunctionValue, PointerValue};

pub struct Module {
    pub(crate) module: LLVMModuleRef,
}

impl Module {
    pub(crate) fn new(module: LLVMModuleRef) -> Self {
        assert!(!module.is_null());

        Module {
            module: module
        }
    }

    pub fn create(name: &str) -> Self {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let module = unsafe {
            LLVMModuleCreateWithName(c_string.as_ptr())
        };

        Module::new(module)
    }

    pub fn add_function(&self, name: &str, return_type: &FunctionType) -> FunctionValue {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMAddFunction(self.module, c_string.as_ptr(), return_type.as_type_ref())
        };

        // unsafe {
        //     LLVMSetLinkage(value, LLVMCommonLinkage);
        // }

        FunctionValue::new(value)
    }

    pub fn get_context(&self) -> ContextRef {
        let context = unsafe {
            LLVMGetModuleContext(self.module)
        };

        ContextRef::new(Context::new(context))
    }

    pub fn get_first_function(&self) -> Option<FunctionValue> {
        let function = unsafe {
            LLVMGetFirstFunction(self.module)
        };

        if function.is_null() {
            return None;
        }

        Some(FunctionValue::new(function))
    }

    pub fn get_last_function(&self) -> Option<FunctionValue> {
        let function = unsafe {
            LLVMGetLastFunction(self.module)
        };

        if function.is_null() {
            return None;
        }

        Some(FunctionValue::new(function))
    }

    pub fn get_function(&self, name: &str) -> Option<FunctionValue> {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMGetNamedFunction(self.module, c_string.as_ptr())
        };

        if value.is_null() {
            return None;
        }

        Some(FunctionValue::new(value))
    }

    pub fn get_type(&self, name: &str) -> Option<BasicTypeEnum> {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let type_ = unsafe {
            LLVMGetTypeByName(self.module, c_string.as_ptr())
        };

        if type_.is_null() {
            return None;
        }

        Some(BasicTypeEnum::new(type_))
    }

    // TODO: Make this take a targets::Target object by ref and call get_name
    pub fn set_target(&self, target_triple: &str) {
        let c_string = CString::new(target_triple).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMSetTarget(self.module, c_string.as_ptr())
        }
    }

    pub fn get_target(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetTarget(self.module))
        }
    }

    pub fn create_execution_engine(&self, jit_mode: bool) -> Result<ExecutionEngine, String> {
        let mut execution_engine = unsafe { uninitialized() };
        let mut err_str = unsafe { zeroed() };

        if jit_mode {
            unsafe {
                LLVMLinkInMCJIT();
            }
        }

        unsafe {
            LLVMLinkInInterpreter();
        }

        let code = unsafe {
            LLVMCreateExecutionEngineForModule(&mut execution_engine, self.module, &mut err_str) // Should take ownership of module
        };

        if code == 1 {
            let rust_str = unsafe {
                let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

                LLVMDisposeMessage(err_str);

                rust_str
            };

            return Err(rust_str);
        }

        Ok(ExecutionEngine::new(execution_engine, jit_mode))
    }

    pub fn create_function_pass_manager(&self) -> PassManager {
        let pass_manager = unsafe {
            LLVMCreateFunctionPassManagerForModule(self.module)
        };

        PassManager::new(pass_manager)
    }

    // REVIEW: Is this really always a pointer? It would make sense...
    pub fn add_global(&self, type_: &BasicType, init_value: Option<&BasicValue>, name: &str) -> PointerValue {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let value = unsafe {
            LLVMAddGlobal(self.module, type_.as_type_ref(), c_string.as_ptr())
        };

        if let Some(init_val) = init_value {
            unsafe {
                LLVMSetInitializer(value, init_val.as_value_ref())
            }
        }

        PointerValue::new(value)
    }

    pub fn write_bitcode_to_path(&self, path: &Path) -> bool {
        let path_str = path.to_str().expect("Did not find a valid Unicode path string");
        let c_string = CString::new(path_str).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMWriteBitcodeToFile(self.module, c_string.as_ptr()) == 0
        }
    }

    // See GH issue #6
    fn write_bitcode_to_file(&self, file: &File, should_close: bool, unbuffered: bool) -> bool {
        // REVIEW: as_raw_fd docs suggest it only works in *nix
        // Also, should_close should maybe be hardcoded to true?
        unsafe {
            LLVMWriteBitcodeToFD(self.module, file.as_raw_fd(), should_close as i32, unbuffered as i32) == 0
        }
    }

    // REVIEW: Untested
    pub fn write_bitcode_to_memory(&self) -> MemoryBuffer {
        let memory_buffer = unsafe {
            LLVMWriteBitcodeToMemoryBuffer(self.module)
        };

        MemoryBuffer::new(memory_buffer)
    }

    pub fn verify(&self, print: bool) -> bool {
        let err_str: *mut *mut i8 = unsafe { zeroed() };

        let action = if print {
            LLVMVerifierFailureAction::LLVMPrintMessageAction
        } else {
            LLVMVerifierFailureAction::LLVMReturnStatusAction
        };

        let code = unsafe {
            LLVMVerifyModule(self.module, action, err_str)
        };

        if code == 1 && !err_str.is_null() {
            unsafe {
                if print {
                    let rust_str = CStr::from_ptr(*err_str).to_str().unwrap();

                    println!("{}", rust_str); // FIXME: Should probably be stderr?
                }

                LLVMDisposeMessage(*err_str);
            }
        }

        code == 0
    }

    pub fn get_data_layout(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetDataLayout(self.module))
        }
    }

    pub fn set_data_layout(&self, data_layout: DataLayout) {
        unsafe {
            LLVMSetDataLayout(self.module, data_layout.data_layout)
        }
    }

    pub fn print_to_stderr(&self) {
        unsafe {
            LLVMDumpModule(self.module);
        }
    }
}

impl Clone for Module {
    fn clone(&self) -> Self {
        let module = unsafe {
            LLVMCloneModule(self.module)
        };

        Module::new(module)
    }
}

// FIXME: Causes segfault in test(s)
// impl Drop for Module {
//     fn drop(&mut self) {
//         unsafe {
//             LLVMDisposeModule(self.module)
//         }
//     }
// }

#[test]
fn test_write_bitcode_to_path() {
    use context::Context;
    use std::env::temp_dir;
    use std::fs::{File, remove_file};
    use std::io::Read;

    let mut path = temp_dir();

    path.push("temp.bc");

    let context = Context::create();
    let module = context.create_module("my_module");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    module.add_function("my_fn", &fn_type);
    module.write_bitcode_to_path(&path);

    let mut contents = Vec::new();
    let mut file = File::open(&path).expect("Could not open temp file");

    file.read_to_end(&mut contents).expect("Unable to verify written file");

    assert!(contents.len() > 0);

    remove_file(&path).unwrap();
}

// REVIEW: This test infrequently fails. Seems to happen more often on travis.
// Possibly a LLVM bug? Wrapper is really straightforward. See issue #6 on GH
// #[test]
// fn test_write_bitcode_to_file() {
//     use context::Context;
//     use std::env::temp_dir;
//     use std::fs::{File, remove_file};
//     use std::io::{Read, Seek, SeekFrom};

//     let mut path = temp_dir();

//     path.push("temp2.bc");

//     let mut file = File::create(&path).unwrap();

//     let context = Context::create();
//     let module = context.create_module("my_module");
//     let void_type = context.void_type();
//     let fn_type = void_type.fn_type(&[], false);

//     module.add_function("my_fn", &fn_type);
//     module.write_bitcode_to_file(&file, true, false);

//     let mut contents = Vec::new();
//     let mut file2 = File::open(&path).expect("Could not open temp file");

//     file.read_to_end(&mut contents).expect("Unable to verify written file");

//     assert!(contents.len() > 0);

//     remove_file(&path).unwrap();
// }
<|endoftext|>


<commit_before>use std::rc::Rc;

/// A SliceParser is a parser that parses some elements out of the beginning of
/// a slice and returns a parsed value along with the rest of the unparsed slice
pub trait SliceParser  {
  type I: ?Sized;
  type O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>;
}

/// Combinator methods for slice parsers.  In most cases, these methods copy
/// the caller into a higher-order parser
pub trait ParserCombinator : SliceParser + Clone {

  /// Chain this parser with another parser, creating new parser that returns a
  /// tuple of their results
  fn then<P: SliceParser<I=Self::I>>(&self, p: P) -> ChainedParser<Self,P> {
    ChainedParser{first: self.clone(), second: p}
  }

  /// Chain this parser with another parser, but toss the value from this parser
  fn then_r<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<Self::I, ChainedParser<Self, P>, P::O> {
    self.then(p).map(|(_, t)| t)
  }

  /// Chain this parser with another parser, but toss the value from the other parser
  fn then_l<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<Self::I, ChainedParser<Self, P>, Self::O> {
    self.then(p).map(|(t, _)| t)
  }

  /// Create a new parser that will repeat this parser until it returns an error
  fn repeat(&self) -> RepeatParser<Self> {
    RepeatParser{parser: self.clone()}
  }

  /// Map the value of this parser
  fn map<T, F: 'static + Fn(Self::O) -> T>(&self, f: F) -> MapParser<Self::I, Self, T> {
    MapParser{parser: self.clone(), mapper: Rc::new(Box::new(f))}
  }

  /// Create a disjunction with another parser.  If this parser produces an error, the other parser will be used
  fn or<P: SliceParser<I=Self::I, O=Self::O>>(&self, p: P) -> OrParser<Self,P> {
    OrParser{first: self.clone(), second: p}
  }

}

pub type ParseResult<I,O> = Result<(O, I), String>;

/// Create a parser that only recognizes the given literal value
pub fn lit<T: Eq + Clone>(l: T) -> LiteralParser<T> {
  LiteralParser{literal: l}
}

/// Create a parser that will return Some if the given parser is successful, None otherwise
pub fn opt<T: SliceParser>(t: T) -> OptionParser<T> {
  OptionParser{parser: t}
}

/// Create a lazily evaluated parser from a function.  This can be used to generate recursive parsers
pub fn recursive<I:?Sized,O, F:  Fn() -> Box<SliceParser<I=I,O=O>>>(f: F) -> RecursiveParser<I,O,F> {
  RecursiveParser{parser: Rc::new(f)}
}

pub fn matcher<T: Clone, U, F: 'static + Fn(T) -> Option<U>>(f: F) -> MatchParser<T, U> {
  MatchParser{matcher: Rc::new(Box::new(f))}
}

pub fn repsep<I: ?Sized, A: SliceParser<I=I>, B: SliceParser<I=I>>(rep: A, sep: B) -> RepSepParser<A,B> {
  RepSepParser{rep: rep, sep: sep, min_reps: 1}
}

pub fn one_of<T: SliceParser>(t: Vec<T>) -> OneOfParser<T> {
  OneOfParser{options: t}
}

pub fn boxed<I: ?Sized,O>(b: Box<SliceParser<I=I, O=O>>) -> BoxedParser<I,O> {
  BoxedParser{parser: Rc::new(b)}
}

//////////////////////// STRUCTS /////////////////////////////////////////////

/// A Chained parser contains two parsers that will be used in sequence to
/// create a tuple of parsed values
pub struct ChainedParser<A,B> {
  first: A,
  second: B,
}
impl<C: ?Sized, A: SliceParser<I=C>, B: SliceParser<I=C>> SliceParser for ChainedParser<A, B> {
  type I = C;
  type O = (A::O,B::O);

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>{
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

impl<C: ?Sized, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  Clone for ChainedParser<A, B> {

  fn clone(&self) -> Self {
    ChainedParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<C: ?Sized, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  ParserCombinator for ChainedParser<A, B> {}

/// A LiteralParser looks for an exact match of the given item at the beginning
// of the slice
#[derive(Clone)]
pub struct LiteralParser< T: Eq + Clone> {
  pub literal: T,
}

impl<T: Eq + Clone> SliceParser for LiteralParser< T> {
  type I = [T];
  type O = T;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), &data[1..]))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

impl<T: Eq + Clone> ParserCombinator for LiteralParser<T>{}

/// A Parser that repeats the given parser until it encounters an error.  A
/// vector of the accumulated parsed values is returned
pub struct RepeatParser<P: SliceParser> {
  parser: P
}
impl<T: SliceParser> SliceParser for RepeatParser<T> {
  type I = T::I;
  type O = Vec<T::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    let mut remain = data;
    let mut v: Vec<T::O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

impl<T: ParserCombinator> ParserCombinator for RepeatParser<T> {}

impl<T: ParserCombinator> Clone for RepeatParser<T> {
  fn clone(&self) -> Self {
    RepeatParser{parser: self.parser.clone()}
  }
}

/// A Parser that uses a closure to map the result of another parser
pub struct MapParser<I: ?Sized, P: SliceParser<I=I>, T> {
  parser: P,
  mapper: Rc<Box<Fn(P::O) -> T>>,
}

impl<I: ?Sized, P: SliceParser<I=I>, T> SliceParser for MapParser<I,P,T> {
  type I = P::I;
  type O = T;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper)(output), input))
  }

}

impl<I: ?Sized, P: ParserCombinator<I=I>, T> Clone for MapParser<I,P,T> {

  fn clone(&self) -> Self {
    MapParser{parser: self.parser.clone(), mapper: self.mapper.clone()}
  }
}

impl<I: ?Sized, P: ParserCombinator<I=I>, T> ParserCombinator for MapParser<I,P,T> {}

pub struct OrParser<S: SliceParser,T: SliceParser> {
  first: S,
  second: T,
}

impl<I:?Sized,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> SliceParser for OrParser<S,T> {
  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.first.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.second.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

impl<I:?Sized,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> Clone for OrParser<S,T> {

  fn clone(&self) -> Self {
    OrParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<I:?Sized,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> ParserCombinator for OrParser<S,T> {}

#[derive(Clone)]
pub struct OptionParser<P: SliceParser> {
  parser: P
}
impl<P: SliceParser> SliceParser for OptionParser<P> {
  type I = P::I;
  type O = Option<P::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

pub struct RecursiveParser<I: ?Sized, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>>{
  parser: Rc<F>
}

impl<I:?Sized, O, F> SliceParser for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    (self.parser)().parse(data)
  }

}

impl<I:?Sized, O, F> ParserCombinator for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {}

impl<I: ?Sized, O, F> Clone for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {
  fn clone(&self) -> Self {
    RecursiveParser{parser: self.parser.clone()}
  }
}

pub struct MatchParser<T: Clone, U> {
  matcher: Rc<Box<Fn(T) -> Option<U>>>
}

impl<T: Clone, U> SliceParser for MatchParser<T,U> {
  type I = [T];
  type O = U;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], Self::O> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    match (self.matcher)(data[0].clone()) {
      Some(u) => Ok((u, &data[1..])),
      None    => Err(format!("Match failed"))
    }
  }
}

impl<T: Clone, U> ParserCombinator for MatchParser<T,U> {}

impl<T: Clone, U> Clone for MatchParser<T,U> {

  fn clone(&self) -> Self {
    MatchParser{matcher: self.matcher.clone()}
  }

}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<A,B> {
  pub rep: A,
  pub sep: B,
  pub min_reps: usize,
}
impl<I: ?Sized, A: SliceParser<I=I>, B: SliceParser<I=I>> SliceParser for RepSepParser<A,B> {
  type I = I;
  type O = Vec<A::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    let mut remain = data;
    let mut v: Vec<A::O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
  }
}

impl<I: ?Sized, A: ParserCombinator<I=I>, B: ParserCombinator<I=I>> ParserCombinator for RepSepParser<A,B> {}

impl<I: ?Sized, A: ParserCombinator<I=I>, B: ParserCombinator<I=I>> Clone for RepSepParser<A,B> {

  fn clone(&self) -> Self {
    RepSepParser{rep : self.rep.clone(), sep: self.sep.clone(), min_reps: self.min_reps}
  }

}

/// A Parser that takes a vector of parsers (of the exact same type) and
/// returns the value from the first parser to return a non-error.  This parser
/// solely exists because doing a or b or c or d... ends up crushing rustc
#[derive(Clone)]
pub struct OneOfParser<T: SliceParser> {
  options: Vec<T>
}

impl<T: SliceParser> SliceParser for OneOfParser<T> {
  type I = T::I;
  type O = T::O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    for p in self.options.iter() {
      let r = p.parse(data.clone());
      if r.is_ok() {
        return r;
      }
    }
    Err(format!("All options failed"))
  }

}

impl<T: ParserCombinator> ParserCombinator for OneOfParser<T> {}

/// this parser solely exists to avoid insanely long compile times in rustc.
/// When you have a fairly large parser, it's best to box it.  Yes we're
/// introducing extra dynamic dispatch, but only on a small amount.  In some
/// cases this is the only way to get rustc to not take (literally) a million
/// years!
pub struct BoxedParser<I:?Sized,O> {
  parser: Rc<Box<SliceParser<I=I,O=O>>>
}

impl<I:?Sized, O> SliceParser for BoxedParser<I, O> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    self.parser.parse(data)
  }

}

impl<I:?Sized, O> ParserCombinator for BoxedParser<I, O>  {}

impl<I: ?Sized, O> Clone for BoxedParser<I, O>  {
  fn clone(&self) -> Self {
    BoxedParser{parser: self.parser.clone()}
  }
}

<commit_msg>fixing opt<commit_after>use std::rc::Rc;

/// A SliceParser is a parser that parses some elements out of the beginning of
/// a slice and returns a parsed value along with the rest of the unparsed slice
pub trait SliceParser  {
  type I: ?Sized;
  type O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>;
}

/// Combinator methods for slice parsers.  In most cases, these methods copy
/// the caller into a higher-order parser
pub trait ParserCombinator : SliceParser + Clone {

  /// Chain this parser with another parser, creating new parser that returns a
  /// tuple of their results
  fn then<P: SliceParser<I=Self::I>>(&self, p: P) -> ChainedParser<Self,P> {
    ChainedParser{first: self.clone(), second: p}
  }

  /// Chain this parser with another parser, but toss the value from this parser
  fn then_r<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<Self::I, ChainedParser<Self, P>, P::O> {
    self.then(p).map(|(_, t)| t)
  }

  /// Chain this parser with another parser, but toss the value from the other parser
  fn then_l<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<Self::I, ChainedParser<Self, P>, Self::O> {
    self.then(p).map(|(t, _)| t)
  }

  /// Create a new parser that will repeat this parser until it returns an error
  fn repeat(&self) -> RepeatParser<Self> {
    RepeatParser{parser: self.clone()}
  }

  /// Map the value of this parser
  fn map<T, F: 'static + Fn(Self::O) -> T>(&self, f: F) -> MapParser<Self::I, Self, T> {
    MapParser{parser: self.clone(), mapper: Rc::new(Box::new(f))}
  }

  /// Create a disjunction with another parser.  If this parser produces an error, the other parser will be used
  fn or<P: SliceParser<I=Self::I, O=Self::O>>(&self, p: P) -> OrParser<Self,P> {
    OrParser{first: self.clone(), second: p}
  }

}

pub type ParseResult<I,O> = Result<(O, I), String>;

/// Create a parser that only recognizes the given literal value
pub fn lit<T: Eq + Clone>(l: T) -> LiteralParser<T> {
  LiteralParser{literal: l}
}

/// Create a parser that will return Some if the given parser is successful, None otherwise
pub fn opt<T: SliceParser>(t: T) -> OptionParser<T> {
  OptionParser{parser: t}
}

/// Create a lazily evaluated parser from a function.  This can be used to generate recursive parsers
pub fn recursive<I:?Sized,O, F:  Fn() -> Box<SliceParser<I=I,O=O>>>(f: F) -> RecursiveParser<I,O,F> {
  RecursiveParser{parser: Rc::new(f)}
}

pub fn matcher<T: Clone, U, F: 'static + Fn(T) -> Option<U>>(f: F) -> MatchParser<T, U> {
  MatchParser{matcher: Rc::new(Box::new(f))}
}

pub fn repsep<I: ?Sized, A: SliceParser<I=I>, B: SliceParser<I=I>>(rep: A, sep: B) -> RepSepParser<A,B> {
  RepSepParser{rep: rep, sep: sep, min_reps: 1}
}

pub fn one_of<T: SliceParser>(t: Vec<T>) -> OneOfParser<T> {
  OneOfParser{options: t}
}

pub fn boxed<I: ?Sized,O>(b: Box<SliceParser<I=I, O=O>>) -> BoxedParser<I,O> {
  BoxedParser{parser: Rc::new(b)}
}

//////////////////////// STRUCTS /////////////////////////////////////////////

/// A Chained parser contains two parsers that will be used in sequence to
/// create a tuple of parsed values
pub struct ChainedParser<A,B> {
  first: A,
  second: B,
}
impl<C: ?Sized, A: SliceParser<I=C>, B: SliceParser<I=C>> SliceParser for ChainedParser<A, B> {
  type I = C;
  type O = (A::O,B::O);

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>{
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

impl<C: ?Sized, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  Clone for ChainedParser<A, B> {

  fn clone(&self) -> Self {
    ChainedParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<C: ?Sized, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  ParserCombinator for ChainedParser<A, B> {}

/// A LiteralParser looks for an exact match of the given item at the beginning
// of the slice
#[derive(Clone)]
pub struct LiteralParser< T: Eq + Clone> {
  pub literal: T,
}

impl<T: Eq + Clone> SliceParser for LiteralParser< T> {
  type I = [T];
  type O = T;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), &data[1..]))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

impl<T: Eq + Clone> ParserCombinator for LiteralParser<T>{}

/// A Parser that repeats the given parser until it encounters an error.  A
/// vector of the accumulated parsed values is returned
pub struct RepeatParser<P: SliceParser> {
  parser: P
}
impl<T: SliceParser> SliceParser for RepeatParser<T> {
  type I = T::I;
  type O = Vec<T::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    let mut remain = data;
    let mut v: Vec<T::O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

impl<T: ParserCombinator> ParserCombinator for RepeatParser<T> {}

impl<T: ParserCombinator> Clone for RepeatParser<T> {
  fn clone(&self) -> Self {
    RepeatParser{parser: self.parser.clone()}
  }
}

/// A Parser that uses a closure to map the result of another parser
pub struct MapParser<I: ?Sized, P: SliceParser<I=I>, T> {
  parser: P,
  mapper: Rc<Box<Fn(P::O) -> T>>,
}

impl<I: ?Sized, P: SliceParser<I=I>, T> SliceParser for MapParser<I,P,T> {
  type I = P::I;
  type O = T;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper)(output), input))
  }

}

impl<I: ?Sized, P: ParserCombinator<I=I>, T> Clone for MapParser<I,P,T> {

  fn clone(&self) -> Self {
    MapParser{parser: self.parser.clone(), mapper: self.mapper.clone()}
  }
}

impl<I: ?Sized, P: ParserCombinator<I=I>, T> ParserCombinator for MapParser<I,P,T> {}

pub struct OrParser<S: SliceParser,T: SliceParser> {
  first: S,
  second: T,
}

impl<I:?Sized,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> SliceParser for OrParser<S,T> {
  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.first.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.second.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

impl<I:?Sized,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> Clone for OrParser<S,T> {

  fn clone(&self) -> Self {
    OrParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<I:?Sized,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> ParserCombinator for OrParser<S,T> {}

#[derive(Clone)]
pub struct OptionParser<P: SliceParser> {
  parser: P
}
impl<P: SliceParser> SliceParser for OptionParser<P> {
  type I = P::I;
  type O = Option<P::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

impl<P: ParserCombinator> ParserCombinator for OptionParser<P> {}

pub struct RecursiveParser<I: ?Sized, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>>{
  parser: Rc<F>
}

impl<I:?Sized, O, F> SliceParser for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    (self.parser)().parse(data)
  }

}

impl<I:?Sized, O, F> ParserCombinator for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {}

impl<I: ?Sized, O, F> Clone for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {
  fn clone(&self) -> Self {
    RecursiveParser{parser: self.parser.clone()}
  }
}

pub struct MatchParser<T: Clone, U> {
  matcher: Rc<Box<Fn(T) -> Option<U>>>
}

impl<T: Clone, U> SliceParser for MatchParser<T,U> {
  type I = [T];
  type O = U;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], Self::O> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    match (self.matcher)(data[0].clone()) {
      Some(u) => Ok((u, &data[1..])),
      None    => Err(format!("Match failed"))
    }
  }
}

impl<T: Clone, U> ParserCombinator for MatchParser<T,U> {}

impl<T: Clone, U> Clone for MatchParser<T,U> {

  fn clone(&self) -> Self {
    MatchParser{matcher: self.matcher.clone()}
  }

}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<A,B> {
  pub rep: A,
  pub sep: B,
  pub min_reps: usize,
}
impl<I: ?Sized, A: SliceParser<I=I>, B: SliceParser<I=I>> SliceParser for RepSepParser<A,B> {
  type I = I;
  type O = Vec<A::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    let mut remain = data;
    let mut v: Vec<A::O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
  }
}

impl<I: ?Sized, A: ParserCombinator<I=I>, B: ParserCombinator<I=I>> ParserCombinator for RepSepParser<A,B> {}

impl<I: ?Sized, A: ParserCombinator<I=I>, B: ParserCombinator<I=I>> Clone for RepSepParser<A,B> {

  fn clone(&self) -> Self {
    RepSepParser{rep : self.rep.clone(), sep: self.sep.clone(), min_reps: self.min_reps}
  }

}

/// A Parser that takes a vector of parsers (of the exact same type) and
/// returns the value from the first parser to return a non-error.  This parser
/// solely exists because doing a or b or c or d... ends up crushing rustc
#[derive(Clone)]
pub struct OneOfParser<T: SliceParser> {
  options: Vec<T>
}

impl<T: SliceParser> SliceParser for OneOfParser<T> {
  type I = T::I;
  type O = T::O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    for p in self.options.iter() {
      let r = p.parse(data.clone());
      if r.is_ok() {
        return r;
      }
    }
    Err(format!("All options failed"))
  }

}

impl<T: ParserCombinator> ParserCombinator for OneOfParser<T> {}

/// this parser solely exists to avoid insanely long compile times in rustc.
/// When you have a fairly large parser, it's best to box it.  Yes we're
/// introducing extra dynamic dispatch, but only on a small amount.  In some
/// cases this is the only way to get rustc to not take (literally) a million
/// years!
pub struct BoxedParser<I:?Sized,O> {
  parser: Rc<Box<SliceParser<I=I,O=O>>>
}

impl<I:?Sized, O> SliceParser for BoxedParser<I, O> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    self.parser.parse(data)
  }

}

impl<I:?Sized, O> ParserCombinator for BoxedParser<I, O>  {}

impl<I: ?Sized, O> Clone for BoxedParser<I, O>  {
  fn clone(&self) -> Self {
    BoxedParser{parser: self.parser.clone()}
  }
}

<|endoftext|>


<commit_before>//! This module defines the `Opcode` type, which contains all opcodes handled by the VM.

pub use self::Opcode::*;

/// An opcode that can be executed by the VM. This enum is always 32 bits large.
///
/// Note that this `enum` is unstable (it might not even be an enum in the next version), to allow
/// adding special optimized opcodes any time.
///
/// Documentation syntax:
///
/// * `R[n]` is the value stored in register (stack slot) `n`
/// * `U[n]` is the current value of the upvalue with the index `n`
/// * `C[n]` is the constant at index `n` (looked up in the current function's constant table)
/// * `PROTO[n]` is function prototype number `n`
/// * `A`, `B`, `C` are the values of the first, second and third `u8` parameters (resp.)
/// * `Xu` is the value of the second operand, which must be a `u16` (eXtended unsigned)
/// * `Xs` is the value of the second operand, which must be a `i16` (eXtended signed)
/// * `Lu` = `((A << 16) | Xu) as u32` emulates one 24 bit parameter (eg. for jumps)
/// * `Ls` = `((A << 16) | Xu) as i32` signed version of `Lu`
/// * `PC` is the program counter, which holds the number of the next opcode by default
#[packed]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
pub enum Opcode {
    /// > R[A] := R[B]
    MOV(u8, u8),
    /// > R[A] := C[Xu]
    ///
    /// Loads the constant with index `Xu` into `R[A]`.
    LOADK(u8, u16),
    /// > R[A] := nil, R[A+1] := nil, ..., R[A+B] := nil
    ///
    /// Assigns `nil` to the B+1 registers starting at A. If B is 0, assigns `nil` only to `R[A]`.
    LOADNIL(u8, u8),
    /// > R[A], R[A+1], ..., R[A+B] := C
    ///
    /// Assigns a boolean to B+1 registers from `R[A]` to `R[A+B]`. If C is `false`, assign `false`
    /// to the registers, otherwise assign `true`.
    LOADBOOL(u8, u8, bool),
    /// > R[A] := closure of PROTO[Xu]
    ///
    /// Instantiates function prototype number `Xu` and stores a reference to the created closure
    /// in `R[A]`
    FUNC(u8, u16),
    /// > R[A], R[A+1], ..., R[A+C-2] := R\[A](R[A+1], ..., R[A+B-1])
    ///
    /// Calls `R[A]` with B-1 arguments stored in `R[A+1]` through `R[A+B-1]`. If B is 1, no
    /// arguments are passed. If B is 0, passes all arguments from A+1 to the top of the stack
    /// (this is used if the last argument is a function call, which may return an unknown number
    /// of values).
    ///
    /// Stores C-1 return values in `R[A]` through `R[A+C-2]`. If C is 1, no return values are
    /// stored. If C is 0, stores all return values in `R[A]`, `R[A+1]`, ... (if necessary,
    /// expanding the stack to fit all return values in).
    ///
    /// This might invoke a metamethod if `R[A]` has a metatable with a `__call` field.
    CALL(u8, u8, u8),
    /// > return R[A], R[A+1], ..., R[A+B-2]
    ///
    /// Returns B-1 values stored in `R[A]` through `R[A+B-2]` to the caller. If B is 1, returns no
    /// values and just leaves the current function, returning control to the caller. If B is 0,
    /// returns all values from A to the top of the stack.
    ///
    /// If the program's main function executes this opcode, the VM will pass the first return
    /// value (if any) to the code that started the VM.
    RETURN(u8, u8),
    /// > R[A], R[A+1], ..., R[A+B-1] := varargs
    ///
    /// Stores B arguments passed as variable arguments (in `...`) in `R[A]` through `R[A+B-1]`.
    /// If B is 0, stores all varargs in `R[A]`, `R[A+1]`, ... (expanding the stack if necessary).
    VARARGS(u8, u8),
    /// > PC += Ls
    ///
    /// Unconditional jump. Offsets `PC` by `Ls`, which may be negative.
    JMP(u8, u16),
    /// > if R[A]: PC += Xs
    ///
    /// Conditional jump. If the value in `R[A]` is "truthy" (not `false` or `nil`), offsets `PC`
    /// by `Xs`.
    IF(u8, i16),
    /// > if not R[A]: PC += Xs
    ///
    /// If the value in `R[A]` is `false` or `nil`, offsets `PC` by `Xs`.
    IFNOT(u8, i16),
    /// > R[A] := U[B]
    GETUPVAL(u8, u8),
    /// > U[A] := R[B]
    SETUPVAL(u8, u8),
    /// > R[A] := R[B][R[C]]
    ///
    /// Indexes `R[B]` with the value in `R[C]` and stores the result in `R[A]`.
    GETIDX(u8, u8, u8),
    /// > R[A][R[B]] := R[C]
    ///
    /// Stores `R[C]` in `R[A]` at index `R[B]`.
    SETIDX(u8, u8, u8),

    // Operator opcodes. Any of them can call a metafunction if the value in R[B] has an associated
    // metatable that overrides the operator.

    /// > R[A] := R[B] + R[C]
    ADD(u8, u8, u8),
    /// > R[A] := R[B] - R[C]
    SUB(u8, u8, u8),
    /// > R[A] := R[B] * R[C]
    MUL(u8, u8, u8),
    /// > R[A] := R[B] / R[C]
    DIV(u8, u8, u8),
    /// > R[A] := R[B] % R[C]
    MOD(u8, u8, u8),
    /// > R[A] := R[B] ^ R[C]
    POW(u8, u8, u8),

    /// > R[A] := R[B] == R[C]
    EQ(u8, u8, u8),
    /// > R[A] := R[B] != R[C]
    NEQ(u8, u8, u8),
    /// > R[A] := R[B] <= R[C]
    LEQ(u8, u8, u8),
    /// > R[A] := R[B] >= R[C]
    GEQ(u8, u8, u8),
    /// > R[A] := R[B] < R[C]
    LESS(u8, u8, u8),
    /// > R[A] := R[B] > R[C]
    GREATER(u8, u8, u8),

    // LAND and LOR are implemented with jumps because they can shortcut. This also implies that
    // they cannot be overridden via a metatable.

    /// > R[A] := R[B] & R[C]
    BAND(u8, u8, u8),
    /// > R[A] := R[B] | R[C]
    BOR(u8, u8, u8),
    /// > R[A] := R[B] ~ R[C]
    BXOR(u8, u8, u8),
    /// > R[A] := R[B] << R[C]
    SHIFTL(u8, u8, u8),
    /// > R[A] := R[B] >> R[C]
    SHIFTR(u8, u8, u8),

    /// > R[A] := R[B] .. R[B+1] .. ... .. R[B+C+1]
    ///
    /// Concatenates the values in `R[B]` through `R[B+C+1]`: If C is 0, concatenates `R[B]` and
    /// `R[B+1]`.
    CONCAT(u8, u8, u8),

    /// > R[A] := -R[B]
    NEG(u8, u8),
    /// > R[A] := !R[B]
    ///
    /// Any "truthy" value will be converted to `false`, the values `false` and `nil` will be
    /// converted to `true`.
    NOT(u8, u8),
    /// > R[A] := ~R[B]
    INV(u8, u8),
    /// > R[A] := #R[B]
    LEN(u8, u8),
}

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

    use std::mem;

    #[test]
    fn size() {
        // we guarantee that opcodes fit in 32 bits, regardless of the host platform
        assert_eq!(mem::size_of::<Opcode>(), 4);
    }
}
<commit_msg>remove #[packed] from Opcode enum<commit_after>//! This module defines the `Opcode` type, which contains all opcodes handled by the VM.

pub use self::Opcode::*;

/// An opcode that can be executed by the VM. This enum is always 32 bits large.
///
/// Note that this `enum` is unstable (it might not even be an enum in the next version), to allow
/// adding special optimized opcodes any time.
///
/// Documentation syntax:
///
/// * `R[n]` is the value stored in register (stack slot) `n`
/// * `U[n]` is the current value of the upvalue with the index `n`
/// * `C[n]` is the constant at index `n` (looked up in the current function's constant table)
/// * `PROTO[n]` is function prototype number `n`
/// * `A`, `B`, `C` are the values of the first, second and third `u8` parameters (resp.)
/// * `Xu` is the value of the second operand, which must be a `u16` (eXtended unsigned)
/// * `Xs` is the value of the second operand, which must be a `i16` (eXtended signed)
/// * `Lu` = `((A << 16) | Xu) as u32` emulates one 24 bit parameter (eg. for jumps)
/// * `Ls` = `((A << 16) | Xu) as i32` signed version of `Lu`
/// * `PC` is the program counter, which holds the number of the next opcode by default
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
pub enum Opcode {
    /// > R[A] := R[B]
    MOV(u8, u8),
    /// > R[A] := C[Xu]
    ///
    /// Loads the constant with index `Xu` into `R[A]`.
    LOADK(u8, u16),
    /// > R[A] := nil, R[A+1] := nil, ..., R[A+B] := nil
    ///
    /// Assigns `nil` to the B+1 registers starting at A. If B is 0, assigns `nil` only to `R[A]`.
    LOADNIL(u8, u8),
    /// > R[A], R[A+1], ..., R[A+B] := C
    ///
    /// Assigns a boolean to B+1 registers from `R[A]` to `R[A+B]`. If C is `false`, assign `false`
    /// to the registers, otherwise assign `true`.
    LOADBOOL(u8, u8, bool),
    /// > R[A] := closure of PROTO[Xu]
    ///
    /// Instantiates function prototype number `Xu` and stores a reference to the created closure
    /// in `R[A]`
    FUNC(u8, u16),
    /// > R[A], R[A+1], ..., R[A+C-2] := R\[A](R[A+1], ..., R[A+B-1])
    ///
    /// Calls `R[A]` with B-1 arguments stored in `R[A+1]` through `R[A+B-1]`. If B is 1, no
    /// arguments are passed. If B is 0, passes all arguments from A+1 to the top of the stack
    /// (this is used if the last argument is a function call, which may return an unknown number
    /// of values).
    ///
    /// Stores C-1 return values in `R[A]` through `R[A+C-2]`. If C is 1, no return values are
    /// stored. If C is 0, stores all return values in `R[A]`, `R[A+1]`, ... (if necessary,
    /// expanding the stack to fit all return values in).
    ///
    /// This might invoke a metamethod if `R[A]` has a metatable with a `__call` field.
    CALL(u8, u8, u8),
    /// > return R[A], R[A+1], ..., R[A+B-2]
    ///
    /// Returns B-1 values stored in `R[A]` through `R[A+B-2]` to the caller. If B is 1, returns no
    /// values and just leaves the current function, returning control to the caller. If B is 0,
    /// returns all values from A to the top of the stack.
    ///
    /// If the program's main function executes this opcode, the VM will pass the first return
    /// value (if any) to the code that started the VM.
    RETURN(u8, u8),
    /// > R[A], R[A+1], ..., R[A+B-1] := varargs
    ///
    /// Stores B arguments passed as variable arguments (in `...`) in `R[A]` through `R[A+B-1]`.
    /// If B is 0, stores all varargs in `R[A]`, `R[A+1]`, ... (expanding the stack if necessary).
    VARARGS(u8, u8),
    /// > PC += Ls
    ///
    /// Unconditional jump. Offsets `PC` by `Ls`, which may be negative.
    JMP(u8, u16),
    /// > if R[A]: PC += Xs
    ///
    /// Conditional jump. If the value in `R[A]` is "truthy" (not `false` or `nil`), offsets `PC`
    /// by `Xs`.
    IF(u8, i16),
    /// > if not R[A]: PC += Xs
    ///
    /// If the value in `R[A]` is `false` or `nil`, offsets `PC` by `Xs`.
    IFNOT(u8, i16),
    /// > R[A] := U[B]
    GETUPVAL(u8, u8),
    /// > U[A] := R[B]
    SETUPVAL(u8, u8),
    /// > R[A] := R[B][R[C]]
    ///
    /// Indexes `R[B]` with the value in `R[C]` and stores the result in `R[A]`.
    GETIDX(u8, u8, u8),
    /// > R[A][R[B]] := R[C]
    ///
    /// Stores `R[C]` in `R[A]` at index `R[B]`.
    SETIDX(u8, u8, u8),

    // Operator opcodes. Any of them can call a metafunction if the value in R[B] has an associated
    // metatable that overrides the operator.

    /// > R[A] := R[B] + R[C]
    ADD(u8, u8, u8),
    /// > R[A] := R[B] - R[C]
    SUB(u8, u8, u8),
    /// > R[A] := R[B] * R[C]
    MUL(u8, u8, u8),
    /// > R[A] := R[B] / R[C]
    DIV(u8, u8, u8),
    /// > R[A] := R[B] % R[C]
    MOD(u8, u8, u8),
    /// > R[A] := R[B] ^ R[C]
    POW(u8, u8, u8),

    /// > R[A] := R[B] == R[C]
    EQ(u8, u8, u8),
    /// > R[A] := R[B] != R[C]
    NEQ(u8, u8, u8),
    /// > R[A] := R[B] <= R[C]
    LEQ(u8, u8, u8),
    /// > R[A] := R[B] >= R[C]
    GEQ(u8, u8, u8),
    /// > R[A] := R[B] < R[C]
    LESS(u8, u8, u8),
    /// > R[A] := R[B] > R[C]
    GREATER(u8, u8, u8),

    // LAND and LOR are implemented with jumps because they can shortcut. This also implies that
    // they cannot be overridden via a metatable.

    /// > R[A] := R[B] & R[C]
    BAND(u8, u8, u8),
    /// > R[A] := R[B] | R[C]
    BOR(u8, u8, u8),
    /// > R[A] := R[B] ~ R[C]
    BXOR(u8, u8, u8),
    /// > R[A] := R[B] << R[C]
    SHIFTL(u8, u8, u8),
    /// > R[A] := R[B] >> R[C]
    SHIFTR(u8, u8, u8),

    /// > R[A] := R[B] .. R[B+1] .. ... .. R[B+C+1]
    ///
    /// Concatenates the values in `R[B]` through `R[B+C+1]`: If C is 0, concatenates `R[B]` and
    /// `R[B+1]`.
    CONCAT(u8, u8, u8),

    /// > R[A] := -R[B]
    NEG(u8, u8),
    /// > R[A] := !R[B]
    ///
    /// Any "truthy" value will be converted to `false`, the values `false` and `nil` will be
    /// converted to `true`.
    NOT(u8, u8),
    /// > R[A] := ~R[B]
    INV(u8, u8),
    /// > R[A] := #R[B]
    LEN(u8, u8),
}

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

    use std::mem;

    #[test]
    fn size() {
        // we guarantee that opcodes fit in 32 bits, regardless of the host platform
        assert_eq!(mem::size_of::<Opcode>(), 4);
    }
}
<|endoftext|>


<commit_before>/// The focus on this file is to describe the data-structures
/// for IA-32e paging mode.
use core::fmt;

pub type PAddr = u64;
pub type VAddr = usize;

pub const BASE_PAGE_SIZE: u64 = 4096; // 4 KiB
pub const LARGE_PAGE_SIZE: u64 = 1024*1024*2; // 2 MiB
pub const HUGE_PAGE_SIZE: u64 = 1024*1024*1024; // 1 GiB

/// MAXPHYADDR, which is at most 52; (use CPUID for finding system value).
pub const MAXPHYADDR: u64 = 52;

/// Mask to find the physical address of an entry in a page-table.
const ADDRESS_MASK: u64 = ((1 << MAXPHYADDR) - 1) & !0xfff;

/// A PML4 table.
/// In practice this has only 4 entries but it still needs to be the size of a 4K page.
pub type PML4  = [PML4Entry; 512];

/// A page directory pointer table.
pub type PDPT  = [PDPTEntry; 512];

/// A page directory.
pub type PD    = [PDEntry; 512];

/// A page table.
pub type PT    = [PTEntry; 512];

/// Given virtual address calculate corresponding entry in PML4.
pub fn pml4_index(addr: VAddr) -> usize {
    (addr >> 39) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PDPT.
#[inline]
pub fn pdpt_index(addr: VAddr) -> usize {
    (addr >> 30) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PD.
#[inline]
pub fn pd_index(addr: VAddr) -> usize {
    (addr >> 21) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PT.
#[inline]
pub fn pt_index(addr: VAddr) -> usize {
    (addr >> 12) & 0b111111111
}

/// PML4 Entry bits description.
bitflags! {
    flags PML4Entry: u64 {
        /// Present; must be 1 to reference a page-directory-pointer table
        const PML4_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 512-GByte region
        /// controlled by this entry (see Section 4.6)
        const PML4_RW      = 0b00000010,
        /// User/supervisor; if 0, user-mode accesses are not allowed
        /// to the 512-GByte region controlled by this entry.
        const PML4_US      = 0b00000100,
        /// Page-level write-through; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PWT     = 0b00001000,
        /// Page-level cache disable; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PCD     = 0b00010000,
        /// Accessed; indicates whether this entry has been used for linear-address translation.
        const PML4_A       = 0b00100000,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PML4_XD      = 1 << 63,
    }
}

impl PML4Entry {

    /// Creates a new PML4Entry.
    ///
    /// # Arguments
    ///
    ///  * `pdpt` - The physical address of the pdpt table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pdpt: PAddr, flags: PML4Entry) -> PML4Entry {
        assert!(pdpt % BASE_PAGE_SIZE == 0);
        PML4Entry { bits: pdpt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PML4_P)
    }
}

impl fmt::Debug for PML4Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PDPT Entry bits description.
bitflags! {
    flags PDPTEntry: u64 {
        /// Present; must be 1 to map a 1-GByte page or reference a page directory.
        const PDPT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
        const PDPT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.
        const PDPT_US      = 0b00000100,
        /// Page-level write-through.
        const PDPT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PDPT_PCD     = 0b00010000,
        /// Accessed; if PDPT_PS set indicates whether software has accessed the 1-GByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PDPT_A       = 0b00100000,
        /// Dirty; if PDPT_PS indicates whether software has written to the 1-GByte page referenced by this entry.
        /// else ignored.
        const PDPT_D       = 0b01000000,
        /// Page size; if set this entry maps a 1-GByte page; otherwise, this entry references a page directory.
        /// if not PDPT_PS this is ignored.
        const PDPT_PS      = 0b10000000,
        /// Global; if PDPT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PDPT_PS this is ignored.
        const PDPT_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 1-GByte page referenced by this entry.
        const PDPT_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PDPT_XD      = 1 << 63,
    }
}

impl PDPTEntry {

    /// Creates a new PDPTEntry.
    ///
    /// # Arguments
    ///
    ///  * `pd` - The physical address of the page directory.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pd: PAddr, flags: PDPTEntry) -> PDPTEntry {
        assert!(pd % BASE_PAGE_SIZE == 0);
        PDPTEntry { bits: pd | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PDPT_P)
    }
}

impl fmt::Debug for PDPTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PD Entry bits description.
bitflags! {
    flags PDEntry: u64 {
        /// Present; must be 1 to map a 2-MByte page or reference a page table.
        const PD_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
        const PD_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.
        const PD_US      = 0b00000100,
        /// Page-level write-through.
        const PD_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PD_PCD     = 0b00010000,
        /// Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PD_A       = 0b00100000,
        /// Dirty; if PD_PS indicates whether software has written to the 2-MByte page referenced by this entry.
        /// else ignored.
        const PD_D       = 0b01000000,
        /// Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.
        const PD_PS      = 0b10000000,
        /// Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PD_PS this is ignored.
        const PD_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 2-MByte page referenced by this entry.
        /// if not PD_PS this is ignored.
        const PD_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PD_XD      = 1 << 63,
    }
}

impl PDEntry {

    /// Creates a new PDEntry.
    ///
    /// # Arguments
    ///
    ///  * `pt` - The physical address of the page table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pt: PAddr, flags: PDEntry) -> PDEntry {
        assert!(pt % BASE_PAGE_SIZE == 0);
        PDEntry { bits: pt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PD_P)
    }
}

impl fmt::Debug for PDEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PT Entry bits description.
bitflags! {
    flags PTEntry: u64 {
        /// Present; must be 1 to map a 4-KByte page.
        const PT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
        const PT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.
        const PT_US      = 0b00000100,
        /// Page-level write-through.
        const PT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PT_PCD     = 0b00010000,
        /// Accessed; indicates whether software has accessed the 4-KByte page
        const PT_A       = 0b00100000,
        /// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
        const PT_D       = 0b01000000,
        /// Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwise
        const PT_G       = 1<<8,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PT_XD      = 1 << 63,
    }
}

impl PTEntry {

    /// Creates a new PTEntry.
    ///
    /// # Arguments
    ///
    ///  * `page` - The physical address of the backing 4 KiB page.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(page: PAddr, flags: PTEntry) -> PTEntry {
        assert!(page % BASE_PAGE_SIZE == 0);
        PTEntry{ bits: page | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PT_P)
    }
}

impl fmt::Debug for PTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}
<commit_msg>Add cache-line size.<commit_after>/// The focus on this file is to describe the data-structures
/// for IA-32e paging mode.
use core::fmt;

pub type PAddr = u64;
pub type VAddr = usize;

pub const BASE_PAGE_SIZE: u64 = 4096; // 4 KiB
pub const LARGE_PAGE_SIZE: u64 = 1024*1024*2; // 2 MiB
pub const HUGE_PAGE_SIZE: u64 = 1024*1024*1024; // 1 GiB
pub const CACHE_LINE_SIZE: usize = 64; // 64 Bytes

/// MAXPHYADDR, which is at most 52; (use CPUID for finding system value).
pub const MAXPHYADDR: u64 = 52;

/// Mask to find the physical address of an entry in a page-table.
const ADDRESS_MASK: u64 = ((1 << MAXPHYADDR) - 1) & !0xfff;

/// A PML4 table.
/// In practice this has only 4 entries but it still needs to be the size of a 4K page.
pub type PML4  = [PML4Entry; 512];

/// A page directory pointer table.
pub type PDPT  = [PDPTEntry; 512];

/// A page directory.
pub type PD    = [PDEntry; 512];

/// A page table.
pub type PT    = [PTEntry; 512];

/// Given virtual address calculate corresponding entry in PML4.
pub fn pml4_index(addr: VAddr) -> usize {
    (addr >> 39) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PDPT.
#[inline]
pub fn pdpt_index(addr: VAddr) -> usize {
    (addr >> 30) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PD.
#[inline]
pub fn pd_index(addr: VAddr) -> usize {
    (addr >> 21) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PT.
#[inline]
pub fn pt_index(addr: VAddr) -> usize {
    (addr >> 12) & 0b111111111
}

/// PML4 Entry bits description.
bitflags! {
    flags PML4Entry: u64 {
        /// Present; must be 1 to reference a page-directory-pointer table
        const PML4_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 512-GByte region
        /// controlled by this entry (see Section 4.6)
        const PML4_RW      = 0b00000010,
        /// User/supervisor; if 0, user-mode accesses are not allowed
        /// to the 512-GByte region controlled by this entry.
        const PML4_US      = 0b00000100,
        /// Page-level write-through; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PWT     = 0b00001000,
        /// Page-level cache disable; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PCD     = 0b00010000,
        /// Accessed; indicates whether this entry has been used for linear-address translation.
        const PML4_A       = 0b00100000,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PML4_XD      = 1 << 63,
    }
}

impl PML4Entry {

    /// Creates a new PML4Entry.
    ///
    /// # Arguments
    ///
    ///  * `pdpt` - The physical address of the pdpt table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pdpt: PAddr, flags: PML4Entry) -> PML4Entry {
        assert!(pdpt % BASE_PAGE_SIZE == 0);
        PML4Entry { bits: pdpt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PML4_P)
    }
}

impl fmt::Debug for PML4Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PDPT Entry bits description.
bitflags! {
    flags PDPTEntry: u64 {
        /// Present; must be 1 to map a 1-GByte page or reference a page directory.
        const PDPT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
        const PDPT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.
        const PDPT_US      = 0b00000100,
        /// Page-level write-through.
        const PDPT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PDPT_PCD     = 0b00010000,
        /// Accessed; if PDPT_PS set indicates whether software has accessed the 1-GByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PDPT_A       = 0b00100000,
        /// Dirty; if PDPT_PS indicates whether software has written to the 1-GByte page referenced by this entry.
        /// else ignored.
        const PDPT_D       = 0b01000000,
        /// Page size; if set this entry maps a 1-GByte page; otherwise, this entry references a page directory.
        /// if not PDPT_PS this is ignored.
        const PDPT_PS      = 0b10000000,
        /// Global; if PDPT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PDPT_PS this is ignored.
        const PDPT_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 1-GByte page referenced by this entry.
        const PDPT_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PDPT_XD      = 1 << 63,
    }
}

impl PDPTEntry {

    /// Creates a new PDPTEntry.
    ///
    /// # Arguments
    ///
    ///  * `pd` - The physical address of the page directory.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pd: PAddr, flags: PDPTEntry) -> PDPTEntry {
        assert!(pd % BASE_PAGE_SIZE == 0);
        PDPTEntry { bits: pd | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PDPT_P)
    }
}

impl fmt::Debug for PDPTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PD Entry bits description.
bitflags! {
    flags PDEntry: u64 {
        /// Present; must be 1 to map a 2-MByte page or reference a page table.
        const PD_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
        const PD_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.
        const PD_US      = 0b00000100,
        /// Page-level write-through.
        const PD_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PD_PCD     = 0b00010000,
        /// Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PD_A       = 0b00100000,
        /// Dirty; if PD_PS indicates whether software has written to the 2-MByte page referenced by this entry.
        /// else ignored.
        const PD_D       = 0b01000000,
        /// Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.
        const PD_PS      = 0b10000000,
        /// Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PD_PS this is ignored.
        const PD_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 2-MByte page referenced by this entry.
        /// if not PD_PS this is ignored.
        const PD_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PD_XD      = 1 << 63,
    }
}

impl PDEntry {

    /// Creates a new PDEntry.
    ///
    /// # Arguments
    ///
    ///  * `pt` - The physical address of the page table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pt: PAddr, flags: PDEntry) -> PDEntry {
        assert!(pt % BASE_PAGE_SIZE == 0);
        PDEntry { bits: pt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PD_P)
    }
}

impl fmt::Debug for PDEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PT Entry bits description.
bitflags! {
    flags PTEntry: u64 {
        /// Present; must be 1 to map a 4-KByte page.
        const PT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
        const PT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.
        const PT_US      = 0b00000100,
        /// Page-level write-through.
        const PT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PT_PCD     = 0b00010000,
        /// Accessed; indicates whether software has accessed the 4-KByte page
        const PT_A       = 0b00100000,
        /// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
        const PT_D       = 0b01000000,
        /// Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwise
        const PT_G       = 1<<8,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PT_XD      = 1 << 63,
    }
}

impl PTEntry {

    /// Creates a new PTEntry.
    ///
    /// # Arguments
    ///
    ///  * `page` - The physical address of the backing 4 KiB page.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(page: PAddr, flags: PTEntry) -> PTEntry {
        assert!(page % BASE_PAGE_SIZE == 0);
        PTEntry{ bits: page | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PT_P)
    }
}

impl fmt::Debug for PTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}
<|endoftext|>


<commit_before>pub mod engine;
pub mod keys;
pub mod msg;
pub mod config;
pub mod transport;
pub mod bootstrap;

mod cmd_resp;
mod store;
mod peer;
mod peer_storage;
mod region;
mod util;

pub use self::msg::{Msg, Sender};
<commit_msg>raftserver: do some public.<commit_after>pub mod engine;
pub mod keys;
pub mod msg;
pub mod config;
pub mod transport;
pub mod bootstrap;

mod cmd_resp;
mod store;
mod peer;
mod peer_storage;
mod region;
mod util;

pub use self::msg::{Msg, Sender, Callback};
pub use self::store::Store;
pub use self::config::Config;
pub use self::transport::Transport;
pub use self::peer::Peer;
pub use self::bootstrap::{bootstrap_store, bootstrap_region, bootstrap_cluster};
<|endoftext|>


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

use std::str::Chars;
use std::iter::FromIterator;

use combine::{Parser, Stream};
use combine::char::{CrLf, Tab, tab, char, crlf};
use combine::combinator::{Many, NoneOf, Skip, Or, Token, or, many, none_of};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
    definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
    OperationDefinition(Operation),
    SelectionSetDefinition(SelectionSet),
    FragmentDefinition(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
    op_type: OperationType,
    name: Option<Name>,
    variable_definitions: Vec<VariableDefinition>,
    directives: Vec<Directive>,
}

impl Operation {
    fn new(op_type: OperationType,
           name: Option<Name>,
           variable_definitions: Vec<VariableDefinition>,
           directives: Vec<Directive>)
           -> Operation {
        Operation {
            op_type: op_type,
            name: name,
            variable_definitions: variable_definitions,
            directives: directives,
        }
    }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
    Query,
    Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
    variable: Variable,
    var_type: Type,
    default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
    NamedType(Name),
    ListType(Box<Type>),
    NonNullType(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
    Var(Variable),
    IntValue(i32),
    FloatValue(f32),
    StringValue(String),
    BooleanValue(bool),
    NullValue,
    EnumValue(String),
    ListValue(Vec<Value>),
    ObjectValue(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
    name: Name,
    arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
    name: Name,
    value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
    FieldSelection(Field),
    FragmentSpread(Name, Vec<Directive>),
    InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
    alias: Option<Name>,
    name: Name,
    arguments: Vec<Argument>,
    directives: Vec<Directive>,
    selection_set: SelectionSet,
}

impl Field {
    fn new(alias: Option<Name>,
           name: Name,
           arguments: Vec<Argument>,
           directives: Vec<Directive>,
           selection_set: SelectionSet)
           -> Field {
        Field {
            alias: alias,
            name: name,
            arguments: arguments,
            directives: directives,
            selection_set: selection_set,
        }
    }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
    name: Name,
    type_condition: Type,
    directives: Vec<Directive>,
    selection_set: SelectionSet,
}

// ok wtf is going on here
type WhiteSpace<I> = Or<Token<I>, Tab<I>>;
pub fn white_space<I: Stream<Item = char>>() -> WhiteSpace<I> {
    char(' ').or(tab())
}

// ok wtf is going on here
type LineTerminator<I> = Or<Or<CrLf<I>, Token<I>>, Token<I>>;
pub fn line_terminator<I: Stream<Item = char>>() -> LineTerminator<I> {
    crlf().or(char('\r')).or(char('\n'))
}

// ok wtf is going on here
type Comment<I> = Skip<Token<I>, LineTerminator<I>>;
pub fn comment<I: Stream<Item = char>>() -> Comment<I>
{
    char('#')
        // .skip(many(none_of("".chars())))
        .skip(line_terminator())
}

// pub fn comma<I: U8Input>(i: I) -> SimpleResult<I,u8>
// {
//   token(i, b',')
// }

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn operation_type<I: U8Input>(i: I) -> SimpleResult<I,OperationType>
// {
//   let op_type = |i,b,r| string(i,b).map(|_| r);
//   parse!{i;
//       op_type(b"query", OperationType::Query) <|>
//       op_type(b"mutation", OperationType::Mutation)
//   }
// }

// pub fn name<I: U8Input>(i: I) -> SimpleResult<I,Name>
// {
//   parse!{i;
//     let start = satisfy(|c| is_alpha(c) || c == b'_');
//     let rest = take_while(|c| is_alphanumeric(c) || c == b'_');

//     ret {
//       let mut start = String::from_utf8(vec![start]).unwrap();
//       let rest = String::from_utf8(rest.to_vec()).unwrap();
//       start.push_str(&rest);
//       start
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

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

    #[test]
    fn test_parse_comment() {
      assert_eq!(comment().parse("#\r\n").map(|x| x.0), Ok('#'));
    }

    #[test]
    fn test_operation_type() {}

    #[test]
    fn test_alias() {}
}
<commit_msg>macros macros macros<commit_after>use std::collections::HashMap;

use std::str::Chars;
use std::iter::FromIterator;
use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream, parser};
use combine::char::{CrLf, Tab, tab, char, crlf};
use combine::combinator::{Many, FnParser, NoneOf, Skip, Or, Token, or, many, none_of};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
    definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
    OperationDefinition(Operation),
    SelectionSetDefinition(SelectionSet),
    FragmentDefinition(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
    op_type: OperationType,
    name: Option<Name>,
    variable_definitions: Vec<VariableDefinition>,
    directives: Vec<Directive>,
}

impl Operation {
    fn new(op_type: OperationType,
           name: Option<Name>,
           variable_definitions: Vec<VariableDefinition>,
           directives: Vec<Directive>)
           -> Operation {
        Operation {
            op_type: op_type,
            name: name,
            variable_definitions: variable_definitions,
            directives: directives,
        }
    }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
    Query,
    Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
    variable: Variable,
    var_type: Type,
    default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
    NamedType(Name),
    ListType(Box<Type>),
    NonNullType(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
    Var(Variable),
    IntValue(i32),
    FloatValue(f32),
    StringValue(String),
    BooleanValue(bool),
    NullValue,
    EnumValue(String),
    ListValue(Vec<Value>),
    ObjectValue(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
    name: Name,
    arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
    name: Name,
    value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
    FieldSelection(Field),
    FragmentSpread(Name, Vec<Directive>),
    InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
    alias: Option<Name>,
    name: Name,
    arguments: Vec<Argument>,
    directives: Vec<Directive>,
    selection_set: SelectionSet,
}

impl Field {
    fn new(alias: Option<Name>,
           name: Name,
           arguments: Vec<Argument>,
           directives: Vec<Directive>,
           selection_set: SelectionSet)
           -> Field {
        Field {
            alias: alias,
            name: name,
            arguments: arguments,
            directives: directives,
            selection_set: selection_set,
        }
    }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
    name: Name,
    type_condition: Type,
    directives: Vec<Directive>,
    selection_set: SelectionSet,
}

// ok wtf is going on here
type WhiteSpace<I> = Or<Token<I>, Tab<I>>;
pub fn white_space<I: Stream<Item = char>>() -> WhiteSpace<I> {
    char(' ').or(tab())
}

// https://doc.rust-lang.org/error-index.html#E0207
// struct LineTerminator<T> {
//   phantom: PhantomData<T>,
// }

// impl<T> LineTerminator<T> {
//   fn new() -> Self {
//     LineTerminator {
//       phantom: PhantomData
//     }
//   }
// }

macro_rules! make_parser_struct {
  ($name: ident) => {
    pub struct $name<T> {
      phantom: PhantomData<T>,
    }

    impl<T> $name<T> {
      fn new() -> Self {
        $name {
          phantom: PhantomData
        }
      }
    }
  }
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };

}

// make_parser_struct!(LineTerminator);

// impl<I> Parser for LineTerminator<I> where I: Stream<Item=char> {
//   type Input = I;
//   type Output = char;

//   fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
//     crlf()
//       .or(char('\r'))
//       .or(char('\n'))
//       .parse_stream(input)
//   }
// }

// make_parser_struct!(Comment);

// impl<I> Parser for Comment<I> where I: Stream<Item=char> {
//   type Input = I;
//   type Output = char;

//   fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
//     char('#')
//       .skip(LineTerminator::new())
//       .parse_stream(input)
//   }
// }

make_parser!(
  LineTerminator(input: char) -> char {
    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
);

make_parser!(
  Comment(input: char) -> char {
    char('#')
      .skip(LineTerminator::new())
      .parse_stream(input)
  }
);

// ok wtf is going on here
// type LineTerminator<I> = Or<Or<CrLf<I>, Token<I>>, Token<I>>;
// pub fn line_terminator<I: Stream<Item = char>>() -> impl Parser<Input=I> {
//     crlf().or(char('\r')).or(char('\n'))
// }

// fn foo<I: Stream<Item = char>>(input: I) -> ParseResult<I::Item, I> {
//   crlf().or(char('\r')).or(char('\n')).parse_stream(input)
// }

// ok wtf is going on here
// type Comment<I> = Skip<Token<I>, LineTerminator<I>>;
// pub fn comment<I: Stream<Item = char>>() -> impl Parser<Input=I>
// {

//   // let lol = line_terminator();

//     char('#')
//         // .skip(many(none_of("".chars())))
//         .skip(LineTerminator::new())
//         // .skip()
// }

// pub fn comma<I: U8Input>(i: I) -> SimpleResult<I,u8>
// {
//   token(i, b',')
// }

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn operation_type<I: U8Input>(i: I) -> SimpleResult<I,OperationType>
// {
//   let op_type = |i,b,r| string(i,b).map(|_| r);
//   parse!{i;
//       op_type(b"query", OperationType::Query) <|>
//       op_type(b"mutation", OperationType::Mutation)
//   }
// }

// pub fn name<I: U8Input>(i: I) -> SimpleResult<I,Name>
// {
//   parse!{i;
//     let start = satisfy(|c| is_alpha(c) || c == b'_');
//     let rest = take_while(|c| is_alphanumeric(c) || c == b'_');

//     ret {
//       let mut start = String::from_utf8(vec![start]).unwrap();
//       let rest = String::from_utf8(rest.to_vec()).unwrap();
//       start.push_str(&rest);
//       start
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

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

    #[test]
    fn test_parse_comment() {
      assert_eq!(Comment::new().parse("#\r\n").map(|x| x.0), Ok('#'));
    }

    #[test]
    fn test_operation_type() {}

    #[test]
    fn test_alias() {}
}
<|endoftext|>