1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! # Parser
//!
//! Herein is the parser for the `xDy` language. [`Parser::parse`] is the main
//! entry point, which discards leading whitespace before parsing a
//! [function](Function). The recognized grammar is as follows, in Extended
//! Backus-Naur Form (EBNF), where non-terminals are in lowercase and terminals
//! are in uppercase:
//!
//! ```text
//! function ::= parameters? expression
//! parameters ::= parameter (',' parameter)* ':'
//! parameter ::= '{' IDENTIFIER '}'
//! expression ::= add_sub
//! add_sub ::= mul_div_mod (('+' | '-') mul_div_mod)*
//! mul_div_mod ::= unary (('*' | '/' | '%') unary)*
//! unary ::= '-' unary | exponent
//! exponent ::= primary ('^' unary)?
//! primary ::= range | dice | group | variable | binding | CONSTANT
//! group ::= '(' expression ')'
//! variable ::= '{' IDENTIFIER '}'
//! binding ::= '{' IDENTIFIER '}' '@' '(' expression ')'
//! range ::= '[' expression ':' expression ']'
//! dice ::= base_dice drop_clause*
//! base_dice ::= dice_count D_OPERATOR (standard_faces | custom_faces)
//! dice_count ::= CONSTANT | variable | binding | group
//! standard_faces ::= CONSTANT | variable | binding | group
//! custom_faces ::= '[' CONSTANT (',' CONSTANT)* ']'
//! drop_clause ::= 'drop' ('lowest' | 'highest') drop_expression?
//! drop_expression::= CONSTANT | variable | binding | group
//! CONSTANT ::= '-'? DIGIT+
//! D_OPERATOR ::= 'd' | 'D'
//! IDENTIFIER ::= NAME_CHAR (NAME_CHAR | WHITESPACE+ NAME_CHAR)*
//! NAME_CHAR ::= any code point except '{', '}', whitespace, or an
//! invisible character (is_identifier_char)
//! WHITESPACE ::= any whitespace (char::is_whitespace), e.g., ' ', '\t',
//! '\n', or U+00A0
//! ```
//!
//! Every name is braced, whether it names a parameter, a variable, or a
//! binding, so no name can run into the text around it. A lone braced name
//! without a `:` after it begins the expression, as a variable or a binding,
//! rather than declaring a parameter.
//!
//! An identifier may contain any visible character but a brace, e.g.,
//! `{weapon: 2/3}` or `{$env|weapon}`, and whitespace of any kind, so a long
//! name may be broken over lines. But a name is never distinguished by its
//! whitespace: the whitespace inside the braces, around the identifier, is not
//! part of it, and every run of whitespace within it collapses to a single
//! space, so `{ a b }`, `{a b}`, and `{a`, a line feed, and ` b}` all name
//! `a b`. The identifier character set is defined once, by
//! [`is_identifier_char`], which the parser, the [S-expression](crate::s_expr)
//! reader, and the assembler share, and a name is canonicalized once, by
//! [`canonical_name`]. The S-expression reader and the assembler accept only
//! [canonical](is_canonical_name) names, as their writers emit. The
//! [diagnostics](crate::diagnostics) also look for names that lack their
//! braces, but by a narrower character set that stops at operators and
//! delimiters.
//!
//! The following railroad diagram is generated from the EBNF grammar above:
//! Parsing is based on the [`nom`] library, which provides a combinator-based
//! approach to parsing.
//!
//! The grammar is recursive, but the parser is not. The combinators for the
//! recursive productions, from [`function`] down to [`group`] and [`binding`],
//! share a private engine that performs recursive descent with an explicit
//! stack on the heap, so parsing consumes no more of the machine stack for
//! deeply nested input than for shallow input. Parse time is linear in the
//! length of the input.
pub use *;
pub use ;
pub use ;
pub use *;
use ;
use crateFunction;
////////////////////////////////////////////////////////////////////////////////
// Parser. //
////////////////////////////////////////////////////////////////////////////////
/// The `xDy` parser. Use [`Parser::parse`] as the high-level entry point; the
/// individual parser combinators exposed by this module are available for
/// low-level uses but are not recommended for most clients.
;