<commit_before>use frontend::scanner::{scan_into_iterator, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum CompilationError {
    ScannerError(ScannerError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

enum RuleFunction {
    Grouping,
    Unary,
    Binary,
    Number,
}

struct Rule {
    precedence: Precedence,
    prefix: Option<RuleFunction>,
    infix: Option<RuleFunction>,
}

impl Rule {
    /// Finds the rule associated with a Token type.
    /// This is derived straight from the Pratt Parser table.
    fn find(token: &Token) -> Rule {
        match token {
            Token::LeftParen => Rule {
                precedence: Precedence::Call,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightParen => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::LeftBrace => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightBrace => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Comma => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Dot => Rule {
                precedence: Precedence::Call,
                prefix: None,
                infix: None,
            },
            Token::Minus => Rule {
                precedence: Precedence::Term,
                prefix: Some(RuleFunction::Unary),
                infix: Some(RuleFunction::Binary),
            },
            Token::Plus => Rule {
                precedence: Precedence::Term,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Slash => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Star => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Semicolon => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::NumberLiteral(_) => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Number),
                infix: None,
            },
            _ => unimplemented!(),
            /*
  { NULL,     NULL,    PREC_NONE },       // TOKEN_BANG
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_BANG_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EQUAL
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_EQUAL_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IDENTIFIER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_STRING
  { NULL,     NULL,    PREC_AND },        // TOKEN_AND
  { NULL,     NULL,    PREC_NONE },       // TOKEN_CLASS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ELSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FALSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FUN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FOR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IF
  { NULL,     NULL,    PREC_NONE },       // TOKEN_NIL
  { NULL,     NULL,    PREC_OR },         // TOKEN_OR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_PRINT
  { NULL,     NULL,    PREC_NONE },       // TOKEN_RETURN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_SUPER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_THIS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_TRUE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_VAR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_WHILE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ERROR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EOF
*/
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return ()
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn dispatch(&mut self, rule_function: RuleFunction) -> Result<(), ()> {
        match rule_function {
            RuleFunction::Grouping => self.grouping(),
            RuleFunction::Unary => self.unary(),
            RuleFunction::Binary => self.binary(),
            RuleFunction::Number => self.number(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ()> {
        self.skip_to_valid();
        let rule = match self.tokens.peek() {
            Some(Ok(ref token_with_context)) => {
                let prefix_rule = Rule::find(&token_with_context.token);
                match prefix_rule.prefix {
                    Some(prefix_function) => prefix_function,
                    None => return Err(()), // TODO: make it meaningful. Was: error("Expect expression.");
                }
            }
            Some(Err(_)) => unreachable!("We already skipped errors"),
            None => return Ok(()), // TODO: check if this is okay. Do we always expect something?
        };
        self.dispatch(rule)?;
        loop {
            self.skip_to_valid();
            let rule = match self.tokens.peek() {
                Some(Ok(ref token_with_context)) => {
                    let infix_rule = Rule::find(&token_with_context.token);
                    if precedence <= infix_rule.precedence {
                        match infix_rule.infix {
                            None => return Err(()), // TODO: make it meaningful. Was: error("Expect expression.");
                            Some(prefix_function) => prefix_function,
                        }
                    } else {
                        return Ok(());
                    }
                }
                Some(Err(_)) => unreachable!("We already skipped errors"),
                None => return Ok(()), // TODO: check if this is okay. Do we always expect something?
            };
            self.dispatch(rule)?;
        }
    }

    fn expression(&mut self) -> Result<(), ()> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ()> {
        let current = self.advance();
        if let Some(ref token_with_context) = current {
            if token_with_context.token == token {
                Ok(())
            } else {
                Err(())
            }
        } else {
            Err(()) //TODO: make it meaningful. Was "Expect ')' after expression.");
        }
    }

    fn number(&mut self) -> Result<(), ()> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                // TODO: better message. To get here we had to peek a NumberLiteral
                panic!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ()> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ()> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ()> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        self.skip_to_valid();
        let precedence = match self.tokens.peek() {
            Some(Ok(ref token)) => {
                let rule = Rule::find(&token.token);
                rule.precedence.next()
            }
            Some(Err(_)) => unreachable!("We already skipped past errors"),
            // TODO: I think this is not okay.
            // In any case, we need a good error message
            None => return Err(()),
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.expression()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<commit_msg>Unified peeking<commit_after>use frontend::scanner::{scan_into_iterator, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum CompilationError {
    ScannerError(ScannerError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

enum RuleFunction {
    Grouping,
    Unary,
    Binary,
    Number,
}

struct Rule {
    precedence: Precedence,
    prefix: Option<RuleFunction>,
    infix: Option<RuleFunction>,
}

impl Rule {
    /// Finds the rule associated with a Token type.
    /// This is derived straight from the Pratt Parser table.
    fn find(token: &Token) -> Rule {
        match token {
            Token::LeftParen => Rule {
                precedence: Precedence::Call,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightParen => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::LeftBrace => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightBrace => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Comma => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Dot => Rule {
                precedence: Precedence::Call,
                prefix: None,
                infix: None,
            },
            Token::Minus => Rule {
                precedence: Precedence::Term,
                prefix: Some(RuleFunction::Unary),
                infix: Some(RuleFunction::Binary),
            },
            Token::Plus => Rule {
                precedence: Precedence::Term,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Slash => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Star => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Semicolon => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::NumberLiteral(_) => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Number),
                infix: None,
            },
            _ => unimplemented!(),
            /*
  { NULL,     NULL,    PREC_NONE },       // TOKEN_BANG
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_BANG_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EQUAL
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_EQUAL_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IDENTIFIER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_STRING
  { NULL,     NULL,    PREC_AND },        // TOKEN_AND
  { NULL,     NULL,    PREC_NONE },       // TOKEN_CLASS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ELSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FALSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FUN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FOR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IF
  { NULL,     NULL,    PREC_NONE },       // TOKEN_NIL
  { NULL,     NULL,    PREC_OR },         // TOKEN_OR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_PRINT
  { NULL,     NULL,    PREC_NONE },       // TOKEN_RETURN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_SUPER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_THIS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_TRUE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_VAR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_WHILE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ERROR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EOF
*/
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return (),
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn peek(&mut self) -> Option<&TokenWithContext> {
        self.skip_to_valid();
        self.tokens.peek().map(|result| match result {
            Ok(ref token_with_context) => token_with_context,
            Err(_) => unreachable!("We already skipped errors"),
        })
    }

    fn dispatch(&mut self, rule_function: RuleFunction) -> Result<(), ()> {
        match rule_function {
            RuleFunction::Grouping => self.grouping(),
            RuleFunction::Unary => self.unary(),
            RuleFunction::Binary => self.binary(),
            RuleFunction::Number => self.number(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ()> {
        let prefix_function = {
            let peeked = self.peek().ok_or_else(|| ())?; //TODO: fill with details. Is this even okay?
            Rule::find(&peeked.token).prefix.ok_or_else(|| ())? //TODO: fill with details
        };
        self.dispatch(prefix_function)?;
        loop {
            let infix_function = {
                match self.peek() {
                    Some(peeked) => {
                        let infix_rule = Rule::find(&peeked.token);
                        if precedence <= infix_rule.precedence {
                            infix_rule.infix.ok_or_else(|| ())? // TODO: make it meaningful. Was: error("Expect expression.");
                        } else {
                            return Ok(());
                        }
                    }
                    None => return Ok(()),
                }
            };
            self.dispatch(infix_function)?;
        }
    }

    fn expression(&mut self) -> Result<(), ()> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ()> {
        let current = self.advance();
        if let Some(ref token_with_context) = current {
            if token_with_context.token == token {
                Ok(())
            } else {
                Err(())
            }
        } else {
            Err(()) //TODO: make it meaningful. Was "Expect ')' after expression.");
        }
    }

    fn number(&mut self) -> Result<(), ()> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                // TODO: better message. To get here we had to peek a NumberLiteral
                panic!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ()> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ()> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ()> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        let precedence = {
            let peeked = self.peek().ok_or_else(|| ())?; //TODO: fill in details
            Rule::find(&peeked.token).precedence.next()
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.expression()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<|endoftext|>


<commit_before>use frontend::scanner::{scan_into_iterator, Position, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum ParsingError {
    UnexpectedEndOfFile,
    Unexpected(String, Position),
}

enum CompilationError {
    ScannerError(ScannerError),
    ParsingError(ParsingError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return (),
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn peek(&mut self) -> Option<&TokenWithContext> {
        self.skip_to_valid();
        self.tokens.peek().map(|result| match result {
            Ok(ref token_with_context) => token_with_context,
            Err(_) => unreachable!("We already skipped errors"),
        })
    }

    fn find_rule(
        token: &Token,
    ) -> (
        Precedence,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
    )
    where
        I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
    {
        // (Precedence, Prefix, Infix)
        match token {
            Token::LeftParen => (Precedence::Call, Some(Parser::grouping), None),
            Token::RightParen => (Precedence::None, None, None),
            Token::Comma => (Precedence::None, None, None),
            Token::Dot => (Precedence::Call, None, None),
            Token::Minus => (
                Precedence::Term,
                Some(Parser::unary),
                Some(Parser::binary),
            ),
            Token::Plus => (Precedence::Term, None, Some(Parser::binary)),
            Token::Slash => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Star => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Semicolon => (Precedence::None, None, None),
            Token::NumberLiteral(_) => (Precedence::None, Some(Parser::number), None),
            _ => unimplemented!(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ParsingError> {
        let prefix_function = {
            let peeked = self.peek().ok_or(ParsingError::UnexpectedEndOfFile)?;
            let (_, prefix_function, _) = Self::find_rule(&peeked.token);
            prefix_function
                .ok_or_else(|| ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position))?
        };
        prefix_function(self)?;
        loop {
            let infix_function = {
                match self.peek() {
                    Some(peeked) => {
                        let (infix_rule_precedence, _, infix_function) =
                            Self::find_rule(&peeked.token);
                        if precedence <= infix_rule_precedence {
                            infix_function.ok_or_else(|| {
                                ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position)
                            })?
                        } else {
                            return Ok(());
                        }
                    }
                    None => return Ok(()),
                }
            };
            infix_function(self)?;
        }
    }

    fn expression(&mut self) -> Result<(), ParsingError> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ParsingError> {
        let current = self.advance().ok_or(ParsingError::UnexpectedEndOfFile)?;
        if current.token == token {
            Ok(())
        } else {
            Err(ParsingError::Unexpected(
                current.lexeme.clone(),
                current.position,
            ))
        }
    }

    fn number(&mut self) -> Result<(), ParsingError> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                unreachable!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ParsingError> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        let precedence = {
            let peeked = self
                .peek()
                .ok_or_else(|| ParsingError::UnexpectedEndOfFile)?;
            let (precedence, _, _) = Self::find_rule(&peeked.token);
            precedence.next()
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn parse(&mut self) -> Result<(), ()> {
        loop {
            match self.expression() {
                Ok(()) => return Ok(()),
                Err(error) => {
                    self.errors.push(CompilationError::ParsingError(error))
                    //TODO: add recovery mode
                }
            }
        }
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.parse()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<commit_msg>Docs for the Pratt table<commit_after>use frontend::scanner::{scan_into_iterator, Position, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum ParsingError {
    UnexpectedEndOfFile,
    Unexpected(String, Position),
}

enum CompilationError {
    ScannerError(ScannerError),
    ParsingError(ParsingError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return (),
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn peek(&mut self) -> Option<&TokenWithContext> {
        self.skip_to_valid();
        self.tokens.peek().map(|result| match result {
            Ok(ref token_with_context) => token_with_context,
            Err(_) => unreachable!("We already skipped errors"),
        })
    }

    /// Represents the table for the Pratt Parser.
    /// Given the next token it will return a triple containing
    /// (Precedence, Prefix function, Infix function).
    /// The two functions are optional as they might not be specified.
    ///
    /// Note that this function doesn't care about the values possibly
    /// associated with a token. It operates only according to their
    /// variant.
    ///
    /// This is generally used on the token peeked from the front of
    /// the iterator. This lookahead allows us to decide what to do next
    /// according to the "table" below.
    fn find_rule(
        token: &Token,
    ) -> (
        Precedence,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
    )
    where
        I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
    {
        match token {
            Token::LeftParen => (Precedence::Call, Some(Parser::grouping), None),
            Token::RightParen => (Precedence::None, None, None),
            Token::Comma => (Precedence::None, None, None),
            Token::Dot => (Precedence::Call, None, None),
            Token::Minus => (
                Precedence::Term,
                Some(Parser::unary),
                Some(Parser::binary),
            ),
            Token::Plus => (Precedence::Term, None, Some(Parser::binary)),
            Token::Slash => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Star => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Semicolon => (Precedence::None, None, None),
            Token::NumberLiteral(_) => (Precedence::None, Some(Parser::number), None),
            _ => unimplemented!(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ParsingError> {
        let prefix_function = {
            let peeked = self.peek().ok_or(ParsingError::UnexpectedEndOfFile)?;
            let (_, prefix_function, _) = Self::find_rule(&peeked.token);
            prefix_function
                .ok_or_else(|| ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position))?
        };
        prefix_function(self)?;
        loop {
            let infix_function = {
                match self.peek() {
                    Some(peeked) => {
                        let (infix_rule_precedence, _, infix_function) =
                            Self::find_rule(&peeked.token);
                        if precedence <= infix_rule_precedence {
                            infix_function.ok_or_else(|| {
                                ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position)
                            })?
                        } else {
                            return Ok(());
                        }
                    }
                    None => return Ok(()),
                }
            };
            infix_function(self)?;
        }
    }

    fn expression(&mut self) -> Result<(), ParsingError> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ParsingError> {
        let current = self.advance().ok_or(ParsingError::UnexpectedEndOfFile)?;
        if current.token == token {
            Ok(())
        } else {
            Err(ParsingError::Unexpected(
                current.lexeme.clone(),
                current.position,
            ))
        }
    }

    fn number(&mut self) -> Result<(), ParsingError> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                unreachable!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ParsingError> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        let precedence = {
            let peeked = self
                .peek()
                .ok_or_else(|| ParsingError::UnexpectedEndOfFile)?;
            let (precedence, _, _) = Self::find_rule(&peeked.token);
            precedence.next()
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn parse(&mut self) -> Result<(), ()> {
        loop {
            match self.expression() {
                Ok(()) => return Ok(()),
                Err(error) => {
                    self.errors.push(CompilationError::ParsingError(error))
                    //TODO: add recovery mode
                }
            }
        }
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.parse()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<|endoftext|>


<commit_before>/**
  rest={ <next> ...rest }
  init={}
*/

#[macro_export]
macro_rules! assert_valid_self_arg {
    (self) => {}
}

#[macro_export]
macro_rules! declare_types {
    { $($rest:tt)* } => {
        declare_types_internal! {
            state: top_level,
            program: {
                rest: { $($rest)* },
                init: {}
            }
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! declare_types_internal {
    // STATE: top_level

    {
        state: top_level,
        program: {
            rest: { },
            init: $init: tt
        }
    } => {
        println!("DONE {}", stringify!($init));
    };

    {
        state: top_level,
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_class,
            pub: false,
            reopen: false,
            program: $program
        }
    };

    // STATE: parse_class

    {
        state: parse_class,
        pub: false,
        reopen: false,
        program: {
          rest: { pub $($rest:tt)* },
          init: $init:tt
        }
    } => {
        declare_types_internal! {
            state: parse_class,
            pub: true,
            reopen: false,
            program: {
              rest: { $($rest)* },
              init: $init
            }
        }
    };

    {
        state: parse_class,
        pub: $pub:tt,
        reopen: false,
        program: {
          rest: { reopen $($rest:tt)* },
          init: $init:tt
        }
    } => {
        declare_types_internal! {
            state: parse_class,
            pub: $pub,
            reopen: true,
            program: {
              rest: { $($rest)* },
              init: $init
            }
        }
    };

    {
        state: parse_class,
        pub: $pub:tt,
        reopen: $reopen:tt,
        program: {
          rest: { class $name:ident { $($body:tt)* } $($rest:tt)* },
          init: $init:tt
        }
    } => {
        declare_types_internal! {
            state: class,
            class: {
                meta: { pub: $pub, reopen: $reopen, name: $name },
                body: { $($body)* }
            },
            program: {
              rest: { $($rest)* },
              init: $init
            }
        }
    };

    // STATE: class

    {
        state: class,
        class: {
            meta: $meta:tt,
            body: { def $($rest:tt)* }
        },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_method,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            program: $program
        }
    };

    {
        state: class,
        class: {
            meta: $meta:tt,
            body: { struct $($rest:tt)* }
        },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_struct,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            program: $program
        }
    };

    {
        state: class,
        class: {
            meta: $meta:tt,
            body: { }
        },
        program: $program:tt
    } => {
        println!("{}", stringify!(class: {
            meta: $meta
        }));

        declare_types_internal! {
            state: top_level,
            program: $program
        }
    };

    // STATE: parse_method

    {
        state: parse_method,
        class: {
            meta: $meta:tt,
            body: { initialize $($rest:tt)* }
        },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_initialize,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            method: {
                type: initializer,
                name: initialize,
            },
            program: $program
        }
    };

    {
        state: parse_method,
        class: {
            meta: $meta:tt,
            body: { $name:ident ( $($args:tt)* ) $($rest:tt)* }
        },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_arguments_self,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            method: {
                name: $name,
            },
            args: { $($args)* },
            program: $program
        }
    };

    // STATE: parse_arguments_self

    {
        state: parse_arguments_self,
        class: $class:tt,
        method: {
            name: $name:tt,
        },
        args: { & mut $self_arg:ident $($rest:tt)* },
        program: $program:tt
    } => {
        assert_valid_self_arg!($self_arg);

        declare_types_internal! {
            state: parse_arguments_consume_possible_comma,
            class: $class,
            method: {
                type: instance,
                name: $name,
                self: {
                    ownership: { & mut },
                    name: $self_arg
                }
            },
            args: { $($rest)* },
            program: $program
        }
    };

    {
        state: parse_arguments_self,
        class: $class:tt,
        method: {
            name: $name:tt,
        },
        args: { & $self_arg:ident $($rest:tt)* },
        program: $program:tt
    } => {
        assert_valid_self_arg!($self_arg);

        declare_types_internal! {
            state: parse_arguments_consume_possible_comma,
            class: $class,
            method: {
                type: instance,
                name: $name,
                self: {
                    ownership: { & },
                    name: $self_arg
                }
            },
            args: { $($rest)* },
            program: $program
        }
    };

    {
        state: parse_arguments_self,
        class: $class:tt,
        method: {
            name: $name:tt,
        },
        args: { $($rest:tt)* },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_arguments,
            class: $class,
            method: {
                type: class,
                name: $name,
                self: ()
            },
            args: { $($rest)* },
            program: $program
        }
    };

    // STATE: parse_arguments_consume_possible_comma

    {
        state: parse_arguments_consume_possible_comma,
        class: $class:tt,
        method: $method:tt,
        args: { , $($rest:tt)+ },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_arguments,
            class: $class,
            method: $method,
            args: { $($rest)+ },
            program: $program
        }
    };

    {
        state: parse_arguments_consume_possible_comma,
        class: $class:tt,
        method: $method:tt,
        args: { },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_arguments,
            class: $class,
            method: $method,
            args: { },
            program: $program
        }
    };

    // STATE: parse_arguments

    {
        state: parse_arguments,
        class: $class:tt,
        method: {
            type: $type:ident,
            name: $name:tt,
            self: $self:tt
        },
        args: { $($args:tt)* },
        program: $program:tt
    } => {
        declare_types_internal! {
            state: parse_return_type,
            class: $class,
            method: {
                type: $type,
                name: $name,
                self: $self,
                args: { $($args)* }
            },
            program: $program
        }
    };

    // STATE: parse_return_type

    {
        state: parse_return_type,
        class: {
            meta: $meta:tt,
            body: { -> $ret:ty $body:block $($rest:tt)* }
        },
        method: {
            type: $type:ident,
            name: $name:tt,
            self: $self:tt,
            args: $args:tt
        },
        program: $program:tt
    } => {
        println!("{}", stringify!(method: {
            type: $type,
            name: $name,
            self: $self,
            args: $args,
            ret: $ret
        }));

        declare_types_internal! {
            state: class,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            program: $program
        }
    };

    {
        state: parse_return_type,
        class: {
            meta: $meta:tt,
            body: { $body:block $($rest:tt)* }
        },
        method: {
            type: $type:ident,
            name: $name:tt,
            self: $self:tt,
            args: $args:tt
        },
        program: $program:tt
    } => {
        println!("{}", stringify!(method: {
            type: $type,
            name: $name,
            self: $self,
            args: $args,
            ret: ()
        }));

        declare_types_internal! {
            state: class,
            class: {
                meta: $meta,
                body: { $($rest)* }
            },
            program: $program
        }
    };

    // // STATE: class_signature

    // {
    //     state: class_signature,
    //     class_tokens: { }
    //     program: {
    //         rest: {
    //             $($signature:ident)* class $name:ident { $($body:tt)* }
    //             $($rest:tt)*
    //         },
    //         init: $init:tt
    //     }
    // } => {
    //     declare_types_internal! {
    //         class_signature: {
    //           rest: { $($signature)* },
    //           body: { $(body)* },
    //           accum: { pub: false, reopen: false }
    //         },
    //         accum: { rest: { $($rest)* }, init: $init }
    //     }
    // };

    // // Step 2: parse the class signature

    // {
    //     class_signature: {
    //         rest: { pub $($rest:ident)* },
    //         body: $body:tt,
    //         accum: { pub: $pub:tt, reopen: false }
    //     },
    //     accum: $accum:tt
    // } => {
    //     declare_types_internal! {
    //         class_signature: {
    //           rest: { $($rest)* },
    //           body: $body,
    //           accum: { pub: true, reopen: false }
    //         },
    //         accum: $accum
    //     }
    // };

    // {
    //     class_signature: {
    //         rest: { reopen $($rest:ident)* },
    //         body: $body:tt,
    //         accum: { pub: $pub:tt, reopen: false }
    //     },
    //     accum: $accum:tt
    // } => {
    //     declare_types_internal! {
    //         class_signature: {
    //           rest: { $($rest)* },
    //           body: $body,
    //           accum: { pub: $pub, reopen: true }
    //         },
    //         accum: $accum
    //     }
    // };

    // {
    //     class_signature: {
    //         rest: { class $name:ident },
    //         body: $body:tt
    //         accum: { pub: $pub:tt, reopen: $reopen:tt }
    //     },
    //     accum: $accum:tt
    // } => {
    //     declare_types_internal! {
    //         class: {
    //           meta: { name: $name, pub: $pub, reopen: $reopen }
    //           rest: { $(body)* },
    //           accum: { }
    //         },
    //         accum: $accum
    //     }
    // };

    // // Step 3: take a method out of rest

    // {
    //     class: {
    //         meta: $meta:tt,
    //         rest: {
    //             def $name:ident($($args:tt)*) $(-> $ret:ty)* { $($body:tt)* }
    //             $($rest:tt)*
    //         },
    //         accum: $class_accum:tt
    //     },
    //     accum: $accum:tt
    // } => {
    //     declare_types_internal! {
    //         method: {
    //             def $name:ident($($args)*) $(-> $ret)* { $($body)* }
    //         },

    //         class: {
    //             meta:     $meta,
    //             rest:     { $($rest)* },
    //             elements: $elements
    //         },

    //         accum: $class_accum
    //     }
    // };

    // { $($all:tt)* } => {
    //     println!("ERROR: {}", stringify!($($all)*));
    // };
}

fn main() {
    declare_types! {
        class Foo {
            def multiply(&self, one: f64, two: f64) -> f64 {
                one * two
            }
        }
    }
}
<commit_msg>Convert the parser macro into a stack machine<commit_after>#[macro_export]
macro_rules! declare_types {
    { $($rest:tt)* } => {
        parse! {
            state: top_level,
            buffer: { $($rest)* },
            stack: { ast: [] }
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! parse {
    // STATE: top_level

    {
        state: top_level,
        buffer: {},
        stack: { ast: $ast:tt }
    } => {
        codegen!($ast);
    };

    {
        state: top_level,
        buffer: $buffer:tt,
        stack: { $($stack: tt)* }
    } => {
        parse! {
            state: parse_class,
            buffer: $buffer,
            stack: {
                pub: false,
                reopen: false,
                $($stack)*
            }
        }
    };

    // STATE: parse_class

    {
        state: parse_class,
        buffer: { pub $($rest:tt)* },
        stack: {
            pub: false,
            reopen: false,
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_class,
            buffer: { $($rest)* },
            stack: {
                pub: true,
                reopen: false,
                $($stack)*
            }
        }
    };

    {
        state: parse_class,
        buffer: { reopen $($rest:tt)* },
        stack: {
            pub: $pub:tt,
            reopen: false,
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_class,
            buffer: { $($rest)* },
            stack: {
                pub: $pub,
                reopen: true,
                $($stack)*
            }
        }
    };

    {
        state: parse_class,
        buffer: { class $name:ident { $($body:tt)* } $($rest:tt)* },
        stack: {
            pub: $pub:tt,
            reopen: $reopen:tt,
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_class_body,
            buffer: { $($body)* },
            stack: {
                class: {
                    type: class,
                    name: $name,
                    meta: { pub: $pub, reopen: $reopen },
                    struct: uninitialized,
                    methods: []
                },
                program: { $($rest)* },
                $($stack)*
            }
        }
    };

    // STATE: parse_class_body

    {
        state: parse_class_body,
        buffer: { struct { $($struct:tt)* } $($rest:tt)* },
        stack: {
            class: {
                type: class,
                name: $name:ident,
                meta: $meta:tt,
                struct: uninitialized,
                methods : []
            },
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_methods,
            buffer: { $($rest)* },
            stack: {
                class: {
                    type: class,
                    name: $name,
                    meta: $meta,
                    struct: { $($struct)* },
                    methods: []
                },
                $($stack)*
            }
        }
    };

    {
        state: parse_class_body,
        buffer: $buffer:tt,
        stack: {
            class: {
                type: class,
                name: $name:ident,
                meta: $meta:tt,
                struct: uninitialized,
                methods : []
            },
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_methods,
            buffer: $buffer,
            stack: {
                class: {
                    type: class,
                    name: $name,
                    meta: $meta,
                    struct: (),
                    methods: []
                },
                $($stack)*
            }
        }
    };

    // STATE: parse_methods

    {
        state: parse_methods,
        buffer: { def $($rest:tt)* },
        stack: $stack:tt
    } => {
        parse! {
            state: parse_method,
            buffer: { $($rest)* },
            stack: $stack
        }
    };

    {
        state: parse_methods,
        buffer: {},
        stack: {
            class: $class:tt,
            program: $program:tt,
            ast: [ $($ast:tt),* ]
        }
    } => {
        parse! {
            state: top_level,
            buffer: $program,
            stack: {
                ast: [ $($ast,)* $class ]
            }
        }
    };

    // STATE: parse_method

    {
        state: parse_method,
        buffer: { initialize ( $($args:tt)* ) $($rest:tt)* },
        stack: {
            class: $class:tt,
            $($stack:tt)*
        }
    } => {
        assert_struct!(true, $class);

        parse! {
            state: parse_arguments_helix,
            buffer: { $($args)* },
            stack: {
                class_body: { $($rest)* },
                class: $class,
                $($stack)*
            }
        }
    };

    {
        state: parse_method,
        buffer: { $name:ident ( $($args:tt)* ) $($rest:tt)* },
        stack: { $($stack:tt)* }
    } => {
        parse! {
            state: parse_arguments_self,
            buffer: { $($args)* },
            stack: {
                name: $name,
                class_body: { $($rest)* },
                $($stack)*
            }
        }
    };

    // STATE: parse_arguments_helix

    {
        state: parse_arguments_helix,
        buffer: { $helix_arg:ident $($rest:tt)* },
        stack: { $($stack:tt)* }
    } => {
        parse! {
            state: parse_arguments_consume_possible_comma,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: initializer,
                    name: initialize,
                    self: {
                        ownership: { },
                        name: $helix_arg
                    },
                    args: uninitialized,
                    ret: uninitialized,
                    body: uninitialized
                },
                $($stack)*
            }
        }
    };

    // STATE: parse_arguments_self

    {
        state: parse_arguments_self,
        buffer: { &mut $self_arg:ident $($rest:tt)* },
        stack: {
            name: $name:ident,
            $($stack:tt)*
        }
    } => {
        assert_valid_self_arg!($self_arg);

        parse! {
            state: parse_arguments_consume_possible_comma,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: instance_method,
                    name: $name,
                    self: {
                        ownership: { &mut },
                        name: $self_arg
                    },
                    args: uninitialized,
                    ret: uninitialized,
                    body: uninitialized
                },
                $($stack)*
            }
        }
    };

    {
        state: parse_arguments_self,
        buffer: { & $self_arg:ident $($rest:tt)* },
        stack: {
            name: $name:ident,
            $($stack:tt)*
        }
    } => {
        assert_valid_self_arg!($self_arg);

        parse! {
            state: parse_arguments_consume_possible_comma,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: instance_method,
                    name: $name,
                    self: {
                        ownership: { & },
                        name: $self_arg
                    },
                    args: uninitialized,
                    ret: uninitialized,
                    body: uninitialized
                },
                $($stack)*
            }
        }
    };

    {
        state: parse_arguments_self,
        buffer: $buffer:tt,
        stack: {
            name: $name:ident,
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_arguments,
            buffer: $buffer,
            stack: {
                method: {
                    type: class_method,
                    name: $name,
                    self: (),
                    args: uninitialized,
                    ret: uninitialized,
                    body: uninitialized
                },
                $($stack)*
            }
        }
    };

    // STATE: parse_arguments_consume_possible_comma

    {
        state: parse_arguments_consume_possible_comma,
        buffer: { , $($rest:tt)+ },
        stack: $stack:tt
    } => {
        parse! {
            state: parse_arguments,
            buffer: { $($rest)+ },
            stack: $stack
        }
    };

    {
        state: parse_arguments_consume_possible_comma,
        buffer: { },
        stack: $stack:tt
    } => {
        parse! {
            state: parse_arguments,
            buffer: $buffer,
            stack: $stack
        }
    };

    // STATE: parse_arguments

    {
        state: parse_arguments,
        buffer: { $($args:tt)* },
        stack: {
            method: {
                type: $type:tt,
                name: $name:ident,
                self: $self:tt,
                args: uninitialized,
                ret: uninitialized,
                body: uninitialized
            },
            class_body: $class_body:tt,
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_return_type,
            buffer: $class_body,
            stack: {
                method: {
                    type: $type,
                    name: $name,
                    self: $self,
                    args: [ $($args)* ],
                    ret: uninitialized,
                    body: uninitialized
                },
                $($stack)*
            }
        }
    };

    // STATE: parse_return_type

    {
        state: parse_return_type,
        buffer: { -> $ret:ty $body:block $($rest:tt)* },
        stack: {
            method: {
                type: $type:tt,
                name: $name:ident,
                self: $self:tt,
                args: $args:tt,
                ret: uninitialized,
                body: uninitialized
            },
            $($stack:tt)*
        }
    } => {
        assert_no_explict_return_for_initializer!($type, ->);

        parse! {
            state: finish_method,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: $type,
                    name: $name,
                    self: $self,
                    args: $args,
                    ret: $ret,
                    body: $body
                },
                $($stack)*
            }
        }
    };

    {
        state: parse_return_type,
        buffer: { $body:block $($rest:tt)* },
        stack: {
            method: {
                type: initializer,
                name: initialize,
                self: $self:tt,
                args: $args:tt,
                ret: uninitialized,
                body: uninitialized
            },
            class: {
                type: class,
                name: $name:ident,
                meta: $meta:tt,
                struct: $struct:tt,
                methods: $methods:tt
            },
            $($stack:tt)*
        }
    } => {
        parse! {
            state: finish_method,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: initializer,
                    name: initialize,
                    self: $self,
                    args: $args,
                    ret: $name,
                    body: $body
                },
                class: {
                    type: class,
                    name: $name,
                    meta: $meta,
                    struct: $struct,
                    methods: $methods
                },
                $($stack)*
            }
        }
    };

    {
        state: parse_return_type,
        buffer: { $body:block $($rest:tt)* },
        stack: {
            method: {
                type: $type:tt,
                name: $name:ident,
                self: $self:tt,
                args: $args:tt,
                ret: uninitialized,
                body: uninitialized
            },
            $($stack:tt)*
        }
    } => {
        parse! {
            state: finish_method,
            buffer: { $($rest)* },
            stack: {
                method: {
                    type: $type,
                    name: $name,
                    self: $self,
                    args: $args,
                    ret: (),
                    body: $body
                },
                $($stack)*
            }
        }
    };

    // STATE: finish_method

    {
        state: finish_method,
        buffer: $buffer:tt,
        stack: {
            method: $method:tt,
            class: {
                type: class,
                name: $name:ident,
                meta: $meta:tt,
                struct: $struct:tt,
                methods: [ $($methods:tt),* ]
            },
            $($stack:tt)*
        }
    } => {
        parse! {
            state: parse_methods,
            buffer: $buffer,
            stack: {
                class: {
                    type: class,
                    name: $name,
                    meta: $meta,
                    struct: $struct,
                    methods: [ $($methods,)* $method ]
                },
                $($stack)*
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! codegen {
    ($($ast:tt)*) => {
        println!("TODO: codegen; AST = {}", stringify!($($ast)*));
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! assert_struct {
    (true, {
        type: class,
        name: $name:ident,
        meta: $meta:tt,
        struct: { $($struct:tt)+ },
        methods: $methods:tt
    }) => {};

    (false, {
        type: class,
        name: $name:ident,
        meta: $meta:tt,
        struct: (),
        methods: $methods:tt
    }) => {};
}

#[doc(hidden)]
#[macro_export]
macro_rules! assert_valid_self_arg {
    (self) => {}
}

#[doc(hidden)]
#[macro_export]
macro_rules! assert_valid_arg {
    ($arg:ident) => {};
    (_) => {};
}

#[doc(hidden)]
#[macro_export]
macro_rules! assert_no_explict_return_for_initializer {
    (instance_method, $($rest:tt)*) => {};
    (class_method, $($rest:tt)*) => {};
    (initializer, ) => {};
}

fn main() {
    declare_types! {
        class Calculator {
            def add(lhs: f64, rhs: f64) -> f64 {
                Adder::new(lhs).call(rhs)
            }

            def multiply(lhs: f64, rhs: f64) -> f64 {
                Multiplier::new(lhs).call(rhs)
            }
        }

        class Adder {
            struct {
                lhs: f64
            }

            def initialize(helix, value: f64) {
                Adder { helix, value }
            }

            def call(&self, rhs: f64) -> f64 {
                self.lhs + rhs
            }
        }

        class Multiplier {
            struct {
                lhs: f64
            }

            def initialize(helix, value: f64) {
                Multiplier { helix, value }
            }

            def call(&self, rhs: f64) -> f64 {
                self.lhs * rhs
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::iter::repeat;
use rand::{thread_rng, Rng};

fn generate_expression(size: &usize) -> Vec<char> {
    let opens = repeat('[').take(*size);
    let closes = repeat(']').take(*size);
    let mut expr: Vec<char> = opens.chain(closes).collect();

    // Shuffle in place.
    thread_rng().shuffle(&mut expr[..]);

    expr
}

fn well_formed(expr: &Vec<char>) -> bool {
    let mut count = 0;

    for b in expr {
        if count < 0 {
            break;
        }

        match *b {
            '[' => count += 1,
            _ => count -= 1,
        }
    }

    count == 0
}

fn main() {
    for n in (1..10) {
        let expr = generate_expression(&n);
        let wf = well_formed(&expr);

        println!("'{}' is {}",
                 expr.into_iter().collect::<String>(),
                 if wf {"well formed"} else {"NOT well formed"});
    }
}
<commit_msg>Cleaned up balanced_brackets a bit<commit_after>extern crate rand;

use std::iter::repeat;
use rand::{thread_rng, Rng};

fn generate_expression(size: &usize) -> Vec<char> {
    let opens = repeat('[').take(*size);
    let closes = repeat(']').take(*size);
    let mut expr: Vec<char> = opens.chain(closes).collect();

    // Shuffle in place.
    thread_rng().shuffle(&mut expr[..]);

    expr
}

fn well_formed(expr: &Vec<char>) -> bool {
    let mut count = 0;

    for b in expr {
        match *b {
            '[' => count += 1,
            ']' => count -= 1,
            _ => panic!("Invalid expression!"),
        }

        if count < 0 { break; }
    }

    count == 0
}

fn main() {
    for n in (1..10) {
        let expr = generate_expression(&n);
        let wf = well_formed(&expr);

        println!("'{}' is {}",
                 expr.into_iter().collect::<String>(),
                 if wf {"well formed"} else {"NOT well formed"});
    }
}
<|endoftext|>


<commit_before>//! An enum mapping type.
//!
//! It is implemented using an array type, so using it is as fast as using Rust
//! arrays.
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate enum_map;
//!
//! use enum_map::EnumMap;
//!
//! #[derive(Debug, EnumMap)]
//! enum Example {
//!     A,
//!     B,
//!     C,
//! }
//!
//! fn main() {
//!     let mut map = enum_map! {
//!         Example::A => 1,
//!         Example::B => 2,
//!         Example::C => 3,
//!     };
//!     map[Example::C] = 4;
//!
//!     assert_eq!(map[Example::A], 1);
//!
//!     for (key, &value) in &map {
//!         println!("{:?} has {} as value.", key, value);
//!     }
//! }
//! ```

#![no_std]
#![deny(missing_docs)]

#[macro_use]
extern crate array_macro;
// This allows to quiet "proc macro crates and `#[no_link]` crates have no
// effect without `#[macro_use]`" warning. Just using extern DOES have
// an effect of letting me export the macro.
#[allow(unused_imports)]
#[macro_use]
extern crate enum_map_derive;

mod enummap_impls;
mod internal;
mod iter;
mod serde;

pub use internal::Internal;
pub use iter::{Iter, IterMut};
// `*` here means re-exporting a derive procedural macro.
pub use enum_map_derive::*;

use core::slice;

/// An enum mapping.
///
/// This internally uses an array which stores a value for each possible
/// enum value. To work, it requires implementation of internal (private,
/// although public due to macro limitations) trait which allows extracting
/// information about an enum, which can be automatically generated using
/// `#[derive(EnumMap)]` from `enum_map_derive` crate.
///
/// Additionally, `bool` and `u8` automatically derives from `EnumMap`. While
/// `u8` is not technically an enum, it's convenient to consider it like one.
/// In particular, [reverse-complement in benchmark game] could be using `u8`
/// as an enum.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// use enum_map::EnumMap;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = EnumMap::new();
///     // new initializes map with default values
///     assert_eq!(map[Example::A], 0);
///     map[Example::A] = 3;
///     assert_eq!(map[Example::A], 3);
/// }
/// ```
///
/// [reverse-complement in benchmark game]:
///     http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=rust&id=2
#[derive(Debug)]
pub struct EnumMap<K: Internal<V>, V> {
    array: K::Array,
}

impl<K: Internal<V>, V: Default> EnumMap<K, V>
where
    K::Array: Default,
{
    /// Creates an enum map with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// #[derive(EnumMap)]
    /// enum Example {
    ///     A,
    /// }
    ///
    /// fn main() {
    ///     let enum_map = EnumMap::<_, i32>::new();
    ///     assert_eq!(enum_map[Example::A], 0);
    /// }
    /// ```
    pub fn new() -> Self {
        EnumMap::default()
    }
}

impl<K: Internal<V>, V> EnumMap<K, V> {
    /// Returns number of elements in enum map.
    pub fn len(&self) -> usize {
        self.as_slice().len()
    }

    /// Returns whether the enum variant set is empty.
    ///
    /// This isn't particularly useful, as there is no real reason to use
    /// enum map for enums without variants. However, it is provided for
    /// consistency with data structures providing len method (and I will
    /// admit, to avoid clippy warnings).
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// #[derive(EnumMap)]
    /// enum Void {}
    ///
    /// #[derive(EnumMap)]
    /// enum SingleVariant {
    ///     Variant,
    /// }
    ///
    /// fn main() {
    ///     assert_eq!(EnumMap::<Void, ()>::new().is_empty(), true);
    ///     assert_eq!(EnumMap::<SingleVariant, ()>::new().is_empty(), false);
    /// }
    pub fn is_empty(&self) -> bool {
        self.as_slice().is_empty()
    }

    /// Returns an iterator over enum map.
    pub fn iter(&self) -> Iter<K, V> {
        self.into_iter()
    }

    /// Returns a mutable iterator over enum map.
    pub fn iter_mut(&mut self) -> IterMut<K, V> {
        self.into_iter()
    }

    /// Swaps two indexes.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { false => 0, true => 1 };
    ///     map.swap(false, true);
    ///     assert_eq!(map[false], 1);
    ///     assert_eq!(map[true], 0);
    /// }
    /// ```
    pub fn swap(&mut self, a: K, b: K) {
        self.as_mut_slice().swap(a.to_usize(), b.to_usize())
    }

    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    pub fn values(&self) -> slice::Iter<V> {
        self.as_slice().iter()
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    pub fn values_mut(&mut self) -> slice::IterMut<V> {
        self.as_mut_slice().iter_mut()
    }

    /// Converts an enum map to a slice representing values.
    pub fn as_slice(&self) -> &[V] {
        K::slice(&self.array)
    }

    /// Converts a mutable enum map to a mutable slice representing values.
    pub fn as_mut_slice(&mut self) -> &mut [V] {
        K::slice_mut(&mut self.array)
    }

    /// Returns a raw pointer to the enum map's buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this
    /// function returns, or else it will end up pointing to garbage.
    ///
    /// Modifying the container referenced by this slice may cause its buffer
    /// to be reallocated, which would also make any pointers to it invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// fn main() {
    ///     let map = enum_map! { 5 => 42, _ => 0 };
    ///     assert_eq!(unsafe { *map.as_ptr().offset(5) }, 42);
    /// }
    /// ```
    pub fn as_ptr(&self) -> *const V {
        self.as_slice().as_ptr()
    }

    /// Returns an unsafe mutable pointer to the enum map's buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this
    /// function returns, or else it will end up pointing to garbage.
    ///
    /// Modifying the container referenced by this slice may cause its buffer
    /// to be reallocated, which would also make any pointers to it invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 0 };
    ///     unsafe {
    ///         *map.as_mut_ptr().offset(11) = 23
    ///     };
    ///     assert_eq!(map[11], 23);
    /// }
    /// ```
    pub fn as_mut_ptr(&mut self) -> *mut V {
        self.as_mut_slice().as_mut_ptr()
    }
}

impl<F: FnMut(K) -> V, K: Internal<V>, V> From<F> for EnumMap<K, V> {
    fn from(f: F) -> Self {
        EnumMap { array: K::from_function(f) }
    }
}

/// Enum map constructor.
///
/// This macro allows to create a new enum map in a type safe way. It takes
/// a list of `,` separated pairs separated by `=>`. Left side is `|`
/// separated list of enum keys, or `_` to match all unmatched enum keys,
/// while right side is a value.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
///     D,
/// }
///
/// fn main() {
///     let enum_map = enum_map! {
///         Example::A | Example::B => 1,
///         Example::C => 2,
///         _ => 3,
///     };
///     assert_eq!(enum_map[Example::A], 1);
///     assert_eq!(enum_map[Example::B], 1);
///     assert_eq!(enum_map[Example::C], 2);
///     assert_eq!(enum_map[Example::D], 3);
/// }
/// ```
#[macro_export]
macro_rules! enum_map {
    {$($t:tt)*} => {
        $crate::EnumMap::from(|k| match k { $($t)* })
    };
}
<commit_msg>Make iter functions appear first<commit_after>//! An enum mapping type.
//!
//! It is implemented using an array type, so using it is as fast as using Rust
//! arrays.
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate enum_map;
//!
//! use enum_map::EnumMap;
//!
//! #[derive(Debug, EnumMap)]
//! enum Example {
//!     A,
//!     B,
//!     C,
//! }
//!
//! fn main() {
//!     let mut map = enum_map! {
//!         Example::A => 1,
//!         Example::B => 2,
//!         Example::C => 3,
//!     };
//!     map[Example::C] = 4;
//!
//!     assert_eq!(map[Example::A], 1);
//!
//!     for (key, &value) in &map {
//!         println!("{:?} has {} as value.", key, value);
//!     }
//! }
//! ```

#![no_std]
#![deny(missing_docs)]

#[macro_use]
extern crate array_macro;
// This allows to quiet "proc macro crates and `#[no_link]` crates have no
// effect without `#[macro_use]`" warning. Just using extern DOES have
// an effect of letting me export the macro.
#[allow(unused_imports)]
#[macro_use]
extern crate enum_map_derive;

mod enummap_impls;
mod internal;
mod iter;
mod serde;

pub use internal::Internal;
pub use iter::{Iter, IterMut};
// `*` here means re-exporting a derive procedural macro.
pub use enum_map_derive::*;

use core::slice;

/// An enum mapping.
///
/// This internally uses an array which stores a value for each possible
/// enum value. To work, it requires implementation of internal (private,
/// although public due to macro limitations) trait which allows extracting
/// information about an enum, which can be automatically generated using
/// `#[derive(EnumMap)]` from `enum_map_derive` crate.
///
/// Additionally, `bool` and `u8` automatically derives from `EnumMap`. While
/// `u8` is not technically an enum, it's convenient to consider it like one.
/// In particular, [reverse-complement in benchmark game] could be using `u8`
/// as an enum.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// use enum_map::EnumMap;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = EnumMap::new();
///     // new initializes map with default values
///     assert_eq!(map[Example::A], 0);
///     map[Example::A] = 3;
///     assert_eq!(map[Example::A], 3);
/// }
/// ```
///
/// [reverse-complement in benchmark game]:
///     http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=rust&id=2
#[derive(Debug)]
pub struct EnumMap<K: Internal<V>, V> {
    array: K::Array,
}

impl<K: Internal<V>, V: Default> EnumMap<K, V>
where
    K::Array: Default,
{
    /// Creates an enum map with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// #[derive(EnumMap)]
    /// enum Example {
    ///     A,
    /// }
    ///
    /// fn main() {
    ///     let enum_map = EnumMap::<_, i32>::new();
    ///     assert_eq!(enum_map[Example::A], 0);
    /// }
    /// ```
    pub fn new() -> Self {
        EnumMap::default()
    }
}

impl<K: Internal<V>, V> EnumMap<K, V> {
    /// Returns an iterator over enum map.
    pub fn iter(&self) -> Iter<K, V> {
        self.into_iter()
    }

    /// Returns a mutable iterator over enum map.
    pub fn iter_mut(&mut self) -> IterMut<K, V> {
        self.into_iter()
    }

    /// Returns number of elements in enum map.
    pub fn len(&self) -> usize {
        self.as_slice().len()
    }

    /// Returns whether the enum variant set is empty.
    ///
    /// This isn't particularly useful, as there is no real reason to use
    /// enum map for enums without variants. However, it is provided for
    /// consistency with data structures providing len method (and I will
    /// admit, to avoid clippy warnings).
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// #[derive(EnumMap)]
    /// enum Void {}
    ///
    /// #[derive(EnumMap)]
    /// enum SingleVariant {
    ///     Variant,
    /// }
    ///
    /// fn main() {
    ///     assert_eq!(EnumMap::<Void, ()>::new().is_empty(), true);
    ///     assert_eq!(EnumMap::<SingleVariant, ()>::new().is_empty(), false);
    /// }
    pub fn is_empty(&self) -> bool {
        self.as_slice().is_empty()
    }

    /// Swaps two indexes.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { false => 0, true => 1 };
    ///     map.swap(false, true);
    ///     assert_eq!(map[false], 1);
    ///     assert_eq!(map[true], 0);
    /// }
    /// ```
    pub fn swap(&mut self, a: K, b: K) {
        self.as_mut_slice().swap(a.to_usize(), b.to_usize())
    }

    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    pub fn values(&self) -> slice::Iter<V> {
        self.as_slice().iter()
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    pub fn values_mut(&mut self) -> slice::IterMut<V> {
        self.as_mut_slice().iter_mut()
    }

    /// Converts an enum map to a slice representing values.
    pub fn as_slice(&self) -> &[V] {
        K::slice(&self.array)
    }

    /// Converts a mutable enum map to a mutable slice representing values.
    pub fn as_mut_slice(&mut self) -> &mut [V] {
        K::slice_mut(&mut self.array)
    }

    /// Returns a raw pointer to the enum map's buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this
    /// function returns, or else it will end up pointing to garbage.
    ///
    /// Modifying the container referenced by this slice may cause its buffer
    /// to be reallocated, which would also make any pointers to it invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// fn main() {
    ///     let map = enum_map! { 5 => 42, _ => 0 };
    ///     assert_eq!(unsafe { *map.as_ptr().offset(5) }, 42);
    /// }
    /// ```
    pub fn as_ptr(&self) -> *const V {
        self.as_slice().as_ptr()
    }

    /// Returns an unsafe mutable pointer to the enum map's buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this
    /// function returns, or else it will end up pointing to garbage.
    ///
    /// Modifying the container referenced by this slice may cause its buffer
    /// to be reallocated, which would also make any pointers to it invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate enum_map;
    ///
    /// use enum_map::EnumMap;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 0 };
    ///     unsafe {
    ///         *map.as_mut_ptr().offset(11) = 23
    ///     };
    ///     assert_eq!(map[11], 23);
    /// }
    /// ```
    pub fn as_mut_ptr(&mut self) -> *mut V {
        self.as_mut_slice().as_mut_ptr()
    }
}

impl<F: FnMut(K) -> V, K: Internal<V>, V> From<F> for EnumMap<K, V> {
    fn from(f: F) -> Self {
        EnumMap { array: K::from_function(f) }
    }
}

/// Enum map constructor.
///
/// This macro allows to create a new enum map in a type safe way. It takes
/// a list of `,` separated pairs separated by `=>`. Left side is `|`
/// separated list of enum keys, or `_` to match all unmatched enum keys,
/// while right side is a value.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
///     D,
/// }
///
/// fn main() {
///     let enum_map = enum_map! {
///         Example::A | Example::B => 1,
///         Example::C => 2,
///         _ => 3,
///     };
///     assert_eq!(enum_map[Example::A], 1);
///     assert_eq!(enum_map[Example::B], 1);
///     assert_eq!(enum_map[Example::C], 2);
///     assert_eq!(enum_map[Example::D], 3);
/// }
/// ```
#[macro_export]
macro_rules! enum_map {
    {$($t:tt)*} => {
        $crate::EnumMap::from(|k| match k { $($t)* })
    };
}
<|endoftext|>