Newer
Older
use crate::error::ForgeResult;
use crate::lexer::{script_to_tokens, ScriptTokenType};
use crate::parser::ast::{Expression, Program};
use crate::TokenError;
use peg::Parse;
pub type InputSpan<'a, Loc, Tok> = Result<(Loc, Tok, Loc), String>;
type ExprSpan<'a> = InputSpan<'a, usize, ScriptTokenType>;
macro_rules! export_grammar_fn {
($name:ident = $output:ty => $part: tt) => {
pub fn $name(source: &str) -> Result<$output, String> {
let tokens = script_to_tokens(source)
.map_err(|e| format!("{}", e))?
tok.position.location_offset() + tok.token_type.len(),
))
})
.collect::<Vec<ExprSpan>>();
let value = super::forge_grammar::$part::new()
.parse::<ExprSpan, Vec<ExprSpan>>(tokens)
.map_err(|e| format!("{}", e))?;
Ok(value)
}
};
}
export_grammar_fn!(parse_program = Program => ProgramParser);
export_grammar_fn!(parse_expression = Expression => ExpressionParser);
#[cfg(test)]
mod grammar_test {
use super::parse_expression;
use crate::error::ForgeResult;
use crate::parse::ast::Expression;
use test_case::test_case;
#[test_case("123" => matches Ok(_) ; "Parse literal number")]
#[test_case(r#""Basic String""# => matches Ok(_) ; "Parse literal string")]
#[test_case("false" => matches Ok(_) ; "Parse literal false")]
#[test_case("true" => matches Ok(_) ; "Parse literal true")]
#[test_case("null" => matches Ok(_) ; "Parse literal null")]
#[test_case("if foo {}" => matches Ok(_) ; "Parse conditional")]
#[test_case("2 * 4 - 3" => matches Ok(_) ; "Parse arithmetic")]
fn expression_parsing(prog: &str) -> Result<Expression, String> {