Skip to content

Commit e73658a

Browse files
authored
render EBNF grammar in node kind enums doc comments (#545)
1 parent 575037a commit e73658a

34 files changed

Lines changed: 8894 additions & 659 deletions

File tree

.changeset/sweet-bugs-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"changelog": patch
3+
---
4+
5+
render EBNF grammar on top of each `ProductionKind`, `RuleKind`, and `TokenKind`.

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"codegen",
1010
"devcontainer",
1111
"doxygen",
12+
"ebnf",
1213
"inheritdoc",
1314
"ipfs",
1415
"mkdocs",

crates/codegen/ebnf/src/nodes.rs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
#[derive(Clone, Eq, Hash, PartialEq)]
21
pub enum EbnfNode {
3-
BaseProduction,
42
Choice {
53
nodes: Vec<EbnfNode>,
64
},
@@ -27,13 +25,12 @@ pub enum EbnfNode {
2725
Sequence {
2826
nodes: Vec<EbnfNode>,
2927
},
30-
SubStatement {
31-
name: String,
32-
comment: Option<String>,
33-
root_node: Box<EbnfNode>,
34-
},
3528
Terminal {
36-
value: String,
29+
terminal: String,
30+
},
31+
WithComment {
32+
node: Box<EbnfNode>,
33+
comment: String,
3734
},
3835
ZeroOrMore {
3936
node: Box<EbnfNode>,
@@ -42,7 +39,16 @@ pub enum EbnfNode {
4239

4340
impl EbnfNode {
4441
pub fn choice(nodes: Vec<EbnfNode>) -> Self {
45-
Self::Choice { nodes }
42+
let mut results = vec![];
43+
44+
for node in nodes {
45+
match node {
46+
EbnfNode::Choice { nodes } => results.extend(nodes),
47+
_ => results.push(node),
48+
}
49+
}
50+
51+
Self::Choice { nodes: results }
4652
}
4753

4854
pub fn difference(minuend: EbnfNode, subtrahend: EbnfNode) -> Self {
@@ -70,28 +76,40 @@ impl EbnfNode {
7076
}
7177
}
7278

73-
pub fn production_ref(name: String) -> Self {
74-
Self::ProductionRef { name }
79+
pub fn production_ref(name: &str) -> Self {
80+
Self::ProductionRef {
81+
name: name.to_owned(),
82+
}
7583
}
7684

7785
pub fn range(from: char, to: char) -> Self {
7886
Self::Range { from, to }
7987
}
8088

8189
pub fn sequence(nodes: Vec<EbnfNode>) -> Self {
82-
Self::Sequence { nodes }
90+
let mut results = vec![];
91+
92+
for node in nodes {
93+
match node {
94+
EbnfNode::Sequence { nodes } => results.extend(nodes),
95+
_ => results.push(node),
96+
}
97+
}
98+
99+
Self::Sequence { nodes: results }
83100
}
84101

85-
pub fn sub_statement(name: String, comment: Option<String>, root_node: EbnfNode) -> Self {
86-
Self::SubStatement {
87-
name,
88-
comment,
89-
root_node: Box::new(root_node),
102+
pub fn terminal(terminal: &str) -> Self {
103+
Self::Terminal {
104+
terminal: terminal.to_owned(),
90105
}
91106
}
92107

93-
pub fn terminal(value: String) -> Self {
94-
Self::Terminal { value }
108+
pub fn with_comment(node: EbnfNode, comment: String) -> Self {
109+
Self::WithComment {
110+
node: Box::new(node),
111+
comment,
112+
}
95113
}
96114

97115
pub fn zero_or_more(node: EbnfNode) -> Self {
@@ -100,3 +118,30 @@ impl EbnfNode {
100118
}
101119
}
102120
}
121+
122+
impl EbnfNode {
123+
pub fn precedence(&self) -> u8 {
124+
// We are specifying precedence "groups" instead of a flat list.
125+
// This separates members of the same precedence, like both "a b (c | d)" and "a | b | (c d)".
126+
return match self {
127+
// Not an operator
128+
EbnfNode::WithComment { .. } => 0,
129+
130+
// Binary
131+
EbnfNode::Choice { .. } | EbnfNode::Difference { .. } | EbnfNode::Sequence { .. } => 1,
132+
133+
// Prefix
134+
EbnfNode::Not { .. } => 2,
135+
136+
// Postfix
137+
EbnfNode::OneOrMore { .. }
138+
| EbnfNode::Optional { .. }
139+
| EbnfNode::ZeroOrMore { .. } => 3,
140+
141+
// Primary
142+
EbnfNode::ProductionRef { .. } | EbnfNode::Range { .. } | EbnfNode::Terminal { .. } => {
143+
4
144+
}
145+
};
146+
}
147+
}

crates/codegen/ebnf/src/parser.rs

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,62 @@
11
use codegen_schema::types::{ParserDefinition, ParserRef};
22

3-
use crate::{nodes::EbnfNode, serialization::GenerateEbnf};
3+
use crate::nodes::EbnfNode;
44

5-
impl GenerateEbnf for ParserRef {
6-
fn generate_ebnf(&self) -> EbnfNode {
7-
return self.definition.generate_ebnf();
8-
}
9-
}
10-
11-
impl GenerateEbnf for ParserDefinition {
12-
fn generate_ebnf(&self) -> EbnfNode {
13-
match &self {
5+
impl EbnfNode {
6+
pub fn from_parser(parser: &ParserRef) -> Self {
7+
match &parser.definition {
148
ParserDefinition::Choice(parsers) => {
15-
return EbnfNode::choice(
16-
parsers
17-
.iter()
18-
.map(|parser| parser.generate_ebnf())
19-
.collect(),
20-
);
9+
return Self::choice(parsers.iter().map(Self::from_parser).collect());
2110
}
2211

2312
ParserDefinition::DelimitedBy {
2413
open,
2514
parser,
2615
close,
2716
} => {
28-
return EbnfNode::sequence(vec![
29-
EbnfNode::production_ref(open.reference.to_owned()),
30-
parser.generate_ebnf(),
31-
EbnfNode::production_ref(close.reference.to_owned()),
17+
return Self::sequence(vec![
18+
Self::production_ref(&open.reference),
19+
Self::from_parser(&parser),
20+
Self::production_ref(&close.reference),
3221
]);
3322
}
3423

3524
ParserDefinition::OneOrMore(parser) => {
36-
return EbnfNode::one_or_more(parser.generate_ebnf());
25+
return Self::one_or_more(Self::from_parser(&parser));
3726
}
3827

3928
ParserDefinition::Optional(parser) => {
40-
return EbnfNode::optional(parser.generate_ebnf());
29+
return Self::optional(Self::from_parser(&parser));
4130
}
4231

4332
ParserDefinition::Reference(name) => {
44-
return EbnfNode::production_ref(name.to_owned());
33+
return Self::production_ref(&name);
4534
}
4635

4736
ParserDefinition::SeparatedBy { parser, separator } => {
48-
return EbnfNode::sequence(vec![
49-
parser.generate_ebnf(),
50-
EbnfNode::zero_or_more(EbnfNode::sequence(vec![
51-
EbnfNode::production_ref(separator.reference.to_owned()),
52-
parser.generate_ebnf(),
37+
return Self::sequence(vec![
38+
Self::from_parser(&parser),
39+
Self::zero_or_more(Self::sequence(vec![
40+
Self::production_ref(&separator.reference),
41+
Self::from_parser(&parser),
5342
])),
5443
]);
5544
}
5645

5746
ParserDefinition::Sequence(parsers) => {
58-
return EbnfNode::sequence(
59-
parsers
60-
.iter()
61-
.map(|parser| parser.generate_ebnf())
62-
.collect(),
63-
);
47+
return Self::sequence(parsers.iter().map(Self::from_parser).collect());
6448
}
6549

6650
ParserDefinition::TerminatedBy { parser, terminator } => {
67-
return EbnfNode::sequence(vec![
68-
parser.generate_ebnf(),
69-
EbnfNode::production_ref(terminator.reference.to_owned()),
51+
return Self::sequence(vec![
52+
Self::from_parser(&parser),
53+
Self::production_ref(&terminator.reference),
7054
]);
7155
}
7256

7357
ParserDefinition::ZeroOrMore(parser) => {
74-
return EbnfNode::zero_or_more(parser.generate_ebnf());
58+
return Self::zero_or_more(Self::from_parser(&parser));
7559
}
76-
}
60+
};
7761
}
7862
}
Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,74 @@
11
use codegen_schema::types::{OperatorModel, PrecedenceParserRef};
22

3-
use crate::{nodes::EbnfNode, serialization::GenerateEbnf};
4-
5-
impl GenerateEbnf for PrecedenceParserRef {
6-
fn generate_ebnf(&self) -> EbnfNode {
7-
let mut nodes = vec![];
8-
9-
for expression in &self.operator_expressions {
10-
let mut comment = None;
11-
12-
let operator = match expression.model {
13-
OperatorModel::BinaryLeftAssociative => EbnfNode::sequence(vec![
14-
EbnfNode::BaseProduction,
15-
expression.operator.generate_ebnf(),
16-
EbnfNode::BaseProduction,
17-
]),
18-
19-
OperatorModel::BinaryRightAssociative => {
20-
comment = Some("Right Associative".to_owned());
21-
22-
EbnfNode::sequence(vec![
23-
EbnfNode::BaseProduction,
24-
expression.operator.generate_ebnf(),
25-
EbnfNode::BaseProduction,
26-
])
27-
}
28-
OperatorModel::UnaryPrefix => EbnfNode::sequence(vec![
29-
expression.operator.generate_ebnf(),
30-
EbnfNode::BaseProduction,
31-
]),
32-
33-
OperatorModel::UnaryPostfix => EbnfNode::sequence(vec![
34-
EbnfNode::BaseProduction,
35-
expression.operator.generate_ebnf(),
36-
]),
3+
use crate::{nodes::EbnfNode, EbnfSerializer};
4+
5+
impl EbnfNode {
6+
pub fn from_precedence_parser(
7+
precedence_parser: &PrecedenceParserRef,
8+
base_expression: &str,
9+
serializer: &mut EbnfSerializer,
10+
) -> Self {
11+
let mut choices = vec![];
12+
13+
for expression in &precedence_parser.operator_expressions {
14+
let (expression_body, model_description) = match expression.model {
15+
OperatorModel::BinaryLeftAssociative => (
16+
Self::sequence(vec![
17+
Self::production_ref(base_expression),
18+
Self::from_parser(&expression.operator),
19+
Self::production_ref(base_expression),
20+
]),
21+
"Binary Operator, Left Associative",
22+
),
23+
24+
OperatorModel::BinaryRightAssociative => (
25+
Self::sequence(vec![
26+
Self::production_ref(base_expression),
27+
Self::from_parser(&expression.operator),
28+
Self::production_ref(base_expression),
29+
]),
30+
"Binary Operator, Right Associative",
31+
),
32+
33+
OperatorModel::UnaryPrefix => (
34+
Self::sequence(vec![
35+
Self::from_parser(&expression.operator),
36+
Self::production_ref(base_expression),
37+
]),
38+
"Unary Operator, Prefix",
39+
),
40+
41+
OperatorModel::UnaryPostfix => (
42+
Self::sequence(vec![
43+
Self::production_ref(base_expression),
44+
Self::from_parser(&expression.operator),
45+
]),
46+
"Unary Operator, Postfix",
47+
),
48+
};
49+
50+
let serialized_expression_body = {
51+
let mut buffer = String::new();
52+
serializer.serialize_node(&expression_body, &mut buffer);
53+
buffer
3754
};
3855

39-
nodes.push(EbnfNode::sub_statement(
40-
expression.name.to_owned(),
41-
comment,
42-
operator,
56+
choices.push(Self::with_comment(
57+
Self::with_comment(
58+
Self::production_ref(&expression.name),
59+
serialized_expression_body,
60+
),
61+
model_description.to_owned(),
4362
));
63+
64+
serializer.serialize_statement(
65+
&expression.name,
66+
&Self::with_comment(expression_body, model_description.to_owned()),
67+
);
4468
}
4569

46-
nodes.push(self.primary_expression.generate_ebnf());
70+
choices.push(Self::from_parser(&precedence_parser.primary_expression));
4771

48-
return EbnfNode::choice(nodes);
72+
return Self::choice(choices);
4973
}
5074
}

0 commit comments

Comments
 (0)