Skip to content

Commit

Permalink
wip: add a way to validate the fields error recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
Xanewok committed Feb 27, 2024
1 parent 15a59bf commit 13aa1e1
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use std::collections::HashSet;
use crate::compiler::analysis::{Analysis, ItemMetadata};
use crate::compiler::version_set::VersionSet;
use crate::internals::Spanned;
use crate::model::{Identifier, SpannedItem, SpannedVersionSpecifier};
use crate::model::{Identifier, SpannedFieldsErrorRecovery, SpannedItem, SpannedVersionSpecifier};

pub(crate) fn analyze_definitions(analysis: &mut Analysis) {
collect_top_level_items(analysis);

check_enum_items(analysis);
check_precedence_items(analysis);
check_field_error_recovery(analysis);
}

fn collect_top_level_items(analysis: &mut Analysis) {
Expand Down Expand Up @@ -97,6 +98,39 @@ fn check_precedence_items(analysis: &mut Analysis) {
}
}

fn check_field_error_recovery(analysis: &mut Analysis) {
let mut visit_item = |item: &Spanned<SpannedFieldsErrorRecovery>| {
if item.recover_from_no_match.is_some() && item.delimiters.is_none() {
analysis
.errors
.add(item, &Errors::RecoverFromNoMatchWithoutDelimiters);
}
};

// Visit PrecedenceOperators and SpannedItem::Structs:
for item in analysis.language.clone().items() {
match item {
SpannedItem::Precedence { item } => {
for er in item
.precedence_expressions
.iter()
.flat_map(|x| &x.operators)
.filter_map(|x| x.error_recovery.as_ref())
{
visit_item(er);
}
}

SpannedItem::Struct { item } => {
if let Some(abc) = item.error_recovery.as_ref() {
visit_item(abc);
}
}
_ => {}
}
}
}

fn get_item_name(item: &SpannedItem) -> &Spanned<Identifier> {
match item {
SpannedItem::Struct { item } => &item.name,
Expand Down Expand Up @@ -168,4 +202,6 @@ enum Errors<'err> {
ExistingVariant(&'err Identifier),
#[error("An expression with the name '{0}' already exists.")]
ExistingExpression(&'err Identifier),
#[error("The field 'recover_from_no_match' can only be defined if 'delimiters' is defined.")]
RecoverFromNoMatchWithoutDelimiters,
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ fn get_spanned_type(input: Type) -> Type {
| "EnumVariant"
| "Field"
| "FieldDelimiters"
| "FieldsErrorRecovery"
| "FragmentItem"
| "InputItem"
| "Item"
Expand Down Expand Up @@ -143,7 +142,7 @@ fn get_spanned_type(input: Type) -> Type {

// These are model Types that have a derived 'SpannedXXX' type.
// Let's use that instead, but also wrap it in 'Spanned<T>' because we want to capture its complete span for validation:
"OperatorModel" | "VersionSpecifier" => {
"OperatorModel" | "VersionSpecifier" | "FieldsErrorRecovery" => {
let spanned_type = format_ident!("{}", add_spanned_prefix(type_name));
parse_quote! {
crate::internals::Spanned<crate::model::#spanned_type>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#![allow(unused_crate_dependencies)]

codegen_language_macros::compile!(Language(
name = Foo,
documentation_dir = "foo/bar",
root_item = Bar,
leading_trivia = Sequence([]),
trailing_trivia = Sequence([]),
versions = ["1.0.0", "2.0.0", "3.0.0"],
sections = [Section(
title = "Section One",
topics = [Topic(
title = "Topic One",
items = [
Struct(
name = Bar,
error_recovery =
FieldsErrorRecovery(terminator = semicolon, recover_from_no_match = true),
fields = (
field_4 = Optional(
// correct
reference = Baz,
enabled = Range(from = "2.0.0", till = "3.0.0")
),
semicolon = Required(Semicolon)
)
),
Token(
name = Semicolon,
definitions = [TokenDefinition(scanner = Atom(";"))]
),
Token(
name = Baz,
definitions = [TokenDefinition(
enabled = Range(from = "2.0.0", till = "3.0.0"),
scanner = Atom("baz")
)]
)
]
)]
)]
));

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: The field 'recover_from_no_match' can only be defined if 'delimiters' is defined.
--> src/fail/references/recovered_only_for_delimited/test.rs:18:25
|
18 | FieldsErrorRecovery(terminator = semicolon, recover_from_no_match = true),
| ^^^^^^^^^^^^^^^^^^^

0 comments on commit 13aa1e1

Please sign in to comment.