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

Fix parsing of conformance test documents with multiple extension clauses (like Then) #930

Merged
merged 1 commit into from
Mar 7, 2025
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
8 changes: 8 additions & 0 deletions tests/conformance_dsl/continuation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use ion_rs::{Element, ElementReader, Sequence};

#[derive(Clone, Debug)]
pub(crate) enum Continuation {
// Used internally.
None,

// expectations

// Verify that reading the current document produces the expected data provided.
Expand Down Expand Up @@ -71,8 +74,13 @@ impl Continuation {
Err(_e) => Ok(()),
Ok(_) => Err(ConformanceErrorKind::ExpectedSignal(msg.to_owned()))?,
},
Continuation::None => unreachable!(),
}
}

pub fn is_extension(&self) -> bool {
matches!(self, Self::Then(..) | Self::Each(..))
}
}

impl Default for Continuation {
Expand Down
53 changes: 49 additions & 4 deletions tests/conformance_dsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub(crate) enum ConformanceErrorKind {
MismatchedDenotes,
UnexpectedValue,
UnknownVersion,
UnexpectedContinuation,
}

impl From<std::io::Error> for ConformanceErrorKind {
Expand Down Expand Up @@ -153,6 +154,7 @@ pub(crate) fn parse_document_like<T: DocumentLike>(clause: &Clause) -> InnerResu
// let clause: Clause = Clause::try_from(seq)?;
let mut doc_like = T::default();
let mut sequence_idx = 0;
let mut continuation = continuation::Continuation::None;

// We have an optional name as the second argument..
if let Some(elem) = clause.body.first().filter(|e| e.ion_type() == IonType::String) {
Expand Down Expand Up @@ -186,12 +188,35 @@ pub(crate) fn parse_document_like<T: DocumentLike>(clause: &Clause) -> InnerResu
let Some(seq) = element.as_sequence() else {
return Err(ConformanceErrorKind::ExpectedClause)
};
let clause: Clause = seq.clone().try_into().expect("unable to convert to clause");
match continuation::parse_continuation(clause) {
Ok(c) => doc_like.set_continuation(c),

let inner_clause: Clause = seq.clone().try_into().expect("unable to convert to clause");
match continuation::parse_continuation(inner_clause) {
Ok(c) => {
use continuation::Continuation::*;
continuation = match continuation {
None => c,
Each(..) | Then(..) => Extensions(vec!(continuation, c)),
Extensions(ref mut exts) => {
exts.push(c.clone());
continuation
}
_ => {
// We cannot mix continuations and extensions
return Err(ConformanceErrorKind::UnexpectedContinuation);
}
};

// If we have a continuation already, we need to extend it to Extensions.
let expect_more = continuation.is_extension() && (sequence_idx + 1) < clause.body.len();
if !expect_more {
doc_like.set_continuation(continuation);
break;
}

sequence_idx += 1;
}
Err(e) => return Err(e),
}
break;
}
}
Ok(doc_like)
Expand Down Expand Up @@ -485,4 +510,24 @@ mod tests {
.unwrap_or_else(|e| panic!("Test failed for simple doc: <<{}>>\n{:?}", test, e));
}
}

#[test]
fn test_then_clauses() {
let test =
r#"(ion_1_1 (mactab (macro foo () bar))
(then (text "(:foo)")
(produces bar))
(then (text "(:foo)")
(produces halb))
)
"#;
println!("Testing: {}", test);
let doc = Document::from_str(test)
.unwrap_or_else(|e| panic!("Failed to load document: <<{}>>\n{:?}", test, e));
println!("Document: {:?}", doc);
match doc.run() {
Err(_) => (),
Ok(_) => panic!("Unexpected successful test evaluation"),
}
}
}
32 changes: 26 additions & 6 deletions tests/conformance_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,39 @@ mod ion_tests {
skip!("ion-tests/conformance/data_model/float.ion",
"Ion 1.1 binary" // PANIC: not yet implemented: implement half-precision floats
),
// e-expression transcription
// Mismatched produces due to symbol id transcription.
skip!("ion-tests/conformance/core/toplevel_produces.ion"),
// Unrecognized encoding 'int8'
skip!("ion-tests/conformance/demos/metaprogramming.ion"),
// error: flatten only accepts sequences
skip!("ion-tests/conformance/eexp/arg_inlining.ion"),
// Out dated macro invocation in TDL syntax
skip!("ion-tests/conformance/eexp/basic_system_macros.ion"),
// Mismatched produces, due to out-of-date encoding block
skip!("ion-tests/conformance/ion_encoding/mactab.ion"),
skip!("ion-tests/conformance/ion_encoding/module/macro/cardinality/invoke_cardinality_ee.ion"),
skip!("ion-tests/conformance/ion_encoding/module/macro/cardinality/invoke_cardinality_ee.ion",
"? parameters", // Parameter used incorrectly in tdl.
"* parameters" // Parameter used incorrectly in tdl.
),
// Incorrectly constructed macro table.
skip!("ion-tests/conformance/ion_encoding/module/macro/template/literal_form.ion"),
// Incorrectly used parameters in TDL.
skip!("ion-tests/conformance/ion_encoding/module/macro/template/quasiliteral.ion"),
// Incorrectly used parameters in TDL.
skip!("ion-tests/conformance/ion_encoding/module/macro/template/variable_reference.ion"),
// Incorrectly used parameters in TDL
skip!("ion-tests/conformance/ion_encoding/module/macro/template/if.ion"),
// Incorrectly constructed macro table / module.
skip!("ion-tests/conformance/ion_encoding/module/macro/trivial/literal_value.ion"),
skip!("ion-tests/conformance/ion_encoding/module/macro/trivial/invoke_ee.ion"),
// Error: Mismatched denotes
skip!("ion-tests/conformance/ion_encoding/module/macro/trivial/invoke_ee.ion",
"Invocation by address" // Cannot find macro with id "M"; invalid macro invocation
// syntax.
),
// Error: Unrecognized encoding (of various forms: flex_sym, uint8, uint16, uint32, etc)
skip!("ion-tests/conformance/eexp/binary/tagless_types.ion"),
// Error: Unexpected EOF
// Error: Unexpected EOF and unrecognized encodings.
skip!("ion-tests/conformance/eexp/binary/argument_encoding.ion"),
// Error: Mismatched Produce
// Error: Mismatched Produces; incorrect symbol table creation.
skip!("ion-tests/conformance/ion_encoding/symtab.ion"),
skip!("ion-tests/conformance/ion_encoding/load_symtab.ion"),
skip!("ion-tests/conformance/ion_encoding/trivial_forms.ion"),
Expand Down Expand Up @@ -107,6 +123,10 @@ mod ion_tests {
skip!("ion-tests/conformance/system_macros/sum.ion"),
// System macro make_timestamp not yet implemented
skip!("ion-tests/conformance/system_macros/make_timestamp.ion"),
// Annot clause not currently supported.
skip!("ion-tests/conformance/system_macros/annotate.ion"),
// error reading struct: `make_field`'s first argument must be a text value
skip!("ion-tests/conformance/system_macros/make_field.ion"),
// Expected Signal: invalid macro definition
skip!("ion-tests/conformance/tdl/expression_groups.ion"),
// Mismatched encodings for nested contexts.
Expand Down
Loading