From 2a9167ce264f3ff2fa623d6002cdcd53366499ee Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 21 Feb 2024 23:37:40 +0900 Subject: [PATCH] refactor: simplify token parsing Create a `surround` parser for delimiters that performs the common task of wrapping any parser with an opening and closing delimiter. Also, create some helper parsers for each token to reduce the amount of boilerplate wherever the tokens are used together with other parsers. --- crates/mabo-compiler/src/simplify.rs | 2 +- crates/mabo-parser/src/parser.rs | 29 ++++- crates/mabo-parser/src/parser/aliases.rs | 18 ++- crates/mabo-parser/src/parser/attributes.rs | 28 +++-- crates/mabo-parser/src/parser/consts.rs | 23 ++-- crates/mabo-parser/src/parser/enums.rs | 30 ++--- crates/mabo-parser/src/parser/fields.rs | 47 +++----- crates/mabo-parser/src/parser/generics.rs | 45 +++----- crates/mabo-parser/src/parser/imports.rs | 18 ++- crates/mabo-parser/src/parser/literals.rs | 16 ++- crates/mabo-parser/src/parser/modules.rs | 34 +++--- crates/mabo-parser/src/parser/structs.rs | 4 +- crates/mabo-parser/src/parser/types.rs | 118 +++++++------------- crates/mabo-parser/src/token.rs | 25 +++++ 14 files changed, 192 insertions(+), 245 deletions(-) diff --git a/crates/mabo-compiler/src/simplify.rs b/crates/mabo-compiler/src/simplify.rs index 193fb36..b5f03bb 100644 --- a/crates/mabo-compiler/src/simplify.rs +++ b/crates/mabo-compiler/src/simplify.rs @@ -503,7 +503,7 @@ fn simplify_import<'a>(item: &'a mabo_parser::Import<'_>) -> Import<'a> { element: item .element .as_ref() - .map(|(_,element)| element.get().into()), + .map(|(_, element)| element.get().into()), } } diff --git a/crates/mabo-parser/src/parser.rs b/crates/mabo-parser/src/parser.rs index 8f2f37c..b10c4b6 100644 --- a/crates/mabo-parser/src/parser.rs +++ b/crates/mabo-parser/src/parser.rs @@ -2,11 +2,11 @@ use std::ops::Range; use winnow::{ ascii::{multispace0, newline, space0}, - combinator::{fail, opt, peek, preceded, repeat, terminated, trace}, + combinator::{cut_err, fail, opt, peek, preceded, repeat, terminated, trace}, dispatch, error::{ErrMode, ParserError}, prelude::*, - stream::{AsChar, Stream, StreamIsPartial}, + stream::{AsChar, Compare, Location, Stream, StreamIsPartial}, token::any, }; @@ -29,6 +29,7 @@ use crate::{ error::{ParseDefinitionError, ParseSchemaCause}, ext::ParserExt, punctuated::Punctuated, + token::Delimiter, Definition, Schema, }; @@ -217,10 +218,9 @@ where pub fn punctuate(mut f: F, mut g: G) -> impl Parser, E> where I: Stream, - P: Copy + From>, E: ParserError, - F: Parser), E>, - G: Parser>), E>, + F: Parser, + G: Parser), E>, { trace("punctuate", move |i: &mut I| { let mut values = Vec::new(); @@ -236,7 +236,7 @@ where return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); } - values.push((o, range.into())); + values.push((o, range)); start_prev = Some(start); } Err(ErrMode::Backtrack(_)) => { @@ -267,3 +267,20 @@ where } }) } + +pub fn surround(f: F) -> impl Parser +where + I: Compare + Location + Stream + StreamIsPartial, + I::Token: Clone + AsChar, + D: Delimiter + From<(Range, Range)>, + E: ParserError, + F: Parser, +{ + let mut parser = (D::OPEN.span(), cut_err((f, ws(D::CLOSE.span())))); + + trace("surround", move |i: &mut I| { + parser + .parse_next(i) + .map(|(open, (o, close))| ((open, close).into(), o)) + }) +} diff --git a/crates/mabo-parser/src/parser/aliases.rs b/crates/mabo-parser/src/parser/aliases.rs index c59a923..3691558 100644 --- a/crates/mabo-parser/src/parser/aliases.rs +++ b/crates/mabo-parser/src/parser/aliases.rs @@ -11,11 +11,7 @@ use winnow::{ }; use super::{generics, types, Input, ParserExt, Result}; -use crate::{ - highlight, - token::{self, Punctuation}, - Comment, Name, TypeAlias, -}; +use crate::{highlight, token, Comment, Name, TypeAlias}; /// Encountered an invalid `type` alias declaration. #[derive(Debug, ParserError)] @@ -68,25 +64,25 @@ pub enum Cause { pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> { ( - terminated(token::Type::NAME.span(), space1), + terminated(token::Type::parser(), space1), cut_err(( parse_name, opt(generics::parse.map_err(Cause::Generics)), - preceded(space0, token::Equal::VALUE.span()), + preceded(space0, token::Equal::parser()), preceded(space0, types::parse.map_err(Cause::from)), - preceded(space0, token::Semicolon::VALUE.span()), + preceded(space0, token::Semicolon::parser()), )), ) .parse_next(input) .map( |(keyword, (name, generics, equal, target, semicolon))| TypeAlias { comment: Comment::default(), - keyword: keyword.into(), + keyword, name, generics, - equal: equal.into(), + equal, target, - semicolon: semicolon.into(), + semicolon, }, ) .map_err(|e| { diff --git a/crates/mabo-parser/src/parser/attributes.rs b/crates/mabo-parser/src/parser/attributes.rs index 429bde4..ed36c40 100644 --- a/crates/mabo-parser/src/parser/attributes.rs +++ b/crates/mabo-parser/src/parser/attributes.rs @@ -11,7 +11,11 @@ use winnow::{ }; use super::{literals, ws, Input, ParserExt, Result}; -use crate::{highlight, Attribute, AttributeValue, Attributes, Literal}; +use crate::{ + highlight, + token::{self, Delimiter}, + Attribute, AttributeValue, Attributes, Literal, +}; /// Encountered an invalid `#[...]` attribute declaration. #[derive(Debug, ParserError)] @@ -63,17 +67,17 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseEr fn parse_attribute<'i>(input: &mut Input<'i>) -> Result>, Cause> { preceded( - "#[", + (token::Pound::parser(), token::Bracket::OPEN), cut_err(terminated( terminated( separated( 1.., ws((parse_name, parse_value)).map(|(name, value)| Attribute { name, value }), - ws(','), + ws(token::Comma::parser()), ), - opt(','), + opt(token::Comma::parser()), ), - ws(']'), + ws(token::Bracket::CLOSE), )), ) .parse_next(input) @@ -99,24 +103,28 @@ fn parse_value<'i>(input: &mut Input<'i>) -> Result, Cause> { fn parse_multi_value<'i>(input: &mut Input<'i>) -> Result>, Cause> { preceded( - '(', + token::Parenthesis::OPEN, cut_err(terminated( terminated( separated( 1.., ws((parse_name, parse_value)).map(|(name, value)| Attribute { name, value }), - ws(','), + ws(token::Comma::parser()), ), - opt(','), + opt(token::Comma::parser()), ), - ws(')'), + ws(token::Parenthesis::CLOSE), )), ) .parse_next(input) } fn parse_single_value(input: &mut Input<'_>) -> Result { - preceded((space0, '=', space0), literals::parse.map_err(Cause::from)).parse_next(input) + preceded( + (space0, token::Equal::parser(), space0), + literals::parse.map_err(Cause::from), + ) + .parse_next(input) } fn parse_unit_value(input: &mut Input<'_>) -> Result<(), Cause> { diff --git a/crates/mabo-parser/src/parser/consts.rs b/crates/mabo-parser/src/parser/consts.rs index 3aac8b7..31e1685 100644 --- a/crates/mabo-parser/src/parser/consts.rs +++ b/crates/mabo-parser/src/parser/consts.rs @@ -11,11 +11,7 @@ use winnow::{ }; use super::{literals, types, Input, ParserExt, Result}; -use crate::{ - highlight, location, - token::{self, Punctuation}, - Comment, Const, Name, -}; +use crate::{highlight, location, token, Comment, Const, Name}; /// Encountered an invalid `const` declaration. #[derive(Debug, ParserError)] @@ -83,15 +79,14 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> let start = input.checkpoint(); ( - terminated(token::Const::NAME.span(), space1), + terminated(token::Const::parser(), space1), cut_err(( parse_name, - token::Colon::VALUE.span(), + token::Colon::parser(), preceded(space0, types::parse.map_err(Cause::from)), - preceded(space0, token::Equal::VALUE.span()), + preceded(space0, token::Equal::parser()), preceded(space0, literals::parse.map_err(Cause::from)), - token::Semicolon::VALUE - .span() + token::Semicolon::parser() .map_err_loc(|at, ()| Cause::UnexpectedChar { at, expected: ';' }), )), ) @@ -99,13 +94,13 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> .map( |(keyword, (name, colon, ty, equal, value, semicolon))| Const { comment: Comment::default(), - keyword: keyword.into(), + keyword, name, - colon: colon.into(), + colon, ty, - equal: equal.into(), + equal, value, - semicolon: semicolon.into(), + semicolon, }, ) .map_err(|e| { diff --git a/crates/mabo-parser/src/parser/enums.rs b/crates/mabo-parser/src/parser/enums.rs index 6d53110..613ec1e 100644 --- a/crates/mabo-parser/src/parser/enums.rs +++ b/crates/mabo-parser/src/parser/enums.rs @@ -10,13 +10,8 @@ use winnow::{ Parser, }; -use super::{comments, fields, generics, ids, punctuate, ws, Input, ParserExt, Result}; -use crate::{ - highlight, - punctuated::Punctuated, - token::{self, Delimiter, Punctuation}, - Attributes, Comment, Enum, Name, Variant, -}; +use super::{comments, fields, generics, ids, punctuate, surround, ws, Input, ParserExt, Result}; +use crate::{highlight, punctuated::Punctuated, token, Attributes, Comment, Enum, Name, Variant}; /// Encountered an invalid `enum` declaration. #[derive(Debug, ParserError)] @@ -91,7 +86,7 @@ pub enum Cause { pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> { ( - terminated(token::Enum::NAME.span(), space1), + terminated(token::Enum::parser(), space1), cut_err(( parse_name, opt(generics::parse.map_err(Cause::from)), @@ -102,7 +97,7 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> { .map(|(keyword, (name, generics, (brace, variants)))| Enum { comment: Comment::default(), attributes: Attributes::default(), - keyword: keyword.into(), + keyword, name, generics, brace, @@ -132,18 +127,11 @@ pub(super) fn parse_name<'i>(input: &mut Input<'i>) -> Result, Cause> { fn parse_variants<'i>( input: &mut Input<'i>, ) -> Result<(token::Brace, Punctuated>), Cause> { - ( - token::Brace::OPEN.span(), - cut_err(( - punctuate( - (parse_variant, ws(token::Comma::VALUE.span())), - (parse_variant, opt(ws(token::Comma::VALUE.span()))), - ), - ws(token::Brace::CLOSE.span()), - )), - ) - .parse_next(input) - .map(|(brace_open, (variants, brace_close))| ((brace_open, brace_close).into(), variants)) + surround(punctuate( + (parse_variant, ws(token::Comma::parser())), + (parse_variant, opt(ws(token::Comma::parser()))), + )) + .parse_next(input) } fn parse_variant<'i>(input: &mut Input<'i>) -> Result, Cause> { diff --git a/crates/mabo-parser/src/parser/fields.rs b/crates/mabo-parser/src/parser/fields.rs index ab25f65..7f2a9ab 100644 --- a/crates/mabo-parser/src/parser/fields.rs +++ b/crates/mabo-parser/src/parser/fields.rs @@ -3,7 +3,7 @@ use std::ops::Range; use mabo_derive::{ParserError, ParserErrorCause}; use winnow::{ ascii::space0, - combinator::{cut_err, opt, peek, preceded}, + combinator::{opt, peek, preceded}, dispatch, error::ErrorKind, stream::{Location, Stream}, @@ -11,12 +11,9 @@ use winnow::{ Parser, }; -use super::{comments, ids, punctuate, types, ws, Input, ParserExt, Result}; +use super::{comments, ids, punctuate, surround, types, ws, Input, ParserExt, Result}; use crate::{ - highlight, location, - punctuated::Punctuated, - token::{self, Delimiter, Punctuation}, - Fields, Name, NamedField, UnnamedField, + highlight, location, punctuated::Punctuated, token, Fields, Name, NamedField, UnnamedField, }; /// Encountered an invalid field declaration. @@ -94,35 +91,21 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> fn parse_named<'i>( input: &mut Input<'i>, ) -> Result<(token::Brace, Punctuated>), Cause> { - ( - token::Brace::OPEN.span(), - cut_err(( - punctuate( - (parse_named_field, ws(token::Comma::VALUE.span())), - (parse_named_field, opt(ws(token::Comma::VALUE.span()))), - ), - ws(token::Brace::CLOSE.span()), - )), - ) - .parse_next(input) - .map(|(brace_open, (fields, brace_close))| ((brace_open, brace_close).into(), fields)) + surround(punctuate( + (parse_named_field, ws(token::Comma::parser())), + (parse_named_field, opt(ws(token::Comma::parser()))), + )) + .parse_next(input) } fn parse_unnamed<'i>( input: &mut Input<'i>, ) -> Result<(token::Parenthesis, Punctuated>), Cause> { - ( - token::Parenthesis::OPEN.span(), - cut_err(( - punctuate( - (parse_unnamed_field, ws(token::Comma::VALUE.span())), - (parse_unnamed_field, opt(ws(token::Comma::VALUE.span()))), - ), - ws(token::Parenthesis::CLOSE.span()), - )), - ) - .parse_next(input) - .map(|(paren_open, (fields, paren_close))| ((paren_open, paren_close).into(), fields)) + surround(punctuate( + (parse_unnamed_field, ws(token::Comma::parser())), + (parse_unnamed_field, opt(ws(token::Comma::parser()))), + )) + .parse_next(input) } fn parse_unit(input: &mut Input<'_>) -> Result<(), Cause> { @@ -148,7 +131,7 @@ fn parse_named_field<'i>(input: &mut Input<'i>) -> Result, Cause> ws(comments::parse.map_err(Cause::from)), ( preceded(space0, parse_field_name), - preceded(space0, token::Colon::VALUE.span()), + preceded(space0, token::Colon::parser()), preceded(space0, types::parse.map_err(Cause::from)), opt(preceded(space0, ids::parse.map_err(Cause::from))), ) @@ -158,7 +141,7 @@ fn parse_named_field<'i>(input: &mut Input<'i>) -> Result, Cause> .map(|(comment, ((name, colon, ty, id), span))| NamedField { comment, name, - colon: colon.into(), + colon, ty, id, span: span.into(), diff --git a/crates/mabo-parser/src/parser/generics.rs b/crates/mabo-parser/src/parser/generics.rs index b842854..77487f5 100644 --- a/crates/mabo-parser/src/parser/generics.rs +++ b/crates/mabo-parser/src/parser/generics.rs @@ -2,20 +2,12 @@ use std::ops::Range; use mabo_derive::{ParserError, ParserErrorCause}; use winnow::{ - ascii::alphanumeric0, - combinator::{cut_err, opt}, - error::ErrorKind, - stream::Location, - token::one_of, + ascii::alphanumeric0, combinator::opt, error::ErrorKind, stream::Location, token::one_of, Parser, }; -use super::{punctuate, ws, Input, Result}; -use crate::{ - highlight, - token::{self, Delimiter, Punctuation}, - Generics, Name, -}; +use super::{punctuate, surround, ws, Input, Result}; +use crate::{highlight, token, Generics, Name}; /// Encountered an invalid `<...>` generics declaration. #[derive(Debug, ParserError)] @@ -52,27 +44,18 @@ pub enum Cause { } pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> { - ( - token::Angle::OPEN.span(), - cut_err(( - punctuate( - (ws(parse_name), ws(token::Comma::VALUE.span())), - (ws(parse_name), opt(ws(token::Comma::VALUE.span()))), - ), - ws(token::Angle::CLOSE.span()), - )), - ) - .parse_next(input) - .map(|(angle_open, (types, angle_close))| Generics { - angle: (angle_open, angle_close).into(), - types, - }) - .map_err(|e| { - e.map(|cause| ParseError { - at: input.location()..input.location(), - cause, - }) + surround(punctuate( + (ws(parse_name), ws(token::Comma::parser())), + (ws(parse_name), opt(ws(token::Comma::parser()))), + )) + .parse_next(input) + .map(|(angle, types)| Generics { angle, types }) + .map_err(|e| { + e.map(|cause| ParseError { + at: input.location()..input.location(), + cause, }) + }) } fn parse_name<'i>(input: &mut Input<'i>) -> Result, Cause> { diff --git a/crates/mabo-parser/src/parser/imports.rs b/crates/mabo-parser/src/parser/imports.rs index b13b770..a291913 100644 --- a/crates/mabo-parser/src/parser/imports.rs +++ b/crates/mabo-parser/src/parser/imports.rs @@ -11,11 +11,7 @@ use winnow::{ }; use super::{enums, structs, Input, ParserExt, Result}; -use crate::{ - highlight, location, - token::{self, Punctuation}, - Import, Name, -}; +use crate::{highlight, location, token, Import, Name}; /// Encountered an invalid `use` declaration. #[derive(Debug, ParserError)] @@ -70,12 +66,12 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> let start = input.checkpoint(); ( - terminated(token::Use::NAME.span(), space1), + terminated(token::Use::parser(), space1), cut_err(( ( - separated(1.., parse_segment, token::DoubleColon::VALUE.span()), + separated(1.., parse_segment, token::DoubleColon::parser()), opt(( - token::DoubleColon::VALUE.span().output_into(), + token::DoubleColon::parser(), alt(( structs::parse_name.map_err(Cause::from), enums::parse_name.map_err(Cause::from), @@ -84,17 +80,17 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> ) .with_recognized() .with_span(), - token::Semicolon::VALUE.span(), + token::Semicolon::parser(), )), ) .parse_next(input) .map( |(keyword, ((((segments, element), full), range), semicolon))| Import { - keyword: keyword.into(), + keyword, full: (full, range).into(), segments, element, - semicolon: semicolon.into(), + semicolon, }, ) .map_err(|e| { diff --git a/crates/mabo-parser/src/parser/literals.rs b/crates/mabo-parser/src/parser/literals.rs index 632a844..31e1aa9 100644 --- a/crates/mabo-parser/src/parser/literals.rs +++ b/crates/mabo-parser/src/parser/literals.rs @@ -14,7 +14,11 @@ use winnow::{ }; use super::{ws, Input, Result}; -use crate::{highlight, Literal, LiteralValue}; +use crate::{ + highlight, + token::{self, Delimiter, Punctuation}, + Literal, LiteralValue, +}; /// Encountered an invalid literal declaration. #[derive(Debug, ParserError)] @@ -206,9 +210,9 @@ fn parse_string_unicode(input: &mut Input<'_>) -> Result { preceded( 'u', cut_err(delimited( - '{', + token::Brace::OPEN, take_while(1..=6, ('0'..='9', 'a'..='f', 'A'..='F')), - '}', + token::Brace::CLOSE, )), ) .try_map(|hex| u32::from_str_radix(hex, 16)) @@ -222,10 +226,10 @@ fn parse_string_escaped_whitespace<'i>(input: &mut Input<'i>) -> Result<&'i str, fn parse_bytes(input: &mut Input<'_>) -> Result, Cause> { preceded( - '[', + token::Bracket::OPEN, cut_err(terminated( - separated(1.., ws(dec_uint::<_, u8, _>), ws(',')), - (opt(ws(',')), ws(']')), + separated(1.., ws(dec_uint::<_, u8, _>), ws(token::Comma::VALUE)), + (opt(ws(token::Comma::VALUE)), ws(token::Bracket::CLOSE)), )), ) .parse_next(input) diff --git a/crates/mabo-parser/src/parser/modules.rs b/crates/mabo-parser/src/parser/modules.rs index 3c01576..2413a45 100644 --- a/crates/mabo-parser/src/parser/modules.rs +++ b/crates/mabo-parser/src/parser/modules.rs @@ -10,13 +10,8 @@ use winnow::{ Parser, }; -use super::{parse_definition, ws, Input, ParserExt, Result}; -use crate::{ - error::ParseDefinitionError, - highlight, location, - token::{self, Delimiter}, - Comment, Module, Name, -}; +use super::{parse_definition, surround, ws, Input, ParserExt, Result}; +use crate::{error::ParseDefinitionError, highlight, location, token, Comment, Module, Name}; /// Encountered an invalid `mod` declaration. #[derive(Debug, ParserError)] @@ -68,24 +63,23 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> let start = input.checkpoint(); ( - terminated(token::Mod::NAME.span(), space1), + terminated(token::Mod::parser(), space1), cut_err(( parse_name, - preceded(space0, token::Brace::OPEN.span()), - repeat(0.., ws(parse_definition.map_err(Cause::from))), - ws(token::Brace::CLOSE.span()), + preceded( + space0, + surround(repeat(0.., ws(parse_definition.map_err(Cause::from)))), + ), )), ) .parse_next(input) - .map( - |(keyword, (name, brace_open, definitions, brace_close))| Module { - comment: Comment::default(), - keyword: keyword.into(), - name, - brace: (brace_open, brace_close).into(), - definitions, - }, - ) + .map(|(keyword, (name, (brace, definitions)))| Module { + comment: Comment::default(), + keyword, + name, + brace, + definitions, + }) .map_err(|e| { e.map(|cause| ParseError { at: location::from_until(*input, &start, ['}', '\n']), diff --git a/crates/mabo-parser/src/parser/structs.rs b/crates/mabo-parser/src/parser/structs.rs index 2b315b6..88c7014 100644 --- a/crates/mabo-parser/src/parser/structs.rs +++ b/crates/mabo-parser/src/parser/structs.rs @@ -66,7 +66,7 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> let start = input.checkpoint(); ( - terminated(token::Struct::NAME.span(), space1), + terminated(token::Struct::parser(), space1), cut_err(( parse_name, opt(generics::parse.map_err(Cause::Generics)), @@ -77,7 +77,7 @@ pub(super) fn parse<'i>(input: &mut Input<'i>) -> Result, ParseError> .map(|(keyword, (name, generics, kind))| Struct { comment: Comment::default(), attributes: Attributes::default(), - keyword: keyword.into(), + keyword, name, generics, fields: kind, diff --git a/crates/mabo-parser/src/parser/types.rs b/crates/mabo-parser/src/parser/types.rs index 35ad3af..7ce4593 100644 --- a/crates/mabo-parser/src/parser/types.rs +++ b/crates/mabo-parser/src/parser/types.rs @@ -12,11 +12,7 @@ use winnow::{ }; use super::{imports, punctuate, ws, Input, ParserExt, Result}; -use crate::{ - highlight, - token::{self, Delimiter, Punctuation}, - DataType, ExternalType, Name, Type, -}; +use crate::{highlight, parser::surround, token, DataType, ExternalType, Name, Type}; /// Encountered an invalid type definition. #[derive(Debug, ParserError)] @@ -109,13 +105,9 @@ fn parse_generic<'i>(input: &mut Input<'i>) -> Result, Cause> { convert: impl Fn(token::Angle, Type<'i>) -> DataType<'i>, ) -> impl Fn(&mut Input<'i>) -> Result, Cause> { move |input| { - cut_err(( - token::Angle::OPEN.span(), - parse.map_err(Cause::from), - token::Angle::CLOSE.span(), - )) - .parse_next(input) - .map(|(open, ty, close)| convert((open, close).into(), ty)) + cut_err(surround(parse.map_err(Cause::from))) + .parse_next(input) + .map(|(angle, ty)| convert(angle, ty)) } } @@ -126,17 +118,13 @@ fn parse_generic<'i>(input: &mut Input<'i>) -> Result, Cause> { convert: impl Fn(token::Angle, Type<'i>, token::Comma, Type<'i>) -> DataType<'i>, ) -> impl Fn(&mut Input<'i>) -> Result, Cause> { move |input| { - cut_err(( - token::Angle::OPEN.span(), + cut_err(surround(( parse.map_err(Cause::from), - preceded(space0, token::Comma::VALUE.span()), + preceded(space0, token::Comma::parser()), preceded(space0, parse.map_err(Cause::from)), - token::Angle::CLOSE.span(), - )) + ))) .parse_next(input) - .map(|(open, ty1, comma, ty2, close)| { - convert((open, close).into(), ty1, comma.into(), ty2) - }) + .map(|(angle, (ty1, comma, ty2))| convert(angle, ty1, comma, ty2)) } } @@ -175,48 +163,30 @@ fn parse_generic<'i>(input: &mut Input<'i>) -> Result, Cause> { } fn parse_tuple<'i>(input: &mut Input<'i>) -> Result, Cause> { - ( - token::Parenthesis::OPEN.span(), - cut_err(( - punctuate( - ( - ws(parse.map_err(Cause::from)), - ws(token::Comma::VALUE.span()), - ), - ( - ws(parse.map_err(Cause::from)), - opt(ws(token::Comma::VALUE.span())), - ), - ), - ws(token::Parenthesis::CLOSE.span()), - )), - ) - .parse_next(input) - .map(|(paren_open, (types, paren_close))| DataType::Tuple { - paren: (paren_open, paren_close).into(), - types, - }) + surround(punctuate( + (ws(parse.map_err(Cause::from)), ws(token::Comma::parser())), + ( + ws(parse.map_err(Cause::from)), + opt(ws(token::Comma::parser())), + ), + )) + .parse_next(input) + .map(|(paren, types)| DataType::Tuple { paren, types }) } fn parse_array<'i>(input: &mut Input<'i>) -> Result, Cause> { - ( - token::Bracket::OPEN.span(), - cut_err(( - ws(parse.map_err(Cause::from)), - ws(token::Semicolon::VALUE.span()), - ws(dec_uint), - ws(token::Bracket::CLOSE.span()), - )), - ) - .parse_next(input) - .map( - |(bracket_open, (ty, semicolon, size, bracket_close))| DataType::Array { - bracket: (bracket_open, bracket_close).into(), - ty: Box::new(ty), - semicolon: semicolon.into(), - size, - }, - ) + surround(( + ws(parse.map_err(Cause::from)), + ws(token::Semicolon::parser()), + ws(dec_uint), + )) + .parse_next(input) + .map(|(bracket, (ty, semicolon, size))| DataType::Array { + bracket, + ty: Box::new(ty), + semicolon, + size, + }) } fn parse_external<'i>(input: &mut Input<'i>) -> Result, Cause> { @@ -225,34 +195,22 @@ fn parse_external<'i>(input: &mut Input<'i>) -> Result, Cause> 1.., ( imports::parse_segment.map_err(Cause::from), - token::DoubleColon::VALUE.span().output_into(), + token::DoubleColon::parser(), ), )) .map(Option::unwrap_or_default), parse_external_name, - opt(( - token::Angle::OPEN.span(), - cut_err(( - punctuate( - ( - ws(parse.map_err(Cause::from)), - ws(token::Comma::VALUE.span()), - ), - ( - ws(parse.map_err(Cause::from)), - opt(ws(token::Comma::VALUE.span())), - ), - ), - ws(token::Angle::CLOSE.span()), - )), - )), + opt(surround(punctuate( + (ws(parse.map_err(Cause::from)), ws(token::Comma::parser())), + ( + ws(parse.map_err(Cause::from)), + opt(ws(token::Comma::parser())), + ), + ))), ) .parse_next(input) .map(|(path, name, generics)| { - let (angle, generics) = match generics { - Some((open, (generics, close))) => (Some((open, close).into()), Some(generics)), - None => (None, None), - }; + let (angle, generics) = generics.unzip(); ExternalType { path, name, diff --git a/crates/mabo-parser/src/token.rs b/crates/mabo-parser/src/token.rs index 063782b..f522c8b 100644 --- a/crates/mabo-parser/src/token.rs +++ b/crates/mabo-parser/src/token.rs @@ -6,6 +6,11 @@ use std::{ }; use mabo_derive::Debug; +use winnow::{ + error::ParserError, + stream::{Compare, Location, Stream, StreamIsPartial}, + Parser, +}; use crate::{Print, Span, Spanned}; @@ -48,6 +53,15 @@ macro_rules! define_keywords { impl $name { /// Literal raw name of this keyword. pub const NAME: &'static str = $token; + + #[inline] + pub(crate) fn parser<'a, I, E>() -> impl Parser + where + I: Compare<&'a str> + Location + Stream + StreamIsPartial, + E: ParserError, + { + |i: &mut I| Self::NAME.span().output_into().parse_next(i) + } } )* }; @@ -104,6 +118,17 @@ macro_rules! define_punctuation { /// Literal raw string of this punctuation. const VALUE: &'static str = $token; } + + impl $name { + #[inline] + pub(crate) fn parser<'a, I, E>() -> impl Parser + where + I: Compare<&'a str> + Location + Stream + StreamIsPartial, + E: ParserError, + { + |i: &mut I| Self::VALUE.span().output_into().parse_next(i) + } + } )* }; }