<commit_before>// Copyright 2012-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.

use middle::ty::Region;
use mir::repr::*;
use rustc_data_structures::tuple_slice::TupleSlice;

pub trait Visitor<'tcx> {
    // Override these, and call `self.super_xxx` to revert back to the
    // default behavior.

    fn visit_mir(&mut self, mir: &Mir<'tcx>) {
        self.super_mir(mir);
    }

    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
        self.super_basic_block_data(block, data);
    }

    fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
        self.super_statement(block, statement);
    }

    fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
        self.super_assign(block, lvalue, rvalue);
    }

    fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
        self.super_terminator(block, terminator);
    }

    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
        self.super_rvalue(rvalue);
    }

    fn visit_operand(&mut self, operand: &Operand<'tcx>) {
        self.super_operand(operand);
    }

    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
        self.super_lvalue(lvalue, context);
    }

    fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
        self.super_branch(source, target);
    }

    fn visit_constant(&mut self, constant: &Constant<'tcx>) {
        self.super_constant(constant);
    }

    // The `super_xxx` methods comprise the default behavior and are
    // not meant to be overidden.

    fn super_mir(&mut self, mir: &Mir<'tcx>) {
        for block in mir.all_basic_blocks() {
            let data = mir.basic_block_data(block);
            self.visit_basic_block_data(block, data);
        }
    }

    fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
        for statement in &data.statements {
            self.visit_statement(block, statement);
        }
        self.visit_terminator(block, &data.terminator);
    }

    fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
        match statement.kind {
            StatementKind::Assign(ref lvalue, ref rvalue) => {
                self.visit_assign(block, lvalue, rvalue);
            }
            StatementKind::Drop(_, ref lvalue) => {
                self.visit_lvalue(lvalue, LvalueContext::Drop);
            }
        }
    }

    fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
        self.visit_lvalue(lvalue, LvalueContext::Store);
        self.visit_rvalue(rvalue);
    }

    fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
        match *terminator {
            Terminator::Goto { target } |
            Terminator::Panic { target } => {
                self.visit_branch(block, target);
            }

            Terminator::If { ref cond, ref targets } => {
                self.visit_operand(cond);
                for &target in targets.as_slice() {
                    self.visit_branch(block, target);
                }
            }

            Terminator::Switch { ref discr, adt_def: _, ref targets } => {
                self.visit_lvalue(discr, LvalueContext::Inspect);
                for &target in targets {
                    self.visit_branch(block, target);
                }
            }

            Terminator::SwitchInt { ref discr, switch_ty: _, values: _, ref targets } => {
                self.visit_lvalue(discr, LvalueContext::Inspect);
                for &target in targets {
                    self.visit_branch(block, target);
                }
            }

            Terminator::Diverge |
            Terminator::Return => {
            }

            Terminator::Call { ref data, ref targets } => {
                self.visit_lvalue(&data.destination, LvalueContext::Store);
                self.visit_operand(&data.func);
                for arg in &data.args {
                    self.visit_operand(arg);
                }
                for &target in targets.as_slice() {
                    self.visit_branch(block, target);
                }
            }
        }
    }

    fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
        match *rvalue {
            Rvalue::Use(ref operand) => {
                self.visit_operand(operand);
            }

            Rvalue::Repeat(ref value, ref len) => {
                self.visit_operand(value);
                self.visit_constant(len);
            }

            Rvalue::Ref(r, bk, ref path) => {
                self.visit_lvalue(path, LvalueContext::Borrow {
                    region: r,
                    kind: bk
                });
            }

            Rvalue::Len(ref path) => {
                self.visit_lvalue(path, LvalueContext::Inspect);
            }

            Rvalue::Cast(_, ref operand, _) => {
                self.visit_operand(operand);
            }

            Rvalue::BinaryOp(_, ref lhs, ref rhs) => {
                self.visit_operand(lhs);
                self.visit_operand(rhs);
            }

            Rvalue::UnaryOp(_, ref op) => {
                self.visit_operand(op);
            }

            Rvalue::Box(_) => {
            }

            Rvalue::Aggregate(_, ref operands) => {
                for operand in operands {
                    self.visit_operand(operand);
                }
            }

            Rvalue::Slice { ref input, from_start, from_end } => {
                self.visit_lvalue(input, LvalueContext::Slice {
                    from_start: from_start,
                    from_end: from_end,
                });
            }

            Rvalue::InlineAsm(_) => {
            }
        }
    }

    fn super_operand(&mut self, operand: &Operand<'tcx>) {
        match *operand {
            Operand::Consume(ref lvalue) => {
                self.visit_lvalue(lvalue, LvalueContext::Consume);
            }
            Operand::Constant(ref constant) => {
                self.visit_constant(constant);
            }
        }
    }

    fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) {
        match *lvalue {
            Lvalue::Var(_) |
            Lvalue::Temp(_) |
            Lvalue::Arg(_) |
            Lvalue::Static(_) |
            Lvalue::ReturnPointer => {
            }
            Lvalue::Projection(ref proj) => {
                self.visit_lvalue(&proj.base, LvalueContext::Projection);
            }
        }
    }

    fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
    }

    fn super_constant(&mut self, _constant: &Constant<'tcx>) {
    }
}

#[derive(Copy, Clone, Debug)]
pub enum LvalueContext {
    // Appears as LHS of an assignment or as dest of a call
    Store,

    // Being dropped
    Drop,

    // Being inspected in some way, like loading a len
    Inspect,

    // Being borrowed
    Borrow { region: Region, kind: BorrowKind },

    // Being sliced -- this should be same as being borrowed, probably
    Slice { from_start: usize, from_end: usize },

    // Used as base for another lvalue, e.g. `x` in `x.y`
    Projection,

    // Consumed as part of an operand
    Consume,
}
<commit_msg>Add visit_defid(), visit_span(), and visit_literal() to MIR visitor<commit_after>// Copyright 2012-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.

use middle::def_id::DefId;
use middle::ty::Region;
use mir::repr::*;
use rustc_data_structures::tuple_slice::TupleSlice;
use syntax::codemap::Span;

pub trait Visitor<'tcx> {
    // Override these, and call `self.super_xxx` to revert back to the
    // default behavior.

    fn visit_mir(&mut self, mir: &Mir<'tcx>) {
        self.super_mir(mir);
    }

    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
        self.super_basic_block_data(block, data);
    }

    fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
        self.super_statement(block, statement);
    }

    fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
        self.super_assign(block, lvalue, rvalue);
    }

    fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
        self.super_terminator(block, terminator);
    }

    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
        self.super_rvalue(rvalue);
    }

    fn visit_operand(&mut self, operand: &Operand<'tcx>) {
        self.super_operand(operand);
    }

    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
        self.super_lvalue(lvalue, context);
    }

    fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
        self.super_branch(source, target);
    }

    fn visit_constant(&mut self, constant: &Constant<'tcx>) {
        self.super_constant(constant);
    }

    fn visit_literal(&mut self, literal: &Literal<'tcx>) {
        self.super_literal(literal);
    }

    fn visit_def_id(&mut self, def_id: DefId) {
        self.super_def_id(def_id);
    }

    fn visit_span(&mut self, span: Span) {
        self.super_span(span);
    }

    // The `super_xxx` methods comprise the default behavior and are
    // not meant to be overidden.

    fn super_mir(&mut self, mir: &Mir<'tcx>) {
        for block in mir.all_basic_blocks() {
            let data = mir.basic_block_data(block);
            self.visit_basic_block_data(block, data);
        }
    }

    fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
        for statement in &data.statements {
            self.visit_statement(block, statement);
        }
        self.visit_terminator(block, &data.terminator);
    }

    fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
        self.visit_span(statement.span);

        match statement.kind {
            StatementKind::Assign(ref lvalue, ref rvalue) => {
                self.visit_assign(block, lvalue, rvalue);
            }
            StatementKind::Drop(_, ref lvalue) => {
                self.visit_lvalue(lvalue, LvalueContext::Drop);
            }
        }
    }

    fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
        self.visit_lvalue(lvalue, LvalueContext::Store);
        self.visit_rvalue(rvalue);
    }

    fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
        match *terminator {
            Terminator::Goto { target } |
            Terminator::Panic { target } => {
                self.visit_branch(block, target);
            }

            Terminator::If { ref cond, ref targets } => {
                self.visit_operand(cond);
                for &target in targets.as_slice() {
                    self.visit_branch(block, target);
                }
            }

            Terminator::Switch { ref discr, adt_def: _, ref targets } => {
                self.visit_lvalue(discr, LvalueContext::Inspect);
                for &target in targets {
                    self.visit_branch(block, target);
                }
            }

            Terminator::SwitchInt { ref discr, switch_ty: _, values: _, ref targets } => {
                self.visit_lvalue(discr, LvalueContext::Inspect);
                for &target in targets {
                    self.visit_branch(block, target);
                }
            }

            Terminator::Diverge |
            Terminator::Return => {
            }

            Terminator::Call { ref data, ref targets } => {
                self.visit_lvalue(&data.destination, LvalueContext::Store);
                self.visit_operand(&data.func);
                for arg in &data.args {
                    self.visit_operand(arg);
                }
                for &target in targets.as_slice() {
                    self.visit_branch(block, target);
                }
            }
        }
    }

    fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
        match *rvalue {
            Rvalue::Use(ref operand) => {
                self.visit_operand(operand);
            }

            Rvalue::Repeat(ref value, ref len) => {
                self.visit_operand(value);
                self.visit_constant(len);
            }

            Rvalue::Ref(r, bk, ref path) => {
                self.visit_lvalue(path, LvalueContext::Borrow {
                    region: r,
                    kind: bk
                });
            }

            Rvalue::Len(ref path) => {
                self.visit_lvalue(path, LvalueContext::Inspect);
            }

            Rvalue::Cast(_, ref operand, _) => {
                self.visit_operand(operand);
            }

            Rvalue::BinaryOp(_, ref lhs, ref rhs) => {
                self.visit_operand(lhs);
                self.visit_operand(rhs);
            }

            Rvalue::UnaryOp(_, ref op) => {
                self.visit_operand(op);
            }

            Rvalue::Box(_) => {
            }

            Rvalue::Aggregate(_, ref operands) => {
                for operand in operands {
                    self.visit_operand(operand);
                }
            }

            Rvalue::Slice { ref input, from_start, from_end } => {
                self.visit_lvalue(input, LvalueContext::Slice {
                    from_start: from_start,
                    from_end: from_end,
                });
            }

            Rvalue::InlineAsm(_) => {
            }
        }
    }

    fn super_operand(&mut self, operand: &Operand<'tcx>) {
        match *operand {
            Operand::Consume(ref lvalue) => {
                self.visit_lvalue(lvalue, LvalueContext::Consume);
            }
            Operand::Constant(ref constant) => {
                self.visit_constant(constant);
            }
        }
    }

    fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) {
        match *lvalue {
            Lvalue::Var(_) |
            Lvalue::Temp(_) |
            Lvalue::Arg(_) |
            Lvalue::Static(_) |
            Lvalue::ReturnPointer => {
            }
            Lvalue::Projection(ref proj) => {
                self.visit_lvalue(&proj.base, LvalueContext::Projection);
            }
        }
    }

    fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
    }

    fn super_constant(&mut self, constant: &Constant<'tcx>) {
        self.visit_span(constant.span);
        self.visit_literal(&constant.literal);
    }

    fn super_literal(&mut self, literal: &Literal<'tcx>) {
        match *literal {
            Literal::Item { def_id, .. } => {
                self.visit_def_id(def_id);
            },
            Literal::Value { .. } => {
                // Nothing to do
            }
        }
    }

    fn super_def_id(&mut self, _def_id: DefId) {
    }

    fn super_span(&mut self, _span: Span) {
    }
}

#[derive(Copy, Clone, Debug)]
pub enum LvalueContext {
    // Appears as LHS of an assignment or as dest of a call
    Store,

    // Being dropped
    Drop,

    // Being inspected in some way, like loading a len
    Inspect,

    // Being borrowed
    Borrow { region: Region, kind: BorrowKind },

    // Being sliced -- this should be same as being borrowed, probably
    Slice { from_start: usize, from_end: usize },

    // Used as base for another lvalue, e.g. `x` in `x.y`
    Projection,

    // Consumed as part of an operand
    Consume,
}
<|endoftext|>


<commit_before>use std::result::Result;

use silkthread_base::*;
use silkthread_base::basic::*;

use super::super::lex::lex_tool::*;
use super::script::*;

///
/// Represents a parse error
///
#[derive(Serialize, Deserialize, Debug)]
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, _remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()

        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // let identifier = expression
            self.parse_let()

        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // var identifier = expression
            self.parse_var()

        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // def fn args { statements }
            self.parse_def()

        } else if self.accept(ScriptLexerToken::If).is_some() {
            // if expression { statements }
            self.parse_if()

        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // using expression { statements }
            self.parse_using()

        } else if self.accept(ScriptLexerToken::While).is_some() {
            // while expression { statements }
            self.parse_while()

        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // loop { statements }
            self.parse_loop()

        } else if self.accept(ScriptLexerToken::For).is_some() {
            // for identifier in expression { statements }
            self.parse_for()

        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()

        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        // Get the LHS of the expression
        let left_expr = self.parse_simple_expression();

        // Look for a RHS
        left_expr.and_then(|left_expr| {
            if self.accept(ScriptLexerToken::Symbol(String::from("."))).is_some() {
                let right_expr = self.parse_expression();

                right_expr.map(|right_expr| Expression::FieldAccess(Box::new((left_expr, right_expr))))

            } else {
                Ok(left_expr)

            }
        })
    }

    ///
    /// Parses a simple expression
    ///
    pub fn parse_simple_expression(&mut self) -> Result<Expression, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Ignore newlines within an expression
            self.parse_expression()

        } else if let Some(identifier) = self.accept(ScriptLexerToken::Identifier) {
            // Simple expression
            Ok(Expression::Identifier(identifier.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::Number) {
            // Simple expression
            Ok(Expression::Number(number.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::HexNumber) {
            // Hex numbers work like normal numbers
            Ok(Expression::Number(number.clone()))

        } else if let Some(string) = self.accept(ScriptLexerToken::String) {
            // Simple expression
            Ok(Expression::String(string.clone()))

        } else {
            // Syntax error
            Err(ParseError::new())

        }
    }

    pub fn parse_let(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_var(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_def(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_if(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_using(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_while(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_loop(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_for(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }
}

impl ParseScriptTool {
    ///
    /// Creates a new tool from the parse script tool
    ///
    pub fn new_tool() -> Box<Tool> {
        Box::new(make_tool(move |script: Vec<LexerMatch>| -> Result<Vec<Script>, ParseError> {
            ParseScriptTool::parse(&script)
        }))
    }

    ///
    /// Tries to parse a script from the output of the lexer
    ///
    pub fn parse(input: &[LexerMatch]) -> Result<Vec<Script>, ParseError> {
        // Convert to script tokens
        let as_script_token: Vec<ScriptToken> = input
            .iter()
            .map(|token| ScriptToken::from_lexer_match(token))
            .collect();

        // Parse until we reach the end of the file
        let mut parser = ParseState { remaining: &as_script_token };
        let mut result = vec![];

        while !parser.lookahead_is(ScriptLexerToken::EndOfFile) {
            let next_statement = parser.parse_statement();

            match next_statement {
                // Fail out if we get a parse failure
                Err(failure)        => return Err(failure),

                // Build out the result otherwise
                Ok(next_statement)  => result.push(next_statement)
            }

            // Swallow any trailing newlines
            while parser.accept(ScriptLexerToken::Newline).is_some() { }
        }

        Ok(result)
    }
}

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

    ///
    /// Performs lexing
    ///
    fn lex(text: &str) -> Vec<LexerMatch> {
        let lexer = create_lex_script_tool();

        lexer.lex(text)
    }

    fn parse(text: &str) -> Result<Vec<Script>, ParseError> {
        let lexed = lex(text);
        ParseScriptTool::parse(&lexed)
    }

    #[test]
    fn can_parse_command_statement() {
        let statement   = "some-command";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::Identifier(_), None) => true, _ => false});
    }

    #[test]
    fn can_parse_field_access() {
        let statement   = "some-command.some-field";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::FieldAccess(_), None) => true, _ => false});
    }

    #[test]
    fn can_parse_command_statement_with_parameter() {
        let statement   = "some-command 1";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::Identifier(_), Some(Expression::Number(_))) => true, _ => false});
    }

    #[test]
    fn cannot_try_to_put_multiple_statements_on_one_line() {
        let statement   = "some-command 1 some-other-command";
        let parsed      = parse(statement);

        assert!(parsed.is_err());
    }

    #[test]
    fn can_parse_multiple_lines() {
        let statement   = "some-command\nsome-other-command";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());
        assert!(parsed.unwrap().len() == 2);
    }
}
<commit_msg>Add support for indexing expressions<commit_after>use std::result::Result;

use silkthread_base::*;
use silkthread_base::basic::*;

use super::super::lex::lex_tool::*;
use super::script::*;

///
/// Represents a parse error
///
#[derive(Serialize, Deserialize, Debug)]
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, _remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()

        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // let identifier = expression
            self.parse_let()

        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // var identifier = expression
            self.parse_var()

        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // def fn args { statements }
            self.parse_def()

        } else if self.accept(ScriptLexerToken::If).is_some() {
            // if expression { statements }
            self.parse_if()

        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // using expression { statements }
            self.parse_using()

        } else if self.accept(ScriptLexerToken::While).is_some() {
            // while expression { statements }
            self.parse_while()

        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // loop { statements }
            self.parse_loop()

        } else if self.accept(ScriptLexerToken::For).is_some() {
            // for identifier in expression { statements }
            self.parse_for()

        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()

        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        // Get the LHS of the expression
        let left_expr = self.parse_simple_expression();

        // Look for a RHS
        left_expr.and_then(|left_expr| {
            if self.accept(ScriptLexerToken::Symbol(String::from("."))).is_some() {
                // 'a.b' field access
                let right_expr = self.parse_expression();

                right_expr.map(|right_expr| Expression::FieldAccess(Box::new((left_expr, right_expr))))

            } else if self.accept(ScriptLexerToken::Symbol(String::from("["))).is_some() {
                // a[b] indexing
                let right_expr = self.parse_expression();

                right_expr.and_then(|right_expr| {
                    if self.accept(ScriptLexerToken::Symbol(String::from("]"))).is_some() {
                        // Got all of a[b]
                        Ok(Expression::Index(Box::new((left_expr, right_expr))))
                    } else {
                        // Missing ']'
                        Err(ParseError::new())
                    }
                })

            } else {
                Ok(left_expr)

            }
        })
    }

    ///
    /// Parses a simple expression
    ///
    pub fn parse_simple_expression(&mut self) -> Result<Expression, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Ignore newlines within an expression
            self.parse_expression()

        } else if let Some(identifier) = self.accept(ScriptLexerToken::Identifier) {
            // Simple expression
            Ok(Expression::Identifier(identifier.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::Number) {
            // Simple expression
            Ok(Expression::Number(number.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::HexNumber) {
            // Hex numbers work like normal numbers
            Ok(Expression::Number(number.clone()))

        } else if let Some(string) = self.accept(ScriptLexerToken::String) {
            // Simple expression
            Ok(Expression::String(string.clone()))

        } else {
            // Syntax error
            Err(ParseError::new())

        }
    }

    pub fn parse_let(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_var(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_def(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_if(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_using(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_while(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_loop(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_for(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }
}

impl ParseScriptTool {
    ///
    /// Creates a new tool from the parse script tool
    ///
    pub fn new_tool() -> Box<Tool> {
        Box::new(make_tool(move |script: Vec<LexerMatch>| -> Result<Vec<Script>, ParseError> {
            ParseScriptTool::parse(&script)
        }))
    }

    ///
    /// Tries to parse a script from the output of the lexer
    ///
    pub fn parse(input: &[LexerMatch]) -> Result<Vec<Script>, ParseError> {
        // Convert to script tokens
        let as_script_token: Vec<ScriptToken> = input
            .iter()
            .map(|token| ScriptToken::from_lexer_match(token))
            .collect();

        // Parse until we reach the end of the file
        let mut parser = ParseState { remaining: &as_script_token };
        let mut result = vec![];

        while !parser.lookahead_is(ScriptLexerToken::EndOfFile) {
            let next_statement = parser.parse_statement();

            match next_statement {
                // Fail out if we get a parse failure
                Err(failure)        => return Err(failure),

                // Build out the result otherwise
                Ok(next_statement)  => result.push(next_statement)
            }

            // Swallow any trailing newlines
            while parser.accept(ScriptLexerToken::Newline).is_some() { }
        }

        Ok(result)
    }
}

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

    ///
    /// Performs lexing
    ///
    fn lex(text: &str) -> Vec<LexerMatch> {
        let lexer = create_lex_script_tool();

        lexer.lex(text)
    }

    fn parse(text: &str) -> Result<Vec<Script>, ParseError> {
        let lexed = lex(text);
        ParseScriptTool::parse(&lexed)
    }

    #[test]
    fn can_parse_command_statement() {
        let statement   = "some-command";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::Identifier(_), None) => true, _ => false});
    }

    #[test]
    fn can_parse_field_access() {
        let statement   = "some-command.some-field";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::FieldAccess(_), None) => true, _ => false});
    }

    #[test]
    fn can_parse_array_indexing() {
        let statement   = "some-command[0]";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::Index(_), None) => true, _ => false});
    }

    #[test]
    fn can_parse_command_statement_with_parameter() {
        let statement   = "some-command 1";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());

        let result = parsed.unwrap();
        assert!(result.len() == 1);

        let ref cmd = result[0];
        assert!(match cmd { &Script::RunCommand(Expression::Identifier(_), Some(Expression::Number(_))) => true, _ => false});
    }

    #[test]
    fn cannot_try_to_put_multiple_statements_on_one_line() {
        let statement   = "some-command 1 some-other-command";
        let parsed      = parse(statement);

        assert!(parsed.is_err());
    }

    #[test]
    fn can_parse_multiple_lines() {
        let statement   = "some-command\nsome-other-command";
        let parsed      = parse(statement);

        assert!(parsed.is_ok());
        assert!(parsed.unwrap().len() == 2);
    }
}
<|endoftext|>


<commit_before>fn f() -> i32 {
    42
}

fn g(i: i32) -> i32 {
    i*42
}

fn h(i: i32, j: i32) -> i32 {
    j * i * 7
}

fn return_fn_ptr(f: fn() -> i32) -> fn() -> i32 {
    f
}

fn call_fn_ptr() -> i32 {
    return_fn_ptr(f)()
}

fn indirect<F: Fn() -> i32>(f: F) -> i32 { f() }
fn indirect_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() }
fn indirect_once<F: FnOnce() -> i32>(f: F) -> i32 { f() }

fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }

fn indirect3<F: Fn(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
fn indirect_mut3<F: FnMut(i32, i32) -> i32>(mut f: F) -> i32 { f(10, 3) }
fn indirect_once3<F: FnOnce(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }

fn main() {
    assert_eq!(call_fn_ptr(), 42);
    assert_eq!(indirect(f), 42);
    assert_eq!(indirect_mut(f), 42);
    assert_eq!(indirect_once(f), 42);
    assert_eq!(indirect2(g), 420);
    assert_eq!(indirect_mut2(g), 420);
    assert_eq!(indirect_once2(g), 420);
    assert_eq!(indirect3(h), 210);
    assert_eq!(indirect_mut3(h), 210);
    assert_eq!(indirect_once3(h), 210);
    let g = f as fn() -> i32;
    assert!(return_fn_ptr(g) == g);
    assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32);
    assert!(return_fn_ptr(f) != f);
}
<commit_msg>fix ptr comparison test<commit_after>trait Answer {
    fn answer() -> Self;
}

impl Answer for i32 {
    fn answer() -> i32 {
        42
    }
}

// A generic function, to make its address unstable
fn f<T: Answer>() -> T {
    Answer::answer()
}

fn g(i: i32) -> i32 {
    i*42
}

fn h(i: i32, j: i32) -> i32 {
    j * i * 7
}

fn return_fn_ptr(f: fn() -> i32) -> fn() -> i32 {
    f
}

fn call_fn_ptr() -> i32 {
    return_fn_ptr(f)()
}

fn indirect<F: Fn() -> i32>(f: F) -> i32 { f() }
fn indirect_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() }
fn indirect_once<F: FnOnce() -> i32>(f: F) -> i32 { f() }

fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }

fn indirect3<F: Fn(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
fn indirect_mut3<F: FnMut(i32, i32) -> i32>(mut f: F) -> i32 { f(10, 3) }
fn indirect_once3<F: FnOnce(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }

fn main() {
    assert_eq!(call_fn_ptr(), 42);
    assert_eq!(indirect(f), 42);
    assert_eq!(indirect_mut(f), 42);
    assert_eq!(indirect_once(f), 42);
    assert_eq!(indirect2(g), 420);
    assert_eq!(indirect_mut2(g), 420);
    assert_eq!(indirect_once2(g), 420);
    assert_eq!(indirect3(h), 210);
    assert_eq!(indirect_mut3(h), 210);
    assert_eq!(indirect_once3(h), 210);
    let g = f as fn() -> i32;
    assert!(return_fn_ptr(g) == g);
    assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32);
    assert!(return_fn_ptr(f) != f);
}
<|endoftext|>


<commit_before>use crate::io::{self, Error, ErrorKind};
use libc::{self, c_int};
use libc::{RTP_ID};

use crate::sys::cvt;
use crate::sys::process::rtp;
use crate::sys::process::process_common::*;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use crate::sys::{cvt_r};
        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }
        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
        let mut p = Process { pid: 0, status: None };

        unsafe {
            macro_rules! t {
                ($e:expr) => (match $e {
                    Ok(e) => e,
                    Err(e) => return Err(e.into()),
                })
            }

            let mut orig_stdin = libc::STDIN_FILENO;
            let mut orig_stdout = libc::STDOUT_FILENO;
            let mut orig_stderr = libc::STDERR_FILENO;

            if let Some(fd) = theirs.stdin.fd() {
                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
            }
            if let Some(fd) = theirs.stdout.fd() {
                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
            }
            if let Some(fd) = theirs.stderr.fd() {
                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
            }

            if let Some(ref cwd) = *self.get_cwd() {
                t!(cvt(libc::chdir(cwd.as_ptr())));
            }

            //            let envp = envp.map(|c| c.as_ptr())
            //                .unwrap_or(*sys::os::environ() as *const _);
            // FIXME: https://github.com/rust-lang/rust/issues/61993
            let envp_empty = CStringArray::with_capacity(0);
            let envp = match envp {
                Some(x) => x,
                None => envp_empty,
            };
            let envp = envp.as_ptr();
            let ret = rtp::rtpSpawn(
                self.get_argv()[0],                   // executing program
                self.get_argv().as_ptr() as *const _, // argv
                envp as *const _,                     // environment variable pointers
                100 as c_int,                         // initial priority
                0x16000,                                    // initial stack size. 0 defaults
                                                      // to 0x4000 in 32 bit and 0x8000 in 64 bit
                0,                                    // options
                0                                     // task options
            );

            // Because FileDesc was not used, each duplicated file descriptor
            // needs to be closed manually
            if orig_stdin != libc::STDIN_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
                libc::close(orig_stdin);
            }
            if orig_stdout != libc::STDOUT_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
                libc::close(orig_stdout);
            }
            if orig_stderr != libc::STDERR_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
                libc::close(orig_stderr);
            }

            if ret != rtp::RTP_ID_ERROR {
                p.pid = ret;
                Ok((p, ours))
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let ret = Command::spawn(self, default, false);
        match ret {
            Ok(t) => unsafe {
                let mut status = 0 as c_int;
                libc::waitpid(t.0.pid, &mut status, 0);
                libc::exit(0);
            },
            Err(e) => e,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: RTP_ID,
    status: Option<ExitStatus>,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.pid as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<commit_msg>Rollup merge of #63117 - BaoshanPang:bugfix, r=alexcrichton<commit_after>use crate::io::{self, Error, ErrorKind};
use libc::{self, c_int, c_char};
use libc::{RTP_ID};
use crate::sys;
use crate::sys::cvt;
use crate::sys::process::rtp;
use crate::sys::process::process_common::*;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use crate::sys::{cvt_r};
        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        if self.saw_nul() {
            return Err(io::Error::new(ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }
        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
        let mut p = Process { pid: 0, status: None };

        unsafe {
            macro_rules! t {
                ($e:expr) => (match $e {
                    Ok(e) => e,
                    Err(e) => return Err(e.into()),
                })
            }

            let mut orig_stdin = libc::STDIN_FILENO;
            let mut orig_stdout = libc::STDOUT_FILENO;
            let mut orig_stderr = libc::STDERR_FILENO;

            if let Some(fd) = theirs.stdin.fd() {
                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
            }
            if let Some(fd) = theirs.stdout.fd() {
                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
            }
            if let Some(fd) = theirs.stderr.fd() {
                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
            }

            if let Some(ref cwd) = *self.get_cwd() {
                t!(cvt(libc::chdir(cwd.as_ptr())));
            }

            let ret = rtp::rtpSpawn(
                self.get_argv()[0],                   // executing program
                self.get_argv().as_ptr() as *const _, // argv
                *sys::os::environ() as *const *const c_char,
                100 as c_int,                         // initial priority
                0x16000,                                    // initial stack size. 0 defaults
                                                      // to 0x4000 in 32 bit and 0x8000 in 64 bit
                0,                                    // options
                0                                     // task options
            );

            // Because FileDesc was not used, each duplicated file descriptor
            // needs to be closed manually
            if orig_stdin != libc::STDIN_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
                libc::close(orig_stdin);
            }
            if orig_stdout != libc::STDOUT_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
                libc::close(orig_stdout);
            }
            if orig_stderr != libc::STDERR_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
                libc::close(orig_stderr);
            }

            if ret != rtp::RTP_ID_ERROR {
                p.pid = ret;
                Ok((p, ours))
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let ret = Command::spawn(self, default, false);
        match ret {
            Ok(t) => unsafe {
                let mut status = 0 as c_int;
                libc::waitpid(t.0.pid, &mut status, 0);
                libc::exit(0);
            },
            Err(e) => e,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: RTP_ID,
    status: Option<ExitStatus>,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.pid as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<|endoftext|>


<commit_before>//! [PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey)

use ruma_api::ruma_api;
use ruma_events::EventType;
use ruma_identifiers::{EventId, RoomId};
use serde_json::value::RawValue as RawJsonValue;

ruma_api! {
    metadata: {
        description: "Send a state event to a room associated with a given state key.",
        method: PUT,
        name: "create_state_event_for_key",
        path: "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key",
        rate_limited: false,
        requires_authentication: true,
    }

    request: {
        /// The room to set the state in.
        #[ruma_api(path)]
        pub room_id: &'a RoomId,

        /// The type of event to send.
        #[ruma_api(path)]
        pub event_type: EventType,

        /// The state_key for the state to send. Defaults to the empty string.
        #[ruma_api(path)]
        pub state_key: &'a str,

        /// The event's content. The type for this field will be updated in a
        /// future release, until then you can create a value using
        /// `serde_json::value::to_raw_value`.
        #[ruma_api(body)]
        pub data: Box<RawJsonValue>,
    }

    response: {
        /// A unique identifier for the event.
        pub event_id: EventId,
    }

    error: crate::Error
}
<commit_msg>Use AnyStateEventContent in send_state_event_for_key<commit_after>//! [PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey)

use std::convert::TryFrom;

use ruma_api::{
    error::{
        FromHttpRequestError, FromHttpResponseError, IntoHttpError, RequestDeserializationError,
        ResponseDeserializationError, ServerError,
    },
    EndpointError, Metadata, Outgoing,
};
use ruma_events::{AnyStateEventContent, EventContent as _};
use ruma_identifiers::{EventId, RoomId};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue;

/// Data for a request to the `send_state_event_for_key` API endpoint.
///
/// Send a state event to a room associated with a given state key.
#[derive(Clone, Debug, Outgoing)]
#[non_exhaustive]
#[incoming_no_deserialize]
pub struct Request<'a> {
    /// The room to set the state in.
    pub room_id: &'a RoomId,

    /// The state_key for the state to send. Defaults to the empty string.
    pub state_key: &'a str,

    /// The event content to send.
    pub content: &'a AnyStateEventContent,
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given room id, state key and event content.
    pub fn new(room_id: &'a RoomId, state_key: &'a str, content: &'a AnyStateEventContent) -> Self {
        Self { room_id, state_key, content }
    }
}

/// Data in the response from the `send_message_event` API endpoint.
#[derive(Clone, Debug, Outgoing)]
#[non_exhaustive]
#[incoming_no_deserialize]
pub struct Response {
    /// A unique identifier for the event.
    pub event_id: EventId,
}

impl Response {
    /// Creates a new `Response` with the given event id.
    pub fn new(event_id: EventId) -> Self {
        Self { event_id }
    }
}

const METADATA: Metadata = Metadata {
    description: "Send a state event to a room associated with a given state key.",
    method: http::Method::PUT,
    name: "send_state_event_for_key",
    path: "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key",
    rate_limited: false,
    requires_authentication: true,
};

impl TryFrom<http::Request<Vec<u8>>> for IncomingRequest {
    type Error = FromHttpRequestError;

    fn try_from(request: http::Request<Vec<u8>>) -> Result<Self, Self::Error> {
        let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();

        let room_id = {
            let decoded =
                match percent_encoding::percent_decode(path_segments[4].as_bytes()).decode_utf8() {
                    Ok(val) => val,
                    Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
                };

            match RoomId::try_from(&*decoded) {
                Ok(val) => val,
                Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
            }
        };

        let state_key =
            match percent_encoding::percent_decode(path_segments[7].as_bytes()).decode_utf8() {
                Ok(val) => val.into_owned(),
                Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
            };

        let content = {
            let request_body: Box<RawJsonValue> =
                match serde_json::from_slice(request.body().as_slice()) {
                    Ok(val) => val,
                    Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
                };

            let event_type = {
                match percent_encoding::percent_decode(path_segments[6].as_bytes()).decode_utf8() {
                    Ok(val) => val,
                    Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
                }
            };

            match AnyStateEventContent::from_parts(&event_type, request_body) {
                Ok(content) => content,
                Err(err) => return Err(RequestDeserializationError::new(err, request).into()),
            }
        };

        Ok(Self { room_id, state_key, content })
    }
}

/// Data in the response body.
#[derive(Debug, Deserialize, Serialize)]
struct ResponseBody {
    /// A unique identifier for the event.
    event_id: EventId,
}

impl TryFrom<Response> for http::Response<Vec<u8>> {
    type Error = IntoHttpError;

    fn try_from(response: Response) -> Result<Self, Self::Error> {
        let response = http::Response::builder()
            .header(http::header::CONTENT_TYPE, "application/json")
            .body(serde_json::to_vec(&ResponseBody { event_id: response.event_id })?)
            .unwrap();

        Ok(response)
    }
}

impl TryFrom<http::Response<Vec<u8>>> for Response {
    type Error = FromHttpResponseError<crate::Error>;

    fn try_from(response: http::Response<Vec<u8>>) -> Result<Self, Self::Error> {
        if response.status().as_u16() < 400 {
            let response_body: ResponseBody =
                match serde_json::from_slice(response.body().as_slice()) {
                    Ok(val) => val,
                    Err(err) => return Err(ResponseDeserializationError::new(err, response).into()),
                };

            Ok(Self { event_id: response_body.event_id })
        } else {
            match <crate::Error as EndpointError>::try_from_response(response) {
                Ok(err) => Err(ServerError::Known(err).into()),
                Err(response_err) => Err(ServerError::Unknown(response_err).into()),
            }
        }
    }
}

impl<'a> ruma_api::OutgoingRequest for Request<'a> {
    type EndpointError = crate::Error;
    type IncomingResponse = Response;

    /// Metadata for the `send_message_event` endpoint.
    const METADATA: Metadata = METADATA;

    fn try_into_http_request(
        self,
        base_url: &str,
        access_token: Option<&str>,
    ) -> Result<http::Request<Vec<u8>>, IntoHttpError> {
        use http::header::{HeaderValue, AUTHORIZATION};
        use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};

        let http_request = http::Request::builder()
            .method(http::Method::PUT)
            .uri(format!(
                "{}/_matrix/client/r0/rooms/{}/state/{}/{}",
                base_url.strip_suffix("/").unwrap_or(base_url),
                utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC),
                utf8_percent_encode(self.content.event_type(), NON_ALPHANUMERIC),
                utf8_percent_encode(&self.state_key, NON_ALPHANUMERIC),
            ))
            .header(
                AUTHORIZATION,
                HeaderValue::from_str(&format!(
                    "Bearer {}",
                    access_token.ok_or(IntoHttpError::NeedsAuthentication)?
                ))?,
            )
            .body(serde_json::to_vec(&self.content)?)?;

        Ok(http_request)
    }
}

impl ruma_api::IncomingRequest for IncomingRequest {
    type EndpointError = crate::Error;
    type OutgoingResponse = Response;

    /// Metadata for the `send_message_event` endpoint.
    const METADATA: Metadata = METADATA;
}
<|endoftext|>


<commit_before>use cmd;
use channel;
use channel::{Channel};
use channel::util::{Secret, Private};
use msg::RawMessage;
use util;

use server::{Server};
use con::{Peer};
/// Handles the WHO message
/// The reply consists of two parts:
///
/// ```
/// 352    RPL_WHOREPLY
///        "<channel> <user> <host> <server> <nick>
///        ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
///        :<hopcount> <real name>"
///
/// 315    RPL_ENDOFWHO
///        "<name> :End of WHO list"
/// ```
///
/// Unfortunately the RFC 2812 does not specify what H, G, *, @ or + mean.
/// @/+ is op/voice.
/// * is maybe irc op
/// H/G means here/gone in terms of the away status
///
pub struct Who {
    raw: RawMessage,
    mask: String,
    op_only: bool
}
impl Who {
    pub fn handle_who(&self, channel: &Channel, client: Peer) {
        if (channel.has_flag(Private) || channel.has_flag(Secret))
        && !channel.member_with_id(client.id()).is_some() {
            // Don't give information about this channel to the outside
            // this should also be ok for secret because RPL_ENDOFWHO is
            // always sent.
            channel.send_response(&client, cmd::RPL_ENDOFWHO, [
                self.mask.as_slice(), "End of WHO list"
            ]);
        } else {
            let sender = channel.list_sender(&client, cmd::RPL_WHOREPLY, cmd::RPL_ENDOFWHO);
            for member in channel.members() {
                sender.feed_line(&[
                    channel.name(),
                    member.username(),
                    member.hostname(),
                    channel.server_name(),
                    member.nick(),
                    format!("{}{}{}",
                        "H", // always here as long away is not implemented
                        "", // * is not supported yet
                        member.decoration()
                    ).as_slice(),
                    format!("0 {}", member.realname()).as_slice()
                ]);
            }
            sender.end_of_list()
        }
    }
}
impl super::MessageHandler for Who {
    fn from_message(message: RawMessage) -> Result<Box<Who>, RawMessage> {
        let mask = message.params().as_slice().get(0).map_or("0".to_string(),
            |&v| String::from_utf8_lossy(v).to_string());
        let op_only = match message.params().as_slice().get(1) {
            Some(&o) => o == b"o",
            None => false
        };
        Ok(box Who {
            raw: message, mask: mask, op_only: op_only
        })
    }
    fn invoke(self, server: &mut Server, origin: Peer) {
        match server.channels.find(&self.mask) {
            Some(channel) => {
                channel.send(channel::Handle(proc(channel) {
                    self.handle_who(channel, origin)
                }))
            },
            None => {} // handle later
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}

/// Handles NAMES message
pub struct Names {
    raw: RawMessage,
    receivers: Vec<util::Receiver>
}
impl Names {
    /// Sends the list of users to the client
    pub fn handle_names(channel: &Channel, proxy: &Peer) {
        // TODO check if channel is visible to user…
        // TODO replace with generic list sending function
        for member in channel.members() {
            channel.send_response(proxy, cmd::RPL_NAMREPLY, [
                String::from_str("= ").append(channel.name()).as_slice(),
                member.decorated_nick()
            ])
        }
        channel.send_response(proxy, cmd::RPL_ENDOFNAMES,
            [channel.name(), "End of /NAMES list"])
    }
}
impl super::MessageHandler for Names {
    fn from_message(message: RawMessage) -> Result<Box<Names>, RawMessage> {
        if message.params().len() > 0 {
            Ok(box Names {
                raw: message.clone(),
                receivers: message.params()[0].as_slice().split(|c| *c == b',').map(|v|
                    util::verify_receiver(v)
                ).collect()
            })
        } else {
            Err(RawMessage::new(cmd::REPLY(cmd::ERR_NEEDMOREPARAMS), [
                "*", message.command().to_string().as_slice(),
                "not enought params given"
            ], None))
        }
    }
    fn invoke(self, server: &mut Server, origin: Peer) {
        let host = server.host().to_string(); // clone due to #6393
        for recv in self.receivers.iter() {
            match recv {
                &util::ChannelName(ref name) => {
                    match server.channels.find_mut(&name.to_string()) {
                        Some(channel) => {
                            let proxy = origin.clone();
                            channel.send(channel::Handle(proc(channel) {
                                Names::handle_names(channel, &proxy)
                            }))
                        },
                        None => origin.send_response(cmd::ERR_NOSUCHCHANNEL,
                            &[name.as_slice(), "No such channel"],
                            host.as_slice()
                        )
                    }
                },
                _ => {}
            }

        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<commit_msg>Check for op only in WHO<commit_after>use cmd;
use channel;
use channel::{Channel};
use channel::util::{Secret, Private};
use msg::RawMessage;
use util;

use server::{Server};
use con::{Peer};
/// Handles the WHO message
/// The reply consists of two parts:
///
/// ```
/// 352    RPL_WHOREPLY
///        "<channel> <user> <host> <server> <nick>
///        ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
///        :<hopcount> <real name>"
///
/// 315    RPL_ENDOFWHO
///        "<name> :End of WHO list"
/// ```
///
/// Unfortunately the RFC 2812 does not specify what H, G, *, @ or + mean.
/// @/+ is op/voice.
/// * is maybe irc op
/// H/G means here/gone in terms of the away status
///
pub struct Who {
    raw: RawMessage,
    mask: String,
    op_only: bool
}
impl Who {
    pub fn handle_who(&self, channel: &Channel, client: Peer) {
        if (channel.has_flag(Private) || channel.has_flag(Secret))
        && !channel.member_with_id(client.id()).is_some() {
            // Don't give information about this channel to the outside
            // this should also be ok for secret because RPL_ENDOFWHO is
            // always sent.
            channel.send_response(&client, cmd::RPL_ENDOFWHO, [
                self.mask.as_slice(), "End of WHO list"
            ]);
        } else {
            let sender = channel.list_sender(&client, cmd::RPL_WHOREPLY, cmd::RPL_ENDOFWHO);
            for member in channel.members() {
                if !self.op_only || member.is_op() {
                    sender.feed_line(&[
                        channel.name(),
                        member.username(),
                        member.hostname(),
                        channel.server_name(),
                        member.nick(),
                        format!("{}{}{}",
                            "H", // always here as long away is not implemented
                            "", // * is not supported yet
                            member.decoration()
                        ).as_slice(),
                        format!("0 {}", member.realname()).as_slice()
                    ]);
                }
            }
            sender.end_of_list()
        }
    }
}
impl super::MessageHandler for Who {
    fn from_message(message: RawMessage) -> Result<Box<Who>, RawMessage> {
        let mask = message.params().as_slice().get(0).map_or("0".to_string(),
            |&v| String::from_utf8_lossy(v).to_string());
        let op_only = match message.params().as_slice().get(1) {
            Some(&o) => o == b"o",
            None => false
        };
        Ok(box Who {
            raw: message, mask: mask, op_only: op_only
        })
    }
    fn invoke(self, server: &mut Server, origin: Peer) {
        match server.channels.find(&self.mask) {
            Some(channel) => {
                channel.send(channel::Handle(proc(channel) {
                    self.handle_who(channel, origin)
                }))
            },
            None => {} // handle later
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}

/// Handles NAMES message
pub struct Names {
    raw: RawMessage,
    receivers: Vec<util::Receiver>
}
impl Names {
    /// Sends the list of users to the client
    pub fn handle_names(channel: &Channel, proxy: &Peer) {
        // TODO check if channel is visible to user…
        // TODO replace with generic list sending function
        for member in channel.members() {
            channel.send_response(proxy, cmd::RPL_NAMREPLY, [
                String::from_str("= ").append(channel.name()).as_slice(),
                member.decorated_nick()
            ])
        }
        channel.send_response(proxy, cmd::RPL_ENDOFNAMES,
            [channel.name(), "End of /NAMES list"])
    }
}
impl super::MessageHandler for Names {
    fn from_message(message: RawMessage) -> Result<Box<Names>, RawMessage> {
        if message.params().len() > 0 {
            Ok(box Names {
                raw: message.clone(),
                receivers: message.params()[0].as_slice().split(|c| *c == b',').map(|v|
                    util::verify_receiver(v)
                ).collect()
            })
        } else {
            Err(RawMessage::new(cmd::REPLY(cmd::ERR_NEEDMOREPARAMS), [
                "*", message.command().to_string().as_slice(),
                "not enought params given"
            ], None))
        }
    }
    fn invoke(self, server: &mut Server, origin: Peer) {
        let host = server.host().to_string(); // clone due to #6393
        for recv in self.receivers.iter() {
            match recv {
                &util::ChannelName(ref name) => {
                    match server.channels.find_mut(&name.to_string()) {
                        Some(channel) => {
                            let proxy = origin.clone();
                            channel.send(channel::Handle(proc(channel) {
                                Names::handle_names(channel, &proxy)
                            }))
                        },
                        None => origin.send_response(cmd::ERR_NOSUCHCHANNEL,
                            &[name.as_slice(), "No such channel"],
                            host.as_slice()
                        )
                    }
                },
                _ => {}
            }

        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<|endoftext|>


<commit_before>use rustc_serialize::json;
use std::convert::From;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::io;
use std::path::PathBuf;

#[derive(Debug)]
pub enum Error {
    AuthError(String),
    Ota(OtaReason),
    ParseError(String),
    PackageError(String),
    ClientError(String),
    Config(ConfigReason),
    JsonEncode(json::EncoderError),
    JsonDecode(json::DecoderError),
    Io(io::Error)
}

impl From<json::EncoderError> for Error {
    fn from(e: json::EncoderError) -> Error {
        Error::JsonEncode(e)
    }
}

impl From<json::DecoderError> for Error {
    fn from(e: json::DecoderError) -> Error {
        Error::JsonDecode(e)
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

#[derive(Debug)]
pub enum OtaReason {
    CreateFile(PathBuf, io::Error),
    Client(String, String),
}

#[derive(Debug)]
pub enum PackageManagerReason {
    FileDoesNotExist(String),
    InstallFailed(String)
}

#[derive(Debug)]
pub enum ConfigReason {
    Parse(ParseReason),
    Io(io::Error),
}

#[derive(Debug)]
pub enum ParseReason {
    InvalidToml,
    InvalidSection(String),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            Error::AuthError(ref s)    => format!("Authentication error, {}", s.clone()),
            Error::Ota(ref e)          => format!("Ota error, {}", e.clone()),
            Error::ParseError(ref s)   => s.clone(),
            Error::PackageError(ref s) => s.clone(),
            Error::ClientError(ref s)  => s.clone(),
            Error::Config(ref e)       => format!("Failed to {}", e.clone()),
            Error::JsonEncode(ref e)   => format!("Failed to encode JSON: {}", e.clone()),
            Error::JsonDecode(ref e)   => format!("Failed to decode JSON: {}", e.clone()),
            Error::Io(ref e)           => format!("IO Error{:?}", e.clone()),
        };
        write!(f, "{}", inner)
    }
}

impl Display for OtaReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            OtaReason::CreateFile(ref f, ref e) =>
                format!("failed to create file {:?}: {}", f.clone(), e.clone()),
            OtaReason::Client(ref r, ref e) =>
                format!("the request: {},\nresults in the following error: {}", r.clone(), e.clone()),
        };
        write!(f, "{}", inner)
    }
}

impl Display for ConfigReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            ConfigReason::Parse(ref e) => format!("parse config: {}", e.clone()),
            ConfigReason::Io   (ref e) => format!("load config: {}", e.clone())
        };
        write!(f, "{}", inner)
    }
}

impl Display for ParseReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            ParseReason::InvalidToml           => "invalid toml".to_string(),
            ParseReason::InvalidSection(ref s) => format!("invalid section: {}", s),
        };
        write!(f, "{}", inner)
    }
}

#[macro_export]
macro_rules! exit {
    ($fmt:expr) => ({
        print!(concat!($fmt, "\n"));
        std::process::exit(1);
    });
    ($fmt:expr, $($arg:tt)*) => ({
        print!(concat!($fmt, "\n"), $($arg)*);
        std::process::exit(1);
    })
}
<commit_msg>Remove unused package manager reason.<commit_after>use rustc_serialize::json;
use std::convert::From;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::io;
use std::path::PathBuf;

#[derive(Debug)]
pub enum Error {
    AuthError(String),
    Ota(OtaReason),
    ParseError(String),
    PackageError(String),
    ClientError(String),
    Config(ConfigReason),
    JsonEncode(json::EncoderError),
    JsonDecode(json::DecoderError),
    Io(io::Error)
}

impl From<json::EncoderError> for Error {
    fn from(e: json::EncoderError) -> Error {
        Error::JsonEncode(e)
    }
}

impl From<json::DecoderError> for Error {
    fn from(e: json::DecoderError) -> Error {
        Error::JsonDecode(e)
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

#[derive(Debug)]
pub enum OtaReason {
    CreateFile(PathBuf, io::Error),
    Client(String, String),
}

#[derive(Debug)]
pub enum ConfigReason {
    Parse(ParseReason),
    Io(io::Error),
}

#[derive(Debug)]
pub enum ParseReason {
    InvalidToml,
    InvalidSection(String),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            Error::AuthError(ref s)    => format!("Authentication error, {}", s.clone()),
            Error::Ota(ref e)          => format!("Ota error, {}", e.clone()),
            Error::ParseError(ref s)   => s.clone(),
            Error::PackageError(ref s) => s.clone(),
            Error::ClientError(ref s)  => s.clone(),
            Error::Config(ref e)       => format!("Failed to {}", e.clone()),
            Error::JsonEncode(ref e)   => format!("Failed to encode JSON: {}", e.clone()),
            Error::JsonDecode(ref e)   => format!("Failed to decode JSON: {}", e.clone()),
            Error::Io(ref e)           => format!("IO Error{:?}", e.clone()),
        };
        write!(f, "{}", inner)
    }
}

impl Display for OtaReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            OtaReason::CreateFile(ref f, ref e) =>
                format!("failed to create file {:?}: {}", f.clone(), e.clone()),
            OtaReason::Client(ref r, ref e) =>
                format!("the request: {},\nresults in the following error: {}", r.clone(), e.clone()),
        };
        write!(f, "{}", inner)
    }
}

impl Display for ConfigReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            ConfigReason::Parse(ref e) => format!("parse config: {}", e.clone()),
            ConfigReason::Io   (ref e) => format!("load config: {}", e.clone())
        };
        write!(f, "{}", inner)
    }
}

impl Display for ParseReason {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let inner: String = match *self {
            ParseReason::InvalidToml           => "invalid toml".to_string(),
            ParseReason::InvalidSection(ref s) => format!("invalid section: {}", s),
        };
        write!(f, "{}", inner)
    }
}

#[macro_export]
macro_rules! exit {
    ($fmt:expr) => ({
        print!(concat!($fmt, "\n"));
        std::process::exit(1);
    });
    ($fmt:expr, $($arg:tt)*) => ({
        print!(concat!($fmt, "\n"), $($arg)*);
        std::process::exit(1);
    })
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![feature(collections)]
#![feature(libc)]

#[macro_use]
extern crate grust;

extern crate "glib-2_0-sys" as glib;
extern crate libc;

use grust::gstr;
use grust::gstr::{Utf8Buf, OwnedGStr};

use grust::types::gchar;

use glib::g_strdup;

static TEST_CSTR: &'static str = "¡Hola, amigos!\0";
static TEST_STR:  &'static str = "¡Hola, amigos!";

fn owned_g_str(source: &str) -> OwnedGStr {
    assert!(source.ends_with("\0"));
    unsafe {
        let p = source.as_ptr();
        OwnedGStr::from_ptr(g_strdup(p as *const gchar))
    }
}

fn owned_g_str_from_bytes(source: &[u8]) -> OwnedGStr {
    assert!(source.last() == Some(&0u8));
    unsafe {
        let p = source.as_ptr();
        OwnedGStr::from_ptr(g_strdup(p as *const gchar))
    }
}

fn g_str_equal(p1: *const gchar, p2: *const gchar) -> bool {
    let cmp_res = unsafe { libc::strcmp(p1, p2) };
    cmp_res == 0
}

#[test]
fn test_owned_g_str_to_utf8() {
    let str = owned_g_str(TEST_CSTR);
    let res = str.to_utf8();
    assert!(res.is_ok());
    assert_eq!(res.unwrap(), TEST_STR);
}

#[test]
fn test_owned_g_str_to_utf8_invalid() {
    let s = owned_g_str_from_bytes(b"a\x80\0");
    let res = s.to_utf8();
    assert!(res.is_err());
    match res {
        Err(_) => {}
        _ => unreachable!()
    }
}

#[test]
fn test_owned_g_str_to_bytes() {
    let str = owned_g_str_from_bytes(b"a\x80\0");
    let bytes = str.to_bytes();
    assert_eq!(bytes.len(), 2);
    assert_eq!(bytes[0], b'a');
    assert_eq!(bytes[1], b'\x80');
}

#[test]
fn test_owned_g_str_clone() {
    let str1 = owned_g_str(TEST_CSTR);
    let str2 = str1.clone();
    let s = str2.to_utf8().unwrap();
    assert_eq!(s, TEST_STR.to_string());
}

#[test]
fn test_owned_g_str_eq() {
    let s1 = owned_g_str(TEST_CSTR);
    let s2 = owned_g_str(TEST_CSTR);
    assert!(s1 == s2);
}

#[test]
fn test_owned_g_str_ne() {
    let s1 = owned_g_str(TEST_CSTR);
    let s2 = owned_g_str("This is not the string you are looking for\0");
    assert!(s1 != s2);
}

#[test]
fn test_owned_g_str_deref() {
    let s = owned_g_str(TEST_CSTR);
    let p = s.as_ptr();
    assert!(g_str_equal(p, TEST_CSTR.as_ptr() as *const gchar));
}

#[test]
fn test_g_str_macro() {
    let s = g_str!("Hello!");
    assert!(g_str_equal(s.as_ptr(), "Hello!\0".as_ptr() as *const gchar));
}

#[test]
fn test_g_utf8_macro() {
    let s = g_utf8!("Hello!");
    assert!(g_str_equal(s.as_ptr(), "Hello!\0".as_ptr() as *const gchar));
}

#[test]
fn test_utf8_from_static_str() {
    let s = gstr::Utf8::from_static_str(TEST_CSTR);
    assert_eq!(s.as_ptr(), TEST_CSTR.as_ptr() as *const gchar);
}

#[test]
fn test_utf8_buf_from_str() {
    let s = String::from_str(TEST_STR);
    let buf = Utf8Buf::from_str(&s[]).unwrap();
    assert!(g_str_equal(buf.as_ptr(), TEST_CSTR.as_ptr() as *const gchar));

    let res = Utf8Buf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.position, 3);
}

#[test]
fn test_utf8_buf_from_string() {
    let s = String::from_str(TEST_STR);
    let buf = Utf8Buf::from_string(s).unwrap();
    assert!(g_str_equal(buf.as_ptr(), TEST_CSTR.as_ptr() as *const gchar));

    let s = String::from_str("got\0nul");
    let res = Utf8Buf::from_string(s);
    let err = res.err().unwrap();
    assert_eq!(err.nul_error().position, 3);
}
<commit_msg>Use modern slice syntax<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![feature(collections)]
#![feature(libc)]

#[macro_use]
extern crate grust;

extern crate "glib-2_0-sys" as glib;
extern crate libc;

use grust::gstr;
use grust::gstr::{Utf8Buf, OwnedGStr};

use grust::types::gchar;

use glib::g_strdup;

static TEST_CSTR: &'static str = "¡Hola, amigos!\0";
static TEST_STR:  &'static str = "¡Hola, amigos!";

fn owned_g_str(source: &str) -> OwnedGStr {
    assert!(source.ends_with("\0"));
    unsafe {
        let p = source.as_ptr();
        OwnedGStr::from_ptr(g_strdup(p as *const gchar))
    }
}

fn owned_g_str_from_bytes(source: &[u8]) -> OwnedGStr {
    assert!(source.last() == Some(&0u8));
    unsafe {
        let p = source.as_ptr();
        OwnedGStr::from_ptr(g_strdup(p as *const gchar))
    }
}

fn g_str_equal(p1: *const gchar, p2: *const gchar) -> bool {
    let cmp_res = unsafe { libc::strcmp(p1, p2) };
    cmp_res == 0
}

#[test]
fn test_owned_g_str_to_utf8() {
    let str = owned_g_str(TEST_CSTR);
    let res = str.to_utf8();
    assert!(res.is_ok());
    assert_eq!(res.unwrap(), TEST_STR);
}

#[test]
fn test_owned_g_str_to_utf8_invalid() {
    let s = owned_g_str_from_bytes(b"a\x80\0");
    let res = s.to_utf8();
    assert!(res.is_err());
    match res {
        Err(_) => {}
        _ => unreachable!()
    }
}

#[test]
fn test_owned_g_str_to_bytes() {
    let str = owned_g_str_from_bytes(b"a\x80\0");
    let bytes = str.to_bytes();
    assert_eq!(bytes.len(), 2);
    assert_eq!(bytes[0], b'a');
    assert_eq!(bytes[1], b'\x80');
}

#[test]
fn test_owned_g_str_clone() {
    let str1 = owned_g_str(TEST_CSTR);
    let str2 = str1.clone();
    let s = str2.to_utf8().unwrap();
    assert_eq!(s, TEST_STR.to_string());
}

#[test]
fn test_owned_g_str_eq() {
    let s1 = owned_g_str(TEST_CSTR);
    let s2 = owned_g_str(TEST_CSTR);
    assert!(s1 == s2);
}

#[test]
fn test_owned_g_str_ne() {
    let s1 = owned_g_str(TEST_CSTR);
    let s2 = owned_g_str("This is not the string you are looking for\0");
    assert!(s1 != s2);
}

#[test]
fn test_owned_g_str_deref() {
    let s = owned_g_str(TEST_CSTR);
    let p = s.as_ptr();
    assert!(g_str_equal(p, TEST_CSTR.as_ptr() as *const gchar));
}

#[test]
fn test_g_str_macro() {
    let s = g_str!("Hello!");
    assert!(g_str_equal(s.as_ptr(), "Hello!\0".as_ptr() as *const gchar));
}

#[test]
fn test_g_utf8_macro() {
    let s = g_utf8!("Hello!");
    assert!(g_str_equal(s.as_ptr(), "Hello!\0".as_ptr() as *const gchar));
}

#[test]
fn test_utf8_from_static_str() {
    let s = gstr::Utf8::from_static_str(TEST_CSTR);
    assert_eq!(s.as_ptr(), TEST_CSTR.as_ptr() as *const gchar);
}

#[test]
fn test_utf8_buf_from_str() {
    let s = String::from_str(TEST_STR);
    let buf = Utf8Buf::from_str(&s[..]).unwrap();
    assert!(g_str_equal(buf.as_ptr(), TEST_CSTR.as_ptr() as *const gchar));

    let res = Utf8Buf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.position, 3);
}

#[test]
fn test_utf8_buf_from_string() {
    let s = String::from_str(TEST_STR);
    let buf = Utf8Buf::from_string(s).unwrap();
    assert!(g_str_equal(buf.as_ptr(), TEST_CSTR.as_ptr() as *const gchar));

    let s = String::from_str("got\0nul");
    let res = Utf8Buf::from_string(s);
    let err = res.err().unwrap();
    assert_eq!(err.nul_error().position, 3);
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    syn::parse2::<Expr>(tokens).unwrap();
}
<commit_msg>Add snapshot test for group with trailer expr<commit_after>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}
<|endoftext|>