Start hooking up comb to tests

This commit is contained in:
Greg Shuflin 2021-11-17 16:53:03 -08:00
parent c1e6bc8c4c
commit 8ace37c5cf
3 changed files with 85 additions and 38 deletions

View File

@ -19,7 +19,7 @@ use crate::identifier::{Id, IdStore};
type StoreRef = Rc<RefCell<IdStore<ASTItem>>>; type StoreRef = Rc<RefCell<IdStore<ASTItem>>>;
type Span<'a> = LocatedSpan<&'a str, StoreRef>; pub type Span<'a> = LocatedSpan<&'a str, StoreRef>;
type ParseResult<'a, O> = IResult<Span<'a>, O, VerboseError<Span<'a>>>; type ParseResult<'a, O> = IResult<Span<'a>, O, VerboseError<Span<'a>>>;
use crate::ast::*; use crate::ast::*;
@ -108,7 +108,7 @@ fn statement(input: Span) -> ParseResult<Statement> {
)(input) )(input)
} }
fn expression(input: Span) -> ParseResult<Expression> { pub fn expression(input: Span) -> ParseResult<Expression> {
let id = fresh_id(&input); let id = fresh_id(&input);
map(pair(expression_kind, opt(type_anno)), move |(kind, maybe_anno)| Expression::new(id, kind))(input) map(pair(expression_kind, opt(type_anno)), move |(kind, maybe_anno)| Expression::new(id, kind))(input)
} }
@ -136,8 +136,10 @@ pub fn expression_kind(input: Span) -> ParseResult<ExpressionKind> {
} }
fn precedence_expr(input: Span) -> ParseResult<ExpressionKind> { fn precedence_expr(input: Span) -> ParseResult<ExpressionKind> {
map(pair(prefix_expr, many0(precedence_continuation)), map(
|(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!())(input) pair(prefix_expr, many0(precedence_continuation)),
|(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!(),
)(input)
} }
fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> { fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> {
@ -145,41 +147,37 @@ fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)>
} }
fn operator(input: Span) -> ParseResult<BinOp> { fn operator(input: Span) -> ParseResult<BinOp> {
tok( tok(map(
map( tuple((not(tag("*/")), recognize(many1(one_of("+-*/%<>=!$&|?^`"))))),
tuple(( |(_, sigil_span): ((), Span)| BinOp::from_sigil(sigil_span.fragment()),
not(tag("*/")), ))(input)
recognize(many1(one_of("+-*/%<>=!$&|?^`"))),
)), |(_, sigil_span): ((), Span)| BinOp::from_sigil(sigil_span.fragment())))(input)
} }
fn prefix_op(input: Span) -> ParseResult<PrefixOp> { fn prefix_op(input: Span) -> ParseResult<PrefixOp> {
tok( tok(map(recognize(one_of("+-!")), |sigil: Span| PrefixOp::from_sigil(sigil.fragment())))(input)
map(recognize(one_of("+-!")),
|sigil: Span| PrefixOp::from_sigil(sigil.fragment())))(input)
} }
fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> { fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
let handle = input.extra.clone(); let handle = input.extra.clone();
context("prefix-expr", context(
map( "prefix-expr",
pair(opt(prefix_op), extended_expr), move |(prefix, expr)| { map(pair(opt(prefix_op), extended_expr), move |(prefix, expr)| {
if let Some(prefix) = prefix { if let Some(prefix) = prefix {
let expr = Expression::new(fresh_id_rc(&handle), expr); let expr = Expression::new(fresh_id_rc(&handle), expr);
ExpressionKind::PrefixExp(prefix, Box::new(expr)) ExpressionKind::PrefixExp(prefix, Box::new(expr))
} else { } else {
expr expr
} }
}))(input) }),
)(input)
} }
fn extended_expr(input: Span) -> ParseResult<ExpressionKind> { fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
context("extended-expr", context("extended-expr", primary_expr)(input)
primary_expr)(input)
} }
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> { fn primary_expr(input: Span) -> ParseResult<ExpressionKind> {
context("primary-expr", alt((number_literal, bool_literal, identifier_expr)))(input) context("primary-expr", alt((float_literal, number_literal, bool_literal, identifier_expr)))(input)
} }
fn identifier_expr(input: Span) -> ParseResult<ExpressionKind> { fn identifier_expr(input: Span) -> ParseResult<ExpressionKind> {
@ -207,6 +205,16 @@ fn bool_literal(input: Span) -> ParseResult<ExpressionKind> {
)(input) )(input)
} }
fn float_literal(input: Span) -> ParseResult<ExpressionKind> {
tok(map(
alt((
recognize(tuple((digits(digit_group_dec), char('.'), opt(digits(digit_group_dec))))),
recognize(tuple((char('.'), digits(digit_group_dec)))),
)),
|ds| ExpressionKind::FloatLiteral(ds.fragment().parse().unwrap()),
))(input)
}
fn number_literal(input: Span) -> ParseResult<ExpressionKind> { fn number_literal(input: Span) -> ParseResult<ExpressionKind> {
map(alt((tok(hex_literal), tok(bin_literal), tok(dec_literal))), ExpressionKind::NatLiteral)(input) map(alt((tok(hex_literal), tok(bin_literal), tok(dec_literal))), ExpressionKind::NatLiteral)(input)
} }
@ -344,7 +352,6 @@ mod test {
ExpressionKind::Value(qn!(barnaby)) ExpressionKind::Value(qn!(barnaby))
); );
let source = "!4"; let source = "!4";
let parsed = span!(expression_kind, source).map_err(|err| match err { let parsed = span!(expression_kind, source).map_err(|err| match err {
Err::Error(err) | Err::Failure(err) => { Err::Error(err) | Err::Failure(err) => {
@ -361,8 +368,13 @@ mod test {
panic!("parse error desu!"); panic!("parse error desu!");
} }
assert_eq!(parsed.unwrap().1, ExpressionKind::PrefixExp(PrefixOp::from_sigil("!"), assert_eq!(
Box::new(Expression::new(Default::default(), ExpressionKind::NatLiteral(4))))); parsed.unwrap().1,
ExpressionKind::PrefixExp(
PrefixOp::from_sigil("!"),
Box::new(Expression::new(Default::default(), ExpressionKind::NatLiteral(4)))
)
);
} }
#[test] #[test]

View File

@ -31,6 +31,29 @@ impl Parser {
peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg) peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg)
} }
#[cfg(test)]
fn expression_comb(&mut self, input: &str) -> Result<Expression, ParseError> {
use std::{cell::RefCell, rc::Rc};
use combinator::Span;
use nom::{error::VerboseError, Err};
let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra(input, Rc::new(RefCell::new(id_store)));
combinator::expression(span)
.map_err(|err| match err {
Err::Error(err) | Err::Failure(err) => {
let err = VerboseError {
errors: err.errors.into_iter().map(|(sp, kind)| (*sp.fragment(), kind)).collect(),
};
let msg = nom::error::convert_error(input, err);
ParseError { msg, location: (0).into() }
}
_ => panic!(),
})
.map(|(_, output)| output)
}
#[cfg(test)] #[cfg(test)]
fn block(&mut self, input: &str) -> Result<Block, ParseError> { fn block(&mut self, input: &str) -> Result<Block, ParseError> {
peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg) peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg)

View File

@ -118,6 +118,18 @@ macro_rules! assert_expr {
}; };
} }
macro_rules! assert_expr_comb {
($input:expr, $correct:expr) => {
let mut parser = Parser::new();
let expr = parser.expression_comb($input);
if expr.is_err() {
println!("Expression parse error: {}", expr.unwrap_err().msg);
panic!();
}
assert_eq!(expr.unwrap(), $correct);
};
}
macro_rules! assert_fail_expr { macro_rules! assert_fail_expr {
($input:expr, $failure:expr) => { ($input:expr, $failure:expr) => {
let mut parser = Parser::new(); let mut parser = Parser::new();
@ -130,15 +142,15 @@ macro_rules! assert_fail_expr {
fn basic_literals() { fn basic_literals() {
use ExpressionKind::*; use ExpressionKind::*;
assert_expr!(".2", expr(FloatLiteral(0.2))); assert_expr_comb!(".2", expr(FloatLiteral(0.2)));
assert_expr!("8.1", expr(FloatLiteral(8.1))); assert_expr_comb!("8.1", expr(FloatLiteral(8.1)));
assert_expr!("0b010", expr(NatLiteral(2))); assert_expr_comb!("0b010", expr(NatLiteral(2)));
assert_expr!("0b0_1_0", expr(NatLiteral(2))); assert_expr_comb!("0b0_1_0", expr(NatLiteral(2)));
assert_expr!("0xff", expr(NatLiteral(255))); assert_expr_comb!("0xff", expr(NatLiteral(255)));
assert_expr!("0x032f", expr(NatLiteral(815))); assert_expr_comb!("0x032f", expr(NatLiteral(815)));
assert_expr!("0xf_f_", expr(NatLiteral(255))); assert_expr_comb!("0xf_f_", expr(NatLiteral(255)));
assert_expr!("false", expr(BoolLiteral(false))); assert_expr_comb!("false", expr(BoolLiteral(false)));
assert_expr!("true", expr(BoolLiteral(true))); assert_expr_comb!("true", expr(BoolLiteral(true)));
} }
#[test] #[test]