Skip to content

Commit c7ccffb

Browse files
zestererHedgehogo
andauthored
Added Spanned combinator (#713)
* Added Spanned combinator * Fixed doc test * refactor: move `<T>` from `Spanned` to `WrappingSpan` * Added Input::split_spanned --------- Co-authored-by: Hedgehogo <lologlek8@gmail.com>
1 parent c952e41 commit c7ccffb

File tree

7 files changed

+194
-58
lines changed

7 files changed

+194
-58
lines changed

examples/mini_ml.rs

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ impl fmt::Display for Token<'_> {
5050
}
5151
}
5252

53-
pub type Spanned<T> = (T, SimpleSpan);
54-
5553
fn lexer<'src>(
5654
) -> impl Parser<'src, &'src str, Vec<Spanned<Token<'src>>>, extra::Err<Rich<'src, char>>> {
5755
recursive(|token| {
@@ -82,7 +80,7 @@ fn lexer<'src>(
8280
.as_context()
8381
.map(Token::Parens),
8482
))
85-
.map_with(|t, e| (t, e.span()))
83+
.spanned()
8684
.padded()
8785
})
8886
.repeated()
@@ -128,7 +126,7 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser<
128126
ident.map(Expr::Var),
129127
// let x = y in z
130128
just(Token::Let)
131-
.ignore_then(ident.map_with(|x, e| (x, e.span())))
129+
.ignore_then(ident.spanned())
132130
.then_ignore(just(Token::Eq))
133131
.then(expr.clone())
134132
.then_ignore(just(Token::In))
@@ -141,45 +139,39 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser<
141139
));
142140

143141
choice((
144-
atom.map_with(|expr, e| (expr, e.span())),
142+
atom.spanned(),
145143
// fn x y = z
146-
just(Token::Fn).ignore_then(
147-
ident.map_with(|x, e| (x, e.span())).repeated().foldr_with(
148-
just(Token::Eq).ignore_then(expr.clone()),
149-
|arg, body, e| {
150-
(
151-
Expr::Func {
152-
arg: Box::new(arg),
153-
body: Box::new(body),
154-
},
155-
e.span(),
156-
)
157-
},
158-
),
159-
),
144+
just(Token::Fn).ignore_then(ident.spanned().repeated().foldr_with(
145+
just(Token::Eq).ignore_then(expr.clone()),
146+
|arg, body, e| {
147+
Expr::Func {
148+
arg: Box::new(arg),
149+
body: Box::new(body),
150+
}
151+
.with_span(e.span())
152+
},
153+
)),
160154
// ( x )
161-
expr.nested_in(select_ref! { Token::Parens(ts) = e => ts.split_token_span(e.span()) }),
155+
expr.nested_in(select_ref! { Token::Parens(ts) = e => ts.split_spanned(e.span()) }),
162156
))
163157
.pratt(vec![
164158
// Multiply
165159
infix(left(10), just(Token::Asterisk), |x, _, y, e| {
166-
(Expr::Mul(Box::new(x), Box::new(y)), e.span())
160+
Expr::Mul(Box::new(x), Box::new(y)).with_span(e.span())
167161
})
168162
.boxed(),
169163
// Add
170164
infix(left(9), just(Token::Plus), |x, _, y, e| {
171-
(Expr::Add(Box::new(x), Box::new(y)), e.span())
165+
Expr::Add(Box::new(x), Box::new(y)).with_span(e.span())
172166
})
173167
.boxed(),
174168
// Calls
175169
infix(left(1), empty(), |x, _, y, e| {
176-
(
177-
Expr::Apply {
178-
func: Box::new(x),
179-
arg: Box::new(y),
180-
},
181-
e.span(),
182-
)
170+
Expr::Apply {
171+
func: Box::new(x),
172+
arg: Box::new(y),
173+
}
174+
.with_span(e.span())
183175
})
184176
.boxed(),
185177
])
@@ -270,17 +262,17 @@ impl Solver<'_> {
270262
expr: &Spanned<Expr<'src>>,
271263
env: &mut Vec<(&'src str, TyVar)>,
272264
) -> TyVar {
273-
match &expr.0 {
274-
Expr::Num(_) => self.create_ty(TyInfo::Num, expr.1),
275-
Expr::Bool(_) => self.create_ty(TyInfo::Bool, expr.1),
265+
match &**expr {
266+
Expr::Num(_) => self.create_ty(TyInfo::Num, expr.span),
267+
Expr::Bool(_) => self.create_ty(TyInfo::Bool, expr.span),
276268
Expr::Var(name) => {
277269
env.iter()
278270
.rev()
279271
.find(|(n, _)| n == name)
280272
.unwrap_or_else(|| {
281273
failure(
282274
format!("No such local '{name}'"),
283-
("not found in scope".to_string(), expr.1),
275+
("not found in scope".to_string(), expr.span),
284276
None,
285277
self.src,
286278
)
@@ -289,32 +281,32 @@ impl Solver<'_> {
289281
}
290282
Expr::Let { lhs, rhs, then } => {
291283
let rhs_ty = self.check(rhs, env);
292-
env.push((lhs.0, rhs_ty));
284+
env.push((**lhs, rhs_ty));
293285
let out_ty = self.check(then, env);
294286
env.pop();
295287
out_ty
296288
}
297289
Expr::Func { arg, body } => {
298-
let arg_ty = self.create_ty(TyInfo::Unknown, arg.1);
299-
env.push((arg.0, arg_ty));
290+
let arg_ty = self.create_ty(TyInfo::Unknown, arg.span);
291+
env.push((&**arg, arg_ty));
300292
let body_ty = self.check(body, env);
301293
env.pop();
302-
self.create_ty(TyInfo::Func(arg_ty, body_ty), expr.1)
294+
self.create_ty(TyInfo::Func(arg_ty, body_ty), expr.span)
303295
}
304296
Expr::Apply { func, arg } => {
305297
let func_ty = self.check(func, env);
306298
let arg_ty = self.check(arg, env);
307-
let out_ty = self.create_ty(TyInfo::Unknown, expr.1);
308-
let func_req_ty = self.create_ty(TyInfo::Func(arg_ty, out_ty), func.1);
309-
self.unify(func_req_ty, func_ty, expr.1);
299+
let out_ty = self.create_ty(TyInfo::Unknown, expr.span);
300+
let func_req_ty = self.create_ty(TyInfo::Func(arg_ty, out_ty), func.span);
301+
self.unify(func_req_ty, func_ty, expr.span);
310302
out_ty
311303
}
312304
Expr::Add(l, r) | Expr::Mul(l, r) => {
313-
let out_ty = self.create_ty(TyInfo::Num, expr.1);
305+
let out_ty = self.create_ty(TyInfo::Num, expr.span);
314306
let l_ty = self.check(l, env);
315-
self.unify(out_ty, l_ty, expr.1);
307+
self.unify(out_ty, l_ty, expr.span);
316308
let r_ty = self.check(r, env);
317-
self.unify(out_ty, r_ty, expr.1);
309+
self.unify(out_ty, r_ty, expr.span);
318310
out_ty
319311
}
320312
}
@@ -363,14 +355,14 @@ pub struct Vm<'src> {
363355

364356
impl<'src> Vm<'src> {
365357
pub fn eval(&mut self, expr: &'src Spanned<Expr<'src>>) -> Value<'src> {
366-
match &expr.0 {
358+
match &**expr {
367359
Expr::Num(x) => Value::Num(*x),
368360
Expr::Bool(x) => Value::Bool(*x),
369361
Expr::Var(var) => self
370362
.stack
371363
.iter()
372364
.rev()
373-
.find(|(v, _)| v.0 == *var)
365+
.find(|(v, _)| **v == *var)
374366
.unwrap()
375367
.1
376368
.clone(),
@@ -456,7 +448,7 @@ fn main() {
456448
.unwrap_or_else(|errs| parse_failure(&errs[0], src));
457449

458450
let expr = parser()
459-
.parse(tokens[..].split_token_span((0..src.len()).into()))
451+
.parse(tokens[..].split_spanned((0..src.len()).into()))
460452
.into_result()
461453
.unwrap_or_else(|errs| parse_failure(&errs[0], src));
462454

src/combinator.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,13 +539,51 @@ where
539539
#[inline(always)]
540540
fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, I::Span> {
541541
let before = inp.cursor();
542-
self.parser.go::<M>(inp)?;
542+
self.parser.go::<Check>(inp)?;
543543
Ok(M::bind(|| inp.span_since(&before)))
544544
}
545545

546546
go_extra!(I::Span);
547547
}
548548

549+
/// See [`Parser::spanned`].
550+
pub struct Spanned<A, OA> {
551+
pub(crate) parser: A,
552+
#[allow(dead_code)]
553+
pub(crate) phantom: EmptyPhantom<OA>,
554+
}
555+
556+
impl<A: Copy, OA> Copy for Spanned<A, OA> {}
557+
impl<A: Clone, OA> Clone for Spanned<A, OA> {
558+
fn clone(&self) -> Self {
559+
Self {
560+
parser: self.parser.clone(),
561+
phantom: EmptyPhantom::new(),
562+
}
563+
}
564+
}
565+
566+
impl<'src, I, OA, E, A> Parser<'src, I, <I::Span as WrappingSpan<OA>>::Spanned, E>
567+
for Spanned<A, OA>
568+
where
569+
I: Input<'src>,
570+
E: ParserExtra<'src, I>,
571+
A: Parser<'src, I, OA, E>,
572+
I::Span: WrappingSpan<OA>,
573+
{
574+
#[inline(always)]
575+
fn go<M: Mode>(
576+
&self,
577+
inp: &mut InputRef<'src, '_, I, E>,
578+
) -> PResult<M, <I::Span as WrappingSpan<OA>>::Spanned> {
579+
let before = inp.cursor();
580+
let out = self.parser.go::<M>(inp)?;
581+
Ok(M::map(out, |out| inp.span_since(&before).make_wrapped(out)))
582+
}
583+
584+
go_extra!(<I::Span as WrappingSpan<OA>>::Spanned);
585+
}
586+
549587
/// See [`Parser::try_foldl`].
550588
pub struct TryFoldl<F, A, B, OB, E> {
551589
pub(crate) parser_a: A,

src/input.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,18 @@ pub trait Input<'src>: 'src {
257257
self.map(eoi, |(t, s)| (t, s))
258258
}
259259

260+
/// Take an input (such as a slice) with token type `T` where `T` is a spanned type, and split it into its inner value and token.
261+
///
262+
/// See the documentation for [`Input::split_token_span`], which is nearly identical in concept.
263+
fn split_spanned<T, S>(self, eoi: S) -> MappedInput<'src, T, S, Self>
264+
where
265+
Self: Input<'src, Token = S::Spanned, MaybeToken = &'src S::Spanned> + Sized,
266+
T: 'src,
267+
S: WrappingSpan<T> + 'src,
268+
{
269+
self.map(eoi, |spanned| (S::inner_of(spanned), S::span_of(spanned)))
270+
}
271+
260272
/// Map the spans output for this input to a different output span.
261273
///
262274
/// This is useful if you wish to include extra context that applies to all spans emitted during a parse, such as

src/inspector.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
//! beside his pillar and woken him with a start."*
77
use super::*;
88
use crate::input::{Checkpoint, Cursor};
9-
use core::ops::{Deref, DerefMut};
10-
11-
#[allow(unused)] // for intra-doc links
12-
use crate::Parser;
139

1410
/// A type that receives event hooks when certain parsing actions occur.
1511
///

src/lib.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub mod prelude {
8080
},
8181
recovery::{nested_delimiters, skip_then_retry_until, skip_until, via_parser},
8282
recursive::{recursive, Recursive},
83-
span::{SimpleSpan, Span as _},
83+
span::{SimpleSpan, Span as _, SpanWrap as _, Spanned},
8484
text, Boxed, ConfigIterParser, ConfigParser, IterParser, ParseResult, Parser,
8585
};
8686
pub use crate::{select, select_ref};
@@ -104,7 +104,7 @@ use core::{
104104
hash::Hash,
105105
marker::PhantomData,
106106
mem::MaybeUninit,
107-
ops::{Range, RangeFrom},
107+
ops::{Deref, DerefMut, Range, RangeFrom},
108108
panic::Location,
109109
str::FromStr,
110110
};
@@ -126,7 +126,7 @@ use self::{
126126
primitive::Any,
127127
private::{Check, Emit, IPResult, Located, MaybeUninitExt, Mode, PResult, Sealed},
128128
recovery::{RecoverWith, Strategy},
129-
span::Span,
129+
span::{Span, WrappingSpan},
130130
text::*,
131131
util::{IntoMaybe, MaybeMut, MaybeRef},
132132
};
@@ -770,6 +770,22 @@ pub trait Parser<'src, I: Input<'src>, O, E: ParserExtra<'src, I> = extra::Defau
770770
}
771771
}
772772

773+
/// Wrap the output of this parser in the pattern's span.
774+
///
775+
/// This is often used to preserve the span of AST nodes for error generation by future passes.
776+
///
777+
/// The output type of this parser is `<I::Span as WrappingSpan>::Spanned<O>`. For parsers using [`SimpleSpan`],
778+
/// that means the output type is [`Spanned<O, SimpleSpan>`].
779+
fn spanned(self) -> combinator::Spanned<Self, O>
780+
where
781+
Self: Sized,
782+
{
783+
combinator::Spanned {
784+
parser: self,
785+
phantom: EmptyPhantom::new(),
786+
}
787+
}
788+
773789
/// After a successful parse, apply a fallible function to the output. If the function produces an error, treat it
774790
/// as a parsing error.
775791
///

0 commit comments

Comments
 (0)