1use alloc::string::String;
9use alloc::vec::Vec;
10
11use crate::error::RuleError;
12use crate::rules::{Indent, MAX_INDENT_STEP, NodeRule, Rules, Space, TokenRule, Trailing};
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
18pub(crate) struct Sp {
19 pub(crate) space: bool,
21 pub(crate) brk: u8,
23}
24
25impl Sp {
26 pub(crate) const NONE: Sp = Sp {
27 space: false,
28 brk: 0,
29 };
30 pub(crate) const SINGLE: Sp = Sp {
31 space: true,
32 brk: 0,
33 };
34 pub(crate) const HARD: Sp = Sp {
35 space: false,
36 brk: 2,
37 };
38
39 #[inline]
40 pub(crate) fn join(self, other: Sp) -> Sp {
41 Sp {
42 space: self.space | other.space,
43 brk: self.brk.max(other.brk),
44 }
45 }
46
47 #[inline]
48 pub(crate) fn is_hard(self) -> bool {
49 self.brk >= 2
50 }
51}
52
53impl From<Space> for Sp {
54 #[inline]
55 fn from(space: Space) -> Self {
56 match space {
57 Space::None => Sp::NONE,
58 Space::Single => Sp::SINGLE,
59 Space::SoftLine => Sp {
60 space: false,
61 brk: 1,
62 },
63 Space::Line => Sp {
64 space: true,
65 brk: 1,
66 },
67 Space::Hard => Sp::HARD,
68 }
69 }
70}
71
72#[inline]
75pub(crate) fn join_opt(acc: Option<Sp>, add: Option<Sp>) -> Option<Sp> {
76 match (acc, add) {
77 (Some(a), Some(b)) => Some(a.join(b)),
78 (a, None) => a,
79 (None, b) => b,
80 }
81}
82
83#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
85pub(crate) struct Sides {
86 pub(crate) before: Option<Sp>,
87 pub(crate) after: Option<Sp>,
88}
89
90impl Sides {
91 fn merge(self, later: Sides) -> Sides {
92 Sides {
93 before: later.before.or(self.before),
94 after: later.after.or(self.after),
95 }
96 }
97}
98
99#[derive(Clone, Debug)]
101pub(crate) struct TokenTable<K> {
102 exact: Vec<(K, Sides)>,
103 any: Sides,
104}
105
106impl<K> Default for TokenTable<K> {
107 fn default() -> Self {
108 Self {
109 exact: Vec::new(),
110 any: Sides::default(),
111 }
112 }
113}
114
115impl<K: Ord> TokenTable<K> {
116 #[inline]
117 fn sides(&self, kind: &K) -> Sides {
118 match self.exact.binary_search_by(|(k, _)| k.cmp(kind)) {
119 Ok(i) => self.exact.get(i).map_or(Sides::default(), |(_, s)| *s),
120 Err(_) => Sides::default(),
121 }
122 }
123
124 #[inline]
125 fn before(&self, kind: &K) -> Option<Sp> {
126 self.sides(kind).before.or(self.any.before)
127 }
128
129 #[inline]
130 fn after(&self, kind: &K) -> Option<Sp> {
131 self.sides(kind).after.or(self.any.after)
132 }
133}
134
135#[derive(Clone, Debug)]
137pub(crate) struct Delims<K> {
138 pub(crate) open: K,
139 pub(crate) close: K,
140 pub(crate) inner: Sp,
141}
142
143#[derive(Clone, Debug)]
145pub(crate) struct Sep<K> {
146 pub(crate) kind: K,
147 pub(crate) text: String,
148 pub(crate) before: Sp,
149 pub(crate) after: Sp,
150 pub(crate) trailing: Trailing,
151}
152
153#[derive(Clone, Debug)]
155pub(crate) struct NodeStyle<K> {
156 pub(crate) kind: K,
157 pub(crate) group: bool,
158 pub(crate) indent: Indent,
159 pub(crate) before: Option<Sp>,
160 pub(crate) after: Option<Sp>,
161 pub(crate) delims: Option<Delims<K>>,
162 pub(crate) empty: Sp,
163 pub(crate) sep: Option<Sep<K>>,
164 pub(crate) blank_lines: Option<u8>,
165 tokens: TokenTable<K>,
166}
167
168impl<K: Ord> NodeStyle<K> {
169 #[inline]
172 pub(crate) fn owns_doc(&self) -> bool {
173 self.group || self.indent != Indent::None
174 }
175}
176
177#[derive(Clone, Debug)]
197pub struct Style<K> {
198 pub(crate) indent: u32,
199 pub(crate) max_indent: u32,
200 pub(crate) blank_lines: u8,
201 pub(crate) final_newline: bool,
202 pub(crate) touch: fn(&str, &str) -> bool,
203 verbatim: Vec<K>,
204 tokens: TokenTable<K>,
205 nodes: Vec<NodeStyle<K>>,
206}
207
208impl<K> Default for Style<K> {
209 fn default() -> Self {
210 let rules = Rules::new();
211 Self {
212 indent: u32::from(rules.indent),
213 max_indent: u32::from(rules.max_indent),
214 blank_lines: rules.max_blank_lines,
215 final_newline: rules.final_newline,
216 touch: crate::can_touch,
217 verbatim: Vec::new(),
218 tokens: TokenTable::default(),
219 nodes: Vec::new(),
220 }
221 }
222}
223
224impl<K> Style<K> {
225 #[must_use]
247 pub fn with_touch(mut self, touch: fn(&str, &str) -> bool) -> Self {
248 self.touch = touch;
249 self
250 }
251}
252
253impl<K: Ord> Style<K> {
254 #[inline]
256 pub(crate) fn node_index(&self, kind: &K) -> Option<u32> {
257 self.nodes
258 .binary_search_by(|n| n.kind.cmp(kind))
259 .ok()
260 .and_then(|i| u32::try_from(i).ok())
261 }
262
263 #[inline]
264 pub(crate) fn node(&self, index: Option<u32>) -> Option<&NodeStyle<K>> {
265 index.and_then(|i| self.nodes.get(i as usize))
266 }
267
268 #[inline]
269 pub(crate) fn is_verbatim(&self, kind: &K) -> bool {
270 self.verbatim.binary_search(kind).is_ok()
271 }
272
273 pub(crate) fn token_after(&self, parent: Option<&NodeStyle<K>>, kind: &K) -> Option<Sp> {
276 if let Some(p) = parent {
277 if let Some(sep) = &p.sep {
278 if sep.kind == *kind {
279 return Some(sep.after);
280 }
281 }
282 if let Some(sp) = p.tokens.after(kind) {
283 return Some(sp);
284 }
285 }
286 self.tokens.after(kind)
287 }
288
289 pub(crate) fn token_before(&self, parent: Option<&NodeStyle<K>>, kind: &K) -> Option<Sp> {
291 if let Some(p) = parent {
292 if let Some(sep) = &p.sep {
293 if sep.kind == *kind {
294 return Some(sep.before);
295 }
296 }
297 if let Some(sp) = p.tokens.before(kind) {
298 return Some(sp);
299 }
300 }
301 self.tokens.before(kind)
302 }
303}
304
305impl Rules {
306 pub fn compile<K: Ord + Clone>(
347 &self,
348 mut resolve: impl FnMut(&str) -> Option<K>,
349 ) -> Result<Style<K>, RuleError> {
350 if self.indent > MAX_INDENT_STEP {
351 return Err(RuleError::IndentTooWide {
352 columns: self.indent,
353 });
354 }
355 let mut verbatim = Vec::with_capacity(self.verbatim.len());
356 for name in &self.verbatim {
357 verbatim.push(required(&mut resolve, name)?);
358 }
359 verbatim.sort();
360 verbatim.dedup();
361
362 let tokens = compile_tokens(&self.tokens, &mut resolve)?;
363
364 let mut nodes: Vec<(NodeStyle<K>, &str)> = Vec::with_capacity(self.nodes.len());
365 for rule in &self.nodes {
366 if let Some(node) = compile_node(rule, &mut resolve)? {
367 nodes.push((node, rule.kind.as_str()));
368 }
369 }
370 nodes.sort_by(|a, b| a.0.kind.cmp(&b.0.kind));
371 for pair in nodes.windows(2) {
372 if let [a, b] = pair {
373 if a.0.kind == b.0.kind {
374 return Err(RuleError::DuplicateNode { name: b.1.into() });
375 }
376 }
377 }
378
379 Ok(Style {
380 indent: u32::from(self.indent),
381 max_indent: u32::from(self.max_indent),
382 blank_lines: self.max_blank_lines,
383 final_newline: self.final_newline,
384 touch: crate::can_touch,
385 verbatim,
386 tokens,
387 nodes: nodes.into_iter().map(|(n, _)| n).collect(),
388 })
389 }
390}
391
392fn required<K>(resolve: &mut impl FnMut(&str) -> Option<K>, name: &str) -> Result<K, RuleError> {
393 resolve(name).ok_or_else(|| RuleError::UnknownKind { name: name.into() })
394}
395
396fn resolve_in<K>(
398 resolve: &mut impl FnMut(&str) -> Option<K>,
399 name: &str,
400 optional: bool,
401) -> Result<Option<K>, RuleError> {
402 match resolve(name) {
403 Some(k) => Ok(Some(k)),
404 None if optional => Ok(None),
405 None => Err(RuleError::UnknownKind { name: name.into() }),
406 }
407}
408
409fn compile_tokens<K: Ord>(
410 rules: &[TokenRule],
411 resolve: &mut impl FnMut(&str) -> Option<K>,
412) -> Result<TokenTable<K>, RuleError> {
413 let mut table = TokenTable::default();
414 let mut exact: Vec<(K, Sides)> = Vec::with_capacity(rules.len());
415 for rule in rules {
416 let sides = Sides {
417 before: rule.before.map(Sp::from),
418 after: rule.after.map(Sp::from),
419 };
420 match &rule.kind {
421 None => table.any = table.any.merge(sides),
422 Some(name) => {
423 if let Some(kind) = resolve_in(resolve, name, rule.optional)? {
424 exact.push((kind, sides));
425 }
426 }
427 }
428 }
429 exact.sort_by(|a, b| a.0.cmp(&b.0));
432 for (kind, sides) in exact {
433 match table.exact.last_mut() {
434 Some((last, merged)) if *last == kind => *merged = merged.merge(sides),
435 _ => table.exact.push((kind, sides)),
436 }
437 }
438 Ok(table)
439}
440
441fn compile_node<K: Ord + Clone>(
442 rule: &NodeRule,
443 resolve: &mut impl FnMut(&str) -> Option<K>,
444) -> Result<Option<NodeStyle<K>>, RuleError> {
445 let opt = rule.optional;
446 let Some(kind) = resolve_in(resolve, &rule.kind, opt)? else {
447 return Ok(None);
448 };
449 let delims = match &rule.delimiters {
450 None => None,
451 Some(d) => {
452 let (Some(open), Some(close)) = (
453 resolve_in(resolve, &d.open, opt)?,
454 resolve_in(resolve, &d.close, opt)?,
455 ) else {
456 return Ok(None);
457 };
458 Some(Delims {
459 open,
460 close,
461 inner: Sp::from(d.inner),
462 })
463 }
464 };
465 let sep = match &rule.separator {
466 None => None,
467 Some(s) => {
468 let Some(sep_kind) = resolve_in(resolve, &s.kind, opt)? else {
469 return Ok(None);
470 };
471 if let Some(d) = &delims {
472 if d.open == sep_kind || d.close == sep_kind {
473 return Err(RuleError::SeparatorIsDelimiter {
474 node: rule.kind.clone(),
475 });
476 }
477 }
478 if s.trailing != Trailing::Preserve && delims.is_none() {
479 return Err(RuleError::TrailingNeedsDelimiters {
480 node: rule.kind.clone(),
481 });
482 }
483 Some(Sep {
484 kind: sep_kind,
485 text: s.text.clone().unwrap_or_else(|| s.kind.clone()),
486 before: Sp::from(s.before),
487 after: Sp::from(s.after),
488 trailing: s.trailing,
489 })
490 }
491 };
492 let tokens = if opt {
493 let relaxed: Vec<TokenRule> = rule.tokens.iter().cloned().map(|t| t.optional()).collect();
495 compile_tokens(&relaxed, resolve)?
496 } else {
497 compile_tokens(&rule.tokens, resolve)?
498 };
499 Ok(Some(NodeStyle {
500 kind,
501 group: rule.group,
502 indent: rule.indent,
503 before: rule.before.map(Sp::from),
504 after: rule.after.map(Sp::from),
505 delims,
506 empty: Sp::from(rule.empty),
507 sep,
508 blank_lines: rule.blank_lines,
509 tokens,
510 }))
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516 use crate::rules::NodeRule;
517
518 fn names(name: &str) -> Option<&'static str> {
519 [
520 "a", "b", ",", "(", ")", "[", "]", "+", "list", "stmt", "ERROR",
521 ]
522 .into_iter()
523 .find(|k| *k == name)
524 }
525
526 #[test]
527 fn test_join_is_the_lattice_max() {
528 let soft = Sp::from(Space::SoftLine);
529 let single = Sp::from(Space::Single);
530 assert_eq!(soft.join(single), Sp::from(Space::Line));
531 assert_eq!(Sp::from(Space::Line).join(Sp::HARD).brk, 2);
532 assert_eq!(Sp::NONE.join(Sp::NONE), Sp::NONE);
533 assert_eq!(join_opt(None, None), None);
534 assert_eq!(join_opt(Some(Sp::NONE), None), Some(Sp::NONE));
535 }
536
537 #[test]
538 fn test_later_token_rules_refine_earlier() {
539 let style = Rules::new()
540 .token(TokenRule::new("+").before(Space::None).after(Space::None))
541 .token(TokenRule::new("+").after(Space::Single))
542 .compile(names)
543 .unwrap_or_default();
544 assert_eq!(style.token_before(None, &"+"), Some(Sp::NONE));
545 assert_eq!(style.token_after(None, &"+"), Some(Sp::SINGLE));
546 assert_eq!(style.token_after(None, &"a"), None);
547 }
548
549 #[test]
550 fn test_context_rules_win_over_top_level() {
551 let style = Rules::new()
552 .token(TokenRule::new("+").around(Space::Single))
553 .node(NodeRule::new("list").token(TokenRule::any().after(Space::None)))
554 .compile(names)
555 .unwrap_or_default();
556 let list = style.node(style.node_index(&"list"));
557 assert!(list.is_some());
558 assert_eq!(style.token_after(list, &"+"), Some(Sp::NONE));
559 assert_eq!(style.token_before(list, &"+"), Some(Sp::SINGLE));
561 }
562
563 #[test]
564 fn test_unknown_kinds_are_errors_unless_optional() {
565 let err = Rules::new()
566 .token(TokenRule::new("nope").before(Space::None))
567 .compile(names)
568 .map(|_| ());
569 assert_eq!(
570 err,
571 Err(RuleError::UnknownKind {
572 name: "nope".into()
573 })
574 );
575 assert!(
576 Rules::new()
577 .token(TokenRule::new("nope").optional())
578 .node(NodeRule::new("missing").optional())
579 .node(
580 NodeRule::new("list")
581 .delimiters("{", "}", Space::Line)
582 .optional()
583 )
584 .compile(names)
585 .is_ok()
586 );
587 assert!(Rules::conventional().compile(names).is_ok());
588 }
589
590 #[test]
591 fn test_rule_consistency_errors() {
592 let dup = Rules::new()
593 .node(NodeRule::new("list"))
594 .node(NodeRule::new("list"))
595 .compile(names)
596 .map(|_| ());
597 assert_eq!(
598 dup,
599 Err(RuleError::DuplicateNode {
600 name: "list".into()
601 })
602 );
603 let wide = Rules::new().indent(17).compile(names).map(|_| ());
604 assert_eq!(wide, Err(RuleError::IndentTooWide { columns: 17 }));
605 let same = Rules::new()
606 .node(
607 NodeRule::new("list")
608 .delimiters("(", ")", Space::None)
609 .separator(")", Space::Single, Trailing::Preserve),
610 )
611 .compile(names)
612 .map(|_| ());
613 assert_eq!(
614 same,
615 Err(RuleError::SeparatorIsDelimiter {
616 node: "list".into()
617 })
618 );
619 let trailing = Rules::new()
620 .node(NodeRule::new("list").separator(",", Space::Single, Trailing::Always))
621 .compile(names)
622 .map(|_| ());
623 assert_eq!(
624 trailing,
625 Err(RuleError::TrailingNeedsDelimiters {
626 node: "list".into()
627 })
628 );
629 }
630
631 #[test]
632 fn test_verbatim_and_node_lookup() {
633 let style = Rules::new()
634 .verbatim("ERROR")
635 .verbatim("ERROR")
636 .node(NodeRule::new("stmt").group())
637 .node(NodeRule::new("list"))
638 .compile(names)
639 .unwrap_or_default();
640 assert!(style.is_verbatim(&"ERROR"));
641 assert!(!style.is_verbatim(&"stmt"));
642 let stmt = style.node(style.node_index(&"stmt"));
643 assert!(stmt.is_some_and(NodeStyle::owns_doc));
644 let list = style.node(style.node_index(&"list"));
645 assert!(list.is_some_and(|n| !n.owns_doc()));
646 assert!(style.node_index(&"a").is_none());
647 }
648
649 #[test]
650 fn test_separator_text_defaults_to_kind_name() {
651 let style = Rules::new()
652 .node(
653 NodeRule::new("list")
654 .delimiters("[", "]", Space::None)
655 .separator(",", Space::Single, Trailing::Always),
656 )
657 .compile(names)
658 .unwrap_or_default();
659 let sep = style
660 .node(style.node_index(&"list"))
661 .and_then(|n| n.sep.as_ref())
662 .map(|s| s.text.as_str());
663 assert_eq!(sep, Some(","));
664 }
665}