Skip to content

Commit

Permalink
Clean up precedence parser codegen since DSL v2 (#699)
Browse files Browse the repository at this point in the history
Part of #638

This PR:
- Removes the `PrecedenceExpression::rule_name` in favour of using the
name directly for its rule/node kind
- Deduplicates the individual precedence expressions in the parser
codegen (regressed in
#687 (comment))
- Allows to parse individual precedence expressions and adds rule kinds
for them
- ... so we can remove `ProductionKind` in favour of the now-complete
`RuleKind`

I can split this up but since all of this is interconnected, it made
sense to work on them at the same time and submit work that solves all
of the aforementioned issues.

---------

Co-authored-by: Omar Tawfik <15987992+OmarTawfik@users.noreply.github.com>
  • Loading branch information
Xanewok and OmarTawfik authored Dec 9, 2023
1 parent 68b8a93 commit ddfebfe
Show file tree
Hide file tree
Showing 89 changed files with 2,898 additions and 5,882 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-otters-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/slang": minor
---

Remove `ProductionKind` in favor of `RuleKind`
5 changes: 5 additions & 0 deletions .changeset/new-monkeys-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/slang": minor
---

Allow parsing individual precedence expressions, like `ShiftExpression`
8 changes: 3 additions & 5 deletions crates/codegen/grammar/src/precedence_parser_definition.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use std::fmt::Debug;
use std::rc::Rc;

use super::{
GrammarVisitor, ParserDefinitionNode, ParserDefinitionRef, VersionQualityRange, Visitable,
};
use super::{GrammarVisitor, ParserDefinitionNode, Visitable};

pub trait PrecedenceParserDefinition: Debug {
fn name(&self) -> &'static str;
Expand All @@ -24,11 +22,11 @@ impl Visitable for PrecedenceParserDefinitionRef {
pub struct PrecedenceParserDefinitionNode {
pub primary_expression: Box<ParserDefinitionNode>,
pub operators: Vec<(
Vec<VersionQualityRange>,
PrecedenceOperatorModel,
&'static str, // name
ParserDefinitionRef,
ParserDefinitionNode,
)>,
pub precedence_expression_names: Vec<&'static str>,
}

impl Visitable for PrecedenceParserDefinitionNode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@ fn check_precedence(
let enablement = update_enablement(analysis, enablement, enabled);

for precedence_expression in precedence_expressions {
let SpannedPrecedenceExpression {
name: _,
rule_name: _,
operators,
} = precedence_expression;
let SpannedPrecedenceExpression { name: _, operators } = precedence_expression;

for operator in operators {
let SpannedPrecedenceOperator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ pub struct PrecedenceItem {
pub struct PrecedenceExpression {
pub name: Identifier,

// TODO(#638): Remove this, once we adapt the DSL v1 codegen model to the new v2 definition.
pub rule_name: Identifier,

pub operators: Vec<PrecedenceOperator>,
}

Expand All @@ -37,7 +34,7 @@ pub struct PrecedenceOperator {
pub fields: IndexMap<Identifier, Field>,
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize)]
#[derive_spanned_type(ParseInputTokens, WriteOutputTokens)]
pub enum OperatorModel {
Prefix,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ codegen_language_macros::compile!(Language(
Precedence(
name = Bar,
precedence_expressions = [
PrecedenceExpression(name = Expression1, rule_name = X, operators = []),
PrecedenceExpression(name = Expression2, rule_name = X, operators = []),
PrecedenceExpression(name = Expression1, rule_name = X, operators = [])
PrecedenceExpression(name = Expression1, operators = []),
PrecedenceExpression(name = Expression2, operators = []),
PrecedenceExpression(name = Expression1, operators = [])
],
primary_expressions = [PrimaryExpression(reference = Baz)]
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: An expression with the name 'Expression1' already exists.
--> src/fail/definitions/duplicate_expression_name/test.rs:19:53
|
19 | PrecedenceExpression(name = Expression1, rule_name = X, operators = [])
19 | PrecedenceExpression(name = Expression1, operators = [])
| ^^^^^^^^^^^
25 changes: 10 additions & 15 deletions crates/codegen/parser/generator/src/code_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::{
use anyhow::Result;
use codegen_grammar::{
Grammar, GrammarVisitor, ParserDefinitionNode, ParserDefinitionRef,
PrecedenceParserDefinitionNode, PrecedenceParserDefinitionRef, ScannerDefinitionNode,
ScannerDefinitionRef, TriviaParserDefinitionRef,
PrecedenceParserDefinitionRef, ScannerDefinitionNode, ScannerDefinitionRef,
TriviaParserDefinitionRef,
};
use infra_utils::{cargo::CargoWorkspace, codegen::Codegen};
use quote::{format_ident, quote};
Expand All @@ -27,7 +27,6 @@ pub struct CodeGenerator {

rule_kinds: BTreeSet<&'static str>,
token_kinds: BTreeSet<&'static str>,
production_kinds: BTreeSet<&'static str>,
trivia_kinds: BTreeSet<&'static str>,

top_level_scanner_names: BTreeSet<&'static str>,
Expand Down Expand Up @@ -216,7 +215,6 @@ impl GrammarVisitor for CodeGenerator {

fn trivia_parser_definition_enter(&mut self, parser: &TriviaParserDefinitionRef) {
self.set_current_context(parser.context());
self.production_kinds.insert(parser.name());
self.rule_kinds.insert(parser.name());
self.trivia_kinds.insert(parser.name());
self.parser_functions.push((
Expand All @@ -234,7 +232,6 @@ impl GrammarVisitor for CodeGenerator {
// Have to set this regardless so that we can collect referenced scanners
self.set_current_context(parser.context());
if !parser.is_inline() {
self.production_kinds.insert(parser.name());
self.rule_kinds.insert(parser.name());
let code = parser.to_parser_code();
self.parser_functions.push((
Expand All @@ -250,11 +247,17 @@ impl GrammarVisitor for CodeGenerator {

fn precedence_parser_definition_enter(&mut self, parser: &PrecedenceParserDefinitionRef) {
self.set_current_context(parser.context());
self.production_kinds.insert(parser.name());
self.rule_kinds.insert(parser.name());
for (_, _, name, _) in &parser.node().operators {
for (_, name, _) in &parser.node().operators {
self.rule_kinds.insert(name);
}

// While it's not common to parse a precedence expression as a standalone rule,
// we generate a function for completeness.
for (name, code) in parser.to_precedence_expression_parser_code() {
self.parser_functions.push((name, code.to_string()));
}

self.parser_functions.push((
parser.name(),
{
Expand Down Expand Up @@ -315,12 +318,4 @@ impl GrammarVisitor for CodeGenerator {
_ => {}
};
}

fn precedence_parser_definition_node_enter(&mut self, node: &PrecedenceParserDefinitionNode) {
for operator in &node.operators {
for vqr in &operator.0 {
self.referenced_versions.insert(vqr.from.clone());
}
}
}
}
12 changes: 0 additions & 12 deletions crates/codegen/parser/generator/src/parser_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ impl ParserDefinitionNodeExtensions for ParserDefinitionNode {

pub trait VersionQualityRangeVecExtensions {
fn wrap_code(&self, if_true: TokenStream, if_false: Option<TokenStream>) -> TokenStream;
fn disambiguating_name_suffix(&self) -> String;
}

impl VersionQualityRangeVecExtensions for Vec<VersionQualityRange> {
Expand All @@ -282,15 +281,4 @@ impl VersionQualityRangeVecExtensions for Vec<VersionQualityRange> {
quote! { if #(#flags)&&* { #if_true } #else_part }
}
}

fn disambiguating_name_suffix(&self) -> String {
let mut suffix = String::new();
for vqr in self {
suffix.push('_');
suffix.push_str(&vqr.quality.to_string().to_lowercase());
suffix.push_str("_from_");
suffix.push_str(&vqr.from.to_string().replace('.', "_"));
}
suffix
}
}
Loading

0 comments on commit ddfebfe

Please sign in to comment.