use std::{
collections::BTreeMap,
fmt::{Debug, Display},
};
use tecta_lex::{
Delimiter as GroupDelimiter, Span, Spanned, SpanningChars, pat_ident_body, pat_ident_start,
pat_punct,
};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum AnyDelimiter {
Parenthesis,
Bracket,
Brace,
AngleBrackets,
}
impl AnyDelimiter {
pub fn to_group(&self) -> Option<GroupDelimiter> {
match self {
Self::Parenthesis => Some(GroupDelimiter::Parenthesis),
Self::Bracket => Some(GroupDelimiter::Bracket),
Self::Brace => Some(GroupDelimiter::Brace),
Self::AngleBrackets => None,
}
}
pub fn opener(&self) -> char {
match self {
Self::Parenthesis => '(',
Self::Bracket => '[',
Self::Brace => '{',
Self::AngleBrackets => '<',
}
}
pub fn closer(&self) -> char {
match self {
Self::Parenthesis => ')',
Self::Bracket => ']',
Self::Brace => '}',
Self::AngleBrackets => '>',
}
}
}
impl From<GroupDelimiter> for AnyDelimiter {
fn from(value: GroupDelimiter) -> Self {
match value {
GroupDelimiter::Parenthesis => Self::Parenthesis,
GroupDelimiter::Bracket => Self::Bracket,
GroupDelimiter::Brace => Self::Brace,
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Control(pub ControlKind, pub Span);
impl Display for Control {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum ControlKind {
SequenceStart,
GroupStart(GroupDelimiter),
}
impl Display for ControlKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ControlKind::SequenceStart => write!(f, "<"),
ControlKind::GroupStart(delimiter) => write!(f, "{}", delimiter.opener()),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum AtLeast {
Zero,
One,
}
impl Display for AtLeast {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::One => write!(f, "+"),
Self::Zero => write!(f, "*"),
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct RepeatRule {
pub element: Box<Rule>,
pub separator: Box<Rule>,
pub at_least: AtLeast,
pub allow_trailing: bool,
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Rule(pub RuleKind, pub Span);
impl Rule {
pub fn sequence(rules: Vec<Rule>, weak: bool, span: Span) -> Self {
Self(RuleKind::Sequence { rules, weak }, span)
}
pub fn record(rules: Vec<(Spanned<Option<String>>, Rule)>, span: Span) -> Self {
Self(RuleKind::Record(rules), span)
}
pub fn choice(rules: Vec<Rule>, span: Span) -> Self {
Self(RuleKind::Choice(rules), span)
}
pub fn named_choice(rules: Vec<(Spanned<String>, Rule)>, span: Span) -> Self {
Self(RuleKind::NamedChoice(rules), span)
}
pub fn group(delimiter: GroupDelimiter, rule: Rule, span: Span) -> Self {
Self(RuleKind::Group(delimiter, Box::new(rule)), span)
}
pub fn repeat(element: Rule, separator: Rule, at_least: AtLeast, span: Span) -> Self {
Self(
RuleKind::Repeat(RepeatRule {
element: Box::new(element),
separator: Box::new(separator),
at_least,
allow_trailing: false,
}),
span,
)
}
pub fn optional(rule: Rule, span: Span) -> Self {
Self(RuleKind::Optional(Box::new(rule)), span)
}
pub fn boxed(rule: Rule, span: Span) -> Self {
Self(RuleKind::Boxed(Box::new(rule)), span)
}
pub fn punctuation(repr: String, span: Span) -> Self {
Self(RuleKind::Punctuation(repr), span)
}
pub fn keyword(repr: String, span: Span) -> Self {
Self(RuleKind::Keyword(repr), span)
}
pub fn other(repr: String, span: Span) -> Self {
Self(RuleKind::Other(repr), span)
}
pub fn builtin(repr: String, span: Span) -> Self {
Self(RuleKind::Builtin(repr), span)
}
pub fn peg(self) -> Peg {
Peg::Rule(self)
}
}
impl Debug for Rule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} @{}", self.0, self.1)
}
}
impl Display for Rule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum RuleKind {
Sequence { rules: Vec<Rule>, weak: bool },
Record(Vec<(Spanned<Option<String>>, Rule)>),
Choice(Vec<Rule>),
NamedChoice(Vec<(Spanned<String>, Rule)>),
Group(GroupDelimiter, Box<Rule>),
Repeat(RepeatRule),
Optional(Box<Rule>),
Boxed(Box<Rule>),
Punctuation(String),
Keyword(String),
Other(String),
Builtin(String),
}
impl RuleKind {
pub fn with(self, span: impl Into<Span>) -> Rule {
Rule(self, span.into())
}
}
impl Display for RuleKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RuleKind::Sequence { rules, weak } => match &rules[..] {
[] => {
if *weak {
Ok(())
} else {
write!(f, "<>")
}
}
[most @ .., last] => {
if !*weak {
write!(f, "<")?;
}
for rule in most {
write!(f, "{rule} ")?;
}
write!(f, "{last}")?;
if *weak {
Ok(())
} else {
write!(f, ">")
}
}
},
RuleKind::Record(fields) => {
write!(f, "&{{ ")?;
for (Spanned(_, name), rule) in fields {
let name = match name {
Some(name) => name,
None => "!",
};
write!(f, "{name}: {rule}; ")?;
}
write!(f, "}}")
}
RuleKind::Choice(rules) => match &rules[..] {
[] => write!(f, "!"),
[most @ .., last] => {
write!(f, "<")?;
for rule in most {
write!(f, "{rule} | ")?;
}
write!(f, "{last}>")
}
},
RuleKind::NamedChoice(rules) => {
write!(f, "&[ ")?;
for (Spanned(_, name), rule) in rules {
write!(f, "{name}: {rule}; ")?;
}
write!(f, "]")
}
RuleKind::Group(delimiter, inner) => {
write!(f, "{}{}{}", delimiter.opener(), inner, delimiter.closer())
}
RuleKind::Repeat(RepeatRule {
element,
separator,
at_least,
allow_trailing,
}) => write!(
f,
"{} {} {}{}",
element,
separator,
at_least,
if *allow_trailing { "~" } else { "" }
),
RuleKind::Optional(rule) => write!(f, "{rule}?"),
RuleKind::Boxed(rule) => write!(f, "{rule}^"),
RuleKind::Punctuation(punct) => write!(f, "'{punct}'"),
RuleKind::Keyword(kw) => write!(f, "\"{kw}\""),
RuleKind::Other(name) => write!(f, "{name}"),
RuleKind::Builtin(builtin) => write!(f, "@{builtin}"),
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Peg {
Control(Control),
Rule(Rule),
}
impl Peg {
pub fn sequence_start(span: Span) -> Self {
Self::Control(Control(ControlKind::SequenceStart, span))
}
pub fn group_start(delimiter: GroupDelimiter, span: Span) -> Self {
Self::Control(Control(ControlKind::GroupStart(delimiter), span))
}
pub fn try_as_rule(self) -> Result<Rule> {
match self {
Peg::Rule(rule) => Ok(rule),
Peg::Control(control) => Err(ErrorKind::StrayControl(control.0).with(control.1)),
}
}
pub fn try_as_mut_rule(&mut self) -> Result<&mut Rule> {
match self {
Peg::Rule(rule) => Ok(rule),
Peg::Control(control) => Err(ErrorKind::StrayControl(control.0).with(control.1)),
}
}
pub fn span(&self) -> Span {
let (Peg::Control(Control(_, span)) | Peg::Rule(Rule(_, span))) = self;
*span
}
}
impl Display for Peg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Peg::Control(control) => write!(f, "{control}"),
Peg::Rule(rule) => write!(f, "{rule}"),
}
}
}
pub struct PegStack(pub Vec<Peg>);
impl PegStack {
pub fn raw_pop_rule(&mut self, operator_span: Span) -> Result<Rule> {
match self.0.pop() {
Some(Peg::Rule(rule)) => Ok(rule),
Some(Peg::Control(control)) => Err(ErrorKind::StrayControl(control.0).with(control.1)),
None => Err(ErrorKind::StackEmpty("expected rule".into()).with(operator_span)),
}
}
pub fn take_rule(&mut self, operator_span: Span) -> Result<Rule> {
match self.0.pop() {
Some(Peg::Rule(Rule(RuleKind::Choice(mut choices), span))) if !choices.is_empty() => {
let rule = match choices
.pop()
.expect("internal parser error: choices was in fact empty")
{
Rule(
RuleKind::Sequence {
mut rules,
weak: true,
},
span,
) => {
let rule = rules.pop().ok_or(
ErrorKind::StackEmpty(
"no more rules to take from choice variant".to_owned(),
)
.with(operator_span),
)?;
choices.push(Rule(RuleKind::Sequence { rules, weak: true }, span));
rule
}
other => {
choices.push(Rule(
RuleKind::Sequence {
rules: vec![],
weak: true,
},
span,
));
other
}
};
self.0
.push(Peg::Rule(Rule(RuleKind::Choice(choices), span)));
Ok(rule)
}
Some(Peg::Rule(other_rule)) => Ok(other_rule),
Some(Peg::Control(control)) => Err(ErrorKind::StrayControl(control.0).with(control.1)),
None => Err(ErrorKind::StackEmpty("expected rule".into()).with(operator_span)),
}
}
pub fn add_rule(&mut self, rule: Rule) {
match self.0.pop() {
Some(Peg::Rule(Rule(RuleKind::Choice(mut variants), span))) => {
if let Some(old_last_variant) = variants.pop() {
let total_span = old_last_variant.1 + span;
if let RuleKind::Sequence {
mut rules,
weak: true,
} = old_last_variant.0
{
rules.push(rule);
variants.push(Rule(RuleKind::Sequence { rules, weak: true }, total_span));
} else {
variants.push(Rule::sequence(
vec![old_last_variant, rule],
true,
total_span,
));
}
} else {
variants.push(rule);
}
self.0.push(Rule::choice(variants, span).peg());
}
Some(other) => {
self.0.push(other);
self.0.push(rule.peg());
}
None => {
self.0.push(rule.peg());
}
}
}
pub fn add_rule_kind(&mut self, kind: RuleKind, span: Span) {
self.add_rule(Rule(kind, span));
}
}
impl Display for PegStack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let [most @ .., last] = &self.0[..] else {
return Ok(());
};
for peg in most {
write!(f, "{peg} ")?;
}
write!(f, "{last}")
}
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ParseInput<I: Iterator<Item = Spanned<char>>> {
chars: I,
end_span: Span,
}
impl<I: Iterator<Item = Spanned<char>>> ParseInput<I> {
pub fn new(chars: I, end_span: Span) -> Self {
Self { chars, end_span }
}
pub fn current_span(&self) -> Span
where
I: Clone,
{
match self.chars.clone().next() {
Some(Spanned(span, _)) => span,
None => self.end_span,
}
}
fn eof(&self) -> Error {
Error::eof(self.end_span)
}
}
impl<I: Iterator<Item = Spanned<char>>> Iterator for ParseInput<I> {
type Item = Spanned<char>;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next()
}
}
macro_rules! parse_input {
() => {
ParseInput<impl Iterator<Item = Spanned<char>> + Clone>
};
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum ErrorKind {
ExpectedFound(String, String),
StackEmpty(String),
StrayControl(ControlKind),
EOF,
InvalidCloser {
expected: AnyDelimiter,
got: AnyDelimiter,
},
ExistingPreamble(String),
}
impl ErrorKind {
fn with(self, span: impl Into<Span>) -> Error {
Error(self, span.into())
}
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ErrorKind::ExpectedFound(expected, found) => {
write!(f, "expected {expected}, found {found}")
}
ErrorKind::StackEmpty(expected) => write!(f, "stack empty; {expected}"),
ErrorKind::StrayControl(control) => {
write!(f, "expected a rule, got a control ({control:?})")
}
ErrorKind::EOF => write!(f, "unexpected end of file"),
ErrorKind::InvalidCloser { expected, got } => write!(
f,
"expected {} to match {}, got {}",
expected.closer(),
expected.opener(),
got.closer()
),
ErrorKind::ExistingPreamble(preamble) => {
write!(f, "preamble #{preamble} already exists")
}
}
}
}
impl core::error::Error for ErrorKind {}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Error(ErrorKind, Span);
impl Error {
pub fn span(&self) -> Span {
self.1
}
fn eof(end_span: Span) -> Self {
ErrorKind::EOF.with(end_span)
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (at {})", self.0, self.1)
}
}
impl core::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;
pub fn skip_ws(input: &mut parse_input!()) {
while let Some(Spanned(_, ch)) = input.clone().next() {
if !ch.is_whitespace() {
return;
}
input.next();
}
}
pub fn expect_identifier(input: &mut parse_input!()) -> Result<Option<Spanned<String>>> {
let (mut span, ch) = match input.next() {
Some(Spanned(span, ch @ pat_ident_start!())) => (span, ch),
Some(Spanned(span, other)) => {
return Err(ErrorKind::ExpectedFound(
"identifier".to_owned(),
format!("character `{other}`"),
)
.with(span));
}
None => return Ok(None),
};
let mut output = String::from(ch);
consume_identifier_rest(input, &mut span, &mut output);
Ok(Some(Spanned(span, output)))
}
pub fn identifier_or_eof(input: &mut parse_input!()) -> Result<Spanned<String>> {
expect_identifier(input)?.ok_or(input.eof())
}
pub fn consume_identifier_rest(
input: &mut parse_input!(),
into_span: &mut Span,
into: &mut String,
) {
while let Some(Spanned(span, ch @ pat_ident_body!())) = input.clone().next() {
input.next();
*into_span += span;
into.push(ch);
}
}
pub fn expect_exactly(input: &mut parse_input!(), string: &str) -> Result<Span> {
let mut collected = String::new();
let mut acc_span = input.current_span();
for ch in string.chars() {
let next = input.next();
if let Some(Spanned(span, test_ch)) = next {
acc_span += span;
collected.push(test_ch);
if test_ch != ch {
return Err(ErrorKind::ExpectedFound(
format!("`{string}`"),
format!("`{collected}`"),
)
.with(span));
}
} else {
return Err(input.eof());
}
}
Ok(acc_span)
}
pub fn parse_fields(
input: &mut parse_input!(),
terminator: char,
) -> Result<Spanned<Vec<(Spanned<Option<String>>, Rule)>>> {
let mut record_fields = vec![];
let mut total_span = input.current_span();
loop {
skip_ws(input);
if let Some(Spanned(span, ch)) = input.clone().next()
&& ch == terminator
{
total_span += span;
input.next();
break;
}
let identifier = if let Some(Spanned(span, '!')) = input.clone().next() {
input.next();
Spanned(span, None)
} else {
let identifier = expect_identifier(input)?.ok_or(input.eof())?;
Spanned(identifier.0, Some(identifier.1))
};
total_span += identifier.0;
skip_ws(input);
total_span += expect_exactly(input, ":")?;
skip_ws(input);
let start = input.current_span();
let mut rule_stack = PegStack(vec![]);
while let RuleStatus::Continue = next_rule(input, &mut rule_stack)? {
skip_ws(input);
}
let mut rules = rule_stack
.0
.into_iter()
.map(|rule| rule.try_as_rule())
.collect::<Result<Vec<_>>>()?;
let rule_span = rules.iter().map(|rule| rule.1).fold(start, |a, b| a + b);
total_span += rule_span;
record_fields.push((
identifier,
if rules.len() == 1 {
rules.pop().unwrap()
} else {
Rule::sequence(rules, true, rule_span)
},
));
}
Ok(Spanned(total_span, record_fields))
}
pub enum RuleStatus {
Continue,
End,
}
pub fn next_rule(input: &mut parse_input!(), stack: &mut PegStack) -> Result<RuleStatus> {
let Spanned(mut peg_span, ch) = input.next().ok_or(input.eof())?;
match ch {
'"' => {
let mut keyword = String::new();
loop {
let Spanned(span, ch) = input.next().ok_or(input.eof())?;
peg_span += span;
if ch == '"' {
break;
}
keyword.push(ch);
}
stack.add_rule(Rule::keyword(keyword, peg_span));
}
'\'' => {
let mut punct = String::new();
loop {
let Spanned(span, ch) = input.next().ok_or(input.eof())?;
if ch == '\'' {
peg_span += span;
break;
}
if !matches!(ch, pat_punct!()) {
return Err(ErrorKind::ExpectedFound(
"punctuation".to_owned(),
format!("character `{ch}`"),
)
.with(span));
}
peg_span += span;
punct.push(ch);
}
stack.add_rule(Rule::punctuation(punct, peg_span));
}
'*' => {
let separator = stack.raw_pop_rule(peg_span)?;
let element = stack.take_rule(peg_span)?;
let other_span = element.1 + separator.1;
stack.add_rule(Rule::repeat(
element,
separator,
AtLeast::Zero,
peg_span + other_span,
));
}
'+' => {
let separator = stack.raw_pop_rule(peg_span)?;
let element = stack.take_rule(peg_span)?;
let other_span = element.1 + separator.1;
stack.add_rule(Rule::repeat(
element,
separator,
AtLeast::One,
peg_span + other_span,
));
}
'~' => {
let Rule(kind, span) = stack.take_rule(peg_span)?;
let RuleKind::Repeat(mut repeat) = kind else {
return Err(ErrorKind::ExpectedFound(
"repetition rule".to_owned(),
"other rule".to_owned(),
)
.with(peg_span));
};
repeat.allow_trailing = true;
stack.add_rule_kind(RuleKind::Repeat(repeat), peg_span + span);
}
'?' => {
let element = stack.take_rule(peg_span)?;
let element_span = element.1;
stack.add_rule(Rule::optional(element, peg_span + element_span));
}
'^' => {
let element = stack.take_rule(peg_span)?;
let element_span = element.1;
stack.add_rule(Rule::boxed(element, peg_span + element_span));
}
'.' => stack.add_rule(Rule::sequence(vec![], false, peg_span)),
'<' => stack.0.push(Peg::sequence_start(peg_span)),
'(' => stack
.0
.push(Peg::group_start(GroupDelimiter::Parenthesis, peg_span)),
'[' => stack
.0
.push(Peg::group_start(GroupDelimiter::Bracket, peg_span)),
'{' => stack
.0
.push(Peg::group_start(GroupDelimiter::Brace, peg_span)),
'>' => {
let mut sequence = vec![];
let mut total_span = peg_span;
loop {
let peg = stack.0.pop().ok_or(
ErrorKind::StackEmpty("missing start control".to_owned()).with(peg_span),
)?;
total_span += peg.span();
match peg {
Peg::Rule(rule) => {
total_span += rule.1;
sequence.push(rule);
}
Peg::Control(Control(ControlKind::GroupStart(delimiter), span)) => {
return Err(ErrorKind::ExpectedFound(
"sequence start control (`<`)".into(),
format!("group start control ({})", delimiter.opener()),
)
.with(span));
}
Peg::Control(Control(ControlKind::SequenceStart, span)) => {
sequence.reverse();
stack.add_rule(Rule::sequence(sequence, false, total_span + span));
break;
}
}
}
}
ch @ (')' | ']' | '}') => {
let closer = match ch {
')' => GroupDelimiter::Parenthesis,
']' => GroupDelimiter::Bracket,
'}' => GroupDelimiter::Brace,
_ => unreachable!(),
};
let mut sequence = vec![];
let mut inner_span = Span::default();
loop {
let peg = stack.0.pop().ok_or(
ErrorKind::StackEmpty("missing start control".to_owned()).with(peg_span),
)?;
peg_span += peg.span();
match peg {
Peg::Rule(rule) => {
inner_span += rule.1;
sequence.push(rule);
}
Peg::Control(Control(ControlKind::GroupStart(opener), span)) => {
peg_span += span + inner_span;
if opener == closer {
sequence.reverse();
stack.add_rule(Rule::group(
opener,
if sequence.len() == 1 {
sequence.pop().unwrap()
} else {
Rule::sequence(sequence, true, inner_span)
},
peg_span,
));
break;
} else {
return Err(ErrorKind::InvalidCloser {
expected: opener.into(),
got: closer.into(),
}
.with(span));
}
}
Peg::Control(Control(ControlKind::SequenceStart, span)) => {
return Err(ErrorKind::InvalidCloser {
expected: AnyDelimiter::AngleBrackets,
got: closer.into(),
}
.with(span));
}
}
}
}
'|' => {
let after = parse_single_grammar(input)?;
let first = stack.raw_pop_rule(peg_span)?;
let rule = match first {
Rule(RuleKind::Choice(mut choices), span) => {
choices.push(after);
Rule::choice(choices, peg_span + span)
}
other => {
let mut first_variant_span = other.1;
let mut first_variant_sequence = vec![other];
while let Some(peg) = stack.0.pop() {
match peg {
Peg::Control(control) => {
stack.0.push(Peg::Control(control));
peg_span += control.1;
break;
}
Peg::Rule(rule) => {
first_variant_span += rule.1;
first_variant_sequence.push(rule);
}
}
}
first_variant_sequence.reverse();
let first_variant_rule = if first_variant_sequence.len() == 1 {
first_variant_sequence.pop().unwrap()
} else {
Rule::sequence(first_variant_sequence, true, first_variant_span)
};
let after_span = after.1;
Rule::choice(
vec![first_variant_rule, after],
first_variant_span + peg_span + after_span,
)
}
};
stack.add_rule(rule);
}
'@' => {
let Spanned(span, builtin) = expect_identifier(input)?.ok_or(input.eof())?;
stack.add_rule(Rule::builtin(builtin, span));
}
'&' => match input.next().ok_or(input.eof())? {
Spanned(span, '{') => {
peg_span += span;
let Spanned(span, fields) = parse_fields(input, '}')?;
peg_span += span;
stack.add_rule(Rule::record(fields, peg_span));
}
Spanned(span, '[') => {
peg_span += span;
let Spanned(span, fields) = parse_fields(input, ']')?;
let fields = fields
.into_iter()
.map(|(name, rule)| {
Ok((
Spanned(
name.0,
name.1.ok_or_else(|| {
ErrorKind::ExpectedFound(
"name".to_owned(),
"`!` (named choices cannot have anonymous fields)"
.to_owned(),
)
.with(name.0)
})?,
),
rule,
))
})
.collect::<Result<Vec<_>>>()?;
peg_span += span;
stack.add_rule(Rule::named_choice(fields, peg_span));
}
other => {
return Err(ErrorKind::ExpectedFound(
"one of `{` or `[`".to_owned(),
format!("`{}`", other.1),
)
.with(other.0));
}
},
';' => return Ok(RuleStatus::End),
ch @ pat_ident_start!() => {
let mut rule_name = String::from(ch);
consume_identifier_rest(input, &mut peg_span, &mut rule_name);
stack.add_rule(Rule::other(rule_name, peg_span));
}
other => {
return Err(ErrorKind::ExpectedFound(
"rule".to_owned(),
format!("character `{other}`"),
)
.with(peg_span));
}
}
Ok(RuleStatus::Continue)
}
pub fn parse_single_grammar(input: &mut parse_input!()) -> Result<Rule> {
let mut stack = PegStack(vec![]);
while stack.0.is_empty()
|| stack
.0
.iter()
.any(|peg: &Peg| matches!(&peg, Peg::Control(_)))
{
skip_ws(input);
if let RuleStatus::End = next_rule(input, &mut stack)? {
return Err(input.eof());
}
}
Ok(stack.0.pop().unwrap().try_as_rule()?)
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Keywords {
pub soft: Vec<Spanned<String>>,
pub hard: Vec<Spanned<String>>,
}
impl Display for Keywords {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let [most @ .., last] = &self.soft[..] {
write!(f, "#keywords soft: ")?;
for Spanned(_, word) in most {
write!(f, "{word} ")?;
}
writeln!(f, "{};", last.1)?;
}
if let [most @ .., last] = &self.hard[..] {
write!(f, "#keywords hard: ")?;
for Spanned(_, word) in most {
write!(f, "{word} ")?;
}
writeln!(f, "{};", last.1)?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Preambles {
pub keywords: Keywords,
}
impl Display for Preambles {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.keywords)
}
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct TectaPegModule {
pub preambles: Preambles,
pub rules: BTreeMap<String, Vec<Rule>>,
}
impl Display for TectaPegModule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.preambles)?;
for (rule_name, rules) in &self.rules {
write!(f, "{rule_name} =")?;
for rule in rules {
write!(f, " {rule}")?;
}
writeln!(f, ";")?;
}
Ok(())
}
}
pub fn parse_basic_identifier_list(input: &mut parse_input!()) -> Result<Vec<Spanned<String>>> {
let mut identifiers = vec![];
loop {
skip_ws(input);
if let Some(Spanned(_, ';')) = input.clone().next() {
return Ok(identifiers);
}
identifiers.push(identifier_or_eof(input)?);
}
}
pub fn parse_module_inner(input: &mut parse_input!()) -> Result<TectaPegModule> {
let mut module = TectaPegModule::default();
loop {
skip_ws(input);
if let Some(Spanned(_, '#')) = input.clone().next() {
input.next();
let Spanned(span, name) = identifier_or_eof(input)?;
match &name[..] {
"keywords" => {
skip_ws(input);
let Spanned(span, name) = identifier_or_eof(input)?;
let is_hard = match &name[..] {
"hard" => true,
"soft" => false,
other => {
return Err(ErrorKind::ExpectedFound(
"keyword hardness".into(),
format!("`{other}`"),
)
.with(span));
}
};
let colon_span = expect_exactly(input, ":")?;
let specified_keywords = parse_basic_identifier_list(input)?;
if specified_keywords.is_empty() {
return Err(ErrorKind::ExpectedFound(
"non-empty keyword list".into(),
"empty list".into(),
)
.with(colon_span));
}
let target_keyword_set = if is_hard {
&mut module.preambles.keywords.hard
} else {
&mut module.preambles.keywords.soft
};
if !target_keyword_set.is_empty() {
return Err(ErrorKind::ExistingPreamble(format!(
"keywords {}",
if is_hard { "hard" } else { "soft" }
))
.with(colon_span));
}
*target_keyword_set = specified_keywords;
}
other => {
return Err(
ErrorKind::ExpectedFound("preamble".into(), format!("`{other}`"))
.with(span),
);
}
}
expect_exactly(input, ";")?;
} else if let Some(Spanned(_, rule_name)) = expect_identifier(input)? {
skip_ws(input);
let _eq_span = expect_exactly(input, "=")?;
skip_ws(input);
let mut peg_stack = PegStack(vec![]);
while let RuleStatus::Continue = next_rule(input, &mut peg_stack)? {
skip_ws(input);
}
skip_ws(input);
let sequence = peg_stack
.0
.into_iter()
.map(Peg::try_as_rule)
.collect::<Result<Vec<_>>>()?;
module.rules.insert(rule_name, sequence);
} else {
break;
}
}
Ok(module)
}
pub fn parse_module(str: &str) -> Result<TectaPegModule> {
let end_span = match str.lines().enumerate().last() {
Some((index, line)) => Span {
start_line: index + 1,
end_line: index + 1,
start_column: line.len(),
end_column: line.len(),
},
None => Span::default(),
};
parse_module_inner(&mut ParseInput {
chars: SpanningChars::new(str.chars()),
end_span,
})
}