Skip to content

Commit abce185

Browse files
committed
docs: More detail in Expression::precedence_level
Addresses the following comment: * winnow-rs#804 (comment)
1 parent 14430c0 commit abce185

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

src/combinator/expression.rs

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,91 @@ where
208208
}
209209
}
210210

211-
/// Sets the precedence level of the parser.
211+
/// Sets the precedence level for the current instance of the parser.
212+
///
213+
/// It defaults to 0, which is traditionally treated as the "lowest"
214+
/// possible precedence when parsing an expression.
212215
///
213216
/// This is useful to disambiguate grammars based on the parent operator's
214-
/// precedence.
217+
/// precedence. This comes up primarily when parsing recursive expressions.
218+
///
219+
/// The parsing machinery underpinning [`Expression`] assumes that a "more
220+
/// tightly binding" operator is numerically large, while a "more loosely
221+
/// binding" operator is numerically small. For example, `13` is a higher
222+
/// precedence level than `1` because `13 > 1`.
223+
///
224+
/// Other ways of describing this relationship:
225+
/// - `13` has a higher precedence compared to `1`
226+
/// - `13` has a higher binding power compared to `1`
227+
///
228+
/// Note: Binding power and precedence both refer to the same concept and
229+
/// may be used interchangeably.
230+
///
231+
/// # Motivation
232+
///
233+
/// If you don't understand why this is useful to have, this section tries
234+
/// to explain in more detail.
235+
///
236+
/// The [C-style Expressions][crate::_topic::arithmetic#c-style-expression]
237+
/// example has source code for parsing the expression described below, and
238+
/// can provide a clearer usage example.
239+
///
240+
/// Consider the following expression in the C language:
241+
///
242+
/// ```c
243+
/// int x = (1 == 1 ? 0 : 1, -123); // <-- let's parse this
244+
/// printf("%d\n", x); // -123
245+
/// ```
246+
///
247+
/// Let's look at the right-hand side of the expression on the first line,
248+
/// and replace some of the sub-expressions with symbols:
249+
///
250+
/// ```text
251+
/// (1 == 1 ? 0 : 1, -123) // rhs
252+
/// (a ? b : c, d ) // symbolic
253+
/// (a ? b : c, d) // remove whitespace
254+
/// (, (? a b c) d) // prefix notation
255+
/// ```
256+
///
257+
/// Written symbolically:
258+
/// - `a` is the condition, like `1 == 1`
259+
/// - `b` is the value when the condition is true
260+
/// - `c` is the value when the condition is false
261+
/// - `d` is a secondary expression unrelated to the ternary
262+
///
263+
/// In prefix notation, it's easier to see the specific operators and what
264+
/// they bind to:
265+
/// - COMMA (`,`) binds to `(? a b c)` and `d`
266+
/// - TERNARY (`?`) binds to `a`, `b`, and `c`
267+
///
268+
/// ## Parsing `c` and `d`
269+
///
270+
/// Let's focus on parsing the sub-expressions `c` and `d`, as that
271+
/// motivates why a parser precedence level is necessary.
272+
///
273+
/// To parse `c`, we would really like to re-use the parser produced by
274+
/// [`expression()`], because `c` is really *any* valid expression that
275+
/// can be parsed by `expression()` already.
276+
///
277+
/// However, we can't re-use the parser naively. When parsing `c`, we need
278+
/// to "escape" from the inner parser when encountering the comma separating
279+
/// `c` from `d`.
280+
///
281+
/// The reason we have to "escape" is because of how operator precedence is
282+
/// defined in the C language: the comma operator has the lowest precedence
283+
/// among all the operators. When we're parsing `c`, we're in the context of
284+
/// the ternary operator. We don't want to parse any valid expression! Just
285+
/// what the ternary operator captures.
286+
///
287+
/// That's where the precedence level comes in: you specify the minimum
288+
/// precedence this parser is willing to accept. If you come across an
289+
/// expression in the top-level with a lower binding power than the starting
290+
/// precedence, you know to stop parsing.
291+
///
292+
/// The parsing machinery inside of [`Expression`] handles most of this for
293+
/// you, but it can't determine what the precedence level should be for a
294+
/// given expression. That's a language-specific detail, and it depends on
295+
/// what you want to parse.
215296
#[inline(always)]
216297
pub fn precedence_level(
217298
mut self,

0 commit comments

Comments
 (0)