Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CST labels to EBNF #976

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/codegen/ebnf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ codegen_language_definition = { workspace = true }
derive-new = { workspace = true }
indexmap = { workspace = true }
Inflector = { workspace = true }
strum_macros = { workspace = true }

[lints]
workspace = true
Expand Down
91 changes: 70 additions & 21 deletions crates/codegen/ebnf/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ use inflector::Inflector;

use crate::model::{Definition, DefinitionKind, Entry, Expression, Value};

#[allow(dead_code)]
#[derive(strum_macros::AsRefStr)]
#[strum(serialize_all = "snake_case")]
enum BuiltInLabel {
OmarTawfik marked this conversation as resolved.
Show resolved Hide resolved
// _SLANG_INTERNAL_RESERVED_NODE_LABELS_ (keep in sync)
Item,
Variant,
Separator,
Operand,
LeftOperand,
RightOperand,
LeadingTrivia,
TrailingTrivia,
}

pub struct Builder {
section_index: usize,
topic_index: usize,
Expand Down Expand Up @@ -128,7 +143,7 @@ impl Builder {

let variants = variants.iter().map(|EnumVariant { reference, enabled }| {
Value::new(
Self::build_ref(reference),
Self::build_ref(Some(BuiltInLabel::Variant.as_ref()), reference),
Self::build_enabled_comment(enabled),
)
});
Expand All @@ -151,10 +166,11 @@ impl Builder {

self.add_entry(name, Terminal::No, Inlined::No);

let label = BuiltInLabel::Item.as_ref();
let expression = if allow_empty.unwrap_or_default() {
Expression::new_zero_or_more(Self::build_ref(reference).into())
Expression::new_zero_or_more(Self::build_ref(Some(label), reference).into())
} else {
Expression::new_one_or_more(Self::build_ref(reference).into())
Expression::new_one_or_more(Self::build_ref(Some(label), reference).into())
};

self.add_definition(
Expand All @@ -177,11 +193,11 @@ impl Builder {
self.add_entry(name, Terminal::No, Inlined::No);

let mut expression = Expression::new_sequence(vec![
Self::build_ref(reference),
Self::build_ref(Some(BuiltInLabel::Item.as_ref()), reference),
OmarTawfik marked this conversation as resolved.
Show resolved Hide resolved
Expression::new_zero_or_more(
Expression::new_sequence(vec![
Self::build_ref(separator),
Self::build_ref(reference),
Self::build_ref(Some(BuiltInLabel::Separator.as_ref()), separator),
Self::build_ref(Some(BuiltInLabel::Item.as_ref()), reference),
])
.into(),
),
Expand Down Expand Up @@ -214,7 +230,10 @@ impl Builder {
for precedence_expression in precedence_expressions {
let PrecedenceExpression { name, operators } = precedence_expression.as_ref();

values.push(Value::new(Self::build_ref(name), None));
values.push(Value::new(
Self::build_ref(Some(BuiltInLabel::Variant.as_ref()), name),
None,
));

self.add_entry(name, Terminal::No, Inlined::No);

Expand All @@ -227,7 +246,7 @@ impl Builder {
let PrimaryExpression { reference, enabled } = primary_expression;

values.push(Value::new(
Self::build_ref(reference),
Self::build_ref(Some(BuiltInLabel::Variant.as_ref()), reference),
Self::build_enabled_comment(enabled),
));
}
Expand Down Expand Up @@ -260,24 +279,51 @@ impl Builder {
OperatorModel::Prefix => {
leading_comments.push("Prefix unary operator".to_string());

values.push(Value::new(Self::build_ref(base_name), None));
values.push(Value::new(
Self::build_ref(Some(BuiltInLabel::Operand.as_ref()), base_name),
None,
));
}
OperatorModel::Postfix => {
leading_comments.push("Postfix unary operator".to_string());

values.insert(0, Value::new(Self::build_ref(base_name), None));
values.insert(
0,
Value::new(
Self::build_ref(Some(BuiltInLabel::Operand.as_ref()), base_name),
None,
),
);
}
OperatorModel::BinaryLeftAssociative => {
leading_comments.push("Left-associative binary operator".to_string());

values.insert(0, Value::new(Self::build_ref(base_name), None));
values.push(Value::new(Self::build_ref(base_name), None));
values.insert(
0,
Value::new(
Self::build_ref(Some(BuiltInLabel::LeftOperand.as_ref()), base_name),
None,
),
);
values.push(Value::new(
Self::build_ref(Some(BuiltInLabel::RightOperand.as_ref()), base_name),
None,
));
}
OperatorModel::BinaryRightAssociative => {
leading_comments.push("Right-associative binary operator".to_string());

values.insert(0, Value::new(Self::build_ref(base_name), None));
values.push(Value::new(Self::build_ref(base_name), None));
values.insert(
0,
Value::new(
Self::build_ref(Some(BuiltInLabel::LeftOperand.as_ref()), base_name),
None,
),
);
values.push(Value::new(
Self::build_ref(Some(BuiltInLabel::RightOperand.as_ref()), base_name),
None,
));
}
};

Expand All @@ -288,11 +334,13 @@ impl Builder {

fn build_fields(fields: &IndexMap<Identifier, Field>) -> Vec<Value> {
fields
.values()
.map(|field| match field {
Field::Required { reference } => Value::new(Self::build_ref(reference), None),
.iter()
.map(|(identifier, field)| match field {
Field::Required { reference } => {
Value::new(Self::build_ref(Some(identifier), reference), None)
}
Field::Optional { reference, enabled } => Value::new(
Expression::new_optional(Self::build_ref(reference).into()),
Expression::new_optional(Self::build_ref(Some(identifier), reference).into()),
Self::build_enabled_comment(enabled),
),
})
Expand Down Expand Up @@ -454,12 +502,13 @@ impl Builder {
scanner,
not_followed_by: _,
} => Self::build_scanner(scanner),
Scanner::Fragment { reference } => Self::build_ref(reference),
Scanner::Fragment { reference } => Self::build_ref(None, reference),
}
}

fn build_ref(reference: &Identifier) -> Expression {
Expression::new_reference(reference.to_owned())
fn build_ref(label: Option<&str>, reference: &Identifier) -> Expression {
let leading_comment = label.map(|label| format!("{label}:"));
Expression::new_reference(leading_comment, reference.to_owned())
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/codegen/ebnf/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub enum Expression {
atom: String,
},
Reference {
leading_comment: Option<String>,
reference: Identifier,
},
}
Expand Down
9 changes: 8 additions & 1 deletion crates/codegen/ebnf/src/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,14 @@ impl<'s, W: EbnfWriter> Serializer<'s, W> {
Expression::Atom { atom } => {
self.serialize_string_literal(atom)?;
}
Expression::Reference { reference } => {
Expression::Reference {
leading_comment,
reference,
} => {
if let Some(comment) = leading_comment {
self.serialize_comment(comment)?;
self.serialize_punctuation(" ")?;
}
self.serialize_identifier(reference)?;
}
};
Expand Down
13 changes: 12 additions & 1 deletion crates/codegen/spec/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::rc::Rc;

use codegen_ebnf::EbnfModel;
use codegen_language_definition::model::{Identifier, Language, Section, Topic};
use codegen_language_definition::model::{Identifier, Item, Language, Section, Topic};
use inflector::Inflector;
use serde::Serialize;

Expand Down Expand Up @@ -91,6 +91,17 @@ impl SpecTopic {

for item in &topic.items {
items.push(item.name().to_owned());

// We need to also add any precedence expressions, as they define
// items but are not direct children of the topic
if let Item::Precedence {
item: precedence_item,
} = item
{
for precedence_expr in &precedence_item.precedence_expressions {
items.push(precedence_expr.name.clone());
}
}
}

Self { title, slug, items }
Expand Down
Loading