use alloc::string::String;
use alloc::vec::Vec;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Space {
None,
Single,
SoftLine,
Line,
Hard,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum Indent {
#[default]
None,
Block,
Hanging,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum Trailing {
#[default]
Preserve,
Always,
Never,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TokenRule {
pub(crate) kind: Option<String>,
pub(crate) before: Option<Space>,
pub(crate) after: Option<Space>,
pub(crate) optional: bool,
}
impl TokenRule {
#[must_use]
pub fn new(kind: impl Into<String>) -> Self {
Self {
kind: Some(kind.into()),
before: None,
after: None,
optional: false,
}
}
#[must_use]
pub fn any() -> Self {
Self {
kind: None,
before: None,
after: None,
optional: false,
}
}
#[must_use]
pub fn before(mut self, space: Space) -> Self {
self.before = Some(space);
self
}
#[must_use]
pub fn after(mut self, space: Space) -> Self {
self.after = Some(space);
self
}
#[must_use]
pub fn around(self, space: Space) -> Self {
self.before(space).after(space)
}
#[must_use]
pub fn optional(mut self) -> Self {
self.optional = true;
self
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct DelimitersRule {
pub(crate) open: String,
pub(crate) close: String,
pub(crate) inner: Space,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct SeparatorRule {
pub(crate) kind: String,
pub(crate) text: Option<String>,
pub(crate) before: Space,
pub(crate) after: Space,
pub(crate) trailing: Trailing,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NodeRule {
pub(crate) kind: String,
pub(crate) group: bool,
pub(crate) indent: Indent,
pub(crate) before: Option<Space>,
pub(crate) after: Option<Space>,
pub(crate) delimiters: Option<DelimitersRule>,
pub(crate) empty: Space,
pub(crate) separator: Option<SeparatorRule>,
pub(crate) blank_lines: Option<u8>,
pub(crate) tokens: Vec<TokenRule>,
pub(crate) optional: bool,
}
impl NodeRule {
#[must_use]
pub fn new(kind: impl Into<String>) -> Self {
Self {
kind: kind.into(),
group: false,
indent: Indent::None,
before: None,
after: None,
delimiters: None,
empty: Space::None,
separator: None,
blank_lines: None,
tokens: Vec::new(),
optional: false,
}
}
#[must_use]
pub fn group(mut self) -> Self {
self.group = true;
self
}
#[must_use]
pub fn indent(mut self, indent: Indent) -> Self {
self.indent = indent;
self
}
#[must_use]
pub fn before(mut self, space: Space) -> Self {
self.before = Some(space);
self
}
#[must_use]
pub fn after(mut self, space: Space) -> Self {
self.after = Some(space);
self
}
#[must_use]
pub fn delimiters(
mut self,
open: impl Into<String>,
close: impl Into<String>,
inner: Space,
) -> Self {
self.delimiters = Some(DelimitersRule {
open: open.into(),
close: close.into(),
inner,
});
self
}
#[must_use]
pub fn empty(mut self, space: Space) -> Self {
self.empty = space;
self
}
#[must_use]
pub fn separator(mut self, kind: impl Into<String>, after: Space, trailing: Trailing) -> Self {
self.separator = Some(SeparatorRule {
kind: kind.into(),
text: None,
before: Space::None,
after,
trailing,
});
self
}
#[must_use]
pub fn separator_text(mut self, text: impl Into<String>) -> Self {
if let Some(sep) = &mut self.separator {
sep.text = Some(text.into());
}
self
}
#[must_use]
pub fn blank_lines(mut self, max: u8) -> Self {
self.blank_lines = Some(max);
self
}
#[must_use]
pub fn token(mut self, rule: TokenRule) -> Self {
self.tokens.push(rule);
self
}
#[must_use]
pub fn optional(mut self) -> Self {
self.optional = true;
self
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Rules {
pub(crate) indent: u8,
pub(crate) max_indent: u16,
pub(crate) max_blank_lines: u8,
pub(crate) final_newline: bool,
pub(crate) verbatim: Vec<String>,
pub(crate) tokens: Vec<TokenRule>,
pub(crate) nodes: Vec<NodeRule>,
}
pub const MAX_INDENT_STEP: u8 = 16;
impl Default for Rules {
fn default() -> Self {
Self::new()
}
}
impl Rules {
#[must_use]
pub fn new() -> Self {
Self {
indent: 4,
max_indent: 120,
max_blank_lines: 1,
final_newline: true,
verbatim: Vec::new(),
tokens: Vec::new(),
nodes: Vec::new(),
}
}
#[must_use]
pub fn conventional() -> Self {
let mut rules = Self::new();
for kind in [",", ";"] {
rules = rules.token(
TokenRule::new(kind)
.before(Space::None)
.after(Space::Single)
.optional(),
);
}
for kind in [")", "]"] {
rules = rules.token(TokenRule::new(kind).before(Space::None).optional());
}
for kind in ["(", "["] {
rules = rules.token(TokenRule::new(kind).after(Space::None).optional());
}
for kind in [
"=", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&&", "||", "=>", "->",
] {
rules = rules.token(TokenRule::new(kind).around(Space::Single).optional());
}
rules
}
#[must_use]
pub fn indent(mut self, columns: u8) -> Self {
self.indent = columns;
self
}
#[must_use]
pub fn max_indent(mut self, columns: u16) -> Self {
self.max_indent = columns;
self
}
#[must_use]
pub fn max_blank_lines(mut self, max: u8) -> Self {
self.max_blank_lines = max;
self
}
#[must_use]
pub fn final_newline(mut self, yes: bool) -> Self {
self.final_newline = yes;
self
}
#[must_use]
pub fn verbatim(mut self, kind: impl Into<String>) -> Self {
self.verbatim.push(kind.into());
self
}
#[must_use]
pub fn token(mut self, rule: TokenRule) -> Self {
self.tokens.push(rule);
self
}
#[must_use]
pub fn node(mut self, rule: NodeRule) -> Self {
self.nodes.push(rule);
self
}
}