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) + } + } )* }; }