trivet 3.1.0

The trivet Parser Library
Documentation
//! Example of parsing an expression.
//!
//! This example is also worked out in The Trivet Parser book.

use trivet::errors::syntax_error;
use trivet::errors::ParseResult;
use trivet::parse_from_stdin;
use trivet::Parser;

/// Parse a number.  The number can be decimal, octal, hexadecimal, or binary.
/// Underscores can be present to break up long groups of digits, and are ignored.
///
/// On entry the parser is assumed to be pointing at the first character.  On
/// exit any trailing whitespace is consumed.
///
pub fn parse_number_ws(parser: &mut Parser) -> ParseResult<f64> {
    parser.parse_f64_ws()
}

/// Parse a primitive expression.  This could be a number or a parenthesized expression.
///
/// On entry the parser is assumed to be pointing at the first character.  On
/// exit any trailing whitespace is consumed.
///
pub fn parse_primitive_ws(parser: &mut Parser) -> ParseResult<f64> {
    // Look for leading minus sign.
    let is_neg = parser.peek_and_consume('-');

    // Look for a parenthesized expression.  Here is where our bottom-up approach
    // otherwise breaks.
    let value = if parser.peek_and_consume('(') {
        let value = parse_top_expr_ws(parser)?;
        if !parser.peek_and_consume_ws(')') {
            return Err(syntax_error(parser.loc(), "Missing closing parenthesis."));
        }
        value
    } else {
        // Note that we have already parsed the negative sign from the number above, so
        // we wil get back a nonnegative value here.  That's fine, since we will fix it
        // at the end.
        parse_number_ws(parser)?
    };
    Ok(if is_neg { -value } else { value })
}

/// Parse an expression containing exponentiation or bitwise operators.
///
/// On entry the parser is assumed to be pointing at the first character.  On
/// exit any trailing whitespace is consumed.
///
pub fn parse_exp_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
    // Parse an initial primitive.
    let mut left = parse_primitive_ws(parser)?;
    loop {
        // Look for an operator.
        left = if parser.peek_and_consume_str_ws("**") {
            let right = parse_primitive_ws(parser)?;
            left.powf(right)
        } else {
            break;
        }
    }
    Ok(left)
}

/// Parse multiplication, division, and remainder operations.
///
/// On entry the parser is assumed to be pointing at the first character.  On
/// exit any trailing whitespace is consumed.
///
pub fn parse_product_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
    let mut left = parse_exp_expr_ws(parser)?;
    loop {
        left = if parser.peek_and_consume_ws('*') {
            left * parse_exp_expr_ws(parser)?
        } else if parser.peek_and_consume_ws('/') {
            left / parse_exp_expr_ws(parser)?
        } else {
            break;
        }
    }
    Ok(left)
}

/// Parse an expression containing arithmetic and bitwise operators.
///
/// On entry the parser is assumed to be pointing at the first character.  On
/// exit any trailing whitespace is consumed.
///
pub fn parse_top_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
    let mut left = parse_product_expr_ws(parser)?;
    loop {
        left = if parser.peek_and_consume_ws('+') {
            left + parse_product_expr_ws(parser)?
        } else if parser.peek_and_consume_ws('-') {
            left - parse_product_expr_ws(parser)?
        } else {
            break;
        };
    }
    Ok(left)
}

// Main program.
pub fn main() -> ParseResult<()> {
    let mut parser = parse_from_stdin();
    parser.consume_ws();
    while !parser.is_at_eof() {
        let number = parse_top_expr_ws(&mut parser)?;
        println!("  {}", number);
    }
    Ok(())
}