protospec-build 0.3.0

One binary format language to rule them all, One binary format language to find them, One binary format language to bring them all and in the darkness bind them.
Documentation
use crate::ast::*;
use crate::tokenizer::*;

mod error;
pub use error::{ParseError, ParseResult};

mod token_iter;
use token_iter::TokenIter;

mod declaration;
use declaration::*;

mod expression;
use expression::*;

mod types;
use types::*;

mod field;
use field::*;

mod program;
use program::*;

mod transform;
use transform::*;

pub fn parse(script: &str) -> ParseResult<Program> {
    let mut tokens = TokenIter::new(crate::tokenize(script, true)?);

    parse_program(&mut tokens)
}

fn parse_arguments(t: &mut TokenIter, span: &mut Span) -> ParseResult<Vec<Expression>> {
    let mut arguments = vec![];
    if t.eat(Token::LeftParen).is_some() {
        loop {
            if let Some(token) = t.eat(Token::RightParen) {
                *span = *span + token.span;
                break;
            }
            arguments.push(parse_expression(t)?);
            if t.eat(Token::Comma).is_none() {
                *span = *span + t.expect(Token::RightParen)?;
                break;
            }
        }
    }
    Ok(arguments)
}

fn parse_conditional_clause(t: &mut TokenIter) -> ParseResult<Option<Box<Expression>>> {
    Ok(if t.eat(Token::LeftCurly).is_some() {
        let condition = parse_expression(t)?;
        t.expect(Token::RightCurly)?;
        Some(Box::new(condition))
    } else {
        None
    })
}

fn parse_flags(t: &mut TokenIter) -> ParseResult<Vec<Ident>> {
    let mut out = vec![];
    while t.eat(Token::Plus).is_some() {
        out.push(t.expect_ident()?);
    }
    Ok(out)
}