diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 444cc5f..1cce387 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -19,7 +19,7 @@ use crate::identifier::{Id, IdStore}; type StoreRef = Rc>>; -type Span<'a> = LocatedSpan<&'a str, StoreRef>; +pub type Span<'a> = LocatedSpan<&'a str, StoreRef>; type ParseResult<'a, O> = IResult, O, VerboseError>>; use crate::ast::*; @@ -108,7 +108,7 @@ fn statement(input: Span) -> ParseResult { )(input) } -fn expression(input: Span) -> ParseResult { +pub fn expression(input: Span) -> ParseResult { let id = fresh_id(&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 { } fn precedence_expr(input: Span) -> ParseResult { - map(pair(prefix_expr, many0(precedence_continuation)), - |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!())(input) + map( + pair(prefix_expr, many0(precedence_continuation)), + |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!(), + )(input) } 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 { - tok( - map( - tuple(( - not(tag("*/")), - recognize(many1(one_of("+-*/%<>=!$&|?^`"))), - )), |(_, sigil_span): ((), Span)| BinOp::from_sigil(sigil_span.fragment())))(input) + tok(map( + tuple((not(tag("*/")), recognize(many1(one_of("+-*/%<>=!$&|?^`"))))), + |(_, sigil_span): ((), Span)| BinOp::from_sigil(sigil_span.fragment()), + ))(input) } fn prefix_op(input: Span) -> ParseResult { - tok( - map(recognize(one_of("+-!")), - |sigil: Span| PrefixOp::from_sigil(sigil.fragment())))(input) + tok(map(recognize(one_of("+-!")), |sigil: Span| PrefixOp::from_sigil(sigil.fragment())))(input) } fn prefix_expr(input: Span) -> ParseResult { let handle = input.extra.clone(); - context("prefix-expr", - map( - pair(opt(prefix_op), extended_expr), move |(prefix, expr)| { - if let Some(prefix) = prefix { - let expr = Expression::new(fresh_id_rc(&handle), expr); - ExpressionKind::PrefixExp(prefix, Box::new(expr)) - } else { - expr - } - }))(input) + context( + "prefix-expr", + map(pair(opt(prefix_op), extended_expr), move |(prefix, expr)| { + if let Some(prefix) = prefix { + let expr = Expression::new(fresh_id_rc(&handle), expr); + ExpressionKind::PrefixExp(prefix, Box::new(expr)) + } else { + expr + } + }), + )(input) } fn extended_expr(input: Span) -> ParseResult { - context("extended-expr", - primary_expr)(input) + context("extended-expr", primary_expr)(input) } fn primary_expr(input: Span) -> ParseResult { - 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 { @@ -207,6 +205,16 @@ fn bool_literal(input: Span) -> ParseResult { )(input) } +fn float_literal(input: Span) -> ParseResult { + 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 { map(alt((tok(hex_literal), tok(bin_literal), tok(dec_literal))), ExpressionKind::NatLiteral)(input) } @@ -344,7 +352,6 @@ mod test { ExpressionKind::Value(qn!(barnaby)) ); - let source = "!4"; let parsed = span!(expression_kind, source).map_err(|err| match err { Err::Error(err) | Err::Failure(err) => { @@ -361,8 +368,13 @@ mod test { panic!("parse error desu!"); } - assert_eq!(parsed.unwrap().1, ExpressionKind::PrefixExp(PrefixOp::from_sigil("!"), - Box::new(Expression::new(Default::default(), ExpressionKind::NatLiteral(4))))); + assert_eq!( + parsed.unwrap().1, + ExpressionKind::PrefixExp( + PrefixOp::from_sigil("!"), + Box::new(Expression::new(Default::default(), ExpressionKind::NatLiteral(4))) + ) + ); } #[test] diff --git a/schala-lang/src/parsing/mod.rs b/schala-lang/src/parsing/mod.rs index bfe9371..3e952a9 100644 --- a/schala-lang/src/parsing/mod.rs +++ b/schala-lang/src/parsing/mod.rs @@ -31,6 +31,29 @@ impl Parser { peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg) } + #[cfg(test)] + fn expression_comb(&mut self, input: &str) -> Result { + use std::{cell::RefCell, rc::Rc}; + + use combinator::Span; + use nom::{error::VerboseError, Err}; + + let id_store: IdStore = 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)] fn block(&mut self, input: &str) -> Result { peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg) diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 4169e1e..146ee41 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -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 { ($input:expr, $failure:expr) => { let mut parser = Parser::new(); @@ -130,15 +142,15 @@ macro_rules! assert_fail_expr { fn basic_literals() { use ExpressionKind::*; - assert_expr!(".2", expr(FloatLiteral(0.2))); - assert_expr!("8.1", expr(FloatLiteral(8.1))); - assert_expr!("0b010", expr(NatLiteral(2))); - assert_expr!("0b0_1_0", expr(NatLiteral(2))); - assert_expr!("0xff", expr(NatLiteral(255))); - assert_expr!("0x032f", expr(NatLiteral(815))); - assert_expr!("0xf_f_", expr(NatLiteral(255))); - assert_expr!("false", expr(BoolLiteral(false))); - assert_expr!("true", expr(BoolLiteral(true))); + assert_expr_comb!(".2", expr(FloatLiteral(0.2))); + assert_expr_comb!("8.1", expr(FloatLiteral(8.1))); + assert_expr_comb!("0b010", expr(NatLiteral(2))); + assert_expr_comb!("0b0_1_0", expr(NatLiteral(2))); + assert_expr_comb!("0xff", expr(NatLiteral(255))); + assert_expr_comb!("0x032f", expr(NatLiteral(815))); + assert_expr_comb!("0xf_f_", expr(NatLiteral(255))); + assert_expr_comb!("false", expr(BoolLiteral(false))); + assert_expr_comb!("true", expr(BoolLiteral(true))); } #[test]