<commit_before>//! Chomp is a fast monadic-style parser combinator library for the Rust programming language. It was
//! written as the culmination of the experiments detailed in these blog posts:
//!
//! * [Part 1](http://m4rw3r.github.io/parser-combinator-experiments-rust)
//! * [Part 2](http://m4rw3r.github.io/parser-combinator-experiments-errors)
//! * [Part 3](http://m4rw3r.github.io/parser-combinator-experiments-part-3)
//! * [Chomp 0.1 Announcement](http://m4rw3r.github.io/parser-combinators-road-chomp-0-1)
//!
//! For its current capabilities, you will find that Chomp performs consistently as well, if not
//! better, than optimized C parsers, while being vastly more expressive. For an example that
//! builds a performant HTTP parser out of smaller parsers, see
//! [`http_parser.rs`](examples/http_parser.rs).
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! use chomp::prelude::*;
//!
//! #[derive(Debug, Eq, PartialEq)]
//! struct Name<B: Buffer> {
//!     first: B,
//!     last:  B,
//! }
//!
//! fn name<I: U8Input>(i: I) -> SimpleResult<I, Name<I::Buffer>> {
//!     parse!{i;
//!         let first = take_while1(|c| c != b' ');
//!                     token(b' ');  // skipping this char
//!         let last  = take_while1(|c| c != b'\n');
//!
//!         ret Name{
//!             first: first,
//!             last:  last,
//!         }
//!     }
//! }
//!
//! assert_eq!(parse_only(name, "Martin Wernstål\n".as_bytes()), Ok(Name{
//!     first: &b"Martin"[..],
//!     last: "Wernstål".as_bytes()
//! }));
//! # }
//! ```
//!
//! # Usage
//!
//! Chomp's functionality is split between three modules:
//!
//! * `parsers` contains the basic parsers used to parse streams of input.
//! * `combinators` contains functions which take parsers and return new ones.
//! * `primitives` contains the building blocks used to make new parsers. This is advanced usage and
//!   is far more involved than using the pre-existing parsers, but is sometimes unavoidable.
//!
//! A parser is, at its simplest, a function that takes a slice of input and returns a
//! `ParserResult<I, T, E>`, where `I`, `T`, and `E` are the input, output, and error types,
//! respectively. Parsers are usually parameterized over values or other parsers as well, so these
//! appear as extra arguments in the parsing function. As an example, here is the signature of the
//! `token` parser, which matches a particular input.
//!
//! ```ignore
//! fn token<I: Input>(i: I, t: I::Token) -> ParseResult<I, I::Token, Error<I::Token>> { ... }
//! ```
//!
//! Notice that the first argument is an `Input<I>`, and the second argument is some `I`.
//! `Input<I>` is just a datatype over the current state of the parser and a slice of input `I`,
//! and prevents the parser writer from accidentally mutating the state of the parser. Later, when
//! we introduce the `parse!` macro, we will see that using a parser in this macro just means
//! supplying all of the arguments but the input, as so:
//!
//! ```ignore
//! token(b'T');
//! ```
//!
//! Note that you cannot do this outside of the `parse!` macro. `SimpleResult<I, T>` is a
//! convenience type alias over `ParseResult<I, T, Error<u8>>`, and `Error<I>` is just a convenient
//! "default" error type that will be sufficient for most uses. For more sophisticated usage, one
//! can always write a custom error type.
//!
//! A very useful parser is the `satisfy` parser:
//!
//! ```ignore
//! fn satisfy<I: Input, F>(mut i: I, f: F) -> ParseResult<I, I::Token, Error<I::Token>>
//!   where F: FnOnce(I::Token) -> bool { ... }
//! ```
//!
//! Besides the input state, satisfy's only parameter is a predicate function and will succeed only
//! if the next piece of input satisfies the supplied predicate. Here's an example that might be
//! used in the `parse!` macro:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! # use chomp::prelude::*;
//! # let r = parse_only(parser!{
//! satisfy(|c| {
//!     match c {
//!         b'c' | b'h' | b'a' | b'r' => true,
//!         _ => false,
//!     }
//! })
//! # }, b"h");
//! # assert_eq!(r, Ok(b'h'));
//! # }
//! ```
//!
//! This parser will only succeed if the character is one of the characters in "char".
//!
//! Lastly, here is the parser combinator `count`, which will attempt to run a parser a number of
//! times on its input.
//!
//! ```ignore
//! pub fn count<I: Input, T, E, F, U>(i: I, num: usize, p: F) -> ParseResult<I, T, E>
//!   where F: FnMut(I) -> ParseResult<I, U, E>,
//!         T: FromIterator<U> { ... }
//! ```
//!
//! Using parsers is almost entirely done using the `parse!` macro, which enables us to do three
//! distinct things:
//!
//! * Sequence parsers over the remaining input
//! * Store intermediate results into datatypes
//! * Return a datatype at the end, which may be the result of any arbitrary computation over the
//! intermediate results.
//!
//! In other words, just as a normal Rust function usually looks something like this:
//!
//! ```
//! # fn launch_missiles() {}
//! # fn read_number() -> u8 { 3 }
//! fn f() -> (u8, u8, u8) {
//!     let a = read_number();
//!     let b = read_number();
//!     launch_missiles();
//!     return (a, b, a + b);
//! }
//! # assert_eq!(f(), (3, 3, 6));
//! ```
//!
//! A Chomp parser with a similar structure looks like this:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # use chomp::prelude::*;
//! fn f<I: U8Input>(i: I) -> SimpleResult<I, (u8, u8, u8)> {
//!     parse!{i;
//!         let a = digit();
//!         let b = digit();
//!                 string(b"missiles");
//!         ret (a, b, a + b)
//!     }
//! }
//!
//! fn digit<I: U8Input>(i: I) -> SimpleResult<I, u8> {
//!     satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
//! }
//! # fn main() {
//! #     let r = parse_only(f, b"33missiles");
//! #     assert_eq!(r, Ok((3, 3, 6)));
//! # }
//! ```
//!
//! Readers familiar with Haskell or F# will recognize this as a "monadic computation" or
//! "computation expression".
//!
//! You use the `parse!` macro as follows:
//!
//! - Write the input parameter first, with a semicolon.
//! - Write any number of valid parser actions or identifier bindings, where:
//!    - a parser action takes the form `parser(params*)`, with the input parameter omitted.
//!    - an identifier binding takes the form `let identifer = parser(params*);`, with the input
//!      parameter omitted.
//! - Write the final line of the macro, which must always be either a parser action, or a return
//!   statement which takes the form `ret expression`. The type of `expression` becomes the return
//!   type of the entire parser, should it succeed.
//!
//! The entire grammar for the macro is listed elsewhere in this documentation.
//!
//! # Features
//!
//! * `backtrace`:
#![cfg_attr(feature="backtrace", doc = " enabled.")]
#![cfg_attr(not(feature="backtrace"), doc = " disabled (default).")]
//!
//!    This feature enables backtraces for parse-errors, either by calling `Error::trace` or by
//!    printing it using `fmt::Debug`.
//!
//!    This incurs a performance-hit every time a `chomp::parsers` parser fails since a backtrace
//!    must be collected.
//!
//!    In the `dev` and `test` profiles backtraces will always be enabled. This does not incur any
//!    cost when built using the `release` profile unless the `backtrace` feature is enabled.
//!
//! * `noop_error`:
#![cfg_attr(not(feature="noop_error"), doc = " disabled (default).")]
#![cfg_attr(feature="noop_error", doc = " enabled.")]
//!
//!    The built-in `chomp::parsers::Error` type is zero-sized and carry no error-information. This
//!    increases performance somewhat.
//!
//! * `core`:
#![cfg_attr(not(feature="core"), doc = " disabled (default).")]
#![cfg_attr(feature="core", doc = " enabled.")]
//!
//!    Chomp excludes all features which rely on Rust's `std` library, using the `no_std` feature.
//!
//!    Excluded items:
//!
//!     * `ascii::float` support for `type::Buffer` implementations other than `&[u8]`.
//!     * `buffer` module.
//!     * `combinators::choice` combinator.
//!     * `parsers::Error` no longer implements the `std::error::Error` trait.
//!     * `types::Buffer::to_vec`
//!     * `types::Buffer::into_vec`

#![warn(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts,
        unused_import_braces,
        unused_qualifications)]

#![cfg_attr(has_specialization, feature(specialization))]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(
    nonminimal_bool,
    option_unwrap_used,
    print_stdout,
    result_unwrap_used,
    shadow_reuse,
    shadow_same,
    shadow_unrelated,
    single_match_else))]
#![cfg_attr(feature="clippy", allow(inline_always, many_single_char_names))]

#![cfg_attr(all(feature="core", not(test)), no_std)]

/// Inner module to emulate std when using `core`.
///
/// Skipped when using test since we use std for tests.
#[cfg(all(feature = "core", not(test)))]
mod std {
    pub use core::{cell, cmp, fmt, iter, marker, mem, ops, ptr};
}

#[cfg(feature = "tendril")]
extern crate tendril;

#[macro_use]
extern crate bitflags;
extern crate conv;
extern crate either;
extern crate debugtrace;

#[macro_use]
mod macros;
mod parse;

pub mod ascii;
// TODO: Rework buffer module so that at least a part of it can be exposed provided the user
// provides their own buffers allocated from outside.
#[cfg(not(feature="core"))]
pub mod buffer;
pub mod combinators;
pub mod parsers;
pub mod primitives;
pub mod types;

pub use parse::parse_only;
pub use parse::parse_only_str;
pub use parse::run_parser;

/// Basic prelude.
pub mod prelude {
    pub use parsers::{
        any,
        eof,
        not_token,
        peek,
        peek_next,
        run_scanner,
        satisfy,
        satisfy_with,
        scan,
        skip_while,
        string,
        take,
        take_remainder,
        take_till,
        take_while,
        take_while1,
        token,
    };
    pub use parsers::{
        Error,
        SimpleResult,
    };
    pub use combinators::{
        count,
        option,
        or,
        either,
        many,
        many1,
        sep_by,
        sep_by1,
        many_till,
        skip_many,
        skip_many1,
        matched_by,
    };
    pub use types::{
        Buffer,
        Input,
        U8Input,
        ParseResult,
    };

    pub use either::*;
    pub use parse_only;
    pub use parse_only_str;
}
<commit_msg>Added str dependency to core std module<commit_after>//! Chomp is a fast monadic-style parser combinator library for the Rust programming language. It was
//! written as the culmination of the experiments detailed in these blog posts:
//!
//! * [Part 1](http://m4rw3r.github.io/parser-combinator-experiments-rust)
//! * [Part 2](http://m4rw3r.github.io/parser-combinator-experiments-errors)
//! * [Part 3](http://m4rw3r.github.io/parser-combinator-experiments-part-3)
//! * [Chomp 0.1 Announcement](http://m4rw3r.github.io/parser-combinators-road-chomp-0-1)
//!
//! For its current capabilities, you will find that Chomp performs consistently as well, if not
//! better, than optimized C parsers, while being vastly more expressive. For an example that
//! builds a performant HTTP parser out of smaller parsers, see
//! [`http_parser.rs`](examples/http_parser.rs).
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! use chomp::prelude::*;
//!
//! #[derive(Debug, Eq, PartialEq)]
//! struct Name<B: Buffer> {
//!     first: B,
//!     last:  B,
//! }
//!
//! fn name<I: U8Input>(i: I) -> SimpleResult<I, Name<I::Buffer>> {
//!     parse!{i;
//!         let first = take_while1(|c| c != b' ');
//!                     token(b' ');  // skipping this char
//!         let last  = take_while1(|c| c != b'\n');
//!
//!         ret Name{
//!             first: first,
//!             last:  last,
//!         }
//!     }
//! }
//!
//! assert_eq!(parse_only(name, "Martin Wernstål\n".as_bytes()), Ok(Name{
//!     first: &b"Martin"[..],
//!     last: "Wernstål".as_bytes()
//! }));
//! # }
//! ```
//!
//! # Usage
//!
//! Chomp's functionality is split between three modules:
//!
//! * `parsers` contains the basic parsers used to parse streams of input.
//! * `combinators` contains functions which take parsers and return new ones.
//! * `primitives` contains the building blocks used to make new parsers. This is advanced usage and
//!   is far more involved than using the pre-existing parsers, but is sometimes unavoidable.
//!
//! A parser is, at its simplest, a function that takes a slice of input and returns a
//! `ParserResult<I, T, E>`, where `I`, `T`, and `E` are the input, output, and error types,
//! respectively. Parsers are usually parameterized over values or other parsers as well, so these
//! appear as extra arguments in the parsing function. As an example, here is the signature of the
//! `token` parser, which matches a particular input.
//!
//! ```ignore
//! fn token<I: Input>(i: I, t: I::Token) -> ParseResult<I, I::Token, Error<I::Token>> { ... }
//! ```
//!
//! Notice that the first argument is an `Input<I>`, and the second argument is some `I`.
//! `Input<I>` is just a datatype over the current state of the parser and a slice of input `I`,
//! and prevents the parser writer from accidentally mutating the state of the parser. Later, when
//! we introduce the `parse!` macro, we will see that using a parser in this macro just means
//! supplying all of the arguments but the input, as so:
//!
//! ```ignore
//! token(b'T');
//! ```
//!
//! Note that you cannot do this outside of the `parse!` macro. `SimpleResult<I, T>` is a
//! convenience type alias over `ParseResult<I, T, Error<u8>>`, and `Error<I>` is just a convenient
//! "default" error type that will be sufficient for most uses. For more sophisticated usage, one
//! can always write a custom error type.
//!
//! A very useful parser is the `satisfy` parser:
//!
//! ```ignore
//! fn satisfy<I: Input, F>(mut i: I, f: F) -> ParseResult<I, I::Token, Error<I::Token>>
//!   where F: FnOnce(I::Token) -> bool { ... }
//! ```
//!
//! Besides the input state, satisfy's only parameter is a predicate function and will succeed only
//! if the next piece of input satisfies the supplied predicate. Here's an example that might be
//! used in the `parse!` macro:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! # use chomp::prelude::*;
//! # let r = parse_only(parser!{
//! satisfy(|c| {
//!     match c {
//!         b'c' | b'h' | b'a' | b'r' => true,
//!         _ => false,
//!     }
//! })
//! # }, b"h");
//! # assert_eq!(r, Ok(b'h'));
//! # }
//! ```
//!
//! This parser will only succeed if the character is one of the characters in "char".
//!
//! Lastly, here is the parser combinator `count`, which will attempt to run a parser a number of
//! times on its input.
//!
//! ```ignore
//! pub fn count<I: Input, T, E, F, U>(i: I, num: usize, p: F) -> ParseResult<I, T, E>
//!   where F: FnMut(I) -> ParseResult<I, U, E>,
//!         T: FromIterator<U> { ... }
//! ```
//!
//! Using parsers is almost entirely done using the `parse!` macro, which enables us to do three
//! distinct things:
//!
//! * Sequence parsers over the remaining input
//! * Store intermediate results into datatypes
//! * Return a datatype at the end, which may be the result of any arbitrary computation over the
//! intermediate results.
//!
//! In other words, just as a normal Rust function usually looks something like this:
//!
//! ```
//! # fn launch_missiles() {}
//! # fn read_number() -> u8 { 3 }
//! fn f() -> (u8, u8, u8) {
//!     let a = read_number();
//!     let b = read_number();
//!     launch_missiles();
//!     return (a, b, a + b);
//! }
//! # assert_eq!(f(), (3, 3, 6));
//! ```
//!
//! A Chomp parser with a similar structure looks like this:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # use chomp::prelude::*;
//! fn f<I: U8Input>(i: I) -> SimpleResult<I, (u8, u8, u8)> {
//!     parse!{i;
//!         let a = digit();
//!         let b = digit();
//!                 string(b"missiles");
//!         ret (a, b, a + b)
//!     }
//! }
//!
//! fn digit<I: U8Input>(i: I) -> SimpleResult<I, u8> {
//!     satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
//! }
//! # fn main() {
//! #     let r = parse_only(f, b"33missiles");
//! #     assert_eq!(r, Ok((3, 3, 6)));
//! # }
//! ```
//!
//! Readers familiar with Haskell or F# will recognize this as a "monadic computation" or
//! "computation expression".
//!
//! You use the `parse!` macro as follows:
//!
//! - Write the input parameter first, with a semicolon.
//! - Write any number of valid parser actions or identifier bindings, where:
//!    - a parser action takes the form `parser(params*)`, with the input parameter omitted.
//!    - an identifier binding takes the form `let identifer = parser(params*);`, with the input
//!      parameter omitted.
//! - Write the final line of the macro, which must always be either a parser action, or a return
//!   statement which takes the form `ret expression`. The type of `expression` becomes the return
//!   type of the entire parser, should it succeed.
//!
//! The entire grammar for the macro is listed elsewhere in this documentation.
//!
//! # Features
//!
//! * `backtrace`:
#![cfg_attr(feature="backtrace", doc = " enabled.")]
#![cfg_attr(not(feature="backtrace"), doc = " disabled (default).")]
//!
//!    This feature enables backtraces for parse-errors, either by calling `Error::trace` or by
//!    printing it using `fmt::Debug`.
//!
//!    This incurs a performance-hit every time a `chomp::parsers` parser fails since a backtrace
//!    must be collected.
//!
//!    In the `dev` and `test` profiles backtraces will always be enabled. This does not incur any
//!    cost when built using the `release` profile unless the `backtrace` feature is enabled.
//!
//! * `noop_error`:
#![cfg_attr(not(feature="noop_error"), doc = " disabled (default).")]
#![cfg_attr(feature="noop_error", doc = " enabled.")]
//!
//!    The built-in `chomp::parsers::Error` type is zero-sized and carry no error-information. This
//!    increases performance somewhat.
//!
//! * `core`:
#![cfg_attr(not(feature="core"), doc = " disabled (default).")]
#![cfg_attr(feature="core", doc = " enabled.")]
//!
//!    Chomp excludes all features which rely on Rust's `std` library, using the `no_std` feature.
//!
//!    Excluded items:
//!
//!     * `ascii::float` support for `type::Buffer` implementations other than `&[u8]`.
//!     * `buffer` module.
//!     * `combinators::choice` combinator.
//!     * `parsers::Error` no longer implements the `std::error::Error` trait.
//!     * `types::Buffer::to_vec`
//!     * `types::Buffer::into_vec`

#![warn(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts,
        unused_import_braces,
        unused_qualifications)]

#![cfg_attr(has_specialization, feature(specialization))]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(
    nonminimal_bool,
    option_unwrap_used,
    print_stdout,
    result_unwrap_used,
    shadow_reuse,
    shadow_same,
    shadow_unrelated,
    single_match_else))]
#![cfg_attr(feature="clippy", allow(inline_always, many_single_char_names))]

#![cfg_attr(all(feature="core", not(test)), no_std)]

/// Inner module to emulate std when using `core`.
///
/// Skipped when using test since we use std for tests.
#[cfg(all(feature = "core", not(test)))]
mod std {
    pub use core::{cell, cmp, fmt, iter, marker, mem, ops, ptr, str};
}

#[cfg(feature = "tendril")]
extern crate tendril;

#[macro_use]
extern crate bitflags;
extern crate conv;
extern crate either;
extern crate debugtrace;

#[macro_use]
mod macros;
mod parse;

pub mod ascii;
// TODO: Rework buffer module so that at least a part of it can be exposed provided the user
// provides their own buffers allocated from outside.
#[cfg(not(feature="core"))]
pub mod buffer;
pub mod combinators;
pub mod parsers;
pub mod primitives;
pub mod types;

pub use parse::parse_only;
pub use parse::parse_only_str;
pub use parse::run_parser;

/// Basic prelude.
pub mod prelude {
    pub use parsers::{
        any,
        eof,
        not_token,
        peek,
        peek_next,
        run_scanner,
        satisfy,
        satisfy_with,
        scan,
        skip_while,
        string,
        take,
        take_remainder,
        take_till,
        take_while,
        take_while1,
        token,
    };
    pub use parsers::{
        Error,
        SimpleResult,
    };
    pub use combinators::{
        count,
        option,
        or,
        either,
        many,
        many1,
        sep_by,
        sep_by1,
        many_till,
        skip_many,
        skip_many1,
        matched_by,
    };
    pub use types::{
        Buffer,
        Input,
        U8Input,
        ParseResult,
    };

    pub use either::*;
    pub use parse_only;
    pub use parse_only_str;
}
<|endoftext|>


<commit_before>use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token};

ast_enum_of_structs! {
    /// A pattern in a local binding, function signature, match expression, or
    /// various other places.
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Pat {
        /// A pattern that matches any value: `_`.
        pub Wild(PatWild {
            pub underscore_token: Token![_],
        }),

        /// A pattern that binds a new variable: `ref mut binding`.
        pub Ident(PatIdent {
            pub by_ref: Option<Token![ref]>,
            pub mutability: Option<Token![mut]>,
            pub ident: Ident,
        }),

        /// A struct or struct variant pattern: `Variant { x, y, .. }`.
        pub Struct(PatStruct {
            pub path: Path,
            pub brace_token: token::Brace,
            pub fields: Punctuated<FieldPat, Token![,]>,
            pub dot2_token: Option<Token![..]>,
        }),

        /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
        pub TupleStruct(PatTupleStruct {
            pub path: Path,
            pub pat: PatTuple,
        }),

        /// A path pattern like `Color::Red`.
        pub Path(PatPath {
            pub path: Path,
        }),

        /// A tuple pattern: `(a, b)`.
        pub Tuple(PatTuple {
            pub paren_token: token::Paren,
            pub elements: Punctuated<Pat, Token![,]>,
        }),

        /// A reference pattern: `&mut (first, second)`.
        pub Ref(PatRef {
            pub and_token: Token![&],
            pub mutability: Option<Token![mut]>,
            pub pat: Box<Pat>,
        }),
    }
}

ast_struct! {
    /// A single field in a struct pattern.
    ///
    /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
    /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
    pub struct FieldPat {
        pub attrs: Vec<Attribute>,
        pub member: Member,
        pub colon_token: Option<Token![:]>,
        pub pat: Box<Pat>,
    }
}

mod parsing {
    use syn::{
        braced,
        ext::IdentExt,
        parenthesized,
        parse::{Parse, ParseStream, Result},
        punctuated::Punctuated,
        token, Ident, Member, Path, Token,
    };

    use crate::path;

    use super::{
        FieldPat, Pat, PatIdent, PatPath, PatRef, PatStruct, PatTuple, PatTupleStruct, PatWild,
    };

    impl Parse for Pat {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let lookahead = input.lookahead1();
            if lookahead.peek(Token![_]) {
                input.call(pat_wild).map(Pat::Wild)
            } else if input.peek(Ident)
                && ({
                    input.peek2(Token![::])
                        || input.peek2(Token![!])
                        || input.peek2(token::Brace)
                        || input.peek2(token::Paren)
                })
                || input.peek(Token![self]) && input.peek2(Token![::])
                || input.peek(Token![::])
                || input.peek(Token![<])
                || input.peek(Token![Self])
                || input.peek(Token![super])
                || input.peek(Token![extern])
                || input.peek(Token![crate])
            {
                pat_path_or_struct(input)
            } else if input.peek(Token![ref])
                || input.peek(Token![mut])
                || input.peek(Token![self])
                || input.peek(Ident)
            {
                input.call(pat_ident).map(Pat::Ident)
            } else if lookahead.peek(token::Paren) {
                input.call(pat_tuple).map(Pat::Tuple)
            } else if lookahead.peek(Token![&]) {
                input.call(pat_ref).map(Pat::Ref)
            } else {
                Err(lookahead.error())
            }
        }
    }

    fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> {
        let path = path::parse_path(input)?;

        if input.peek(token::Brace) {
            pat_struct(input, path).map(Pat::Struct)
        } else if input.peek(token::Paren) {
            pat_tuple_struct(input, path).map(Pat::TupleStruct)
        } else {
            Ok(Pat::Path(PatPath { path }))
        }
    }

    fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> {
        Ok(PatWild {
            underscore_token: input.parse()?,
        })
    }

    fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> {
        Ok(PatIdent {
            by_ref: input.parse()?,
            mutability: input.parse()?,
            ident: input.call(Ident::parse_any)?,
        })
    }

    fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
        Ok(PatTupleStruct {
            path,
            pat: input.call(pat_tuple)?,
        })
    }

    fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
        let content;
        let brace_token = braced!(content in input);

        let mut fields = Punctuated::new();
        while !content.is_empty() && !content.peek(Token![..]) {
            let value = content.call(field_pat)?;
            fields.push_value(value);
            if !content.peek(Token![,]) {
                break;
            }
            let punct: Token![,] = content.parse()?;
            fields.push_punct(punct);
        }

        let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) {
            Some(content.parse()?)
        } else {
            None
        };

        Ok(PatStruct {
            path,
            brace_token,
            fields,
            dot2_token,
        })
    }

    fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
        let boxed: Option<Token![box]> = input.parse()?;
        let by_ref: Option<Token![ref]> = input.parse()?;
        let mutability: Option<Token![mut]> = input.parse()?;
        let member: Member = input.parse()?;

        if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
            || is_unnamed(&member)
        {
            return Ok(FieldPat {
                attrs: Vec::new(),
                member,
                colon_token: input.parse()?,
                pat: input.parse()?,
            });
        }

        let ident = match member {
            Member::Named(ident) => ident,
            Member::Unnamed(_) => unreachable!(),
        };

        let pat = Pat::Ident(PatIdent {
            by_ref,
            mutability,
            ident: ident.clone(),
        });

        Ok(FieldPat {
            member: Member::Named(ident),
            pat: Box::new(pat),
            attrs: Vec::new(),
            colon_token: None,
        })
    }

    fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> {
        let content;
        let paren_token = parenthesized!(content in input);

        let mut elements = Punctuated::new();
        while !content.is_empty() {
            let value: Pat = content.parse()?;
            elements.push_value(value);
            if content.is_empty() {
                break;
            }
            let punct = content.parse()?;
            elements.push_punct(punct);
        }

        Ok(PatTuple {
            paren_token,
            elements,
        })
    }

    fn pat_ref(input: ParseStream<'_>) -> Result<PatRef> {
        Ok(PatRef {
            and_token: input.parse()?,
            mutability: input.parse()?,
            pat: input.parse()?,
        })
    }

    fn is_unnamed(member: &Member) -> bool {
        match *member {
            Member::Named(_) => false,
            Member::Unnamed(_) => true,
        }
    }

}

mod printing {
    use proc_macro2::TokenStream;
    use quote::ToTokens;
    use syn::Token;

    use super::{
        FieldPat, PatIdent, PatPath, PatRef, PatStruct, PatTuple, PatTupleStruct, PatWild,
    };

    impl ToTokens for PatWild {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.underscore_token.to_tokens(tokens);
        }
    }

    impl ToTokens for PatIdent {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.by_ref.to_tokens(tokens);
            self.mutability.to_tokens(tokens);
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for PatStruct {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.brace_token.surround(tokens, |tokens| {
                self.fields.to_tokens(tokens);
                // NOTE: We need a comma before the dot2 token if it is present.
                if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
                    <Token![,]>::default().to_tokens(tokens);
                }
                self.dot2_token.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for PatTupleStruct {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.pat.to_tokens(tokens);
        }
    }

    impl ToTokens for PatPath {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens)
        }
    }

    impl ToTokens for PatTuple {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.paren_token.surround(tokens, |tokens| {
                self.elements.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for PatRef {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.and_token.to_tokens(tokens);
            self.mutability.to_tokens(tokens);
            self.pat.to_tokens(tokens);
        }
    }

    impl ToTokens for FieldPat {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            if let Some(ref colon_token) = self.colon_token {
                self.member.to_tokens(tokens);
                colon_token.to_tokens(tokens);
            }
            self.pat.to_tokens(tokens);
        }
    }
}
<commit_msg>Remove unnecessary input.peek()<commit_after>use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token};

ast_enum_of_structs! {
    /// A pattern in a local binding, function signature, match expression, or
    /// various other places.
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Pat {
        /// A pattern that matches any value: `_`.
        pub Wild(PatWild {
            pub underscore_token: Token![_],
        }),

        /// A pattern that binds a new variable: `ref mut binding`.
        pub Ident(PatIdent {
            pub by_ref: Option<Token![ref]>,
            pub mutability: Option<Token![mut]>,
            pub ident: Ident,
        }),

        /// A struct or struct variant pattern: `Variant { x, y, .. }`.
        pub Struct(PatStruct {
            pub path: Path,
            pub brace_token: token::Brace,
            pub fields: Punctuated<FieldPat, Token![,]>,
            pub dot2_token: Option<Token![..]>,
        }),

        /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
        pub TupleStruct(PatTupleStruct {
            pub path: Path,
            pub pat: PatTuple,
        }),

        /// A path pattern like `Color::Red`.
        pub Path(PatPath {
            pub path: Path,
        }),

        /// A tuple pattern: `(a, b)`.
        pub Tuple(PatTuple {
            pub paren_token: token::Paren,
            pub elements: Punctuated<Pat, Token![,]>,
        }),

        /// A reference pattern: `&mut (first, second)`.
        pub Ref(PatRef {
            pub and_token: Token![&],
            pub mutability: Option<Token![mut]>,
            pub pat: Box<Pat>,
        }),
    }
}

ast_struct! {
    /// A single field in a struct pattern.
    ///
    /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
    /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
    pub struct FieldPat {
        pub attrs: Vec<Attribute>,
        pub member: Member,
        pub colon_token: Option<Token![:]>,
        pub pat: Box<Pat>,
    }
}

mod parsing {
    use syn::{
        braced,
        ext::IdentExt,
        parenthesized,
        parse::{Parse, ParseStream, Result},
        punctuated::Punctuated,
        token, Ident, Member, Path, Token,
    };

    use crate::path;

    use super::{
        FieldPat, Pat, PatIdent, PatPath, PatRef, PatStruct, PatTuple, PatTupleStruct, PatWild,
    };

    impl Parse for Pat {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let lookahead = input.lookahead1();
            if lookahead.peek(Token![_]) {
                input.call(pat_wild).map(Pat::Wild)
            } else if input.peek(Ident)
                && ({
                    input.peek2(Token![::])
                        || input.peek2(token::Brace)
                        || input.peek2(token::Paren)
                })
                || input.peek(Token![self]) && input.peek2(Token![::])
                || input.peek(Token![::])
                || input.peek(Token![Self])
                || input.peek(Token![super])
                || input.peek(Token![extern])
                || input.peek(Token![crate])
            {
                pat_path_or_struct(input)
            } else if input.peek(Token![ref])
                || input.peek(Token![mut])
                || input.peek(Token![self])
                || input.peek(Ident)
            {
                input.call(pat_ident).map(Pat::Ident)
            } else if lookahead.peek(token::Paren) {
                input.call(pat_tuple).map(Pat::Tuple)
            } else if lookahead.peek(Token![&]) {
                input.call(pat_ref).map(Pat::Ref)
            } else {
                Err(lookahead.error())
            }
        }
    }

    fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> {
        let path = path::parse_path(input)?;

        if input.peek(token::Brace) {
            pat_struct(input, path).map(Pat::Struct)
        } else if input.peek(token::Paren) {
            pat_tuple_struct(input, path).map(Pat::TupleStruct)
        } else {
            Ok(Pat::Path(PatPath { path }))
        }
    }

    fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> {
        Ok(PatWild {
            underscore_token: input.parse()?,
        })
    }

    fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> {
        Ok(PatIdent {
            by_ref: input.parse()?,
            mutability: input.parse()?,
            ident: input.call(Ident::parse_any)?,
        })
    }

    fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
        Ok(PatTupleStruct {
            path,
            pat: input.call(pat_tuple)?,
        })
    }

    fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
        let content;
        let brace_token = braced!(content in input);

        let mut fields = Punctuated::new();
        while !content.is_empty() && !content.peek(Token![..]) {
            let value = content.call(field_pat)?;
            fields.push_value(value);
            if !content.peek(Token![,]) {
                break;
            }
            let punct: Token![,] = content.parse()?;
            fields.push_punct(punct);
        }

        let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) {
            Some(content.parse()?)
        } else {
            None
        };

        Ok(PatStruct {
            path,
            brace_token,
            fields,
            dot2_token,
        })
    }

    fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
        let boxed: Option<Token![box]> = input.parse()?;
        let by_ref: Option<Token![ref]> = input.parse()?;
        let mutability: Option<Token![mut]> = input.parse()?;
        let member: Member = input.parse()?;

        if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
            || is_unnamed(&member)
        {
            return Ok(FieldPat {
                attrs: Vec::new(),
                member,
                colon_token: input.parse()?,
                pat: input.parse()?,
            });
        }

        let ident = match member {
            Member::Named(ident) => ident,
            Member::Unnamed(_) => unreachable!(),
        };

        let pat = Pat::Ident(PatIdent {
            by_ref,
            mutability,
            ident: ident.clone(),
        });

        Ok(FieldPat {
            member: Member::Named(ident),
            pat: Box::new(pat),
            attrs: Vec::new(),
            colon_token: None,
        })
    }

    fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> {
        let content;
        let paren_token = parenthesized!(content in input);

        let mut elements = Punctuated::new();
        while !content.is_empty() {
            let value: Pat = content.parse()?;
            elements.push_value(value);
            if content.is_empty() {
                break;
            }
            let punct = content.parse()?;
            elements.push_punct(punct);
        }

        Ok(PatTuple {
            paren_token,
            elements,
        })
    }

    fn pat_ref(input: ParseStream<'_>) -> Result<PatRef> {
        Ok(PatRef {
            and_token: input.parse()?,
            mutability: input.parse()?,
            pat: input.parse()?,
        })
    }

    fn is_unnamed(member: &Member) -> bool {
        match *member {
            Member::Named(_) => false,
            Member::Unnamed(_) => true,
        }
    }

}

mod printing {
    use proc_macro2::TokenStream;
    use quote::ToTokens;
    use syn::Token;

    use super::{
        FieldPat, PatIdent, PatPath, PatRef, PatStruct, PatTuple, PatTupleStruct, PatWild,
    };

    impl ToTokens for PatWild {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.underscore_token.to_tokens(tokens);
        }
    }

    impl ToTokens for PatIdent {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.by_ref.to_tokens(tokens);
            self.mutability.to_tokens(tokens);
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for PatStruct {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.brace_token.surround(tokens, |tokens| {
                self.fields.to_tokens(tokens);
                // NOTE: We need a comma before the dot2 token if it is present.
                if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
                    <Token![,]>::default().to_tokens(tokens);
                }
                self.dot2_token.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for PatTupleStruct {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.pat.to_tokens(tokens);
        }
    }

    impl ToTokens for PatPath {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens)
        }
    }

    impl ToTokens for PatTuple {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.paren_token.surround(tokens, |tokens| {
                self.elements.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for PatRef {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.and_token.to_tokens(tokens);
            self.mutability.to_tokens(tokens);
            self.pat.to_tokens(tokens);
        }
    }

    impl ToTokens for FieldPat {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            if let Some(ref colon_token) = self.colon_token {
                self.member.to_tokens(tokens);
                colon_token.to_tokens(tokens);
            }
            self.pat.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;

const BCM2708_PERI_BASE: u32 = 0x20000000;
const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4*1024);

#[allow(dead_code)]
struct Bcm2835Peripheral {
    addr_p: *const u8,
    mem_fd: std::fs::File,
    map: mmap::MemoryMap,
    addr: *mut u8
}

fn main() {
    let mut gpio = Bcm2835Peripheral { addr_p: &GPIO_BASE, mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(), map: MemoryMap::new(1024, &[]).unwrap(), addr: ptr::null_mut()};
    map_peripheral(&mut gpio);
    println!("{:?}", gpio.map.data());
    unmap_peripheral(&gpio);
}

fn map_peripheral(ref mut foo: &mut Bcm2835Peripheral) {
    let file = match OpenOptions::new()
                    .read(true)
                    .write(true)
                    .mode(O_SYNC)
                    .open("/dev/mem") {
      Ok(file) => file,
      Err(_e) => panic!("Unable to open /dev/mem, Are you root?")
    };

    let map_opts = &[
        MapOption::MapNonStandardFlags(MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
       // MapOption::MapAddr(foo.addr_p),
        MapOption::MapFd(file.as_raw_fd())
    ];

   let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
     Ok(mmap) => mmap,
     Err(e) => panic!("ERR: {}", e)
    };
    foo.map = mmap;
    foo.addr = foo.map.data();
    println!("{:?}", foo.map.data());
}

fn unmap_peripheral(foo: &Bcm2835Peripheral) {
    drop(&foo.mem_fd);
    drop(&foo.map);
    println!("{:?}", &foo.map.data());
}

fn in_gpio(foo: &Bcm2835Peripheral, y: isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k &= (7<<(((y)%10)*3));
  }
}
<commit_msg>remove unwanted match case since e was not used<commit_after>extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;

const BCM2708_PERI_BASE: u32 = 0x20000000;
const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4*1024);

#[allow(dead_code)]
struct Bcm2835Peripheral {
    addr_p: *const u8,
    mem_fd: std::fs::File,
    map: mmap::MemoryMap,
    addr: *mut u8
}

fn main() {
    let mut gpio = Bcm2835Peripheral { addr_p: &GPIO_BASE, mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(), map: MemoryMap::new(1024, &[]).unwrap(), addr: ptr::null_mut()};
    map_peripheral(&mut gpio);
    println!("{:?}", gpio.map.data());
    unmap_peripheral(&gpio);
}

fn map_peripheral(ref mut foo: &mut Bcm2835Peripheral) {
    let file = OpenOptions::new()
                    .read(true)
                    .write(true)
                    .mode(O_SYNC)
                    .open("/dev/mem")
                    .expect("unable to open /dev/mem, Are you root?");

    let map_opts = &[
        MapOption::MapNonStandardFlags(MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
       // MapOption::MapAddr(foo.addr_p),
        MapOption::MapFd(file.as_raw_fd())
    ];

   let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
     Ok(mmap) => mmap,
     Err(e) => panic!("ERR: {}", e)
    };
    foo.map = mmap;
    foo.addr = foo.map.data();
    println!("{:?}", foo.map.data());
}

fn unmap_peripheral(foo: &Bcm2835Peripheral) {
    drop(&foo.mem_fd);
    drop(&foo.map);
    println!("{:?}", &foo.map.data());
}

fn in_gpio(foo: &Bcm2835Peripheral, y: isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k &= (7<<(((y)%10)*3));
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::IterMut;
use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::string::ToString;

use self::Sym::*;

use parser::ast::NodeId;
use parser::ast::ctxt::*;
use parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    levels: Vec<SymLevel>
}

impl SymTable {
    pub fn new() -> SymTable {
        SymTable {
            levels: vec![SymLevel::new()]
        }
    }

    pub fn push_level(&mut self) {
        self.levels.push(SymLevel::new());
    }

    pub fn pop_level(&mut self) {
        assert!(self.levels.len() > 1);

        self.levels.pop();
    }

    pub fn get(&self, name: Name) -> Option<Sym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_var(&self, name: Name) -> Option<VarInfoId> {
        self.get(name).and_then(|n| n.to_var())
    }

    pub fn get_type(&self, name: Name) -> Option<BuiltinType> {
        self.get(name).and_then(|n| n.to_type())
    }

    pub fn get_function(&self, name: Name) -> Option<FctInfoId> {
        self.get(name).and_then(|n| n.to_function())
    }

    pub fn insert(&mut self, name: Name, sym: Sym) -> Option<Sym> {
        self.levels.last_mut().unwrap().insert(name, sym)
    }
}

#[derive(Debug)]
struct SymLevel {
    map: HashMap<Name, Sym>
}

impl SymLevel {
    // creates a new table
    fn new() -> SymLevel {
        SymLevel {
            map: HashMap::new()
        }
    }

    // finds symbol in table
    fn get(&self, name: Name) -> Option<&Sym> {
        self.map.get(&name)
    }

    fn insert(&mut self, name: Name, sym: Sym) -> Option<Sym> {
        self.map.insert(name, sym)
    }
}

#[derive(Debug, Copy, Clone)]
pub enum SymEntry {
    Empty, Type, Function, Var
}

impl SymEntry {
    pub fn is_empty(self) -> bool {
        match self {
            SymEntry::Empty => true,
            _ => false
        }
    }

    pub fn is_type(self) -> bool {
        match self {
            SymEntry::Type => true,
            _ => false
        }
    }

    pub fn is_function(self) -> bool {
        match self {
            SymEntry::Function => true,
            _ => false
        }
    }

    pub fn is_var(self) -> bool {
        match self {
            SymEntry::Var => true,
            _ => false
        }
    }
}

#[derive(Debug, Clone)]
pub enum Sym {
    SymType(BuiltinType),
    SymFunction(FctInfoId),
    SymVar(VarInfoId),
}

impl Sym {
    pub fn is_type(&self) -> bool {
        match *self {
            SymType(_) => true,
            _ => false
        }
    }

    pub fn to_type(&self) -> Option<BuiltinType> {
        match *self {
            SymType(builtin) => Some(builtin),
            _ => None
        }
    }

    pub fn is_function(&self) -> bool {
        match *self {
            SymFunction(_) => true,
            _ => false
        }
    }

    pub fn to_function(&self) -> Option<FctInfoId> {
        match *self {
            SymFunction(id) => Some(id),
            _ => None
        }
    }

    pub fn is_var(&self) -> bool {
        match *self {
            SymType(_) => true,
            _ => false
        }
    }

    pub fn to_var(&self) -> Option<VarInfoId> {
        match *self {
            SymVar(id) => Some(id),
            _ => None
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BuiltinType {
    Unit,
    Int,
    Bool,
    Str,
}

impl ToString for BuiltinType {
    fn to_string(&self) -> String {
        let name = match *self {
            BuiltinType::Unit => "()",
            BuiltinType::Int => "int",
            BuiltinType::Bool => "bool",
            BuiltinType::Str => "str"
        };

        name.into()
    }
}
<commit_msg>sym: size() for BuiltinType<commit_after>use std::collections::HashMap;
use std::collections::hash_map::IterMut;
use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::string::ToString;

use self::Sym::*;

use parser::ast::NodeId;
use parser::ast::ctxt::*;
use parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    levels: Vec<SymLevel>
}

impl SymTable {
    pub fn new() -> SymTable {
        SymTable {
            levels: vec![SymLevel::new()]
        }
    }

    pub fn push_level(&mut self) {
        self.levels.push(SymLevel::new());
    }

    pub fn pop_level(&mut self) {
        assert!(self.levels.len() > 1);

        self.levels.pop();
    }

    pub fn get(&self, name: Name) -> Option<Sym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_var(&self, name: Name) -> Option<VarInfoId> {
        self.get(name).and_then(|n| n.to_var())
    }

    pub fn get_type(&self, name: Name) -> Option<BuiltinType> {
        self.get(name).and_then(|n| n.to_type())
    }

    pub fn get_function(&self, name: Name) -> Option<FctInfoId> {
        self.get(name).and_then(|n| n.to_function())
    }

    pub fn insert(&mut self, name: Name, sym: Sym) -> Option<Sym> {
        self.levels.last_mut().unwrap().insert(name, sym)
    }
}

#[derive(Debug)]
struct SymLevel {
    map: HashMap<Name, Sym>
}

impl SymLevel {
    // creates a new table
    fn new() -> SymLevel {
        SymLevel {
            map: HashMap::new()
        }
    }

    // finds symbol in table
    fn get(&self, name: Name) -> Option<&Sym> {
        self.map.get(&name)
    }

    fn insert(&mut self, name: Name, sym: Sym) -> Option<Sym> {
        self.map.insert(name, sym)
    }
}

#[derive(Debug, Copy, Clone)]
pub enum SymEntry {
    Empty, Type, Function, Var
}

impl SymEntry {
    pub fn is_empty(self) -> bool {
        match self {
            SymEntry::Empty => true,
            _ => false
        }
    }

    pub fn is_type(self) -> bool {
        match self {
            SymEntry::Type => true,
            _ => false
        }
    }

    pub fn is_function(self) -> bool {
        match self {
            SymEntry::Function => true,
            _ => false
        }
    }

    pub fn is_var(self) -> bool {
        match self {
            SymEntry::Var => true,
            _ => false
        }
    }
}

#[derive(Debug, Clone)]
pub enum Sym {
    SymType(BuiltinType),
    SymFunction(FctInfoId),
    SymVar(VarInfoId),
}

impl Sym {
    pub fn is_type(&self) -> bool {
        match *self {
            SymType(_) => true,
            _ => false
        }
    }

    pub fn to_type(&self) -> Option<BuiltinType> {
        match *self {
            SymType(builtin) => Some(builtin),
            _ => None
        }
    }

    pub fn is_function(&self) -> bool {
        match *self {
            SymFunction(_) => true,
            _ => false
        }
    }

    pub fn to_function(&self) -> Option<FctInfoId> {
        match *self {
            SymFunction(id) => Some(id),
            _ => None
        }
    }

    pub fn is_var(&self) -> bool {
        match *self {
            SymType(_) => true,
            _ => false
        }
    }

    pub fn to_var(&self) -> Option<VarInfoId> {
        match *self {
            SymVar(id) => Some(id),
            _ => None
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BuiltinType {
    Unit,
    Int,
    Bool,
    Str,
}

impl BuiltinType {
    fn size(&self) -> u32 {
        match *self {
            BuiltinType::Unit => 0,
            BuiltinType::Bool => 1,
            BuiltinType::Int => 4,
            BuiltinType::Str => 8,
        }
    }
}

impl ToString for BuiltinType {
    fn to_string(&self) -> String {
        let name = match *self {
            BuiltinType::Unit => "()",
            BuiltinType::Int => "int",
            BuiltinType::Bool => "bool",
            BuiltinType::Str => "str"
        };

        name.into()
    }
}

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

    #[test]
    fn type_size() {
        assert_eq!(0, BuiltinType::Unit.size());
        assert_eq!(1, BuiltinType::Bool.size());
        assert_eq!(4, BuiltinType::Int.size());
        assert_eq!(8, BuiltinType::Str.size());
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: parse_scheme(s),
                authority_end: parse_authority(s),
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        if let Some(auth) = self.authority() {
            let v: Vec<&str> = auth.split(":").collect();
            if v.len() == 2 {
                u16::from_str(v[1]).ok()
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let v: Vec<&str> = s.split("://").collect();
    let auth = v.last().unwrap()
        .split("/")
        .next()
        .unwrap_or(s)
        .len() + if v.len() == 2 { v[0].len() + 3 } else { 0 };

    return Some(auth);
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    //TODO: these should error
    //err("htt:p//host");
    //err("hyper.rs/");
    //err("hyper.rs?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<commit_msg>refactor(uri): Add errors to scheme uri<commit_after>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            let scheme = parse_scheme(s);
            let auth = parse_authority(s);
            if let Some(end) = scheme {
                match &s[..end] {
                    "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {},
                    "blob" | "file" => return Err(Error::Method),
                    _ => return Err(Error::Method),
                }
                if let Some(a) = auth {
                    if (end + 3) == a {
                        return Err(Error::Method);
                    }
                }
            }
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: scheme,
                authority_end: auth,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        if let Some(auth) = self.authority() {
            let v: Vec<&str> = auth.split(":").collect();
            if v.len() == 2 {
                u16::from_str(v[1]).ok()
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let v: Vec<&str> = s.split("://").collect();
    let auth = v.last().unwrap()
        .split("/")
        .next()
        .unwrap_or(s)
        .len() + if v.len() == 2 { v[0].len() + 3 } else { 0 };

    return Some(auth);
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    //TODO: these should error
    //err("htt:p//host");
    //err("hyper.rs/");
    //err("hyper.rs?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    config::{global::Config as GlobalConfig, transaction::Config as TransactionConfig},
    errors::*,
};
use bytecode_verifier::{
    verify_module, verify_module_dependencies, verify_script, verify_script_dependencies,
};
use compiler::{compiler::compile_program, parser::parse_program, util::build_stdlib};
use config::config::VMPublishingOption;
use std::time::Duration;
use transaction_builder::transaction::make_transaction_program;
use types::{
    transaction::{RawTransaction, TransactionArgument, TransactionOutput, TransactionStatus},
    vm_error::{ExecutionStatus, VMStatus},
};
use vm::{
    errors::VerificationError,
    file_format::{CompiledModule, CompiledProgram, CompiledScript},
};
use vm_runtime_tests::{
    account::{AccountData, AccountResource},
    executor::FakeExecutor,
};

/// A transaction to be evaluated by the testing infra.
/// Contains code and a transaction config.
#[derive(Debug)]
pub struct Transaction {
    pub config: TransactionConfig,
    pub program: String,
}

/// Indicates one step in the pipeline the given move module/program goes through.
//  Ord is derived as we need to be able to determine if one stage is before another.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Stage {
    Parser,
    // Right now parser is a separate stage.
    // However it could be merged into the compiler.
    Compiler,
    Verifier,
    Runtime,
}

impl Stage {
    /// Parses the input string as Stage.
    pub fn parse(s: &str) -> Result<Stage> {
        match s {
            "parser" => Ok(Stage::Parser),
            "compiler" => Ok(Stage::Compiler),
            "verifier" => Ok(Stage::Verifier),
            "runtime" => Ok(Stage::Runtime),
            _ => Err(ErrorKind::Other(format!("unrecognized stage '{:?}'", s)).into()),
        }
    }
}

/// Evaluation status: success or failure.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
    Success,
    Failure,
}

/// An entry in the `EvaluationResult`.
#[derive(Debug)]
pub enum EvaluationOutput {
    Transaction,
    Stage(Stage),
    Output(String),
    Error(String),
}

/// A log consisting of outputs from all stages and the final status.
/// This is checked against the directives.
#[derive(Debug)]
pub struct EvaluationResult {
    pub outputs: Vec<EvaluationOutput>,
    pub status: Status,
}

impl EvaluationResult {
    pub fn get_transaction_count(&self) -> usize {
        self.outputs
            .iter()
            .filter(|output| match output {
                EvaluationOutput::Transaction => true,
                _ => false,
            })
            .count()
    }

    pub fn get_last_stage(&self) -> Option<Stage> {
        let mut stage = None;
        for output in self.outputs.iter().rev() {
            if let EvaluationOutput::Stage(s) = output {
                stage = Some(s.clone());
                break;
            }
        }
        stage
    }
}

fn check_verification_errors(errors: Vec<VerificationError>) -> Result<()> {
    if !errors.is_empty() {
        return Err(ErrorKind::VerificationFailure(errors).into());
    }
    Ok(())
}

fn do_verify_module(module: &CompiledModule, deps: &[CompiledModule]) -> Result<()> {
    check_verification_errors(verify_module(module.clone()).1)?;
    check_verification_errors(verify_module_dependencies(module.clone(), deps).1)
}

fn do_verify_script(script: &CompiledScript, deps: &[CompiledModule]) -> Result<()> {
    check_verification_errors(verify_script(script.clone()).1)?;
    check_verification_errors(verify_script_dependencies(script.clone(), deps).1)
}

// TODO: Add a helper function to the verifier
fn do_verify_program(program: &CompiledProgram, deps: &[CompiledModule]) -> Result<()> {
    let mut deps = deps.to_vec();
    for m in &program.modules {
        do_verify_module(m, &deps)?;
        deps.push(m.clone());
    }
    do_verify_script(&program.script, &deps)
}

/// Runs a single transaction using the fake executor.
fn run_transaction(
    exec: &mut FakeExecutor,
    data: &AccountData,
    program: &CompiledProgram,
    args: &[TransactionArgument],
) -> Result<TransactionOutput> {
    let account = data.account();

    let program = make_transaction_program(program, args)?;
    let account_resource = exec.read_account_resource(&account).unwrap();

    let transaction = RawTransaction::new(
        *data.address(),
        AccountResource::read_sequence_number(&account_resource),
        program,
        AccountResource::read_balance(&account_resource),
        // TODO: allow the user to specify this in the config.
        1,
        Duration::from_secs(u64::max_value()),
    )
    .sign(&account.privkey, account.pubkey)?
    .into_inner();

    let mut outputs = exec.execute_block(vec![transaction]);
    if outputs.len() == 1 {
        let output = outputs.pop().unwrap();
        match output.status() {
            TransactionStatus::Keep(VMStatus::Execution(ExecutionStatus::Executed)) => Ok(output),
            TransactionStatus::Keep(_) => Err(ErrorKind::VMExecutionFailure(output).into()),
            TransactionStatus::Discard(_) => Err(ErrorKind::DiscardedTransaction(output).into()),
        }
    } else {
        panic!("transaction outputs size mismatch");
    }
}

/// Tries to unwrap the given result. Upon failure, log the error and aborts.
macro_rules! unwrap_or_log {
    ($res: expr, $log: expr) => {{
        match $res {
            Ok(r) => r,
            Err(e) => {
                $log.outputs
                    .push(EvaluationOutput::Error(format!("{:?}", e)));
                return Ok($log);
            }
        }
    }};
}

/// Feeds all given transactions through the pipeline and produces an EvaluationResult.
pub fn eval(config: &GlobalConfig, transactions: &[Transaction]) -> Result<EvaluationResult> {
    // set up empty evaluation result
    let mut res = EvaluationResult {
        outputs: vec![],
        status: Status::Failure,
    };

    // set up a fake executor with the genesis block and create the accounts
    let mut exec = FakeExecutor::from_genesis_with_options(VMPublishingOption::Open);
    for data in config.accounts.values() {
        exec.add_account_data(&data);
    }

    // set up standard library
    // needed to compile transaction programs
    let stdlib = build_stdlib();

    for transaction in transactions {
        // get the account data of the sender
        let data = config.accounts.get(&transaction.config.sender).unwrap();
        let addr = data.address();

        // start processing a new transaction
        // insert a barrier in the output
        res.outputs.push(EvaluationOutput::Transaction);

        // stage 1: parse the program
        res.outputs.push(EvaluationOutput::Stage(Stage::Parser));
        let parsed_program = unwrap_or_log!(parse_program(&transaction.program), res);
        res.outputs
            .push(EvaluationOutput::Output(format!("{:?}", parsed_program)));

        // stage 2: compile the program
        res.outputs.push(EvaluationOutput::Stage(Stage::Compiler));
        let compiled_program = unwrap_or_log!(compile_program(addr, &parsed_program, &stdlib), res);
        res.outputs
            .push(EvaluationOutput::Output(format!("{:?}", compiled_program)));

        // stage 3: verify the program
        if !transaction.config.no_verify {
            res.outputs.push(EvaluationOutput::Stage(Stage::Verifier));
            unwrap_or_log!(do_verify_program(&compiled_program, &stdlib), res);
            res.outputs.push(EvaluationOutput::Output("".to_string()));
        }

        // stage 4: execute the program
        if !transaction.config.no_execute {
            res.outputs.push(EvaluationOutput::Stage(Stage::Runtime));
            let txn_output = unwrap_or_log!(
                run_transaction(&mut exec, data, &compiled_program, &transaction.config.args),
                res
            );
            res.outputs
                .push(EvaluationOutput::Output(format!("{:?}", txn_output)));

            // apply the writeset
            exec.apply_write_set(txn_output.write_set());
        }
    }

    res.status = Status::Success;
    Ok(res)
}
<commit_msg>[functional tests] remove TODO<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    config::{global::Config as GlobalConfig, transaction::Config as TransactionConfig},
    errors::*,
};
use bytecode_verifier::{
    verify_module, verify_module_dependencies, verify_script, verify_script_dependencies,
};
use compiler::{compiler::compile_program, parser::parse_program, util::build_stdlib};
use config::config::VMPublishingOption;
use std::time::Duration;
use transaction_builder::transaction::make_transaction_program;
use types::{
    transaction::{RawTransaction, TransactionArgument, TransactionOutput, TransactionStatus},
    vm_error::{ExecutionStatus, VMStatus},
};
use vm::{
    errors::VerificationError,
    file_format::{CompiledModule, CompiledProgram, CompiledScript},
};
use vm_runtime_tests::{
    account::{AccountData, AccountResource},
    executor::FakeExecutor,
};

/// A transaction to be evaluated by the testing infra.
/// Contains code and a transaction config.
#[derive(Debug)]
pub struct Transaction {
    pub config: TransactionConfig,
    pub program: String,
}

/// Indicates one step in the pipeline the given move module/program goes through.
//  Ord is derived as we need to be able to determine if one stage is before another.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Stage {
    Parser,
    // Right now parser is a separate stage.
    // However it could be merged into the compiler.
    Compiler,
    Verifier,
    Runtime,
}

impl Stage {
    /// Parses the input string as Stage.
    pub fn parse(s: &str) -> Result<Stage> {
        match s {
            "parser" => Ok(Stage::Parser),
            "compiler" => Ok(Stage::Compiler),
            "verifier" => Ok(Stage::Verifier),
            "runtime" => Ok(Stage::Runtime),
            _ => Err(ErrorKind::Other(format!("unrecognized stage '{:?}'", s)).into()),
        }
    }
}

/// Evaluation status: success or failure.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
    Success,
    Failure,
}

/// An entry in the `EvaluationResult`.
#[derive(Debug)]
pub enum EvaluationOutput {
    Transaction,
    Stage(Stage),
    Output(String),
    Error(String),
}

/// A log consisting of outputs from all stages and the final status.
/// This is checked against the directives.
#[derive(Debug)]
pub struct EvaluationResult {
    pub outputs: Vec<EvaluationOutput>,
    pub status: Status,
}

impl EvaluationResult {
    pub fn get_transaction_count(&self) -> usize {
        self.outputs
            .iter()
            .filter(|output| match output {
                EvaluationOutput::Transaction => true,
                _ => false,
            })
            .count()
    }

    pub fn get_last_stage(&self) -> Option<Stage> {
        let mut stage = None;
        for output in self.outputs.iter().rev() {
            if let EvaluationOutput::Stage(s) = output {
                stage = Some(s.clone());
                break;
            }
        }
        stage
    }
}

fn check_verification_errors(errors: Vec<VerificationError>) -> Result<()> {
    if !errors.is_empty() {
        return Err(ErrorKind::VerificationFailure(errors).into());
    }
    Ok(())
}

fn do_verify_module(module: &CompiledModule, deps: &[CompiledModule]) -> Result<()> {
    check_verification_errors(verify_module(module.clone()).1)?;
    check_verification_errors(verify_module_dependencies(module.clone(), deps).1)
}

fn do_verify_script(script: &CompiledScript, deps: &[CompiledModule]) -> Result<()> {
    check_verification_errors(verify_script(script.clone()).1)?;
    check_verification_errors(verify_script_dependencies(script.clone(), deps).1)
}

// TODO: Add a helper function to the verifier
fn do_verify_program(program: &CompiledProgram, deps: &[CompiledModule]) -> Result<()> {
    let mut deps = deps.to_vec();
    for m in &program.modules {
        do_verify_module(m, &deps)?;
        deps.push(m.clone());
    }
    do_verify_script(&program.script, &deps)
}

/// Runs a single transaction using the fake executor.
fn run_transaction(
    exec: &mut FakeExecutor,
    data: &AccountData,
    program: &CompiledProgram,
    args: &[TransactionArgument],
) -> Result<TransactionOutput> {
    let account = data.account();

    let program = make_transaction_program(program, args)?;
    let account_resource = exec.read_account_resource(&account).unwrap();

    let transaction = RawTransaction::new(
        *data.address(),
        AccountResource::read_sequence_number(&account_resource),
        program,
        AccountResource::read_balance(&account_resource),
        1,
        Duration::from_secs(u64::max_value()),
    )
    .sign(&account.privkey, account.pubkey)?
    .into_inner();

    let mut outputs = exec.execute_block(vec![transaction]);
    if outputs.len() == 1 {
        let output = outputs.pop().unwrap();
        match output.status() {
            TransactionStatus::Keep(VMStatus::Execution(ExecutionStatus::Executed)) => Ok(output),
            TransactionStatus::Keep(_) => Err(ErrorKind::VMExecutionFailure(output).into()),
            TransactionStatus::Discard(_) => Err(ErrorKind::DiscardedTransaction(output).into()),
        }
    } else {
        panic!("transaction outputs size mismatch");
    }
}

/// Tries to unwrap the given result. Upon failure, log the error and aborts.
macro_rules! unwrap_or_log {
    ($res: expr, $log: expr) => {{
        match $res {
            Ok(r) => r,
            Err(e) => {
                $log.outputs
                    .push(EvaluationOutput::Error(format!("{:?}", e)));
                return Ok($log);
            }
        }
    }};
}

/// Feeds all given transactions through the pipeline and produces an EvaluationResult.
pub fn eval(config: &GlobalConfig, transactions: &[Transaction]) -> Result<EvaluationResult> {
    // set up empty evaluation result
    let mut res = EvaluationResult {
        outputs: vec![],
        status: Status::Failure,
    };

    // set up a fake executor with the genesis block and create the accounts
    let mut exec = FakeExecutor::from_genesis_with_options(VMPublishingOption::Open);
    for data in config.accounts.values() {
        exec.add_account_data(&data);
    }

    // set up standard library
    // needed to compile transaction programs
    let stdlib = build_stdlib();

    for transaction in transactions {
        // get the account data of the sender
        let data = config.accounts.get(&transaction.config.sender).unwrap();
        let addr = data.address();

        // start processing a new transaction
        // insert a barrier in the output
        res.outputs.push(EvaluationOutput::Transaction);

        // stage 1: parse the program
        res.outputs.push(EvaluationOutput::Stage(Stage::Parser));
        let parsed_program = unwrap_or_log!(parse_program(&transaction.program), res);
        res.outputs
            .push(EvaluationOutput::Output(format!("{:?}", parsed_program)));

        // stage 2: compile the program
        res.outputs.push(EvaluationOutput::Stage(Stage::Compiler));
        let compiled_program = unwrap_or_log!(compile_program(addr, &parsed_program, &stdlib), res);
        res.outputs
            .push(EvaluationOutput::Output(format!("{:?}", compiled_program)));

        // stage 3: verify the program
        if !transaction.config.no_verify {
            res.outputs.push(EvaluationOutput::Stage(Stage::Verifier));
            unwrap_or_log!(do_verify_program(&compiled_program, &stdlib), res);
            res.outputs.push(EvaluationOutput::Output("".to_string()));
        }

        // stage 4: execute the program
        if !transaction.config.no_execute {
            res.outputs.push(EvaluationOutput::Stage(Stage::Runtime));
            let txn_output = unwrap_or_log!(
                run_transaction(&mut exec, data, &compiled_program, &transaction.config.args),
                res
            );
            res.outputs
                .push(EvaluationOutput::Output(format!("{:?}", txn_output)));

            // apply the writeset
            exec.apply_write_set(txn_output.write_set());
        }
    }

    res.status = Status::Success;
    Ok(res)
}
<|endoftext|>