1mod compile;
13mod executor;
14mod forking;
15mod joins;
16mod keyword_lexing;
17mod lexing;
18mod load;
19mod operations;
20mod ordering;
21mod parting;
22mod precedence;
23mod program;
24mod reducing;
25mod repetition;
26mod results;
27mod roots;
28mod rules;
29mod separators;
30mod text;
31mod token_conflicts;
32mod token_ranks;
33mod tree;
34mod walk;
35
36use std::cell::{Cell, RefCell};
37use std::collections::HashSet;
38use std::fmt;
39use std::rc::Rc;
40
41pub use load::GrammarRuntimeError;
42pub use operations::OperationValue;
43pub use tree::{Ambiguity, LeafText, SyntaxAttributes, SyntaxTree};
44
45use super::Grammar;
46use super::decorators::{decorate_grammar, decorate_syntax_tree};
47use crate::decorators::{DecoratorError, DecoratorLevel, DecoratorSet};
48use executor::Executor;
49use operations::Abort;
50use program::{Compiled, SettlingStep};
51use results::{Expectations, KeywordLexing, Outcome, Shared, TokenOrder};
52
53const DEFAULT_MAX_DEPTH: usize = 1000;
55const DEFAULT_MEMO_LIMIT: usize = 1_000_000;
57const DEFAULT_MEMORY_LIMIT: usize = 2_000_000;
59const PARSE_STACK: usize = 256 * 1024 * 1024;
62
63#[derive(Clone, Debug, Default, PartialEq, Eq)]
66pub struct FeatureParseOptions {
67 pub start_rule: Option<String>,
69 pub max_depth: Option<usize>,
71 pub step_limit: Option<usize>,
74 pub memo_limit: Option<usize>,
76 pub memory_limit: Option<usize>,
82 pub reject_ambiguity: Option<bool>,
84 pub accept_recovery: Option<bool>,
86 pub error_recovery: Option<bool>,
89 pub max_repairs: Option<usize>,
91 pub decorators: DecoratorSet,
96}
97
98impl FeatureParseOptions {
99 fn over(&self, base: &Self) -> Self {
100 Self {
101 start_rule: self.start_rule.clone().or_else(|| base.start_rule.clone()),
102 max_depth: self.max_depth.or(base.max_depth),
103 step_limit: self.step_limit.or(base.step_limit),
104 memo_limit: self.memo_limit.or(base.memo_limit),
105 memory_limit: self.memory_limit.or(base.memory_limit),
106 reject_ambiguity: self.reject_ambiguity.or(base.reject_ambiguity),
107 accept_recovery: self.accept_recovery.or(base.accept_recovery),
108 error_recovery: self.error_recovery.or(base.error_recovery),
109 max_repairs: self.max_repairs.or(base.max_repairs),
110 decorators: if self.decorators.is_empty() {
111 base.decorators.clone()
112 } else {
113 self.decorators.clone()
114 },
115 }
116 }
117}
118
119#[derive(Clone, Debug, PartialEq, Eq)]
121pub struct ParseRejection {
122 pub reason: &'static str,
125 pub offset: Option<usize>,
127 pub line: Option<usize>,
129 pub column: Option<usize>,
131 pub expected: Option<Vec<String>>,
133 pub limit: Option<usize>,
135}
136
137impl ParseRejection {
138 const fn limited(reason: &'static str, limit: usize) -> Self {
139 Self {
140 reason,
141 offset: None,
142 line: None,
143 column: None,
144 expected: None,
145 limit: Some(limit),
146 }
147 }
148
149 fn positioned(reason: &'static str, bytes: &[u8], offset: usize) -> Self {
150 let (line, column) = text::line_and_column(bytes, offset);
151 Self {
152 reason,
153 offset: Some(offset),
154 line: Some(line),
155 column: Some(column),
156 expected: None,
157 limit: None,
158 }
159 }
160}
161
162impl fmt::Display for ParseRejection {
163 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
164 let place = match (self.line, self.column) {
165 (Some(line), Some(column)) => format!(" at line {line} column {column}"),
166 _ => String::new(),
167 };
168 let limit = self.limit.unwrap_or_default();
169 match self.reason {
170 "syntax" => {
171 let expected = self.expected.as_deref().unwrap_or_default();
172 let expected = if expected.is_empty() {
173 "nothing more".to_owned()
174 } else {
175 expected.join(", ")
176 };
177 write!(formatter, "syntax error{place}: expected {expected}")
178 }
179 "nestingDepth" => write!(formatter, "the input nests deeper than {limit} rules"),
180 "stepLimit" => write!(formatter, "the parse needed more than {limit} steps"),
181 "memoryBudget" => write!(formatter, "the parse needed more than {limit} memo cells"),
182 "recovered" => write!(formatter, "the input needed error recovery{place}"),
183 "ambiguity" => write!(formatter, "the input is ambiguous{place}"),
184 reason => write!(formatter, "the input is rejected ({reason})"),
185 }
186 }
187}
188
189#[derive(Clone, Debug, PartialEq, Eq)]
192pub struct ParseOutcome {
193 pub ok: bool,
195 pub tree: Option<SyntaxTree>,
197 pub ambiguities: Vec<Ambiguity>,
199 pub rejection: Option<ParseRejection>,
201}
202
203#[derive(Clone, Debug, PartialEq, Eq)]
205pub struct GrammarParseError {
206 pub rejection: ParseRejection,
208}
209
210impl fmt::Display for GrammarParseError {
211 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
212 self.rejection.fmt(formatter)
213 }
214}
215
216impl std::error::Error for GrammarParseError {}
217
218pub type GrammarResolver<'a> = &'a dyn Fn(&str) -> Option<Grammar>;
220
221#[derive(Debug)]
223pub struct FeatureGrammarParser {
224 compiled: Compiled,
225 options: FeatureParseOptions,
226}
227
228pub fn compile_feature_grammar(
238 grammar: &Grammar,
239 resolve_grammar: Option<GrammarResolver<'_>>,
240 options: FeatureParseOptions,
241) -> Result<FeatureGrammarParser, GrammarRuntimeError> {
242 let decorated = decorate_grammar(grammar, &options.decorators, DecoratorLevel::GrammarRule)
243 .map_err(decorator_error)?;
244 Ok(FeatureGrammarParser {
245 compiled: load::load(&decorated, resolve_grammar)?,
246 options,
247 })
248}
249
250impl FeatureGrammarParser {
251 pub fn parse_tree(
259 &self,
260 source: &[u8],
261 options: &FeatureParseOptions,
262 ) -> Result<ParseOutcome, GrammarRuntimeError> {
263 let options = options.over(&self.options);
264 let program = &self.compiled.programs[self.compiled.main];
265 let start_name = options
266 .start_rule
267 .clone()
268 .or_else(|| program.start.clone())
269 .unwrap_or_default();
270 let Some(&start_rule) = program.rule_index.get(&start_name) else {
271 return Err(GrammarRuntimeError {
272 reason: "reference",
273 message: format!("undefined start rule {start_name}"),
274 });
275 };
276 let compiled = &self.compiled;
277 let mut outcome = std::thread::scope(|scope| {
278 std::thread::Builder::new()
279 .stack_size(PARSE_STACK)
280 .spawn_scoped(scope, || {
281 parse_program(compiled, start_rule, source, &options)
282 })
283 .map_or_else(
284 |_| parse_program(compiled, start_rule, source, &options),
285 |handle| {
286 handle
287 .join()
288 .unwrap_or_else(|panic| std::panic::resume_unwind(panic))
289 },
290 )
291 });
292 if let Some(tree) = &outcome.tree {
293 outcome.tree = Some(
294 decorate_syntax_tree(tree, &options.decorators, source).map_err(decorator_error)?,
295 );
296 }
297 Ok(outcome)
298 }
299
300 pub fn parse(
307 &self,
308 source: &[u8],
309 options: &FeatureParseOptions,
310 ) -> Result<SyntaxTree, GrammarParseError> {
311 let outcome = self
312 .parse_tree(source, options)
313 .map_err(|_| GrammarParseError {
314 rejection: ParseRejection::positioned("syntax", source, 0),
315 })?;
316 match (outcome.rejection, outcome.tree) {
317 (None, Some(tree)) => Ok(tree),
318 (rejection, _) => Err(GrammarParseError {
319 rejection: rejection
320 .unwrap_or_else(|| ParseRejection::positioned("syntax", source, 0)),
321 }),
322 }
323 }
324}
325
326#[derive(Clone, Debug, PartialEq, Eq)]
329pub enum ParseWithGrammarError {
330 Runtime(GrammarRuntimeError),
332 Parse(GrammarParseError),
334}
335
336impl fmt::Display for ParseWithGrammarError {
337 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
338 match self {
339 Self::Runtime(error) => error.fmt(formatter),
340 Self::Parse(error) => error.fmt(formatter),
341 }
342 }
343}
344
345impl std::error::Error for ParseWithGrammarError {}
346
347pub fn parse_with_grammar(
355 grammar: &Grammar,
356 source: &[u8],
357 options: &FeatureParseOptions,
358) -> Result<SyntaxTree, ParseWithGrammarError> {
359 compile_feature_grammar(grammar, None, options.clone())
360 .map_err(ParseWithGrammarError::Runtime)?
361 .parse(source, options)
362 .map_err(ParseWithGrammarError::Parse)
363}
364
365fn decorator_error(error: DecoratorError) -> GrammarRuntimeError {
366 GrammarRuntimeError {
367 reason: "decorator",
368 message: error.message,
369 }
370}
371
372const DEFAULT_MAX_REPAIRS: usize = 32;
374
375fn repair_parse(
382 failed: Outcome,
383 max_repairs: usize,
384 attempt: impl Fn(Option<&HashSet<usize>>) -> Result<Outcome, Abort>,
385) -> Result<Outcome, Abort> {
386 let mut points = HashSet::new();
387 let mut outcome = failed;
388 while points.len() < max_repairs {
389 let Outcome::Failed {
390 farthest,
391 element_farthest,
392 ..
393 } = &outcome
394 else {
395 break;
396 };
397 if !points.insert(element_farthest.unwrap_or(*farthest)) {
398 break;
399 }
400 outcome = match attempt(Some(&points)) {
401 Err(Abort::StepLimit) => break,
402 attempted => attempted?,
403 };
404 if matches!(outcome, Outcome::Parsed(_)) {
405 return Ok(outcome);
406 }
407 }
408 Ok(match outcome {
409 Outcome::Failed {
410 partial: Some(partial),
411 ..
412 } => Outcome::Parsed(partial),
413 outcome => outcome,
414 })
415}
416
417fn parse_program(
418 compiled: &Compiled,
419 start_rule: usize,
420 bytes: &[u8],
421 options: &FeatureParseOptions,
422) -> ParseOutcome {
423 let max_depth = options.max_depth.unwrap_or(DEFAULT_MAX_DEPTH);
424 let limit = options.step_limit.unwrap_or_else(|| {
426 (100_000 + 1000 * bytes.len())
427 * if options.error_recovery == Some(true) {
428 2
429 } else {
430 1
431 }
432 });
433 let refused = |rejection, tree| ParseOutcome {
434 ok: false,
435 tree,
436 ambiguities: Vec::new(),
437 rejection: Some(rejection),
438 };
439 let tokens = compiled.programs[compiled.main]
442 .token_ranks
443 .as_ref()
444 .filter(|_| {
445 compiled.programs[compiled.main]
446 .settling
447 .has(SettlingStep::Tokens)
448 })
449 .map(|ranks| TokenOrder {
450 ranks,
451 bytes,
452 orders: &compiled.programs[compiled.main].precedence_orders,
453 grammar: &compiled.programs[compiled.main].grammar,
454 trivia: &compiled.programs[compiled.main].trivia,
455 });
456 let keywords = tokens.map(|_| RefCell::new(KeywordLexing::default()));
457 let expectations = RefCell::new(Expectations::default());
458 let memory_limit = options.memory_limit.unwrap_or(DEFAULT_MEMORY_LIMIT);
460 let cells = Rc::new(Cell::new(0));
461 let attempt = |points: Option<&HashSet<usize>>| loop {
466 let mut record = expectations.take();
467 record.restart();
468 let shared = Shared {
469 steps: Cell::new(0),
470 limit,
471 frames: Cell::new(0),
472 memo_limit: options.memo_limit.unwrap_or(DEFAULT_MEMO_LIMIT),
473 cells: Rc::clone(&cells),
474 memory_limit,
475 expectations: RefCell::new(record),
476 };
477 let outcome = {
478 let mut executor = Executor::new(
479 compiled,
480 compiled.main,
481 bytes,
482 0,
483 bytes.len(),
484 &shared,
485 max_depth,
486 );
487 executor.repair_points = points.cloned();
488 executor.keywords = keywords.as_ref();
489 executor.run(start_rule)
490 };
491 let record = shared.expectations.into_inner();
492 let stale = record.stale;
493 expectations.replace(record);
494 if outcome.is_err() || !stale {
495 break outcome;
496 }
497 };
498 let recovery = options.error_recovery == Some(true);
499 let outcome = loop {
500 let outcome =
502 attempt(recovery.then(HashSet::new).as_ref()).and_then(|outcome| match outcome {
503 Outcome::Failed { .. } if recovery => repair_parse(
504 outcome,
505 options.max_repairs.unwrap_or(DEFAULT_MAX_REPAIRS),
506 attempt,
507 ),
508 outcome => Ok(outcome),
509 });
510 if let (Ok(Outcome::Parsed(root)), Some(keywords), Some(tokens)) =
511 (&outcome, &keywords, tokens)
512 && keywords.borrow_mut().conflicts(
513 root,
514 tokens,
515 &compiled.programs[compiled.main].rules,
516 )
517 {
518 continue;
519 }
520 break outcome;
521 };
522 let root = match outcome {
523 Err(Abort::StepLimit) => {
524 return refused(ParseRejection::limited("stepLimit", limit), None);
525 }
526 Err(Abort::MemoryBudget) => {
527 return refused(ParseRejection::limited("memoryBudget", memory_limit), None);
528 }
529 Err(Abort::NestingTooDeep) => {
530 let tree = tree::error_tree(bytes, 0, bytes.len(), Some("nestingDepth"));
531 return refused(
532 ParseRejection::limited("nestingDepth", max_depth),
533 Some(tree),
534 );
535 }
536 Ok(Outcome::Failed {
537 farthest, expected, ..
538 }) => {
539 let mut rejection = ParseRejection::positioned("syntax", bytes, farthest);
540 rejection.expected = Some(expected);
541 return refused(rejection, None);
542 }
543 Ok(Outcome::Parsed(root)) => root,
544 };
545 let tree = tree::public_tree(&root, bytes);
546 let mut ambiguities = Vec::new();
547 tree::collect_ambiguities(&root, compiled, compiled.main, &mut ambiguities);
548 let recovered = tree
549 .first_recovery()
550 .filter(|_| options.accept_recovery != Some(true))
551 .map(|recovery| ParseRejection::positioned("recovered", bytes, recovery.start()));
552 let rejection = recovered.or_else(|| {
553 ambiguities
554 .first()
555 .filter(|_| options.reject_ambiguity == Some(true))
556 .map(|first| ParseRejection::positioned("ambiguity", bytes, first.start))
557 });
558 ParseOutcome {
559 ok: rejection.is_none(),
560 tree: Some(tree),
561 ambiguities,
562 rejection,
563 }
564}