1use std::collections::BTreeSet;
10
11use super::{CharClassItem, GrammarExpr};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum FieldType {
16 Choice(&'static [&'static str]),
18 Integer,
20 Name,
22 Text,
24 Expression,
26 Expressions,
28 Condition,
30 Value,
32 Conditions,
34 Block(&'static str, bool),
36}
37
38pub type FormFields = &'static [(&'static str, FieldType)];
40
41pub const FEATURE_EXPRESSION_FORMS: &[(&str, FormFields)] = &[
43 (
44 "precedence",
45 &[
46 ("level", FieldType::Integer),
47 (
48 "associativity",
49 FieldType::Choice(&["left", "right", "none"]),
50 ),
51 ("item", FieldType::Expression),
52 ],
53 ),
54 (
55 "namedPrecedence",
56 &[
57 ("name", FieldType::Name),
58 (
59 "associativity",
60 FieldType::Choice(&["left", "right", "none"]),
61 ),
62 ("item", FieldType::Expression),
63 ],
64 ),
65 (
66 "dynamicPrecedence",
67 &[
68 ("level", FieldType::Integer),
69 ("item", FieldType::Expression),
70 ],
71 ),
72 (
73 "lexicalPrecedence",
74 &[
75 ("level", FieldType::Integer),
76 ("item", FieldType::Expression),
77 ],
78 ),
79 ("longest", &[("items", FieldType::Expressions)]),
80 ("token", &[("item", FieldType::Expression)]),
81 ("immediateToken", &[("item", FieldType::Expression)]),
82 (
83 "alias",
84 &[("name", FieldType::Name), ("item", FieldType::Expression)],
85 ),
86 ("parameter", &[("name", FieldType::Name)]),
87 (
88 "predicate",
89 &[
90 ("item", FieldType::Expression),
91 ("condition", FieldType::Condition),
92 ],
93 ),
94 (
95 "recover",
96 &[
97 ("item", FieldType::Expression),
98 ("synchronize", FieldType::Expression),
99 ],
100 ),
101 ("missing", &[("item", FieldType::Expression)]),
102 (
103 "embed",
104 &[
105 ("language", FieldType::Name),
106 ("item", FieldType::Expression),
107 ],
108 ),
109 (
110 "expand",
111 &[
112 ("name", FieldType::Name),
113 ("arguments", FieldType::Expressions),
114 ],
115 ),
116];
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum OperationCategory {
121 Statement,
123 Condition,
125 Value,
127}
128
129impl OperationCategory {
130 #[must_use]
132 pub const fn as_str(self) -> &'static str {
133 match self {
134 Self::Statement => "statement",
135 Self::Condition => "condition",
136 Self::Value => "value",
137 }
138 }
139}
140
141const TWO_VALUES: FormFields = &[("left", FieldType::Value), ("right", FieldType::Value)];
142const STATEMENT: OperationCategory = OperationCategory::Statement;
143const CONDITION: OperationCategory = OperationCategory::Condition;
144const VALUE: OperationCategory = OperationCategory::Value;
145
146pub const OPERATION_FORMS: &[(&str, OperationCategory, FormFields)] = &[
149 ("advance", STATEMENT, &[]),
150 ("consume", STATEMENT, &[("item", FieldType::Expression)]),
151 ("skip", STATEMENT, &[("item", FieldType::Expression)]),
152 ("mark", STATEMENT, &[]),
153 ("emit", STATEMENT, &[("token", FieldType::Name)]),
154 ("fail", STATEMENT, &[]),
155 (
156 "if",
157 STATEMENT,
158 &[
159 ("condition", FieldType::Condition),
160 ("consequent", FieldType::Block("then", false)),
161 ("alternative", FieldType::Block("else", true)),
162 ],
163 ),
164 (
165 "while",
166 STATEMENT,
167 &[
168 ("condition", FieldType::Condition),
169 ("body", FieldType::Block("do", false)),
170 ],
171 ),
172 (
173 "push",
174 STATEMENT,
175 &[("stack", FieldType::Name), ("value", FieldType::Value)],
176 ),
177 ("pop", STATEMENT, &[("stack", FieldType::Name)]),
178 (
179 "set",
180 STATEMENT,
181 &[("variable", FieldType::Name), ("value", FieldType::Value)],
182 ),
183 ("pushMode", STATEMENT, &[("mode", FieldType::Name)]),
184 ("popMode", STATEMENT, &[]),
185 ("setMode", STATEMENT, &[("mode", FieldType::Name)]),
186 (
187 "setAttribute",
188 STATEMENT,
189 &[("attribute", FieldType::Name), ("value", FieldType::Value)],
190 ),
191 ("buildNode", STATEMENT, &[("kind", FieldType::Name)]),
192 ("valid", CONDITION, &[("token", FieldType::Name)]),
193 ("expected", CONDITION, &[("item", FieldType::Expression)]),
194 ("next", CONDITION, &[("item", FieldType::Expression)]),
195 ("atEnd", CONDITION, &[]),
196 ("equal", CONDITION, TWO_VALUES),
197 ("less", CONDITION, TWO_VALUES),
198 ("greater", CONDITION, TWO_VALUES),
199 ("all", CONDITION, &[("conditions", FieldType::Conditions)]),
200 ("some", CONDITION, &[("conditions", FieldType::Conditions)]),
201 ("not", CONDITION, &[("condition", FieldType::Condition)]),
202 ("integer", VALUE, &[("value", FieldType::Integer)]),
203 ("text", VALUE, &[("value", FieldType::Text)]),
204 ("variable", VALUE, &[("name", FieldType::Name)]),
205 ("top", VALUE, &[("stack", FieldType::Name)]),
206 ("depth", VALUE, &[("stack", FieldType::Name)]),
207 ("column", VALUE, &[]),
208 ("matched", VALUE, &[]),
209 ("mode", VALUE, &[]),
210 (
211 "attribute",
212 VALUE,
213 &[("field", FieldType::Name), ("attribute", FieldType::Name)],
214 ),
215 (
216 "sumOf",
217 VALUE,
218 &[("field", FieldType::Name), ("attribute", FieldType::Name)],
219 ),
220 ("fieldText", VALUE, &[("field", FieldType::Name)]),
221 ("length", VALUE, &[("value", FieldType::Value)]),
222 ("number", VALUE, &[("value", FieldType::Value)]),
223 ("add", VALUE, TWO_VALUES),
224 ("subtract", VALUE, TWO_VALUES),
225 ("multiply", VALUE, TWO_VALUES),
226];
227
228pub const MATCHING_MODES: &[&str] = &["generalized", "peg", "longest"];
231
232pub const SETTLING_STEPS: &[&str] = &["tokens", "precedence", "dynamic", "first", "ambiguity"];
243
244#[must_use]
246pub fn default_settling(matching: &str) -> &'static [&'static str] {
247 match matching {
248 "peg" => &["first"],
249 "longest" => &["tokens", "precedence", "dynamic", "ambiguity"],
250 _ => &["dynamic", "ambiguity"],
251 }
252}
253
254#[must_use]
257pub fn settling_problem<S: AsRef<str>>(steps: &[S]) -> Option<String> {
258 if steps.is_empty() {
259 return Some("the settling names no step".to_owned());
260 }
261 for (index, step) in steps.iter().enumerate() {
262 let step = step.as_ref();
263 if !SETTLING_STEPS.contains(&step) {
264 return Some(format!("unknown settling step {step}"));
265 }
266 if steps.iter().position(|other| other.as_ref() == step) != Some(index) {
267 return Some(format!("the settling step {step} is given twice"));
268 }
269 let tie = step == "first" || step == "ambiguity";
270 if tie != (index == steps.len() - 1) {
271 return Some("the settling ends with exactly one of first and ambiguity".to_owned());
272 }
273 }
274 None
275}
276
277pub const MAX_INTEGER_DIGITS: usize = 15;
279
280#[must_use]
282pub fn feature_expression_fields(head: &str) -> Option<FormFields> {
283 FEATURE_EXPRESSION_FORMS
284 .iter()
285 .find(|(name, _)| *name == head)
286 .map(|(_, fields)| *fields)
287}
288
289#[must_use]
291pub fn operation_form(head: &str) -> Option<(OperationCategory, FormFields)> {
292 OPERATION_FORMS
293 .iter()
294 .find(|(name, _, _)| *name == head)
295 .map(|(_, category, fields)| (*category, *fields))
296}
297
298pub fn check_integer(text: &str) -> Result<i64, String> {
304 let digits = text.strip_prefix('-').unwrap_or(text);
305 if digits.is_empty() || !digits.bytes().all(|byte| byte.is_ascii_digit()) {
306 return Err(format!("expected an integer, not {text}"));
307 }
308 if digits.len() > MAX_INTEGER_DIGITS {
309 return Err(format!("integer {text} is too large"));
310 }
311 text.parse()
312 .map_err(|_| format!("expected an integer, not {text}"))
313}
314
315#[derive(Clone, Debug, PartialEq, Eq)]
317pub enum FieldValue {
318 Word(String),
320 Integer(i64),
322 Name(String),
324 Text(String),
326 Expression(GrammarExpr),
328 Expressions(Vec<GrammarExpr>),
330 Operation(FeatureForm),
332 Operations(Vec<FeatureForm>),
334 Block(Option<Vec<FeatureForm>>),
336}
337
338#[derive(Clone, Debug, PartialEq, Eq)]
341pub struct FeatureForm {
342 pub head: String,
344 pub fields: Vec<FieldValue>,
346}
347
348pub type Operation = FeatureForm;
350
351impl FeatureForm {
352 #[must_use]
354 pub fn new(head: impl Into<String>, fields: Vec<FieldValue>) -> Self {
355 Self {
356 head: head.into(),
357 fields,
358 }
359 }
360
361 #[must_use]
363 pub fn spec(&self) -> FormFields {
364 feature_expression_fields(&self.head)
365 .or_else(|| operation_form(&self.head).map(|(_, fields)| fields))
366 .unwrap_or(&[])
367 }
368
369 #[must_use]
371 pub fn field(&self, key: &str) -> Option<&FieldValue> {
372 let index = self.spec().iter().position(|(name, _)| *name == key)?;
373 self.fields.get(index)
374 }
375
376 #[must_use]
378 pub fn expression(&self, key: &str) -> Option<&GrammarExpr> {
379 match self.field(key)? {
380 FieldValue::Expression(expr) => Some(expr),
381 _ => None,
382 }
383 }
384
385 #[must_use]
387 pub fn expressions(&self, key: &str) -> &[GrammarExpr] {
388 match self.field(key) {
389 Some(FieldValue::Expressions(items)) => items,
390 _ => &[],
391 }
392 }
393
394 #[must_use]
396 pub fn text(&self, key: &str) -> Option<&str> {
397 match self.field(key)? {
398 FieldValue::Word(value) | FieldValue::Name(value) | FieldValue::Text(value) => {
399 Some(value)
400 }
401 _ => None,
402 }
403 }
404
405 #[must_use]
407 pub fn integer(&self, key: &str) -> Option<i64> {
408 match self.field(key)? {
409 FieldValue::Integer(value) => Some(*value),
410 _ => None,
411 }
412 }
413
414 #[must_use]
416 pub fn operation(&self, key: &str) -> Option<&Self> {
417 match self.field(key)? {
418 FieldValue::Operation(operation) => Some(operation),
419 _ => None,
420 }
421 }
422
423 #[must_use]
425 pub fn operations(&self, key: &str) -> Option<&[Self]> {
426 match self.field(key)? {
427 FieldValue::Operations(items) | FieldValue::Block(Some(items)) => Some(items),
428 _ => None,
429 }
430 }
431
432 pub fn for_each_expression<'a>(&'a self, visit: &mut impl FnMut(&'a GrammarExpr)) {
434 for value in &self.fields {
435 match value {
436 FieldValue::Expression(expr) => visit(expr),
437 FieldValue::Expressions(items) => items.iter().for_each(&mut *visit),
438 FieldValue::Operation(operation) => operation.for_each_expression(visit),
439 FieldValue::Operations(items) | FieldValue::Block(Some(items)) => {
440 for operation in items {
441 operation.for_each_expression(visit);
442 }
443 }
444 _ => {}
445 }
446 }
447 }
448
449 pub fn map_expressions(&mut self, map: &mut impl FnMut(&mut GrammarExpr)) {
451 for value in &mut self.fields {
452 match value {
453 FieldValue::Expression(expr) => map(expr),
454 FieldValue::Expressions(items) => items.iter_mut().for_each(&mut *map),
455 FieldValue::Operation(operation) => operation.map_expressions(map),
456 FieldValue::Operations(items) | FieldValue::Block(Some(items)) => {
457 for operation in items {
458 operation.map_expressions(map);
459 }
460 }
461 _ => {}
462 }
463 }
464 }
465}
466
467#[derive(Clone, Copy, Debug, PartialEq, Eq)]
469pub enum ByteClassItem {
470 Byte(u8),
472 Range(u8, u8),
474}
475
476#[derive(Clone, Debug, PartialEq, Eq)]
478pub enum UnicodeClassItem {
479 Char(char),
481 Range(char, char),
483 Category(String),
485 Script(String),
487}
488
489#[must_use]
492pub fn class_expression(negated: bool, items: Vec<UnicodeClassItem>) -> GrammarExpr {
493 let plain = items
494 .iter()
495 .map(|item| match item {
496 UnicodeClassItem::Char(value) => Some(CharClassItem::Char(*value)),
497 UnicodeClassItem::Range(start, end) => Some(CharClassItem::Range(*start, *end)),
498 UnicodeClassItem::Category(_) | UnicodeClassItem::Script(_) => None,
499 })
500 .collect::<Option<Vec<_>>>();
501 plain.map_or_else(
502 || GrammarExpr::feature(FeatureExpr::UnicodeClass { negated, items }),
503 |items| GrammarExpr::CharClass { negated, items },
504 )
505}
506
507#[derive(Clone, Debug, PartialEq, Eq)]
509pub enum FeatureExpr {
510 Form(FeatureForm),
512 ByteClass {
514 negated: bool,
516 items: Vec<ByteClassItem>,
518 },
519 UnicodeClass {
521 negated: bool,
523 items: Vec<UnicodeClassItem>,
525 },
526 Call {
528 name: String,
530 arguments: Vec<GrammarExpr>,
532 },
533}
534
535impl FeatureExpr {
536 #[must_use]
538 pub fn head(&self) -> &str {
539 match self {
540 Self::Form(form) => &form.head,
541 Self::ByteClass { .. } => "byteClass",
542 Self::UnicodeClass { .. } => "charClass",
543 Self::Call { .. } => "ref",
544 }
545 }
546
547 pub fn for_each_expression<'a>(&'a self, visit: &mut impl FnMut(&'a GrammarExpr)) {
549 match self {
550 Self::Form(form) => form.for_each_expression(visit),
551 Self::Call { arguments, .. } => arguments.iter().for_each(visit),
552 Self::ByteClass { .. } | Self::UnicodeClass { .. } => {}
553 }
554 }
555
556 pub fn map_expressions(&mut self, map: &mut impl FnMut(&mut GrammarExpr)) {
558 match self {
559 Self::Form(form) => form.map_expressions(map),
560 Self::Call { arguments, .. } => arguments.iter_mut().for_each(map),
561 Self::ByteClass { .. } | Self::UnicodeClass { .. } => {}
562 }
563 }
564
565 pub(crate) fn collect_references(&self, names: &mut BTreeSet<String>) {
569 match self {
570 Self::Call { name, arguments } => {
571 names.insert(name.clone());
572 for argument in arguments {
573 argument.collect_nonterminals(names);
574 }
575 }
576 Self::Form(form) => {
577 for value in &form.fields {
578 match value {
579 FieldValue::Expression(expr) => expr.collect_nonterminals(names),
580 FieldValue::Expressions(items) => {
581 for item in items {
582 item.collect_nonterminals(names);
583 }
584 }
585 _ => {}
586 }
587 }
588 }
589 Self::ByteClass { .. } | Self::UnicodeClass { .. } => {}
590 }
591 }
592}
593
594#[derive(Clone, Debug, Default, PartialEq, Eq)]
596pub struct RuleAttributes {
597 pub parameters: Vec<String>,
599 pub channel: Option<String>,
601 pub modes: Option<Vec<String>>,
603 pub action: Option<Vec<Operation>>,
605}
606
607impl RuleAttributes {
608 #[must_use]
610 pub fn is_empty(&self) -> bool {
611 self == &Self::default()
612 }
613}
614
615#[derive(Clone, Debug, PartialEq, Eq)]
617pub struct GrammarMacro {
618 pub name: String,
620 pub parameters: Vec<String>,
622 pub expression: GrammarExpr,
624}
625
626#[derive(Clone, Debug, PartialEq, Eq)]
628pub struct GrammarScanner {
629 pub name: String,
631 pub tokens: Vec<String>,
633 pub operations: Vec<Operation>,
635}
636
637#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
640pub enum PrecedenceEntry {
641 Name(String),
643 Rule(String),
645}
646
647impl PrecedenceEntry {
648 #[must_use]
650 pub fn from_kind(kind: &str, value: String) -> Option<Self> {
651 match kind {
652 "name" => Some(Self::Name(value)),
653 "rule" => Some(Self::Rule(value)),
654 _ => None,
655 }
656 }
657
658 #[must_use]
660 pub const fn kind(&self) -> &'static str {
661 match self {
662 Self::Name(_) => "name",
663 Self::Rule(_) => "rule",
664 }
665 }
666
667 #[must_use]
669 pub fn value(&self) -> &str {
670 match self {
671 Self::Name(value) | Self::Rule(value) => value,
672 }
673 }
674}
675
676#[derive(Clone, Debug, Default, PartialEq, Eq)]
678pub struct GrammarDeclarations {
679 pub matching: Option<String>,
681 pub settling: Option<Vec<String>>,
683 pub imports: Vec<String>,
685 pub modes: Vec<String>,
687 pub extras: Vec<GrammarExpr>,
689 pub conflicts: Vec<Vec<String>>,
691 pub precedences: Vec<Vec<PrecedenceEntry>>,
693 pub macros: Vec<GrammarMacro>,
695 pub scanners: Vec<GrammarScanner>,
697}
698
699impl GrammarDeclarations {
700 #[must_use]
702 pub fn is_empty(&self) -> bool {
703 self == &Self::default()
704 }
705
706 #[must_use]
708 pub fn external_tokens(&self) -> Vec<&str> {
709 self.scanners
710 .iter()
711 .flat_map(|scanner| scanner.tokens.iter().map(String::as_str))
712 .collect()
713 }
714
715 #[must_use]
717 pub fn present(&self) -> Vec<&'static str> {
718 let mut present = Vec::new();
719 if self.matching.is_some() {
720 present.push("matching");
721 }
722 if self.settling.is_some() {
723 present.push("settling");
724 }
725 for (name, empty) in [
726 ("imports", self.imports.is_empty()),
727 ("modes", self.modes.is_empty()),
728 ("extras", self.extras.is_empty()),
729 ("conflicts", self.conflicts.is_empty()),
730 ("precedences", self.precedences.is_empty()),
731 ("macros", self.macros.is_empty()),
732 ("scanners", self.scanners.is_empty()),
733 ] {
734 if !empty {
735 present.push(name);
736 }
737 }
738 present
739 }
740}