<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "alloc_system"]
#![crate_type = "rlib"]
#![no_std]
#![allocator]
#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(staged_api)]
#![cfg_attr(unix, feature(libc))]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe { imp::allocate(size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    unsafe { imp::deallocate(ptr, old_size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    size: usize,
                                    align: usize)
                                    -> *mut u8 {
    unsafe { imp::reallocate(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
                                            old_size: usize,
                                            size: usize,
                                            align: usize)
                                            -> usize {
    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
    imp::usable_size(size, align)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use core::cmp;
    use core::ptr;
    use MIN_ALIGN;

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::malloc(size as libc::size_t) as *mut u8
        } else {
            let mut out = ptr::null_mut();
            let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
            if ret != 0 {
                ptr::null_mut()
            } else {
                out as *mut u8
            }
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            if !new_ptr.is_null() {
                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
                deallocate(ptr, old_size, align);
            }
            new_ptr
        }
    }

    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
                                     old_size: usize,
                                     _size: usize,
                                     _align: usize)
                                     -> usize {
        old_size
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
        libc::free(ptr as *mut libc::c_void)
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}

#[cfg(windows)]
#[allow(bad_style)]
mod imp {
    use MIN_ALIGN;

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
        *get_header(aligned) = Header(ptr);
        aligned
    }

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
        } else {
            let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
            if ptr.is_null() {
                return ptr;
            }
            align_ptr(ptr, align)
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
        } else {
            let header = get_header(ptr);
            let new = HeapReAlloc(GetProcessHeap(),
                                  0,
                                  header.0 as LPVOID,
                                  (size + align) as SIZE_T) as *mut u8;
            if new.is_null() {
                return new;
            }
            align_ptr(new, align)
        }
    }

    pub unsafe fn reallocate_inplace(ptr: *mut u8,
                                     old_size: usize,
                                     size: usize,
                                     align: usize)
                                     -> usize {
        if align <= MIN_ALIGN {
            let new = HeapReAlloc(GetProcessHeap(),
                                  HEAP_REALLOC_IN_PLACE_ONLY,
                                  ptr as LPVOID,
                                  size as SIZE_T) as *mut u8;
            if new.is_null() {
                old_size
            } else {
                size
            }
        } else {
            old_size
        }
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
        if align <= MIN_ALIGN {
            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
            debug_assert!(err != 0);
        } else {
            let header = get_header(ptr);
            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
            debug_assert!(err != 0);
        }
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}
<commit_msg>Rollup merge of #33832 - alexcrichton:android-memalign, r=luqmana<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "alloc_system"]
#![crate_type = "rlib"]
#![no_std]
#![allocator]
#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(staged_api)]
#![cfg_attr(unix, feature(libc))]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe { imp::allocate(size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    unsafe { imp::deallocate(ptr, old_size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    size: usize,
                                    align: usize)
                                    -> *mut u8 {
    unsafe { imp::reallocate(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
                                            old_size: usize,
                                            size: usize,
                                            align: usize)
                                            -> usize {
    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
    imp::usable_size(size, align)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use core::cmp;
    use core::ptr;
    use MIN_ALIGN;

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::malloc(size as libc::size_t) as *mut u8
        } else {
            aligned_malloc(size, align)
        }
    }

    #[cfg(target_os = "android")]
    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
        // On android we currently target API level 9 which unfortunately
        // doesn't have the `posix_memalign` API used below. Instead we use
        // `memalign`, but this unfortunately has the property on some systems
        // where the memory returned cannot be deallocated by `free`!
        //
        // Upon closer inspection, however, this appears to work just fine with
        // Android, so for this platform we should be fine to call `memalign`
        // (which is present in API level 9). Some helpful references could
        // possibly be chromium using memalign [1], attempts at documenting that
        // memalign + free is ok [2] [3], or the current source of chromium
        // which still uses memalign on android [4].
        //
        // [1]: https://codereview.chromium.org/10796020/
        // [2]: https://code.google.com/p/android/issues/detail?id=35391
        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
        //                                       /memory/aligned_memory.cc
        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
    }

    #[cfg(not(target_os = "android"))]
    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
        let mut out = ptr::null_mut();
        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
        if ret != 0 {
            ptr::null_mut()
        } else {
            out as *mut u8
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            if !new_ptr.is_null() {
                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
                deallocate(ptr, old_size, align);
            }
            new_ptr
        }
    }

    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
                                     old_size: usize,
                                     _size: usize,
                                     _align: usize)
                                     -> usize {
        old_size
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
        libc::free(ptr as *mut libc::c_void)
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}

#[cfg(windows)]
#[allow(bad_style)]
mod imp {
    use MIN_ALIGN;

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
        *get_header(aligned) = Header(ptr);
        aligned
    }

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
        } else {
            let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
            if ptr.is_null() {
                return ptr;
            }
            align_ptr(ptr, align)
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
        } else {
            let header = get_header(ptr);
            let new = HeapReAlloc(GetProcessHeap(),
                                  0,
                                  header.0 as LPVOID,
                                  (size + align) as SIZE_T) as *mut u8;
            if new.is_null() {
                return new;
            }
            align_ptr(new, align)
        }
    }

    pub unsafe fn reallocate_inplace(ptr: *mut u8,
                                     old_size: usize,
                                     size: usize,
                                     align: usize)
                                     -> usize {
        if align <= MIN_ALIGN {
            let new = HeapReAlloc(GetProcessHeap(),
                                  HEAP_REALLOC_IN_PLACE_ONLY,
                                  ptr as LPVOID,
                                  size as SIZE_T) as *mut u8;
            if new.is_null() {
                old_size
            } else {
                size
            }
        } else {
            old_size
        }
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
        if align <= MIN_ALIGN {
            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
            debug_assert!(err != 0);
        } else {
            let header = get_header(ptr);
            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
            debug_assert!(err != 0);
        }
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}
<|endoftext|>


<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 http://mozilla.org/MPL/2.0/. */

//! The context within which CSS code is parsed.

use context::QuirksMode;
use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
#[cfg(feature = "gecko")]
use style_traits::{PARSING_MODE_DEFAULT, PARSING_MODE_ALLOW_UNITLESS_LENGTH, PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};

/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_parsing_mode_match() {
    use gecko_bindings::structs;

    macro_rules! check_parsing_modes {
        ( $( $a:ident => $b:ident ),*, ) => {
            if cfg!(debug_assertions) {
                let mut modes = ParsingMode::all();
                $(
                    assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b));
                    modes.remove($b);
                )*
                assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion");
            }
        }
    }

    check_parsing_modes! {
        ParsingMode_Default => PARSING_MODE_DEFAULT,
        ParsingMode_AllowUnitlessLength => PARSING_MODE_ALLOW_UNITLESS_LENGTH,
        ParsingMode_AllowAllNumericValues => PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES,
    }
}

/// The context required to report a parse error.
pub struct ParserErrorContext<'a, R: 'a> {
    /// An error reporter to report syntax errors.
    pub error_reporter: &'a R,
}

/// The data that the parser needs from outside in order to parse a stylesheet.
pub struct ParserContext<'a> {
    /// The `Origin` of the stylesheet, whether it's a user, author or
    /// user-agent stylesheet.
    pub stylesheet_origin: Origin,
    /// The extra data we need for resolving url values.
    pub url_data: &'a UrlExtraData,
    /// The current rule type, if any.
    pub rule_type: Option<CssRuleType>,
    /// The mode to use when parsing.
    pub parsing_mode: ParsingMode,
    /// The quirks mode of this stylesheet.
    pub quirks_mode: QuirksMode,
    /// The currently active namespaces.
    pub namespaces: Option<&'a Namespaces>,
}

impl<'a> ParserContext<'a> {
    /// Create a parser context.
    pub fn new(
        stylesheet_origin: Origin,
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: stylesheet_origin,
            url_data: url_data,
            rule_type: rule_type,
            parsing_mode: parsing_mode,
            quirks_mode: quirks_mode,
            namespaces: None,
        }
    }

    /// Create a parser context for on-the-fly parsing in CSSOM
    pub fn new_for_cssom(
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode
    ) -> ParserContext<'a> {
        Self::new(
            Origin::Author,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
        )
    }

    /// Create a parser context based on a previous context, but with a modified rule type.
    pub fn new_with_rule_type(
        context: &'a ParserContext,
        rule_type: CssRuleType,
        namespaces: &'a Namespaces,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: context.stylesheet_origin,
            url_data: context.url_data,
            rule_type: Some(rule_type),
            parsing_mode: context.parsing_mode,
            quirks_mode: context.quirks_mode,
            namespaces: Some(namespaces),
        }
    }

    /// Get the rule type, which assumes that one is available.
    pub fn rule_type(&self) -> CssRuleType {
        self.rule_type.expect("Rule type expected, but none was found.")
    }

    /// Record a CSS parse error with this context’s error reporting.
    pub fn log_css_error<R>(&self,
                            context: &ParserErrorContext<R>,
                            location: SourceLocation,
                            error: ContextualParseError)
        where R: ParseErrorReporter
    {
        let location = SourceLocation {
            line: location.line,
            column: location.column,
        };
        context.error_reporter.report_error(self.url_data, location, error)
    }

    /// Returns whether this is a chrome stylesheets.
    pub fn in_chrome_stylesheet(&self) -> bool {
        self.url_data.is_chrome()
    }
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
    /// Parse a value of this type.
    ///
    /// Returns an error on failure.
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>>;
}

impl<T> Parse for Vec<T>
where
    T: Parse + OneOrMoreSeparated,
    <T as OneOrMoreSeparated>::S: Separator,
{
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
    }
}

impl Parse for UnicodeRange {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        UnicodeRange::parse(input).map_err(|e| e.into())
    }
}
<commit_msg>Auto merge of #19001 - emilio:cleanup-parser-context, r=upsuper<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 http://mozilla.org/MPL/2.0/. */

//! The context within which CSS code is parsed.

use context::QuirksMode;
use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
#[cfg(feature = "gecko")]
use style_traits::{PARSING_MODE_DEFAULT, PARSING_MODE_ALLOW_UNITLESS_LENGTH, PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};

/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_parsing_mode_match() {
    use gecko_bindings::structs;

    macro_rules! check_parsing_modes {
        ( $( $a:ident => $b:ident ),*, ) => {
            if cfg!(debug_assertions) {
                let mut modes = ParsingMode::all();
                $(
                    assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b));
                    modes.remove($b);
                )*
                assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion");
            }
        }
    }

    check_parsing_modes! {
        ParsingMode_Default => PARSING_MODE_DEFAULT,
        ParsingMode_AllowUnitlessLength => PARSING_MODE_ALLOW_UNITLESS_LENGTH,
        ParsingMode_AllowAllNumericValues => PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES,
    }
}

/// The context required to report a parse error.
pub struct ParserErrorContext<'a, R: 'a> {
    /// An error reporter to report syntax errors.
    pub error_reporter: &'a R,
}

/// The data that the parser needs from outside in order to parse a stylesheet.
pub struct ParserContext<'a> {
    /// The `Origin` of the stylesheet, whether it's a user, author or
    /// user-agent stylesheet.
    pub stylesheet_origin: Origin,
    /// The extra data we need for resolving url values.
    pub url_data: &'a UrlExtraData,
    /// The current rule type, if any.
    pub rule_type: Option<CssRuleType>,
    /// The mode to use when parsing.
    pub parsing_mode: ParsingMode,
    /// The quirks mode of this stylesheet.
    pub quirks_mode: QuirksMode,
    /// The currently active namespaces.
    pub namespaces: Option<&'a Namespaces>,
}

impl<'a> ParserContext<'a> {
    /// Create a parser context.
    pub fn new(
        stylesheet_origin: Origin,
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> Self {
        ParserContext {
            stylesheet_origin,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
            namespaces: None,
        }
    }

    /// Create a parser context for on-the-fly parsing in CSSOM
    pub fn new_for_cssom(
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> Self {
        Self::new(
            Origin::Author,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
        )
    }

    /// Create a parser context based on a previous context, but with a modified rule type.
    pub fn new_with_rule_type(
        context: &'a ParserContext,
        rule_type: CssRuleType,
        namespaces: &'a Namespaces,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: context.stylesheet_origin,
            url_data: context.url_data,
            rule_type: Some(rule_type),
            parsing_mode: context.parsing_mode,
            quirks_mode: context.quirks_mode,
            namespaces: Some(namespaces),
        }
    }

    /// Get the rule type, which assumes that one is available.
    pub fn rule_type(&self) -> CssRuleType {
        self.rule_type.expect("Rule type expected, but none was found.")
    }

    /// Record a CSS parse error with this context’s error reporting.
    pub fn log_css_error<R>(
        &self,
        context: &ParserErrorContext<R>,
        location: SourceLocation,
        error: ContextualParseError,
    )
    where
        R: ParseErrorReporter,
    {
        let location = SourceLocation {
            line: location.line,
            column: location.column,
        };
        context.error_reporter.report_error(self.url_data, location, error)
    }

    /// Returns whether this is a chrome stylesheets.
    pub fn in_chrome_stylesheet(&self) -> bool {
        self.url_data.is_chrome()
    }
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
    /// Parse a value of this type.
    ///
    /// Returns an error on failure.
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>>;
}

impl<T> Parse for Vec<T>
where
    T: Parse + OneOrMoreSeparated,
    <T as OneOrMoreSeparated>::S: Separator,
{
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
    }
}

impl Parse for UnicodeRange {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        UnicodeRange::parse(input).map_err(|e| e.into())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/

#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;

extern crate arena;
extern crate fmt_macros;
#[macro_use] extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate rustc_errors as errors;

pub use rustc::dep_graph;
pub use rustc::hir;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use dep_graph::DepNode;
use hir::map as hir_map;
use rustc::infer::TypeOrigin;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::traits::ProjectionMode;
use session::{config, CompileResult};
use util::common::time;

use syntax::ast;
use syntax::abi::Abi;
use syntax_pos::Span;

use std::cell::RefCell;
use util::nodemap::NodeMap;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
pub mod coherence;
pub mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,

    /// A mapping from method call sites to traits that have that method.
    pub trait_map: hir::TraitMap,

    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,

    /// This stack is used to identify cycles in the user's source.
    /// Note that these cycles can cross multiple items.
    pub stack: RefCell<Vec<collect::AstConvRequest>>,

    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
    assert!(!ty.needs_infer());
    ccx.tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {:?})",
               node_id,
               item_substs);

        assert!(!item_substs.substs.types.needs_infer());

        ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
    }
}

fn require_c_abi_if_variadic(tcx: TyCtxt,
                             decl: &hir::FnDecl,
                             abi: Abi,
                             span: Span) {
    if decl.variadic && abi != Abi::C {
        span_err!(tcx.sess, span, E0045,
                  "variadic function must have C calling convention");
    }
}

fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                origin: TypeOrigin,
                                t1: Ty<'tcx>,
                                t2: Ty<'tcx>)
                                -> bool {
    ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
        if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
            infcx.report_mismatched_types(origin, t1, t2, err);
            false
        } else {
            true
        }
    })
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = tcx.node_id_to_type(main_id);
    match main_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(main_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(_, _, _, _, ref generics, _) => {
                            if let Some(gen_span) = generics.span() {
                                struct_span_err!(ccx.tcx.sess, gen_span, E0131,
                                         "main function is not allowed to have type parameters")
                                    .span_label(gen_span,
                                                &format!("main cannot have type parameters"))
                                    .emit();
                                return;
                            }
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let main_def_id = tcx.map.local_def_id(main_id);
            let substs = tcx.mk_substs(Substs::empty());
            let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: ty::FnConverging(tcx.mk_nil()),
                    variadic: false
                })
            }));

            require_same_types(
                ccx,
                TypeOrigin::MainFunctionType(main_span),
                main_t,
                se_ty);
        }
        _ => {
            span_bug!(main_span,
                      "main has a non-function type: found `{}`",
                      main_t);
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = tcx.node_id_to_type(start_id);
    match start_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(start_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(_,_,_,_,ref ps,_)
                        if ps.is_parameterized() => {
                            struct_span_err!(tcx.sess, start_span, E0132,
                                "start function is not allowed to have type parameters")
                                .span_label(ps.span().unwrap(),
                                            &format!("start function cannot have type parameters"))
                                .emit();
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let start_def_id = ccx.tcx.map.local_def_id(start_id);
            let substs = tcx.mk_substs(Substs::empty());
            let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec!(
                        tcx.types.isize,
                        tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                    ),
                    output: ty::FnConverging(tcx.types.isize),
                    variadic: false,
                }),
            }));

            require_same_types(
                ccx,
                TypeOrigin::StartFunctionType(start_span),
                start_t,
                se_ty);
        }
        _ => {
            span_bug!(start_span,
                      "start has a non-function type: found `{}`",
                      start_t);
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
    if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
        match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => bug!("entry function without a type")
        }
    }
}

pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             trait_map: hir::TraitMap)
                             -> CompileResult {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        trait_map: trait_map,
        all_traits: RefCell::new(None),
        stack: RefCell::new(Vec::new()),
        tcx: tcx
    };

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.track_errors(|| {
        time(time_passes, "type collecting", ||
             collect::collect_item_types(&ccx));

    })?;

    time(time_passes, "variance inference", ||
         variance::infer_variance(tcx));

    tcx.sess.track_errors(|| {
      time(time_passes, "coherence checking", ||
          coherence::check_coherence(&ccx));
    })?;

    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;

    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;

    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;

    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;

    check_unused::check_crate(tcx);
    check_for_entry_fn(&ccx);

    let err_count = tcx.sess.err_count();
    if err_count == 0 {
        Ok(())
    } else {
        Err(err_count)
    }
}

__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<commit_msg>Rollup merge of #35477 - GuillaumeGomez:fix_E0132, r=jonathandturner<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/

#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;

extern crate arena;
extern crate fmt_macros;
#[macro_use] extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate rustc_errors as errors;

pub use rustc::dep_graph;
pub use rustc::hir;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use dep_graph::DepNode;
use hir::map as hir_map;
use rustc::infer::TypeOrigin;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::traits::ProjectionMode;
use session::{config, CompileResult};
use util::common::time;

use syntax::ast;
use syntax::abi::Abi;
use syntax_pos::Span;

use std::cell::RefCell;
use util::nodemap::NodeMap;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
pub mod coherence;
pub mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,

    /// A mapping from method call sites to traits that have that method.
    pub trait_map: hir::TraitMap,

    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,

    /// This stack is used to identify cycles in the user's source.
    /// Note that these cycles can cross multiple items.
    pub stack: RefCell<Vec<collect::AstConvRequest>>,

    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
    assert!(!ty.needs_infer());
    ccx.tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {:?})",
               node_id,
               item_substs);

        assert!(!item_substs.substs.types.needs_infer());

        ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
    }
}

fn require_c_abi_if_variadic(tcx: TyCtxt,
                             decl: &hir::FnDecl,
                             abi: Abi,
                             span: Span) {
    if decl.variadic && abi != Abi::C {
        span_err!(tcx.sess, span, E0045,
                  "variadic function must have C calling convention");
    }
}

fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                origin: TypeOrigin,
                                t1: Ty<'tcx>,
                                t2: Ty<'tcx>)
                                -> bool {
    ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
        if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
            infcx.report_mismatched_types(origin, t1, t2, err);
            false
        } else {
            true
        }
    })
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = tcx.node_id_to_type(main_id);
    match main_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(main_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(_, _, _, _, ref generics, _) => {
                            if let Some(gen_span) = generics.span() {
                                struct_span_err!(ccx.tcx.sess, gen_span, E0131,
                                         "main function is not allowed to have type parameters")
                                    .span_label(gen_span,
                                                &format!("main cannot have type parameters"))
                                    .emit();
                                return;
                            }
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let main_def_id = tcx.map.local_def_id(main_id);
            let substs = tcx.mk_substs(Substs::empty());
            let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: ty::FnConverging(tcx.mk_nil()),
                    variadic: false
                })
            }));

            require_same_types(
                ccx,
                TypeOrigin::MainFunctionType(main_span),
                main_t,
                se_ty);
        }
        _ => {
            span_bug!(main_span,
                      "main has a non-function type: found `{}`",
                      main_t);
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = tcx.node_id_to_type(start_id);
    match start_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(start_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(_,_,_,_,ref ps,_)
                        if ps.is_parameterized() => {
                            let sp = if let Some(sp) = ps.span() { sp } else { start_span };
                            struct_span_err!(tcx.sess, sp, E0132,
                                "start function is not allowed to have type parameters")
                                .span_label(sp,
                                            &format!("start function cannot have type parameters"))
                                .emit();
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let start_def_id = ccx.tcx.map.local_def_id(start_id);
            let substs = tcx.mk_substs(Substs::empty());
            let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec!(
                        tcx.types.isize,
                        tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                    ),
                    output: ty::FnConverging(tcx.types.isize),
                    variadic: false,
                }),
            }));

            require_same_types(
                ccx,
                TypeOrigin::StartFunctionType(start_span),
                start_t,
                se_ty);
        }
        _ => {
            span_bug!(start_span,
                      "start has a non-function type: found `{}`",
                      start_t);
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
    if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
        match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => bug!("entry function without a type")
        }
    }
}

pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             trait_map: hir::TraitMap)
                             -> CompileResult {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        trait_map: trait_map,
        all_traits: RefCell::new(None),
        stack: RefCell::new(Vec::new()),
        tcx: tcx
    };

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.track_errors(|| {
        time(time_passes, "type collecting", ||
             collect::collect_item_types(&ccx));

    })?;

    time(time_passes, "variance inference", ||
         variance::infer_variance(tcx));

    tcx.sess.track_errors(|| {
      time(time_passes, "coherence checking", ||
          coherence::check_coherence(&ccx));
    })?;

    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;

    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;

    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;

    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;

    check_unused::check_crate(tcx);
    check_for_entry_fn(&ccx);

    let err_count = tcx.sess.err_count();
    if err_count == 0 {
        Ok(())
    } else {
        Err(err_count)
    }
}

__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<|endoftext|>


<commit_before>//!-----------------------------------------------------------------------------------------------
//!`src/io/interrupt/mod.rs`
//!
//!Structures for manipulating the IDT.
//!-----------------------------------------------------------------------------------------------

pub mod keyboard;

use io::cpuio::Port;
use io::display::*;
use core::fmt::Write;

#[repr(C, packed)]
pub struct IDTEntry {
	offset_low: u16,
	selector: u16,
	zero1: u8,
	type_attr: u8,
	offset_mid: u16,
	offset_high: u32,
	zero2: u32,
}

impl IDTEntry {
	pub fn new(offset: usize, selector: u16, type_attr: u8) -> IDTEntry{
		IDTEntry {
			offset_low: (offset & 0xffff) as u16,
			selector: selector,
			zero1: 0,
			type_attr: type_attr,
			offset_mid: ((offset & 0xffff0000) >> 16) as u16,
			offset_high: ((offset & 0xffffffff00000000) >> 32) as u32,
			zero2: 0
		}
	}
}

#[repr(C, packed)]
pub struct IDTR {
	limit: u16,
	offset: u64,
}

impl IDTR {
	pub fn new(limit: u16, offset: u64) -> IDTR {
		IDTR {limit: limit, offset: offset}
	}
}

pub fn init_idt() {
	let mut term = terminal::Terminal::new();

	let kb_addr: usize;
	unsafe {
		kb_addr = asm_kb_handler as *const () as usize;
	}

	let idt = IDTEntry::new(kb_addr, 0x8, 0x8e);

	let init1 = Port::new(0x20);
	let init2 = Port::new(0xA0);
	let cfg1 = Port::new(0x21);
	let cfg2 = Port::new(0xA1);

	//Start config
	init1.outb(0x11);
	init2.outb(0x11);

	cfg1.outb(0x20);
	cfg2.outb(0x28);

	cfg1.outb(0x00);
	cfg2.outb(0x00);

	cfg1.outb(0x01);
	cfg2.outb(0x01);

	cfg1.outb(0xff);
	cfg2.outb(0xff);

	let idt_addr: usize;
	unsafe {idt_addr = &idt as *const _ as usize;}
	let idtr = IDTR::new(12 as u16, idt_addr as u64);

	term.newline();
	term.newline();
	write!(term, "idt_addr {}", idt_addr);

	unsafe {
		asm_lidt(&idtr as *const _ as u64);
	}

	cfg1.outb(0xfd);
}

//Assembly interrupt wrappers
extern {
	fn asm_lidt(idtr: u64);
	fn asm_kb_handler();
}
<commit_msg>Fixed idtr length<commit_after>//!-----------------------------------------------------------------------------------------------
//!`src/io/interrupt/mod.rs`
//!
//!Structures for manipulating the IDT.
//!-----------------------------------------------------------------------------------------------

pub mod keyboard;

use io::cpuio::Port;
use io::display::*;
use core::fmt::Write;

#[repr(C, packed)]
pub struct IDTEntry {
	offset_low: u16,
	selector: u16,
	zero1: u8,
	type_attr: u8,
	offset_mid: u16,
	offset_high: u32,
	zero2: u32,
}

impl IDTEntry {
	pub fn new(offset: usize, selector: u16, type_attr: u8) -> IDTEntry{
		IDTEntry {
			offset_low: (offset & 0xffff) as u16,
			selector: selector,
			zero1: 0,
			type_attr: type_attr,
			offset_mid: ((offset & 0xffff0000) >> 16) as u16,
			offset_high: ((offset & 0xffffffff00000000) >> 32) as u32,
			zero2: 0
		}
	}
}

#[repr(C, packed)]
pub struct IDTR {
	limit: u16,
	offset: u64,
}

impl IDTR {
	pub fn new(limit: u16, offset: u64) -> IDTR {
		IDTR {limit: limit, offset: offset}
	}
}

pub fn init_idt() {
	let mut term = terminal::Terminal::new();

	let kb_addr: usize;
	unsafe {
		kb_addr = asm_kb_handler as *const () as usize;
	}

	let idt = IDTEntry::new(kb_addr, 0x8, 0x8e);

	let init1 = Port::new(0x20);
	let init2 = Port::new(0xA0);
	let cfg1 = Port::new(0x21);
	let cfg2 = Port::new(0xA1);

	//Start config
	init1.outb(0x11);
	init2.outb(0x11);

	cfg1.outb(0x20);
	cfg2.outb(0x28);

	cfg1.outb(0x00);
	cfg2.outb(0x00);

	cfg1.outb(0x01);
	cfg2.outb(0x01);

	cfg1.outb(0xff);
	cfg2.outb(0xff);

	let idt_addr: usize;
	unsafe {idt_addr = &idt as *const _ as usize;}
	let idtr = IDTR::new(0x10 as u16, idt_addr as u64);

	term.newline();
	term.newline();
	write!(term, "idt_addr {}", idt_addr);

	unsafe {
		asm_lidt(&idtr as *const _ as u64);
	}

	cfg1.outb(0xfd);
}

//Assembly interrupt wrappers
extern {
	fn asm_lidt(idtr: u64);
	fn asm_kb_handler();
}
<|endoftext|>


<commit_before>extern crate sodiumoxide;
extern crate num_traits;
extern crate env_logger;
extern crate godcoin;
extern crate futures;
extern crate tokio;
extern crate ctrlc;
extern crate dirs;
extern crate clap;

#[macro_use]
extern crate log;

use clap::{Arg, App, AppSettings, SubCommand};
use std::sync::{Arc, mpsc};
use tokio::prelude::*;
use godcoin::*;

struct StartNode<'a> {
    bind_address: Option<&'a str>,
    minter_key: Option<KeyPair>,
    peers: Option<Vec<&'a str>>
}

fn generate_keypair(shutdown_handle: &mpsc::Sender<()>) {
    let pair = KeyPair::gen_keypair();
    info!("~~ Keys have been generated ~~");
    info!("Private key WIF: {}", pair.1.to_wif());
    info!("Public key WIF: {}", pair.0.to_wif());
    info!("- Make sure the keys are securely stored");
    info!("- Coins cannot be recovered if you lose your private key");
    info!("- Never give private keys to anyone");
    shutdown_handle.send(()).unwrap();
}

fn start_node(node_opts: &StartNode) {
    use godcoin::blockchain::*;
    use std::{env, path::*};

    let home: PathBuf = {
        use dirs;
        let home = env::var("GODCOIN_HOME").map(|s| {
            PathBuf::from(s)
        }).unwrap_or_else(|_| {
            Path::join(&dirs::data_local_dir().unwrap(), "godcoin")
        });
        if !Path::is_dir(&home) {
            let res = std::fs::create_dir(&home);
            res.unwrap_or_else(|_| panic!("Failed to create dir at {:?}", &home));
            info!("Created GODcoin home at {:?}", &home);
        } else {
            info!("Found GODcoin home at {:?}", &home);
        }
        home
    };

    let mut blockchain = Blockchain::new(&home);
    {
        let create_genesis = blockchain.get_block(0).is_none();
        if create_genesis && node_opts.minter_key.is_some() {
            if let Some(ref key) = node_opts.minter_key {
                blockchain.create_genesis_block(key);
            }
        }
    }

    info!("Using height in block log at {}", blockchain.get_chain_height());

    if let Some(ref key) = node_opts.minter_key {
        let bond = blockchain.get_bond(&key.0).expect("No bond found for minter key");
        let minter = key.clone();
        let staker = bond.staker;
        let producer = producer::Producer::new(Arc::new(blockchain), minter, staker);
        producer.start_timer();
    }

    if let Some(bind) = node_opts.bind_address {
        let addr = bind.parse()
                        .unwrap_or_else(|_| panic!("Failed to parse address: {:?}", bind));
        net::server::start(&addr);
    }
}

fn main() {
    let env = env_logger::Env::new().filter_or(env_logger::DEFAULT_FILTER_ENV, "godcoin=info");
    env_logger::init_from_env(env);

    godcoin::init().unwrap();
    let app = App::new("godcoin")
                .about("GODcoin core CLI")
                .version(env!("CARGO_PKG_VERSION"))
                .setting(AppSettings::VersionlessSubcommands)
                .setting(AppSettings::SubcommandRequiredElseHelp)
                .subcommand(SubCommand::with_name("keygen")
                            .about("Generates a keypair"))
                .subcommand(SubCommand::with_name("node")
                            .about("Starts the blockchain node service")
                            .arg(Arg::with_name("bind_address")
                                .help("Bind address endpoint (i.e 0.0.0.0:7777)")
                                .long("bind")
                                .value_name("address"))
                            .arg(Arg::with_name("peers")
                                .help("Comma-separated list of peers")
                                .long("peers")
                                .value_delimiter(",")
                                .value_name("peers")
                                .use_delimiter(true))
                            .arg(Arg::with_name("minter_key")
                                .help("Private minting key required to mint")
                                .long("minter-key")
                                .value_name("key")));
    let matches = app.get_matches();

    let (tx, rx) = mpsc::channel::<()>();
    let mut rt = tokio::runtime::Runtime::new().unwrap();

    {
        let tx = tx.clone();
        rt.block_on(future::lazy(move || {
            use ::std::io::{Error, ErrorKind};

            if matches.subcommand_matches("keygen").is_some() {
                generate_keypair(&tx);
            } else if let Some(matches) = matches.subcommand_matches("node") {
                start_node(&StartNode {
                    bind_address: matches.value_of("bind_address"),
                    peers: matches.values_of("peers").map(|p| { p.collect() }),
                    minter_key: matches.value_of("minter_key").map(|s| {
                        godcoin::PrivateKey::from_wif(s)
                            .expect("Failed to parse minter key argument")
                    })
                });
            } else {
                return Err(Error::new(ErrorKind::Other, "Failed to match subcommand"))
            }

            Ok(())
        }).map_err(|err| {
            error!("Startup failure: {:?}", err);
        })).unwrap();
    }

    ctrlc::set_handler(move || {
        println!("Received ctrl-c signal, shutting down...");
        tx.send(()).unwrap();
    }).unwrap();

    rx.recv().unwrap();
    rt.shutdown_now().wait().ok().unwrap();
}
<commit_msg>Support environment variables<commit_after>extern crate sodiumoxide;
extern crate num_traits;
extern crate env_logger;
extern crate godcoin;
extern crate futures;
extern crate tokio;
extern crate ctrlc;
extern crate dirs;
extern crate clap;

#[macro_use]
extern crate log;

use clap::{Arg, App, AppSettings, SubCommand};
use std::sync::{Arc, mpsc};
use tokio::prelude::*;
use godcoin::*;

struct StartNode<'a> {
    bind_address: Option<&'a str>,
    minter_key: Option<KeyPair>,
    peers: Option<Vec<&'a str>>
}

fn generate_keypair(shutdown_handle: &mpsc::Sender<()>) {
    let pair = KeyPair::gen_keypair();
    info!("~~ Keys have been generated ~~");
    info!("Private key WIF: {}", pair.1.to_wif());
    info!("Public key WIF: {}", pair.0.to_wif());
    info!("- Make sure the keys are securely stored");
    info!("- Coins cannot be recovered if you lose your private key");
    info!("- Never give private keys to anyone");
    shutdown_handle.send(()).unwrap();
}

fn start_node(node_opts: &StartNode) {
    use godcoin::blockchain::*;
    use std::{env, path::*};

    let home: PathBuf = {
        use dirs;
        let home = env::var("GODCOIN_HOME").map(|s| {
            PathBuf::from(s)
        }).unwrap_or_else(|_| {
            Path::join(&dirs::data_local_dir().unwrap(), "godcoin")
        });
        if !Path::is_dir(&home) {
            let res = std::fs::create_dir(&home);
            res.unwrap_or_else(|_| panic!("Failed to create dir at {:?}", &home));
            info!("Created GODcoin home at {:?}", &home);
        } else {
            info!("Found GODcoin home at {:?}", &home);
        }
        home
    };

    let mut blockchain = Blockchain::new(&home);
    {
        let create_genesis = blockchain.get_block(0).is_none();
        if create_genesis && node_opts.minter_key.is_some() {
            if let Some(ref key) = node_opts.minter_key {
                blockchain.create_genesis_block(key);
            }
        }
    }

    info!("Using height in block log at {}", blockchain.get_chain_height());

    if let Some(ref key) = node_opts.minter_key {
        let bond = blockchain.get_bond(&key.0).expect("No bond found for minter key");
        let minter = key.clone();
        let staker = bond.staker;
        let producer = producer::Producer::new(Arc::new(blockchain), minter, staker);
        producer.start_timer();
    }

    if let Some(bind) = node_opts.bind_address {
        let addr = bind.parse()
                        .unwrap_or_else(|_| panic!("Failed to parse address: {:?}", bind));
        net::server::start(&addr);
    }
}

fn main() {
    let env = env_logger::Env::new().filter_or(env_logger::DEFAULT_FILTER_ENV, "godcoin=info");
    env_logger::init_from_env(env);

    godcoin::init().unwrap();
    let app = App::new("godcoin")
                .about("GODcoin core CLI")
                .version(env!("CARGO_PKG_VERSION"))
                .setting(AppSettings::VersionlessSubcommands)
                .setting(AppSettings::SubcommandRequiredElseHelp)
                .subcommand(SubCommand::with_name("keygen")
                            .about("Generates a keypair"))
                .subcommand(SubCommand::with_name("node")
                            .about("Starts the blockchain node service")
                            .arg(Arg::with_name("bind_address")
                                .help("Bind address endpoint (i.e 0.0.0.0:7777)")
                                .env("GODCOIN_BIND_ADDRESS")
                                .long("bind")
                                .value_name("address"))
                            .arg(Arg::with_name("peers")
                                .help("Comma-separated list of peers")
                                .env("GODCOIN_PEERS")
                                .long("peers")
                                .value_delimiter(",")
                                .value_name("peers")
                                .use_delimiter(true))
                            .arg(Arg::with_name("minter_key")
                                .help("Private minting key required to mint")
                                .env("GODCOIN_MINTER_KEY")
                                .long("minter-key")
                                .value_name("key")));
    let matches = app.get_matches();

    let (tx, rx) = mpsc::channel::<()>();
    let mut rt = tokio::runtime::Runtime::new().unwrap();

    {
        let tx = tx.clone();
        rt.block_on(future::lazy(move || {
            use ::std::io::{Error, ErrorKind};

            if matches.subcommand_matches("keygen").is_some() {
                generate_keypair(&tx);
            } else if let Some(matches) = matches.subcommand_matches("node") {
                start_node(&StartNode {
                    bind_address: matches.value_of("bind_address"),
                    peers: matches.values_of("peers").map(|p| { p.collect() }),
                    minter_key: matches.value_of("minter_key").map(|s| {
                        godcoin::PrivateKey::from_wif(s)
                            .expect("Failed to parse minter key argument")
                    })
                });
            } else {
                return Err(Error::new(ErrorKind::Other, "Failed to match subcommand"))
            }

            Ok(())
        }).map_err(|err| {
            error!("Startup failure: {:?}", err);
        })).unwrap();
    }

    ctrlc::set_handler(move || {
        println!("Received ctrl-c signal, shutting down...");
        tx.send(()).unwrap();
    }).unwrap();

    rx.recv().unwrap();
    rt.shutdown_now().wait().ok().unwrap();
}
<|endoftext|>


<commit_before>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide](https://developer.arm.com/docs/100067/0610)

#[cfg(test)]
use stdsimd_test::assert_instr;

/// This intrinsic inserts a BKPT instruction into the instruction stream generated by the compiler
///
/// It enables you to include a breakpoint instruction in your Rust code
///
/// `val` is a compile-time constant integer whose range is:
///
/// - `0...65535` if you are compiling source as A32 code.
/// - `0...255` if you are compiling source as T32 code.
///
/// [ARM's documentation](https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic)
///
/// **NOTE**: Due to compiler limitations this function only supports the range `0...255` in A32
/// mode.
#[cfg_attr(test, assert_instr(bkpt, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    constify_imm8!(val, call);
}
<commit_msg>aarch64 support and range validation<commit_after>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide](https://developer.arm.com/docs/100067/0610)

#[cfg(test)]
use stdsimd_test::assert_instr;

/// This intrinsic inserts a BKPT instruction into the instruction stream generated by the compiler
///
/// It enables you to include a breakpoint instruction in your Rust code
///
/// `val` is a compile-time constant integer whose range is:
///
/// - `0...65535` if you are compiling source as A32 or A64 code.
/// - `0...255` if you are compiling source as T32 code.
///
/// [ARM's documentation](https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic)
///
/// **NOTE**: Due to compiler limitations this function only supports the range `0...255` in A32 and
/// A64 mode.
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    #[cfg(target_arch = "arm")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    #[cfg(target_arch = "aarch64")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
        }
    }

    // validate range
    assert!(val >= 0 && val <= 255);

    constify_imm8!(val, call);
}
<|endoftext|>


<commit_before>extern crate config;

use std::collections::{HashMap, HashSet};
use error::PathfinderError;
use self::config::{Config, Value};

fn get_value_from_config_as_str(conf: &HashMap<String, Value>, key: &str) -> String {
    match conf.get(key) {
        Some(value) => value.to_owned().into_str().unwrap(),
        None => String::from("")
    }
}

/// Returns a HashMap so that it contains only mapping from URL into
/// certain Kafka topic.
pub fn extract_endpoints(conf: Box<Config>) -> HashMap<String, String> {
    let mut endpoints = HashMap::new();

    let config_endpoints: Vec<Value> = match conf.get_array("endpoints") {
        Ok(array) => array,
        Err(why) => {
            println!("{}", PathfinderError::SettingsError(why));
            Vec::new()
        }
    };

    for endpoint in &config_endpoints {

        // One the high level you have structure like
        // {"search": {"url": ..., "microservice": ...}},
        // but will be convenient for further processing, if we return
        // {"url": ..., "microservice": ...} instead.
        let configuration = match endpoint.clone().into_table() {
            Ok(table) => {
                let endpoint_name = table.keys().last().unwrap().as_str().clone();
                table[endpoint_name].clone().into_table().unwrap()
            },
            Err(_) => {
                let error = format!("endpoint \"{}\" is invalid.", endpoint);
                println!("{}", PathfinderError::InvalidEndpoint(error));
                continue;
            }
        };

        // Check on required fields
        let mut missing_keys = false;
        let required_fields : HashSet<&str> = ["url", "microservice"].iter().cloned().collect();
        for key in required_fields  {
            if !configuration.contains_key(key) {
                let error = format!("key \"{}\" for {} endpoint is missing.", key, endpoint);
                println!("{}", PathfinderError::InvalidEndpoint(error));
                missing_keys = true;
                break;
            }
        }

        if missing_keys {
            continue;
        }

        let url = get_value_from_config_as_str(&configuration, "url");
        let microservice = get_value_from_config_as_str(&configuration, "microservice");
        endpoints.insert(url, microservice);
    }

    endpoints
}

#[cfg(test)]
mod tests {
    use super::super::config::{get_config};
    use super::{extract_endpoints};

    #[test]
    fn test_extract_endpoints_returns_an_empty_dict_by_default() {
        let conf = get_config(&"");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 0);
    }

    #[test]
    fn test_extract_endpoints_returns_an_empty_dict_for_a_file_without_endpoints() {
        let conf = get_config(&"./tests/files/config_without_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 0);
    }

    #[test]
    fn test_extract_endpoints_returns_dict_for_a_file_with_valid_endpoints() {
        let conf = get_config(&"./tests/files/config_with_valid_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 3);
        assert_eq!(endpoints.contains_key("/api/matchmaking/search"), true);
        assert_eq!(endpoints.contains_key("/api/matchmaking/leaderboard"), true);
        assert_eq!(endpoints.contains_key("/api/matchmaking/player-of-the-game"), true);
    }

    #[test]
    fn test_extract_endpoints_returns_dict_without_invalid_endpoints() {
        let conf = get_config(&"./tests/files/config_with_invalid_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 1);
        assert_eq!(endpoints.contains_key("/api/matchmaking/player-of-the-game"), true);
    }
}
<commit_msg>Implemented Endpoint structure<commit_after>extern crate config;

use std::collections::{HashMap, HashSet};
use error::PathfinderError;
use self::config::{Config, Value};

#[derive(Debug)]
pub struct Endpoint {
    url: String,
    microservice: String
}

impl Endpoint {
    pub fn new(url: &str, microservice: &str) -> Endpoint {
        Endpoint {
            url: url.to_string(),
            microservice: microservice.to_string()
        }
    }
}

fn get_value_from_config_as_str(conf: &HashMap<String, Value>, key: &str) -> String {
    match conf.get(key) {
        Some(value) => value.to_owned().into_str().unwrap(),
        None => String::from("")
    }
}

/// Returns a HashMap so that it contains only mapping from URL into
/// certain Kafka topic.
pub fn extract_endpoints(conf: Box<Config>) -> HashMap<String, Endpoint> {
    let mut endpoints = HashMap::new();

    let config_endpoints: Vec<Value> = match conf.get_array("endpoints") {
        Ok(array) => array,
        Err(why) => {
            println!("{}", PathfinderError::SettingsError(why));
            Vec::new()
        }
    };

    for endpoint in &config_endpoints {

        // One the high level you have structure like
        // {"search": {"url": ..., "microservice": ...}},
        // but will be convenient for further processing, if we return
        // {"url": ..., "microservice": ...} instead.
        let configuration = match endpoint.clone().into_table() {
            Ok(table) => {
                let endpoint_name = table.keys().last().unwrap().as_str().clone();
                table[endpoint_name].clone().into_table().unwrap()
            },
            Err(_) => {
                let error = format!("endpoint \"{}\" is invalid.", endpoint);
                println!("{}", PathfinderError::InvalidEndpoint(error));
                continue;
            }
        };

        // Check on required fields
        let mut missing_keys = false;
        let required_fields : HashSet<&str> = ["url", "microservice"].iter().cloned().collect();
        for key in required_fields  {
            if !configuration.contains_key(key) {
                let error = format!("key \"{}\" for {} endpoint is missing.", key, endpoint);
                println!("{}", PathfinderError::InvalidEndpoint(error));
                missing_keys = true;
                break;
            }
        }

        if missing_keys {
            continue;
        }

        let url = get_value_from_config_as_str(&configuration, "url");
        let microservice = get_value_from_config_as_str(&configuration, "microservice");
        let endpoint = Endpoint::new(&url, &microservice);
        endpoints.insert(url, endpoint);
    }

    endpoints
}

#[cfg(test)]
mod tests {
    use super::super::config::{get_config};
    use super::{extract_endpoints};

    #[test]
    fn test_extract_endpoints_returns_an_empty_dict_by_default() {
        let conf = get_config(&"");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 0);
    }

    #[test]
    fn test_extract_endpoints_returns_an_empty_dict_for_a_file_without_endpoints() {
        let conf = get_config(&"./tests/files/config_without_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 0);
    }

    #[test]
    fn test_extract_endpoints_returns_dict_for_a_file_with_valid_endpoints() {
        let conf = get_config(&"./tests/files/config_with_valid_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 3);
        assert_eq!(endpoints.contains_key("/api/matchmaking/search"), true);
        assert_eq!(endpoints.contains_key("/api/matchmaking/leaderboard"), true);
        assert_eq!(endpoints.contains_key("/api/matchmaking/player-of-the-game"), true);
    }

    #[test]
    fn test_extract_endpoints_returns_dict_without_invalid_endpoints() {
        let conf = get_config(&"./tests/files/config_with_invalid_endpoints.yaml");
        let endpoints = extract_endpoints(conf);
        assert_eq!(endpoints.len(), 1);
        assert_eq!(endpoints.contains_key("/api/matchmaking/player-of-the-game"), true);
    }
}
<|endoftext|>


<commit_before>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)                         -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize)           -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        match *self {
            //  TODO: should some of these nodes cause a state fork?
            Root(ref node)          => node.compile(state),
            SExpr(ref node)         => node.compile(state),
            Name(ref node)          => node.compile(state),
            ListConst(ref node)     => node.compile(state),
            NumConst(ref node)      => node.compile(state),
            BoolConst(ref node)     => node.compile(state),
            CharConst(ref node)     => node.compile(state),
            StringConst(ref node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        let ref token = self.operator.name;
        match token.as_ref() {
            "let" => unimplemented!(),
            ref name if state.chain_contains_key(name) => unimplemented!(),
            name => Err("[error] Unknown identifier")
        }
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl NameNode {
    /// Returns true if this is a keyword
    fn is_kw(&self) -> bool {
        match self.name.as_ref() {
            "access" | "define-syntax" | "macro"  | "and"  | "delay"
            | "make-environment" | "begin"  | "do"| "named-lambda"
            | "bkpt" | "fluid-let" | "or" | "case" | "if" | "quasiquote"
            | "cond" | "in-package" | "quote" | "cons-stream" | "lambda"
            | "scode-quote" | "declare" | "let" | "sequence" | "default-object?"
            | "let*" | "set!" | "define" | "let-syntax" | "the-environment"
            | "define-integrable" | "letrec" | "unassigned?" | "define-macro"
            | "local-declare" | "using-syntax" | "define-structure" => true,
            _ => false
        }
    }
    /// Returns true if this is an arithmetic operator
    fn is_arith(&self) -> bool {
      match self.name.as_ref() {
         "+" | "-" | "*" | "/" | "%" => true,
         _ => false
      }
   }
    /// Returns true if this is a comparison operator
    fn is_cmp(&self) -> bool {
      match self.name.as_ref() {
         "=" | "!=" | ">" | "<" | ">=" | "<=" => true,
         _ => false
      }
   }
}

impl ASTNode for NameNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(&self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<commit_msg>Cleaner pattern match for compiling S-exprs<commit_after>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)                         -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize)           -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        match *self {
            //  TODO: should some of these nodes cause a state fork?
            Root(ref node)          => node.compile(state),
            SExpr(ref node)         => node.compile(state),
            Name(ref node)          => node.compile(state),
            ListConst(ref node)     => node.compile(state),
            NumConst(ref node)      => node.compile(state),
            BoolConst(ref node)     => node.compile(state),
            CharConst(ref node)     => node.compile(state),
            StringConst(ref node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        match self.operator {
            ref op if op.is_arith() => unimplemented!(),
            ref op if op.is_cmp()   => unimplemented!(),
            ref op if op.is_kw()    => unimplemented!(),
            ref op                  => match state.get(&op.name.as_ref()) {
                Some(&(x,y)) => unimplemented!(),
                None         => Err("[error] Unknown identifier!")
            }
        }
        /*let ref token = self.operator.name;
        match token.as_ref() {
            "let" => unimplemented!(),
            ref name if state.chain_contains_key(name) => unimplemented!(),
            name => Err("[error] Unknown identifier")
        }*/
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl NameNode {
    /// Returns true if this is a keyword
    fn is_kw(&self) -> bool {
        match self.name.as_ref() {
            "access" | "define-syntax" | "macro"  | "and"  | "delay"
            | "make-environment" | "begin"  | "do"| "named-lambda"
            | "bkpt" | "fluid-let" | "or" | "case" | "if" | "quasiquote"
            | "cond" | "in-package" | "quote" | "cons-stream" | "lambda"
            | "scode-quote" | "declare" | "let" | "sequence" | "default-object?"
            | "let*" | "set!" | "define" | "let-syntax" | "the-environment"
            | "define-integrable" | "letrec" | "unassigned?" | "define-macro"
            | "local-declare" | "using-syntax" | "define-structure" => true,
            _ => false
        }
    }
    /// Returns true if this is an arithmetic operator
    fn is_arith(&self) -> bool {
      match self.name.as_ref() {
         "+" | "-" | "*" | "/" | "%" => true,
         _ => false
      }
   }
    /// Returns true if this is a comparison operator
    fn is_cmp(&self) -> bool {
      match self.name.as_ref() {
         "=" | "!=" | ">" | "<" | ">=" | "<=" => true,
         _ => false
      }
   }
}

impl ASTNode for NameNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(&self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile<'a>(&'a self, state: SymTable<'a>) -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<|endoftext|>