<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsMethods;
use crate::dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsWrap;
use crate::dom::bindings::codegen::UnionTypes::USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::iterable::Iterable;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::weakref::MutableWeakRef;
use crate::dom::globalscope::GlobalScope;
use crate::dom::url::URL;
use dom_struct::dom_struct;
use url::form_urlencoded;

// https://url.spec.whatwg.org/#interface-urlsearchparams
#[dom_struct]
pub struct URLSearchParams {
    reflector_: Reflector,
    // https://url.spec.whatwg.org/#concept-urlsearchparams-list
    list: DomRefCell<Vec<(String, String)>>,
    // https://url.spec.whatwg.org/#concept-urlsearchparams-url-object
    url: MutableWeakRef<URL>,
}

impl URLSearchParams {
    fn new_inherited(url: Option<&URL>) -> URLSearchParams {
        URLSearchParams {
            reflector_: Reflector::new(),
            list: DomRefCell::new(url.map_or(Vec::new(), |url| url.query_pairs())),
            url: MutableWeakRef::new(url),
        }
    }

    pub fn new(global: &GlobalScope, url: Option<&URL>) -> DomRoot<URLSearchParams> {
        reflect_dom_object(
            Box::new(URLSearchParams::new_inherited(url)),
            global,
            URLSearchParamsWrap,
        )
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
    pub fn Constructor(
        global: &GlobalScope,
        init: Option<USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString>,
    ) -> Fallible<DomRoot<URLSearchParams>> {
        // Step 1.
        let query = URLSearchParams::new(global, None);
        match init {
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringSequenceSequence(init)) => {
                // Step 2.

                // Step 2-1.
                if init.iter().any(|pair| pair.len() != 2) {
                    return Err(Error::Type("Sequence initializer must only contain pair elements.".to_string()));
                }

                // Step 2-2.
                *query.list.borrow_mut() =
                    init.iter().map(|pair| (pair[0].to_string(), pair[1].to_string())).collect::<Vec<_>>();
            },
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringUSVStringRecord(init)) => {
                // Step 3.
                *query.list.borrow_mut() =
                    (*init).iter().map(|(name, value)| (name.to_string(), value.to_string())).collect::<Vec<_>>();
            },
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVString(init)) => {
                // Step 4.
                let init_bytes = match init.0.chars().next() {
                    Some(first_char) if first_char == '?' => {
                        let (_, other_bytes) = init.0.as_bytes().split_at(1);

                        other_bytes
                    },
                    _ => init.0.as_bytes(),
                };

                *query.list.borrow_mut() =
                    form_urlencoded::parse(init_bytes).into_owned().collect();
            },
            None => {},
        }

        // Step 5.
        Ok(query)
    }

    pub fn set_list(&self, list: Vec<(String, String)>) {
        *self.list.borrow_mut() = list;
    }
}

impl URLSearchParamsMethods for URLSearchParams {
    // https://url.spec.whatwg.org/#dom-urlsearchparams-append
    fn Append(&self, name: USVString, value: USVString) {
        // Step 1.
        self.list.borrow_mut().push((name.0, value.0));
        // Step 2.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
    fn Delete(&self, name: USVString) {
        // Step 1.
        self.list.borrow_mut().retain(|&(ref k, _)| k != &name.0);
        // Step 2.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-get
    fn Get(&self, name: USVString) -> Option<USVString> {
        let list = self.list.borrow();
        list.iter()
            .find(|&kv| kv.0 == name.0)
            .map(|ref kv| USVString(kv.1.clone()))
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
    fn GetAll(&self, name: USVString) -> Vec<USVString> {
        let list = self.list.borrow();
        list.iter()
            .filter_map(|&(ref k, ref v)| {
                if k == &name.0 {
                    Some(USVString(v.clone()))
                } else {
                    None
                }
            })
            .collect()
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-has
    fn Has(&self, name: USVString) -> bool {
        let list = self.list.borrow();
        list.iter().any(|&(ref k, _)| k == &name.0)
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-set
    fn Set(&self, name: USVString, value: USVString) {
        {
            // Step 1.
            let mut list = self.list.borrow_mut();
            let mut index = None;
            let mut i = 0;
            list.retain(|&(ref k, _)| {
                if index.is_none() {
                    if k == &name.0 {
                        index = Some(i);
                    } else {
                        i += 1;
                    }
                    true
                } else {
                    k != &name.0
                }
            });
            match index {
                Some(index) => list[index].1 = value.0,
                None => list.push((name.0, value.0)), // Step 2.
            };
        } // Un-borrow self.list
          // Step 3.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#stringification-behavior
    fn Stringifier(&self) -> DOMString {
        DOMString::from(self.serialize_utf8())
    }
}

impl URLSearchParams {
    // https://url.spec.whatwg.org/#concept-urlencoded-serializer
    pub fn serialize_utf8(&self) -> String {
        let list = self.list.borrow();
        form_urlencoded::Serializer::new(String::new())
            .extend_pairs(&*list)
            .finish()
    }
}

impl URLSearchParams {
    // https://url.spec.whatwg.org/#concept-urlsearchparams-update
    fn update_steps(&self) {
        if let Some(url) = self.url.root() {
            url.set_query_pairs(&self.list.borrow())
        }
    }
}

impl Iterable for URLSearchParams {
    type Key = USVString;
    type Value = USVString;

    fn get_iterable_length(&self) -> u32 {
        self.list.borrow().len() as u32
    }

    fn get_value_at_index(&self, n: u32) -> USVString {
        let value = self.list.borrow()[n as usize].1.clone();
        USVString(value)
    }

    fn get_key_at_index(&self, n: u32) -> USVString {
        let key = self.list.borrow()[n as usize].0.clone();
        USVString(key)
    }
}
<commit_msg>Combine two `impl`s into one<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsMethods;
use crate::dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsWrap;
use crate::dom::bindings::codegen::UnionTypes::USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::iterable::Iterable;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::weakref::MutableWeakRef;
use crate::dom::globalscope::GlobalScope;
use crate::dom::url::URL;
use dom_struct::dom_struct;
use url::form_urlencoded;

// https://url.spec.whatwg.org/#interface-urlsearchparams
#[dom_struct]
pub struct URLSearchParams {
    reflector_: Reflector,
    // https://url.spec.whatwg.org/#concept-urlsearchparams-list
    list: DomRefCell<Vec<(String, String)>>,
    // https://url.spec.whatwg.org/#concept-urlsearchparams-url-object
    url: MutableWeakRef<URL>,
}

impl URLSearchParams {
    fn new_inherited(url: Option<&URL>) -> URLSearchParams {
        URLSearchParams {
            reflector_: Reflector::new(),
            list: DomRefCell::new(url.map_or(Vec::new(), |url| url.query_pairs())),
            url: MutableWeakRef::new(url),
        }
    }

    pub fn new(global: &GlobalScope, url: Option<&URL>) -> DomRoot<URLSearchParams> {
        reflect_dom_object(
            Box::new(URLSearchParams::new_inherited(url)),
            global,
            URLSearchParamsWrap,
        )
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
    pub fn Constructor(
        global: &GlobalScope,
        init: Option<USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString>,
    ) -> Fallible<DomRoot<URLSearchParams>> {
        // Step 1.
        let query = URLSearchParams::new(global, None);
        match init {
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringSequenceSequence(init)) => {
                // Step 2.

                // Step 2-1.
                if init.iter().any(|pair| pair.len() != 2) {
                    return Err(Error::Type("Sequence initializer must only contain pair elements.".to_string()));
                }

                // Step 2-2.
                *query.list.borrow_mut() =
                    init.iter().map(|pair| (pair[0].to_string(), pair[1].to_string())).collect::<Vec<_>>();
            },
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringUSVStringRecord(init)) => {
                // Step 3.
                *query.list.borrow_mut() =
                    (*init).iter().map(|(name, value)| (name.to_string(), value.to_string())).collect::<Vec<_>>();
            },
            Some(USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVString(init)) => {
                // Step 4.
                let init_bytes = match init.0.chars().next() {
                    Some(first_char) if first_char == '?' => {
                        let (_, other_bytes) = init.0.as_bytes().split_at(1);

                        other_bytes
                    },
                    _ => init.0.as_bytes(),
                };

                *query.list.borrow_mut() =
                    form_urlencoded::parse(init_bytes).into_owned().collect();
            },
            None => {},
        }

        // Step 5.
        Ok(query)
    }

    pub fn set_list(&self, list: Vec<(String, String)>) {
        *self.list.borrow_mut() = list;
    }
}

impl URLSearchParamsMethods for URLSearchParams {
    // https://url.spec.whatwg.org/#dom-urlsearchparams-append
    fn Append(&self, name: USVString, value: USVString) {
        // Step 1.
        self.list.borrow_mut().push((name.0, value.0));
        // Step 2.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
    fn Delete(&self, name: USVString) {
        // Step 1.
        self.list.borrow_mut().retain(|&(ref k, _)| k != &name.0);
        // Step 2.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-get
    fn Get(&self, name: USVString) -> Option<USVString> {
        let list = self.list.borrow();
        list.iter()
            .find(|&kv| kv.0 == name.0)
            .map(|ref kv| USVString(kv.1.clone()))
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
    fn GetAll(&self, name: USVString) -> Vec<USVString> {
        let list = self.list.borrow();
        list.iter()
            .filter_map(|&(ref k, ref v)| {
                if k == &name.0 {
                    Some(USVString(v.clone()))
                } else {
                    None
                }
            })
            .collect()
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-has
    fn Has(&self, name: USVString) -> bool {
        let list = self.list.borrow();
        list.iter().any(|&(ref k, _)| k == &name.0)
    }

    // https://url.spec.whatwg.org/#dom-urlsearchparams-set
    fn Set(&self, name: USVString, value: USVString) {
        {
            // Step 1.
            let mut list = self.list.borrow_mut();
            let mut index = None;
            let mut i = 0;
            list.retain(|&(ref k, _)| {
                if index.is_none() {
                    if k == &name.0 {
                        index = Some(i);
                    } else {
                        i += 1;
                    }
                    true
                } else {
                    k != &name.0
                }
            });
            match index {
                Some(index) => list[index].1 = value.0,
                None => list.push((name.0, value.0)), // Step 2.
            };
        } // Un-borrow self.list
          // Step 3.
        self.update_steps();
    }

    // https://url.spec.whatwg.org/#stringification-behavior
    fn Stringifier(&self) -> DOMString {
        DOMString::from(self.serialize_utf8())
    }
}

impl URLSearchParams {
    // https://url.spec.whatwg.org/#concept-urlencoded-serializer
    pub fn serialize_utf8(&self) -> String {
        let list = self.list.borrow();
        form_urlencoded::Serializer::new(String::new())
            .extend_pairs(&*list)
            .finish()
    }

    // https://url.spec.whatwg.org/#concept-urlsearchparams-update
    fn update_steps(&self) {
        if let Some(url) = self.url.root() {
            url.set_query_pairs(&self.list.borrow())
        }
    }
}

impl Iterable for URLSearchParams {
    type Key = USVString;
    type Value = USVString;

    fn get_iterable_length(&self) -> u32 {
        self.list.borrow().len() as u32
    }

    fn get_value_at_index(&self, n: u32) -> USVString {
        let value = self.list.borrow()[n as usize].1.clone();
        USVString(value)
    }

    fn get_key_at_index(&self, n: u32) -> USVString {
        let key = self.list.borrow()[n as usize].0.clone();
        USVString(key)
    }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015 The Robigalia Project Developers
 * Licensed under the Apache License, Version 2.0
 * <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT
 * license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
 * at your option. All files in the project carrying such
 * notice may not be copied, modified, or distributed except
 * according to those terms.
 */
#![no_std]
#![feature(asm)]
#![feature(thread_local)]
#![allow(bad_style, unused_parens, unused_assignments)]

// NB: this mimics the logic in build.rs
#[cfg(not(any(
    all(target_arch = "arm", target_pointer_width = "32"),
    all(target_arch = "riscv32"),
    all(target_arch = "x86"),
    all(target_arch = "x86_64"),
)))]
use architecture_not_supported_sorry;

pub use seL4_BreakpointAccess::*;
pub use seL4_BreakpointType::*;
pub use seL4_Error::*;
pub use seL4_LookupFailureType::*;
pub use seL4_ObjectType::*;

use core::mem::size_of;

// XXX: These can't be repr(C), but it needs to "match an int" according to the comments on
// SEL4_FORCE_LONG_ENUM. There's no single type that matches in Rust, so it needs to be
// per-architecture. We use a macro to define them all in one whack, with the invoker providing
// only what the size of the enums ought to be. Each arch then invokes it.
macro_rules! error_types {
    ($int_width:ident) => {
        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_Error {
            seL4_NoError = 0,
            seL4_InvalidArgument,
            seL4_InvalidCapability,
            seL4_IllegalOperation,
            seL4_RangeError,
            seL4_AlignmentError,
            seL4_FailedLookup,
            seL4_TruncatedMessage,
            seL4_DeleteFirst,
            seL4_RevokeFirst,
            seL4_NotEnoughMemory,
            // NB: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_LookupFailureType {
            seL4_NoFailure = 0,
            seL4_InvalidRoot,
            seL4_MissingCapability,
            seL4_DepthMismatch,
            seL4_GuardMismatch,
            // XXX: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointType {
            seL4_DataBreakpoint = 0,
            seL4_InstructionBreakpoint,
            seL4_SingleStep,
            seL4_SoftwareBreakRequest,
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointAccess {
            seL4_BreakOnRead = 0,
            seL4_BreakOnWrite,
            seL4_BreakOnReadWrite,
        }
    };
}

// NB: potentially arch-dependent
pub type seL4_Word = usize;
pub type seL4_CPtr = usize;

#[cfg(target_arch = "x86")]
include!("arch/x86.rs");

#[cfg(target_arch = "x86_64")]
include!("arch/x86_64.rs");

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!("arch/arm.rs");

#[cfg(target_arch = "riscv32")]
include!("arch/riscv.rs");

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_invocation.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_invocation.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_invocation.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_invocation.rs"));

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_syscall_stub.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_syscall_stub.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_syscall_stub.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_syscall_stub.rs"));

#[cfg(target_pointer_width = "32")]
include!(concat!(env!("OUT_DIR"), "/types32.rs"));

#[cfg(target_pointer_width = "64")]
include!(concat!(env!("OUT_DIR"), "/types64.rs"));

include!(concat!(env!("OUT_DIR"), "/syscalls.rs"));

// Well-known types from libsel4/include/sel4/types.h

pub type seL4_NodeId = seL4_Word;
pub type seL4_PAddr = seL4_Word;
pub type seL4_Domain = seL4_Word;

pub type seL4_CNode = seL4_CPtr;
pub type seL4_IRQHandler = seL4_CPtr;
pub type seL4_IRQControl = seL4_CPtr;
pub type seL4_TCB = seL4_CPtr;
pub type seL4_Untyped = seL4_CPtr;
pub type seL4_DomainSet = seL4_CPtr;
pub type seL4_SchedContext = seL4_CPtr;
pub type seL4_SchedControl = seL4_CPtr;

// TODO(sleffler): seL4 uses seL4_Uint64 but it's not defined for us
pub type seL4_Time = u64;

pub const seL4_MsgLengthBits: usize = 7;
pub const seL4_MsgMaxLength: usize = 120;
pub const seL4_MsgExtraCapBits: usize = 2;
pub const seL4_MsgMaxExtraCaps: usize = (1usize << seL4_MsgExtraCapBits) - 1;

// Syscall stubs are generated to return seL4_Result unless they return
// an APi struct with an embedded error code. The latter should be replaced
// too but for now we leave it as-is.
pub type seL4_Result = Result<(), seL4_Error>;

// NB: these traits are used by syscall stubs.
impl From<seL4_Error> for seL4_Result {
    fn from(err: seL4_Error) -> seL4_Result {
        if err == seL4_NoError {
            Ok(())
        } else {
            Err(err)
        }
    }
}
// NB: usize works for both 32- and 64-bit architectures
impl From<usize> for seL4_Error {
    fn from(val: usize) -> seL4_Error {
        // TODO(sleffler): 10 is seL4_NotEnoughMemory
        debug_assert!(val <= 10, "Invalid seL4_Error");
        unsafe { ::core::mem::transmute(val) }
    }
}

#[repr(C)]
#[derive(Copy, Debug)]
/// Buffer used to store received IPC messages
pub struct seL4_IPCBuffer {
    /// Message tag
    ///
    /// The kernel does not initialize this.
    pub tag: seL4_MessageInfo,
    /// Message contents
    ///
    /// The kernel only initializes the bytes which were not able to fit into physical registers.
    pub msg: [seL4_Word; seL4_MsgMaxLength],
    /// Arbitrary user data.
    ///
    /// The seL4 C libraries expect this to be a pointer to the IPC buffer in the thread's VSpace.,
    /// but this doesn't really matter.
    pub userData: seL4_Word,
    /// Capabilities to transfer (if sending) or unwrapped badges
    pub caps_or_badges: [seL4_Word; seL4_MsgMaxExtraCaps],
    /// CPtr to a CNode in the thread's CSpace from which to find the receive slot
    pub receiveCNode: seL4_CPtr,
    /// CPtr to the receive slot, relative to receiveCNode
    pub receiveIndex: seL4_CPtr,
    /// Number of bits of receiveIndex to use
    pub receiveDepth: seL4_Word,
}

impl ::core::clone::Clone for seL4_IPCBuffer {
    fn clone(&self) -> Self {
        *self
    }
}

// Bootinfo

// Fixed cap slots for root thread.
pub const seL4_CapNull: seL4_Word = 0; // null cap
pub const seL4_CapInitThreadTCB: seL4_Word = 1; // initial thread's TCB
pub const seL4_CapInitThreadCNode: seL4_Word = 2; // initial thread's root CNode
pub const seL4_CapInitThreadVSpace: seL4_Word = 3; // initial thread's VSpace
pub const seL4_CapIRQControl: seL4_Word = 4; // global IRQ controller
pub const seL4_CapASIDControl: seL4_Word = 5; // global ASID controller
pub const seL4_CapInitThreadASIDPool: seL4_Word = 6; // initial thread's ASID pool
pub const seL4_CapIOPort: seL4_Word = 7; // global IO port (null if not supported)
pub const seL4_CapIOSpace: seL4_Word = 8; // global IO space (null if no IOMMU support)
pub const seL4_CapBootInfoFrame: seL4_Word = 9; // bootinfo frame
pub const seL4_CapInitThreadIPCBuffer: seL4_Word = 10; // initial thread's IPC buffer frame
pub const seL4_CapDomain: seL4_Word = 11; // global domain controller

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// A half-open [start..end) range of slots
pub struct seL4_SlotRegion {
    /// First CNode slot position of the region
    pub start: seL4_Word,
    /// First CNode slot position after the region
    pub end: seL4_Word, /* first CNode slot position AFTER region */
}

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct seL4_UntypedDesc {
    /// Physical address corresponding of the untyped object's backing memory
    pub paddr: seL4_Word,
    pub padding1: u8,
    pub padding2: u8,
    /// log2 size of the region of memory backing the untyped object
    pub sizeBits: u8,
    /// Whether the backing memory corresponds to some device memory
    pub isDevice: u8,
}

// explicitly *not* Copy. the array at the end is tricky to handle.

#[repr(C, packed)]
// #[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
//#[derive(Debug, PartialEq, Eq)]
pub struct seL4_BootInfo {
    /// Length of any additional bootinfo information
    pub extraLen: seL4_Word,
    /// ID [0..numNodes-1] of the current node (0 if uniprocessor)
    pub nodeID: seL4_Word,
    /// Number of seL4 nodes (1 if uniprocessor)
    pub numNodes: seL4_Word,
    /// Number of IOMMU PT levels (0 if no IOMMU support)
    pub numIOPTLevels: seL4_Word,
    /// pointer to root task's IPC buffer */
    pub ipcBuffer: *mut seL4_IPCBuffer,
    /// Empty slots (null caps)
    pub empty: seL4_SlotRegion,
    /// Frames shared between nodes
    pub sharedFrames: seL4_SlotRegion,
    /// Frame caps used for the loaded ELF image of the root task
    pub userImageFrames: seL4_SlotRegion,
    /// PD caps used for the loaded ELF image of the root task
    pub userImagePaging: seL4_SlotRegion,
    /// IOSpace caps for ARM SMMU
    pub ioSpaceCaps: seL4_SlotRegion,
    /// Caps fr anypages used to back the additional bootinfo information
    pub extraBIPages: seL4_SlotRegion,
    /// log2 size of root task's CNode
    pub initThreadCNodeSizeBits: u8,
    /// Root task's domain ID
    pub initThreadDomain: u32,

    #[cfg(feature = "SEL4_CONFIG_KERNEL_MCS")]
    // Caps to sched_control for each node
    pub schedcontrol: seL4_SlotRegion,

    /// Untyped object caps
    pub untyped: seL4_SlotRegion,
    /// Information about each untyped cap
    ///
    /// *Note*! This is actually an array! The actual length depends on kernel configuration which
    /// we have no way of knowing at this point. Use the `untyped_descs` method.
    pub untypedList: seL4_UntypedDesc,
}

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct seL4_BootInfoHeader {
    /// Identifier of the following chunk
    pub id: seL4_Word,
    /// Length of the chunk
    pub len: seL4_Word,
}

impl seL4_BootInfo {
    /// This is safe if you don't mutate the `untyped` field and corrupt its length.
    pub unsafe fn untyped_descs(&self) -> &[seL4_UntypedDesc] {
        let len = self.untyped.end - self.untyped.start;
        // sanity check that the number of untypeds doesn't extend past the end of the page
        debug_assert!(
            len <= (4096 - size_of::<seL4_BootInfo>() + size_of::<seL4_UntypedDesc>())
                / size_of::<seL4_UntypedDesc>()
        );
        core::slice::from_raw_parts(&self.untypedList, len)
    }
}
<commit_msg>sel4-sys: add helper for seL4_UntypedDesc<commit_after>/* Copyright (c) 2015 The Robigalia Project Developers
 * Licensed under the Apache License, Version 2.0
 * <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT
 * license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
 * at your option. All files in the project carrying such
 * notice may not be copied, modified, or distributed except
 * according to those terms.
 */
#![no_std]
#![feature(asm)]
#![feature(thread_local)]
#![allow(bad_style, unused_parens, unused_assignments)]

// NB: this mimics the logic in build.rs
#[cfg(not(any(
    all(target_arch = "arm", target_pointer_width = "32"),
    all(target_arch = "riscv32"),
    all(target_arch = "x86"),
    all(target_arch = "x86_64"),
)))]
use architecture_not_supported_sorry;

pub use seL4_BreakpointAccess::*;
pub use seL4_BreakpointType::*;
pub use seL4_Error::*;
pub use seL4_LookupFailureType::*;
pub use seL4_ObjectType::*;

use core::mem::size_of;

// XXX: These can't be repr(C), but it needs to "match an int" according to the comments on
// SEL4_FORCE_LONG_ENUM. There's no single type that matches in Rust, so it needs to be
// per-architecture. We use a macro to define them all in one whack, with the invoker providing
// only what the size of the enums ought to be. Each arch then invokes it.
macro_rules! error_types {
    ($int_width:ident) => {
        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_Error {
            seL4_NoError = 0,
            seL4_InvalidArgument,
            seL4_InvalidCapability,
            seL4_IllegalOperation,
            seL4_RangeError,
            seL4_AlignmentError,
            seL4_FailedLookup,
            seL4_TruncatedMessage,
            seL4_DeleteFirst,
            seL4_RevokeFirst,
            seL4_NotEnoughMemory,
            // NB: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_LookupFailureType {
            seL4_NoFailure = 0,
            seL4_InvalidRoot,
            seL4_MissingCapability,
            seL4_DepthMismatch,
            seL4_GuardMismatch,
            // XXX: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointType {
            seL4_DataBreakpoint = 0,
            seL4_InstructionBreakpoint,
            seL4_SingleStep,
            seL4_SoftwareBreakRequest,
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointAccess {
            seL4_BreakOnRead = 0,
            seL4_BreakOnWrite,
            seL4_BreakOnReadWrite,
        }
    };
}

// NB: potentially arch-dependent
pub type seL4_Word = usize;
pub type seL4_CPtr = usize;

#[cfg(target_arch = "x86")]
include!("arch/x86.rs");

#[cfg(target_arch = "x86_64")]
include!("arch/x86_64.rs");

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!("arch/arm.rs");

#[cfg(target_arch = "riscv32")]
include!("arch/riscv.rs");

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_invocation.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_invocation.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_invocation.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_invocation.rs"));

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_syscall_stub.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_syscall_stub.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_syscall_stub.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_syscall_stub.rs"));

#[cfg(target_pointer_width = "32")]
include!(concat!(env!("OUT_DIR"), "/types32.rs"));

#[cfg(target_pointer_width = "64")]
include!(concat!(env!("OUT_DIR"), "/types64.rs"));

include!(concat!(env!("OUT_DIR"), "/syscalls.rs"));

// Well-known types from libsel4/include/sel4/types.h

pub type seL4_NodeId = seL4_Word;
pub type seL4_PAddr = seL4_Word;
pub type seL4_Domain = seL4_Word;

pub type seL4_CNode = seL4_CPtr;
pub type seL4_IRQHandler = seL4_CPtr;
pub type seL4_IRQControl = seL4_CPtr;
pub type seL4_TCB = seL4_CPtr;
pub type seL4_Untyped = seL4_CPtr;
pub type seL4_DomainSet = seL4_CPtr;
pub type seL4_SchedContext = seL4_CPtr;
pub type seL4_SchedControl = seL4_CPtr;

// TODO(sleffler): seL4 uses seL4_Uint64 but it's not defined for us
pub type seL4_Time = u64;

pub const seL4_MsgLengthBits: usize = 7;
pub const seL4_MsgMaxLength: usize = 120;
pub const seL4_MsgExtraCapBits: usize = 2;
pub const seL4_MsgMaxExtraCaps: usize = (1usize << seL4_MsgExtraCapBits) - 1;

// Syscall stubs are generated to return seL4_Result unless they return
// an APi struct with an embedded error code. The latter should be replaced
// too but for now we leave it as-is.
pub type seL4_Result = Result<(), seL4_Error>;

// NB: these traits are used by syscall stubs.
impl From<seL4_Error> for seL4_Result {
    fn from(err: seL4_Error) -> seL4_Result {
        if err == seL4_NoError {
            Ok(())
        } else {
            Err(err)
        }
    }
}
// NB: usize works for both 32- and 64-bit architectures
impl From<usize> for seL4_Error {
    fn from(val: usize) -> seL4_Error {
        // TODO(sleffler): 10 is seL4_NotEnoughMemory
        debug_assert!(val <= 10, "Invalid seL4_Error");
        unsafe { ::core::mem::transmute(val) }
    }
}

#[repr(C)]
#[derive(Copy, Debug)]
/// Buffer used to store received IPC messages
pub struct seL4_IPCBuffer {
    /// Message tag
    ///
    /// The kernel does not initialize this.
    pub tag: seL4_MessageInfo,
    /// Message contents
    ///
    /// The kernel only initializes the bytes which were not able to fit into physical registers.
    pub msg: [seL4_Word; seL4_MsgMaxLength],
    /// Arbitrary user data.
    ///
    /// The seL4 C libraries expect this to be a pointer to the IPC buffer in the thread's VSpace.,
    /// but this doesn't really matter.
    pub userData: seL4_Word,
    /// Capabilities to transfer (if sending) or unwrapped badges
    pub caps_or_badges: [seL4_Word; seL4_MsgMaxExtraCaps],
    /// CPtr to a CNode in the thread's CSpace from which to find the receive slot
    pub receiveCNode: seL4_CPtr,
    /// CPtr to the receive slot, relative to receiveCNode
    pub receiveIndex: seL4_CPtr,
    /// Number of bits of receiveIndex to use
    pub receiveDepth: seL4_Word,
}

impl ::core::clone::Clone for seL4_IPCBuffer {
    fn clone(&self) -> Self {
        *self
    }
}

// Bootinfo

// Fixed cap slots for root thread.
pub const seL4_CapNull: seL4_Word = 0; // null cap
pub const seL4_CapInitThreadTCB: seL4_Word = 1; // initial thread's TCB
pub const seL4_CapInitThreadCNode: seL4_Word = 2; // initial thread's root CNode
pub const seL4_CapInitThreadVSpace: seL4_Word = 3; // initial thread's VSpace
pub const seL4_CapIRQControl: seL4_Word = 4; // global IRQ controller
pub const seL4_CapASIDControl: seL4_Word = 5; // global ASID controller
pub const seL4_CapInitThreadASIDPool: seL4_Word = 6; // initial thread's ASID pool
pub const seL4_CapIOPort: seL4_Word = 7; // global IO port (null if not supported)
pub const seL4_CapIOSpace: seL4_Word = 8; // global IO space (null if no IOMMU support)
pub const seL4_CapBootInfoFrame: seL4_Word = 9; // bootinfo frame
pub const seL4_CapInitThreadIPCBuffer: seL4_Word = 10; // initial thread's IPC buffer frame
pub const seL4_CapDomain: seL4_Word = 11; // global domain controller

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// A half-open [start..end) range of slots
pub struct seL4_SlotRegion {
    /// First CNode slot position of the region
    pub start: seL4_Word,
    /// First CNode slot position after the region
    pub end: seL4_Word, /* first CNode slot position AFTER region */
}

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct seL4_UntypedDesc {
    /// Physical address corresponding of the untyped object's backing memory
    pub paddr: seL4_Word,
    pub padding1: u8,
    pub padding2: u8,
    /// log2 size of the region of memory backing the untyped object
    pub sizeBits: u8,
    /// Whether the backing memory corresponds to some device memory
    pub isDevice: u8,
}
impl seL4_UntypedDesc {
    pub fn is_device(&self) -> bool { self.isDevice != 0 }
    pub fn size_bits(&self) -> usize { self.sizeBits as usize }
}

// explicitly *not* Copy. the array at the end is tricky to handle.
// #[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)

#[repr(C, packed)]
pub struct seL4_BootInfo {
    /// Length of any additional bootinfo information
    pub extraLen: seL4_Word,
    /// ID [0..numNodes-1] of the current node (0 if uniprocessor)
    pub nodeID: seL4_Word,
    /// Number of seL4 nodes (1 if uniprocessor)
    pub numNodes: seL4_Word,
    /// Number of IOMMU PT levels (0 if no IOMMU support)
    pub numIOPTLevels: seL4_Word,
    /// pointer to root task's IPC buffer */
    pub ipcBuffer: *mut seL4_IPCBuffer,
    /// Empty slots (null caps)
    pub empty: seL4_SlotRegion,
    /// Frames shared between nodes
    pub sharedFrames: seL4_SlotRegion,
    /// Frame caps used for the loaded ELF image of the root task
    pub userImageFrames: seL4_SlotRegion,
    /// PD caps used for the loaded ELF image of the root task
    pub userImagePaging: seL4_SlotRegion,
    /// IOSpace caps for ARM SMMU
    pub ioSpaceCaps: seL4_SlotRegion,
    /// Caps fr anypages used to back the additional bootinfo information
    pub extraBIPages: seL4_SlotRegion,
    /// log2 size of root task's CNode
    pub initThreadCNodeSizeBits: u8,
    /// Root task's domain ID
    pub initThreadDomain: u32,

    #[cfg(feature = "SEL4_CONFIG_KERNEL_MCS")]
    // Caps to sched_control for each node
    pub schedcontrol: seL4_SlotRegion,

    /// Untyped object caps
    pub untyped: seL4_SlotRegion,
    /// Information about each untyped cap
    ///
    /// *Note*! This is actually an array! The actual length depends on kernel configuration which
    /// we have no way of knowing at this point. Use the `untyped_descs` method.
    pub untypedList: seL4_UntypedDesc,
}

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct seL4_BootInfoHeader {
    /// Identifier of the following chunk
    pub id: seL4_Word,
    /// Length of the chunk
    pub len: seL4_Word,
}

impl seL4_BootInfo {
    /// This is safe if you don't mutate the `untyped` field and corrupt its length.
    pub unsafe fn untyped_descs(&self) -> &[seL4_UntypedDesc] {
        let len = self.untyped.end - self.untyped.start;
        // sanity check that the number of untypeds doesn't extend past the end of the page
        debug_assert!(
            len <= (4096 - size_of::<seL4_BootInfo>() + size_of::<seL4_UntypedDesc>())
                / size_of::<seL4_UntypedDesc>()
        );
        core::slice::from_raw_parts(&self.untypedList, len)
    }
}
<|endoftext|>


<commit_before>use super::protos::{Action, ExplanationPoint,ExplanationPoints};
use scaii_core::{ActionWrapper,ReplayAction};
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::error::Error;
use super::ReplayError;
use prost::Message;

pub struct Explanations {
    pub step_indices: Vec<u32>,
    pub expl_map:  BTreeMap<u32, ExplanationPoint>,
}

pub fn is_empty(explanations_option : &Option<Explanations>) -> bool {
    match explanations_option {
        &None => {
            println!("is_empty()? FOUND NONE");
            true
        }
        &Some(ref explanations) => {
            println!("is_empty()? FOUND SOME:{}", explanations.step_indices.len());
            explanations.step_indices.len() == 0
        }
    }
}
pub fn map_explanations(explanation_points: Vec<ExplanationPoint>) -> Result<Option<Explanations>, Box<Error>> {
    println!("MAPPING EXPL POINTS recieved this many {}", explanation_points.len());
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in explanation_points {
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}

pub fn extract_explanations(replay_actions: Vec<ReplayAction>, r_actions_sans_explanations: &mut Vec<ReplayAction>) -> Result<Vec<ExplanationPoint>, Box<Error>> {
    let mut explanation_points: Vec<ExplanationPoint> = Vec::new();
    for replay_action in replay_actions {
        match replay_action {
            ReplayAction::Delta(action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Delta(new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Keyframe(ser_info, action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Keyframe(ser_info, new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Header(_) => {
                r_actions_sans_explanations.push(replay_action);
            },
        }
    }
    Ok(explanation_points)
}

fn get_serialized_action(action: &Action) -> Result<Vec<u8>, Box<Error>> {
    let mut action_data: Vec<u8> = Vec::new();
    action.encode(&mut action_data)?;
    Ok(action_data)
}

fn extract_explanation_from_action_wrapper(action_wrapper : ActionWrapper, explanation_points : &mut Vec<ExplanationPoint>) -> Result<ActionWrapper, Box<Error>> {
    let data = action_wrapper.serialized_action;
    let action_decode_result = Action::decode(data);
    match action_decode_result {
        Ok(action) =>  {
            match action.explanation_point {
                None => {
                    println!("Explanation?  None");
                },
                Some(explanation_point) => {
                    println!("Explanation?  YES");
                    explanation_points.push(explanation_point);
                },
            }
            // make new Action without Explanation
            let new_action = Action{
                discrete_actions : action.discrete_actions,
                continuous_actions : action.continuous_actions,
                alternate_actions : action.alternate_actions,
                explanation_point : Option::None,
            };
            let mut new_action_data: Vec<u8> = Vec::new();
            new_action.encode(&mut new_action_data)?;
            Ok(ActionWrapper {
                has_explanation: false,
                step: action_wrapper.step,
                title: action_wrapper.title,
                serialized_action: new_action_data,
            })
        }
        Err(err) => {
            Err(Box::new(ReplayError::new("could not decode ActionWrapper during explanation stripping")))
        }
    }
}

pub fn get_explanations_for_replay_file(mut path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    let path_clone = path.clone();
    let filestem_option = path_clone.file_stem();
    match filestem_option {
        Some(os_stem_string) => {
            println!("os_stem_string is {:?}", os_stem_string);
            let filestem: String = os_stem_string.to_str().unwrap().to_string();
            let explanation_filename = format!("{}.exp", filestem);
            path.pop(); // parent dir
            path.push(explanation_filename);
            println!("explanation filepath is {:?}", path);
            get_explanations_for_explanations_file(path)
        },
        None => Ok(None)
    }
}

pub fn get_explanations_for_explanations_file(path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    use std::fs::File;
    use std::io::BufReader;
    use std::io::Read;
    use super::prost::Message;

    if !path.as_path().exists() {
        return Ok(None);
    }
    let replay_file = File::open(path.clone()).expect("file not found");
    let mut bytes : Vec<u8> = Vec::new();
    let mut reader = BufReader::new(replay_file);
    let read_result = reader.read_to_end(&mut bytes);
    match read_result {
        Ok(read_usize) => {
            println!("read this many bytes {:?}", read_usize);
            let explanation_points =
                ExplanationPoints::decode(bytes)?;
           // assert!(explanation_points.explanation_points.len() == 3);
            println!("explanation point count {}", explanation_points.explanation_points.len());
            let explanations_option = get_explanations_for_explanation_points(explanation_points)?;
            Ok(explanations_option)
        },
        Err(err) => {
            return Err(Box::new(ReplayError::new(&format!("ERROR - failed to read explanations file {:?}", path))));
        },
    }
}

fn get_explanations_for_explanation_points(expl_points : ExplanationPoints) -> Result<Option<Explanations>, Box<Error>> {
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in expl_points.explanation_points{
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}<commit_msg>warn rather than assert! over missing explanations<commit_after>use super::protos::{Action, ExplanationPoint,ExplanationPoints};
use scaii_core::{ActionWrapper,ReplayAction};
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::error::Error;
use super::ReplayError;
use prost::Message;

pub struct Explanations {
    pub step_indices: Vec<u32>,
    pub expl_map:  BTreeMap<u32, ExplanationPoint>,
}

pub fn is_empty(explanations_option : &Option<Explanations>) -> bool {
    match explanations_option {
        &None => {
            println!("is_empty()? FOUND NONE");
            true
        }
        &Some(ref explanations) => {
            println!("is_empty()? FOUND SOME:{}", explanations.step_indices.len());
            explanations.step_indices.len() == 0
        }
    }
}
pub fn map_explanations(explanation_points: Vec<ExplanationPoint>) -> Result<Option<Explanations>, Box<Error>> {
    println!("MAPPING EXPL POINTS recieved this many {}", explanation_points.len());
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in explanation_points {
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}

pub fn extract_explanations(replay_actions: Vec<ReplayAction>, r_actions_sans_explanations: &mut Vec<ReplayAction>) -> Result<Vec<ExplanationPoint>, Box<Error>> {
    let mut explanation_points: Vec<ExplanationPoint> = Vec::new();
    for replay_action in replay_actions {
        match replay_action {
            ReplayAction::Delta(action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Delta(new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Keyframe(ser_info, action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Keyframe(ser_info, new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Header(_) => {
                r_actions_sans_explanations.push(replay_action);
            },
        }
    }
    Ok(explanation_points)
}

fn get_serialized_action(action: &Action) -> Result<Vec<u8>, Box<Error>> {
    let mut action_data: Vec<u8> = Vec::new();
    action.encode(&mut action_data)?;
    Ok(action_data)
}

fn extract_explanation_from_action_wrapper(action_wrapper : ActionWrapper, explanation_points : &mut Vec<ExplanationPoint>) -> Result<ActionWrapper, Box<Error>> {
    let data = action_wrapper.serialized_action;
    let action_decode_result = Action::decode(data);
    match action_decode_result {
        Ok(action) =>  {
            match action.explanation {
                None => {
                    println!("Explanation?  None");
                },
                Some(explanation_point) => {
                    println!("Explanation?  YES");
                    explanation_points.push(explanation_point);
                },
            }
            // make new Action without Explanation
            let new_action = Action{
                discrete_actions : action.discrete_actions,
                continuous_actions : action.continuous_actions,
                alternate_actions : action.alternate_actions,
                explanation : Option::None,
            };
            let mut new_action_data: Vec<u8> = Vec::new();
            new_action.encode(&mut new_action_data)?;
            Ok(ActionWrapper {
                has_explanation: false,
                step: action_wrapper.step,
                title: action_wrapper.title,
                serialized_action: new_action_data,
            })
        }
        Err(err) => {
            Err(Box::new(ReplayError::new("could not decode ActionWrapper during explanation stripping")))
        }
    }
}

pub fn get_explanations_for_replay_file(mut path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    let path_clone = path.clone();
    let filestem_option = path_clone.file_stem();
    match filestem_option {
        Some(os_stem_string) => {
            println!("os_stem_string is {:?}", os_stem_string);
            let filestem: String = os_stem_string.to_str().unwrap().to_string();
            let explanation_filename = format!("{}.exp", filestem);
            path.pop(); // parent dir
            path.push(explanation_filename);
            println!("explanation filepath is {:?}", path);
            get_explanations_for_explanations_file(path)
        },
        None => Ok(None)
    }
}

pub fn get_explanations_for_explanations_file(path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    use std::fs::File;
    use std::io::BufReader;
    use std::io::Read;
    use super::prost::Message;

    if !path.as_path().exists() {
        return Ok(None);
    }
    let replay_file = File::open(path.clone()).expect("file not found");
    let mut bytes : Vec<u8> = Vec::new();
    let mut reader = BufReader::new(replay_file);
    let read_result = reader.read_to_end(&mut bytes);
    match read_result {
        Ok(read_usize) => {
            println!("read this many bytes {:?}", read_usize);
            let explanation_points =
                ExplanationPoints::decode(bytes)?;
           // assert!(explanation_points.explanation_points.len() == 3);
            println!("explanation point count {}", explanation_points.explanation_points.len());
            let explanations_option = get_explanations_for_explanation_points(explanation_points)?;
            Ok(explanations_option)
        },
        Err(err) => {
            return Err(Box::new(ReplayError::new(&format!("ERROR - failed to read explanations file {:?}", path))));
        },
    }
}

fn get_explanations_for_explanation_points(expl_points : ExplanationPoints) -> Result<Option<Explanations>, Box<Error>> {
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in expl_points.explanation_points{
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}<|endoftext|>


<commit_before>use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use super::super::{IndyContext, serde_json};

use libindy::wallet::Wallet;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("wallet", "Wallet management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

pub struct OpenCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

pub struct CloseCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new wallet with specified name")
                .add_main_param("name", "The name of new wallet")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet create: >>> execute {:?} while context {:?}", params, self.ctx);
        let pool_name = params.get("pool_name").ok_or((/* TODO error */))?;
        let wallet_name = params.get("name").ok_or((/* TODO error */))?;
        let config: Option<String> = params.get("key").map(|key|
            json!({
                "key": key
            }).to_string());
        Wallet::create_wallet(pool_name,
                              wallet_name,
                              None,
                              config.as_ref().map(String::as_str))
            .map_err(|_| ())?;
        Ok(())
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl OpenCommand {
    pub fn new(ctx: Rc<IndyContext>) -> OpenCommand {
        OpenCommand {
            ctx,
            metadata: CommandMetadata::build("open", "Open wallet with specified name. Also close previously opened.")
                .add_main_param("name", "The name of wallet")
                .finalize()
        }
    }
}

impl Command for OpenCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet open: >>> execute {:?} while context {:?}", params, self.ctx);

        let wallet_name = params.get("name").ok_or((/* TODO error */))?;

        let config: Option<String> =
            if params.contains_key("key")
                || params.contains_key("rekey")
                || params.contains_key("freshness_time") {
                let mut config = serde_json::Map::new();

                for str_config_option in &["key", "rekey"] {
                    if let Some(config_option) = params.get(str_config_option) {
                        config.insert(config_option.to_string(), serde_json::Value::String(config_option.to_string()));
                    }
                }

                if let Some(freshness_time) = params.get("freshness_time") {
                    let freshness_time: i64 = freshness_time.parse().map_err(|_| (/* TODO error */))?;
                    config.insert("freshness_time".to_string(), serde_json::Value::from(freshness_time));
                }

                Some(serde_json::to_string(&serde_json::Value::from(config)).unwrap())
            } else {
                None
            };

        let wallet_handle = Wallet::open_wallet(wallet_name, config.as_ref().map(String::as_str))
            .map_err(|_| ())?;
        //TODO close previously opened wallet
        self.ctx.set_current_wallet(wallet_name, wallet_handle);

        Ok(())
    }
}

impl CloseCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CloseCommand {
        CloseCommand {
            ctx,
            metadata: CommandMetadata::build("close", "Close wallet with specified handle.")
                .add_main_param("handle", "The handle of wallet")
                .finalize()
        }
    }
}

impl Command for CloseCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet close: >>> execute {:?} while context {:?}", params, self.ctx);
        let wallet_handle = self.ctx.get_current_wallet_handle().ok_or((/* TODO error */))?;
        Wallet::close_wallet(wallet_handle).map_err(|_| ())?;
        self.ctx.reset_current_wallet();
        Ok(())
    }
}

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

    use std::cell::RefCell;

    mod create {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = CreateCommand::new(ctx);
            cmd.metadata().help();
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            params.insert("pool_name", "pool");
            cmd.execute(&params).unwrap();
            TestUtils::cleanup_storage();
        }
    }

    mod open {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = OpenCommand::new(ctx);
            let mut params = HashMap::new();
            cmd.metadata().help();
            params.insert("name", "wallet");
            cmd.execute(&params).unwrap_err(); //open not created wallet
            TestUtils::cleanup_storage();
        }

        //TODO add open_for_created_works
    }

    mod close {
        use super::*;

        #[test]
        pub fn exec_for_opened_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));

            let cmd = CreateCommand::new(ctx.clone());
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            params.insert("pool_name", "pool");
            cmd.execute(&params).unwrap();

            let cmd = OpenCommand::new(ctx.clone());
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            cmd.execute(&params).unwrap();

            let cmd = CloseCommand::new(ctx.clone());
            let params = HashMap::new();
            cmd.execute(&params).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}<commit_msg>[cli] Minor wallet close test update.<commit_after>use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use super::super::{IndyContext, serde_json};

use libindy::wallet::Wallet;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("wallet", "Wallet management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

pub struct OpenCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

pub struct CloseCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new wallet with specified name")
                .add_main_param("name", "The name of new wallet")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet create: >>> execute {:?} while context {:?}", params, self.ctx);
        let pool_name = params.get("pool_name").ok_or((/* TODO error */))?;
        let wallet_name = params.get("name").ok_or((/* TODO error */))?;
        let config: Option<String> = params.get("key").map(|key|
            json!({
                "key": key
            }).to_string());
        Wallet::create_wallet(pool_name,
                              wallet_name,
                              None,
                              config.as_ref().map(String::as_str))
            .map_err(|_| ())?;
        Ok(())
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl OpenCommand {
    pub fn new(ctx: Rc<IndyContext>) -> OpenCommand {
        OpenCommand {
            ctx,
            metadata: CommandMetadata::build("open", "Open wallet with specified name. Also close previously opened.")
                .add_main_param("name", "The name of wallet")
                .finalize()
        }
    }
}

impl Command for OpenCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet open: >>> execute {:?} while context {:?}", params, self.ctx);

        let wallet_name = params.get("name").ok_or((/* TODO error */))?;

        let config: Option<String> =
            if params.contains_key("key")
                || params.contains_key("rekey")
                || params.contains_key("freshness_time") {
                let mut config = serde_json::Map::new();

                for str_config_option in &["key", "rekey"] {
                    if let Some(config_option) = params.get(str_config_option) {
                        config.insert(config_option.to_string(), serde_json::Value::String(config_option.to_string()));
                    }
                }

                if let Some(freshness_time) = params.get("freshness_time") {
                    let freshness_time: i64 = freshness_time.parse().map_err(|_| (/* TODO error */))?;
                    config.insert("freshness_time".to_string(), serde_json::Value::from(freshness_time));
                }

                Some(serde_json::to_string(&serde_json::Value::from(config)).unwrap())
            } else {
                None
            };

        let wallet_handle = Wallet::open_wallet(wallet_name, config.as_ref().map(String::as_str))
            .map_err(|_| ())?;
        //TODO close previously opened wallet
        self.ctx.set_current_wallet(wallet_name, wallet_handle);

        Ok(())
    }
}

impl CloseCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CloseCommand {
        CloseCommand {
            ctx,
            metadata: CommandMetadata::build("close", "Close wallet with specified handle.")
                .add_main_param("handle", "The handle of wallet")
                .finalize()
        }
    }
}

impl Command for CloseCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        println!("wallet close: >>> execute {:?} while context {:?}", params, self.ctx);
        let wallet_handle = self.ctx.get_current_wallet_handle().ok_or((/* TODO error */))?;
        Wallet::close_wallet(wallet_handle).map_err(|_| ())?;
        self.ctx.reset_current_wallet();
        Ok(())
    }
}

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

    use std::cell::RefCell;

    mod create {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = CreateCommand::new(ctx);
            cmd.metadata().help();
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            params.insert("pool_name", "pool");
            cmd.execute(&params).unwrap();
            TestUtils::cleanup_storage();
        }
    }

    mod open {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = OpenCommand::new(ctx);
            let mut params = HashMap::new();
            cmd.metadata().help();
            params.insert("name", "wallet");
            cmd.execute(&params).unwrap_err(); //open not created wallet
            TestUtils::cleanup_storage();
        }

        //TODO add open_for_created_works
    }

    mod close {
        use super::*;

        #[test]
        pub fn exec_for_opened_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));

            {
                let cmd = CreateCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                params.insert("pool_name", "pool");
                cmd.execute(&params).unwrap();
            }
            {
                let cmd = OpenCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                cmd.execute(&params).unwrap();
            }

            let cmd = CloseCommand::new(ctx.clone());
            let params = HashMap::new();
            cmd.execute(&params).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}<|endoftext|>


<commit_before>use nom_lua53;
use nom_lua53::Statement;
use nom_lua53::stat_expr_types::Block;
use types::LuaState;
use expression;
use std;
use super::{Result, var_to_string};
use super::types::LuaValue;

pub enum FlowControl {
    None,
    Return(Vec<LuaValue>),
    Break,
}

pub fn exec_statement(stmt: &Statement, ctx: &mut LuaState) -> Result<FlowControl> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            };
            Ok(FlowControl::None)
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
            Ok(FlowControl::None)
        }
        &Statement::Semicolon => {
            Ok(FlowControl::None)
        }
        &Statement::Ite(ref ite) => {
            exec_if_then_else(ite, ctx)
        }
        &Statement::Break => Ok(FlowControl::Break),
        _ => {Ok(FlowControl::None)}
    }
}

pub fn exec_block(block: &Block, ctx: &mut LuaState) -> Result<FlowControl> {
    for stmt in block.stmts.iter() {
        match exec_statement(&stmt, ctx)? {
            FlowControl::Break => return Ok(FlowControl::Break),
            FlowControl::Return(val) => return Ok(FlowControl::Return(val)),
            FlowControl::None => {}
        }
    };
    let ret = if let Some(ref expressions) = block.ret_stmt {
        let mut results = std::vec::Vec::with_capacity(expressions.len());
        for exp in expressions {
            results.push(expression::eval_expr(exp, ctx)?)
        }
        Ok(FlowControl::Return(results))
    } else {
        Ok(FlowControl::None)
    };

    return ret
        }

pub fn exec_if_then_else(ite: &nom_lua53::IfThenElse, ctx: &mut LuaState) -> Result<FlowControl> {
    if expression::boolean_coercion(&expression::eval_expr(&ite.cond, ctx)?) {
        exec_block(&ite.then_blk, ctx)
    } else {
        match ite.elseifs.iter().fold(None,
         |current, &(ref exp, ref block)|
          if current.is_none() {
              match expression::eval_expr(&exp, ctx) {
                  Ok(_) => Some(exec_block(&block, ctx)),
                  Err(err) => Some(Err(err))
              }
          } else { current }) {
              Some(val) => val,
              None => match &ite.else_blk {
                  &Some(ref blk) => exec_block(blk, ctx),
                  &None => Ok(FlowControl::None)
              }
          }
    }
}<commit_msg>Implement scoping<commit_after>use nom_lua53;
use nom_lua53::Statement;
use nom_lua53::stat_expr_types::Block;
use types::LuaState;
use expression;
use std;
use super::{Result, var_to_string};
use super::types::LuaValue;

pub enum FlowControl {
    None,
    Return(Vec<LuaValue>),
    Break,
}

pub fn exec_statement(stmt: &Statement, ctx: &mut LuaState) -> Result<FlowControl> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            };
            Ok(FlowControl::None)
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
            Ok(FlowControl::None)
        }
        &Statement::Semicolon => {
            Ok(FlowControl::None)
        }
        &Statement::Ite(ref ite) => {
            exec_if_then_else(ite, ctx)
        }
        &Statement::Break => Ok(FlowControl::Break),
        _ => {Ok(FlowControl::None)}
    }
}

pub fn exec_block(block: &Block, ctx: &mut LuaState) -> Result<FlowControl> {
    ctx.push_scope();
    for stmt in block.stmts.iter() {
        match exec_statement(&stmt, ctx)? {
            FlowControl::Break => return Ok(FlowControl::Break),
            FlowControl::Return(val) => return Ok(FlowControl::Return(val)),
            FlowControl::None => {}
        }
    };
    let ret = if let Some(ref expressions) = block.ret_stmt {
        let mut results = std::vec::Vec::with_capacity(expressions.len());
        for exp in expressions {
            results.push(expression::eval_expr(exp, ctx)?)
        }
        Ok(FlowControl::Return(results))
    } else {
        Ok(FlowControl::None)
    };

    ctx.pop_scope();
    return ret
}

pub fn exec_if_then_else(ite: &nom_lua53::IfThenElse, ctx: &mut LuaState) -> Result<FlowControl> {
    if expression::boolean_coercion(&expression::eval_expr(&ite.cond, ctx)?) {
        exec_block(&ite.then_blk, ctx)
    } else {
        match ite.elseifs.iter().fold(None,
         |current, &(ref exp, ref block)|
          if current.is_none() {
              match expression::eval_expr(&exp, ctx) {
                  Ok(_) => Some(exec_block(&block, ctx)),
                  Err(err) => Some(Err(err))
              }
          } else { current }) {
              Some(val) => val,
              None => match &ite.else_blk {
                  &Some(ref blk) => exec_block(blk, ctx),
                  &None => Ok(FlowControl::None)
              }
          }
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate interpreter;

#[test]
fn reassign_different_type() {
    run_test!(
        should_warn(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1;
            x = true;
        ");
}

#[test]
fn shadow_function() {
    run_test!(
        should_warn(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            fn x { x*2 }
        ");
}

#[test]
fn call_non_function() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1;
            y = x();
        ");
}

#[test]
fn wrong_num_arguments_named() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f[x=1, y=2, z=3];
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f[];
        ");
}

#[test]
fn wrong_num_arguments_ordered() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f(1, 2, 3);
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f();
        ");
}

#[test]
fn misspelled_argument() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            x = fn[y=5];
        ");
}

#[test]
fn ambiguous_recursion() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { fn(x) }
            y = fn(1);
        ");
}

#[test]
fn wrong_arg_type() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            x = fn(1);
            y = fn(true);
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            z = fn;
            x = z(1);
            y = fn(true);
        ");
}

#[test]
fn wrong_block_type() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = {
                true;
                false;
            };
        ");
}

#[test]
fn non_boolean_condition() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = true if 1 else false;
        ");
}

#[test]
fn reassignment() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = true;
            y = x ^^ true;
            x = 1;
            y = x * 5;
        ");
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = true;
            a { x ^^ true }
            x = 1;
            b { x * 2 }
            w = b();
            z = a();
        ");
}

#[test]
fn variable_not_in_scope() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = a;
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn {
                a = 5;
            }
            x = a;
        ");
}

#[test]
fn mismatched_conditional_types() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1 if true else false;
        ");
}

#[test]
fn wrong_type_numerical_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 + true;
        ");
}

#[test]
fn wrong_type_comparison_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 + true;
        ");
}

#[test]
fn wrong_type_equality_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 == true;
        ");
}

#[test]
fn wrong_type_boolean_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 && true;
        ");
}

#[test]
fn wrong_type_prefix_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = -true;
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = !5;
        ");
}

#[test]
fn internal_block_shadowing_captured_vars() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = 5;
            c = \{x+5};
            z = {
                x = true;
                c();
            };
        ");
}

#[test]
fn default_args_evald_in_new_scope() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = 5;
            fn z=x {
                z%2;
            }
            w = {
                x = true;
                fn();
            };
        ");
}

#[test]
fn default_args() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            fn x, y=3 { x + y }
            a = fn[x=1];
            a = fn[x=1, y=2];
            a = fn[y=1, x=2];
            a = fn(1, 2);
        ");
}

#[test]
fn recursion_numeric() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            a b {
                b;
                a[b-=1] if b > 0 else 0;
            }
            z = a[b=5];
        ");
}

#[test]
fn call_nonexistant_function() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            x = f();
        ");
}

#[test]
fn reference_nonexistant_variable() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            x = f;
        ");
}

#[test]
fn call_default_arg() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            fn d=\e{e} {
                d(5);
            }
            a = fn();
        ");
}

#[test]
fn indirect_recursion() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            a { b() }
            b { a() }
            x = a();
        ");
}

#[test]
fn unused_function() {
    run_test!(
        should_pass(lex, parse),
        should_warn(typecheck)
        => r"
            f x { x }
        ");
}
<commit_msg>Add a test for a weird typechecker bug with recursion, closures, and more recursion.<commit_after>#[macro_use]
extern crate interpreter;

#[test]
fn reassign_different_type() {
    run_test!(
        should_warn(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1;
            x = true;
        ");
}

#[test]
fn shadow_function() {
    run_test!(
        should_warn(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            fn x { x*2 }
        ");
}

#[test]
fn call_non_function() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1;
            y = x();
        ");
}

#[test]
fn wrong_num_arguments_named() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f[x=1, y=2, z=3];
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f[];
        ");
}

#[test]
fn wrong_num_arguments_ordered() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f(1, 2, 3);
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            f x, y=1 { x+y }
            x = f();
        ");
}

#[test]
fn misspelled_argument() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            x = fn[y=5];
        ");
}

#[test]
fn ambiguous_recursion() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { fn(x) }
            y = fn(1);
        ");
}

#[test]
fn wrong_arg_type() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            x = fn(1);
            y = fn(true);
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn x { x }
            z = fn;
            x = z(1);
            y = fn(true);
        ");
}

#[test]
fn wrong_block_type() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = {
                true;
                false;
            };
        ");
}

#[test]
fn non_boolean_condition() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = true if 1 else false;
        ");
}

#[test]
fn reassignment() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = true;
            y = x ^^ true;
            x = 1;
            y = x * 5;
        ");
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = true;
            a { x ^^ true }
            x = 1;
            b { x * 2 }
            w = b();
            z = a();
        ");
}

#[test]
fn variable_not_in_scope() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = a;
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            fn {
                a = 5;
            }
            x = a;
        ");
}

#[test]
fn mismatched_conditional_types() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            x = 1 if true else false;
        ");
}

#[test]
fn wrong_type_numerical_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 + true;
        ");
}

#[test]
fn wrong_type_comparison_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 + true;
        ");
}

#[test]
fn wrong_type_equality_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 == true;
        ");
}

#[test]
fn wrong_type_boolean_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = 5 && true;
        ");
}

#[test]
fn wrong_type_prefix_op() {
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = -true;
        ");
    run_test!(
        should_fail(typecheck),
        should_pass(lex, parse)
        => r"
            a = !5;
        ");
}

#[test]
fn internal_block_shadowing_captured_vars() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = 5;
            c = \{x+5};
            z = {
                x = true;
                c();
            };
        ");
}

#[test]
fn default_args_evald_in_new_scope() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            x = 5;
            fn z=x {
                z%2;
            }
            w = {
                x = true;
                fn();
            };
        ");
}

#[test]
fn default_args() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            fn x, y=3 { x + y }
            a = fn[x=1];
            a = fn[x=1, y=2];
            a = fn[y=1, x=2];
            a = fn(1, 2);
        ");
}

#[test]
fn recursion_numeric() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            a b {
                b;
                a[b-=1] if b > 0 else 0;
            }
            z = a[b=5];
        ");
}

#[test]
fn call_nonexistant_function() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            x = f();
        ");
}

#[test]
fn reference_nonexistant_variable() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            x = f;
        ");
}

#[test]
fn call_default_arg() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            fn d=\e{e} {
                d(5);
            }
            a = fn();
        ");
}

#[test]
fn indirect_recursion() {
    run_test!(
        should_pass(lex, parse),
        should_fail(typecheck)
        => r"
            a { b() }
            b { a() }
            x = a();
        ");
}

#[test]
fn unused_function() {
    run_test!(
        should_pass(lex, parse),
        should_warn(typecheck)
        => r"
            f x { x }
        ");
}

#[test]
fn recursion_closure_issue() {
    run_test!(
        should_pass(lex, parse, typecheck)
        => r"
            fact n {
                n*fact(n-1) if n > 1 else 1;
            }
            summer fn, n {
                fn(n);
                summer(fn, n-1) if n > 0 else 0;
            }
            x = summer(\n { fact(n) }, 5);
        ");
}
<|endoftext|>


<commit_before>
use super::effective_address;
use super::Core;

pub fn ay_pd_8(core: &mut Core) -> u32 {
	let ea = effective_address::predecrement_ay(core);
	core.read_data_byte(ea)
}
pub fn ax_pd_8(core: &mut Core) -> (u32, u32) {
	let ea = effective_address::predecrement_ax(core);
	(core.read_data_byte(ea), ea)
}
pub fn ay_pi_8(core: &mut Core) -> u32 {
	let ea = effective_address::postincrement_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_ai_8(core: &mut Core) -> u32 {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_di_8(core: &mut Core) -> u32 {
	let ea = effective_address::displacement_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_ix_8(core: &mut Core) -> u32 {
	let ea = effective_address::index_ay(core);
	core.read_data_byte(ea)
}
pub fn aw_8(core: &mut Core) -> u32 {
	let ea = effective_address::absolute_word(core);
	core.read_data_byte(ea)
}
pub fn al_8(core: &mut Core) -> u32 {
	let ea = effective_address::absolute_long(core);
	core.read_data_byte(ea)
}
pub fn pcdi_8(core: &mut Core) -> u32 {
	let ea = effective_address::displacement_pc(core);
	core.read_program_byte(ea)
}
pub fn pcix_8(core: &mut Core) -> u32 {
	let ea = effective_address::index_pc(core);
	core.read_program_byte(ea)
}
pub fn imm_8(core: &mut Core) -> u32 {
	let extension = core.read_imm_u16();
	mask_out_above_8!(extension) as u32
}
pub fn dx(core: &mut Core) -> u32 {
	dx!(core)
}
pub fn dy(core: &mut Core) -> u32 {
	dy!(core)
}
#[cfg(test)]
mod tests {
	use super::super::Core;
	use super::{ax_pd_8, ay_pd_8};
	use ram::{AddressBus, SUPERVISOR_DATA};

	#[test]
	fn predecrement_ax() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}
		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;

		assert_eq!(512+4*4, core.dar[8+4]);
		let (dst, ea) = ax_pd_8(core);
		assert_eq!(0x44, dst);
		assert_eq!(512+4*4-1, core.dar[8+4]);
		assert_eq!(512+4*4-1, ea);

		core.ir = 0b1111_1111_1111_1111; // X=7, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		let (dst, ea) = ax_pd_8(core);
		assert_eq!(0x77, dst);
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
		assert_eq!(512+4*7-2, ea);
	}
	#[test]
	fn predecrement_ay() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;
		assert_eq!(512+4*2, core.dar[8+2]);
		assert_eq!(0x22, ay_pd_8(core));
		assert_eq!(512+4*2-1, core.dar[8+2]);

		core.ir = 0b1111_1011_1111_1111; // X=5, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		assert_eq!(0x77, ay_pd_8(core));
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
	}
}
<commit_msg>Add ax, ay as operators for consistency<commit_after>
use super::effective_address;
use super::Core;

pub fn ay_pd_8(core: &mut Core) -> u32 {
	let ea = effective_address::predecrement_ay(core);
	core.read_data_byte(ea)
}
pub fn ax_pd_8(core: &mut Core) -> (u32, u32) {
	let ea = effective_address::predecrement_ax(core);
	(core.read_data_byte(ea), ea)
}
pub fn ay_pi_8(core: &mut Core) -> u32 {
	let ea = effective_address::postincrement_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_ai_8(core: &mut Core) -> u32 {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_di_8(core: &mut Core) -> u32 {
	let ea = effective_address::displacement_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_ix_8(core: &mut Core) -> u32 {
	let ea = effective_address::index_ay(core);
	core.read_data_byte(ea)
}
pub fn aw_8(core: &mut Core) -> u32 {
	let ea = effective_address::absolute_word(core);
	core.read_data_byte(ea)
}
pub fn al_8(core: &mut Core) -> u32 {
	let ea = effective_address::absolute_long(core);
	core.read_data_byte(ea)
}
pub fn pcdi_8(core: &mut Core) -> u32 {
	let ea = effective_address::displacement_pc(core);
	core.read_program_byte(ea)
}
pub fn pcix_8(core: &mut Core) -> u32 {
	let ea = effective_address::index_pc(core);
	core.read_program_byte(ea)
}
pub fn imm_8(core: &mut Core) -> u32 {
	let extension = core.read_imm_u16();
	mask_out_above_8!(extension) as u32
}
pub fn dx(core: &mut Core) -> u32 {
	dx!(core)
}
pub fn dy(core: &mut Core) -> u32 {
	dy!(core)
}
pub fn ax(core: &mut Core) -> u32 {
	ax!(core)
}
pub fn ay(core: &mut Core) -> u32 {
	ay!(core)
}
#[cfg(test)]
mod tests {
	use super::super::Core;
	use super::{ax_pd_8, ay_pd_8};
	use ram::{AddressBus, SUPERVISOR_DATA};

	#[test]
	fn predecrement_ax() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}
		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;

		assert_eq!(512+4*4, core.dar[8+4]);
		let (dst, ea) = ax_pd_8(core);
		assert_eq!(0x44, dst);
		assert_eq!(512+4*4-1, core.dar[8+4]);
		assert_eq!(512+4*4-1, ea);

		core.ir = 0b1111_1111_1111_1111; // X=7, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		let (dst, ea) = ax_pd_8(core);
		assert_eq!(0x77, dst);
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
		assert_eq!(512+4*7-2, ea);
	}
	#[test]
	fn predecrement_ay() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;
		assert_eq!(512+4*2, core.dar[8+2]);
		assert_eq!(0x22, ay_pd_8(core));
		assert_eq!(512+4*2-1, core.dar[8+2]);

		core.ir = 0b1111_1011_1111_1111; // X=5, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		assert_eq!(0x77, ay_pd_8(core));
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
	}
}
<|endoftext|>