Skip to content

Commit

Permalink
Updates ion-tests, fixes to test runner
Browse files Browse the repository at this point in the history
  • Loading branch information
zslayton committed Dec 13, 2024
1 parent 22ae964 commit f6392b4
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 191 deletions.
6 changes: 6 additions & 0 deletions src/element/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ impl AsRef<[Element]> for Sequence {
}
}

impl From<Sequence> for Vec<Element> {
fn from(value: Sequence) -> Self {
value.elements
}
}

// This is more efficient than Sequence::new(), which will iterate over and convert each value to
// an Element for better ergonomics.
impl From<Vec<Element>> for Sequence {
Expand Down
12 changes: 11 additions & 1 deletion src/lazy/encoder/annotation_seq.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use smallvec::SmallVec;

use crate::raw_symbol_ref::SystemSymbol_1_1;
use crate::{RawSymbolRef, SymbolId};
use crate::{Annotations, RawSymbolRef, SymbolId};

/// A sequence of annotations.
///
Expand Down Expand Up @@ -129,3 +129,13 @@ where
annotations
}
}

impl<'a> AnnotationSeq<'a> for &'a Annotations {
fn into_annotations_vec(self) -> AnnotationsVec<'a> {
let mut annotations = AnnotationsVec::new();
for token in self {
annotations.push(token.into());
}
annotations
}
}
8 changes: 7 additions & 1 deletion src/lazy/encoder/binary/v1_0/container_writers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ impl<'value, 'top> BinaryContainerWriter_1_0<'value, 'top> {
};
symbol_ids.push(symbol_address);
}
self.annotations = Some(symbol_ids);
// If this was called with an empty iterator, act as though it was never called at all.
// This prevents writing out an empty annotations sequence in binary, which is illegal.
self.annotations = if !symbol_ids.is_empty() {
Some(symbol_ids)
} else {
None
};
Ok(self)
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ macro_rules! v1_x_tooling_apis {
LazyExpandedField,
LazyExpandedFieldName
},
lazy::expanded::e_expression::{EExpression, EExpressionArgsIterator},
lazy::expanded::e_expression::{EExpression, EExpressionArgsIterator, EExpArgGroup, EExpArgGroupIterator},
lazy::expanded::sequence::{Environment, ExpandedListSource, ExpandedSExpSource, LazyExpandedList, LazyExpandedSExp},
lazy::expanded::{ExpandedStreamItem, LazyExpandedValue, ExpandingReader, ExpandedValueSource, ExpandedAnnotationsSource, ExpandedValueRef},
lazy::system_stream_item::SystemStreamItem,
Expand Down
86 changes: 46 additions & 40 deletions tests/conformance_dsl/continuation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
//! of the test document when read) and Extensions (clauses that allow the chaining, or
//! permutations for document creation).
use super::*;
use super::context::Context;
use super::model::{compare_values, ModelValue};
use super::*;

use ion_rs::{Element, Sequence};
use ion_rs::{Element, ElementReader, Sequence};

#[derive(Clone, Debug)]
pub(crate) enum Continuation {
Expand Down Expand Up @@ -60,39 +60,36 @@ impl Continuation {
}
Continuation::Each(branches, continuation) => {
for branch in branches {
let frags = vec!(branch.fragment.clone());
let frags = vec![branch.fragment.clone()];
let mut new_context = Context::extend(ctx, &frags);
new_context.set_encoding(branch.fragment.required_encoding());
continuation.evaluate(&new_context)?;
}
Ok(())
}
Continuation::Signals(msg) => {
match ctx.read_all(ctx.encoding()) {
Err(_e) => Ok(()),
Ok(_) => Err(ConformanceErrorKind::ExpectedSignal(msg.to_owned()))?,
}
}
Continuation::Signals(msg) => match ctx.read_all(ctx.encoding()) {
Err(_e) => Ok(()),
Ok(_) => Err(ConformanceErrorKind::ExpectedSignal(msg.to_owned()))?,
},
}
}

}

impl Default for Continuation {
fn default() -> Self {
Continuation::Produces(Produces { elems: vec!() })
Continuation::Produces(Produces { elems: vec![] })
}
}

/// Parses a clause known to be a continuation into a proper Continuation instance.
pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
let continuation = match clause.tpe {
ClauseType::Produces => {
Continuation::Produces(Produces { elems: clause.body.clone() })
}
ClauseType::Produces => Continuation::Produces(Produces {
elems: clause.body.clone(),
}),
ClauseType::And => {
if !clause.body.is_empty() {
let mut args = vec!();
let mut args = vec![];
for elem in clause.body {
if let Some(seq) = elem.as_sequence() {
let clause = Clause::try_from(seq)?;
Expand All @@ -108,7 +105,7 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
}
Continuation::And(args)
} else {
return Err(ConformanceErrorKind::ExpectedExpectation)
return Err(ConformanceErrorKind::ExpectedExpectation);
}
}
ClauseType::Not => {
Expand All @@ -129,21 +126,17 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
Continuation::Then(Box::new(then))
}
ClauseType::Denotes => {
let mut values: Vec<ModelValue> = vec!();
let mut values: Vec<ModelValue> = vec![];
for elem in clause.body {
if let Some(seq) = elem.as_sequence() {
let model_value = ModelValue::try_from(seq)?;
values.push(model_value);
} else {
return Err(ConformanceErrorKind::ExpectedModelValue);
}
let model_value = ModelValue::try_from(&elem)?;
values.push(model_value);
}
Continuation::Denotes(Denotes { model: values })
}
ClauseType::Each => {
let mut parsing_branches = true;
let mut sequence_idx = 0;
let mut branches: Vec<EachBranch> = vec!();
let mut branches: Vec<EachBranch> = vec![];
loop {
if sequence_idx >= clause.body.len() {
return Err(ConformanceErrorKind::ExpectedClause);
Expand All @@ -152,12 +145,18 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
let mut name: Option<String> = None;
// Branch: name-string? fragment
// Check for name-string..
if let Some(elem) = clause.body.get(sequence_idx).filter(|e| e.ion_type() == IonType::String) {
if let Some(elem) = clause
.body
.get(sequence_idx)
.filter(|e| e.ion_type() == IonType::String)
{
name = elem.as_string().map(|s| s.to_string());
sequence_idx += 1;
}

let seq = clause.body.get(sequence_idx)
let seq = clause
.body
.get(sequence_idx)
.and_then(|e| e.as_sequence())
.ok_or(ConformanceErrorKind::ExpectedModelValue)?;
let seq_iter = seq.iter().peekable();
Expand All @@ -170,12 +169,11 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
}
Err(x) => return Err(x),
};
branches.push(EachBranch {
name,
fragment,
});
branches.push(EachBranch { name, fragment });
} else {
let seq = clause.body.get(sequence_idx)
let seq = clause
.body
.get(sequence_idx)
.and_then(|e| e.as_sequence())
.ok_or(ConformanceErrorKind::ExpectedModelValue)?;
let clause = Clause::try_from(seq.clone())?;
Expand All @@ -188,7 +186,9 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
}
}
ClauseType::Signals => {
let msg = clause.body.first()
let msg = clause
.body
.first()
.and_then(|e| e.as_string())
.ok_or(ConformanceErrorKind::ExpectedString)?
.to_string();
Expand All @@ -197,7 +197,6 @@ pub fn parse_continuation(clause: Clause) -> InnerResult<Continuation> {
_ => unreachable!(),
};


Ok(continuation)
}

Expand All @@ -219,19 +218,21 @@ impl Produces {
/// Creates a reader using the provided context, and compares the read values from the input
/// document with the elements specified in the associated Produces clause for equality.
pub fn evaluate(&self, ctx: &Context) -> InnerResult<()> {
use ion_rs::{Decoder, AnyEncoding};
use ion_rs::{AnyEncoding, Decoder};
let (input, _encoding) = ctx.input(ctx.encoding())?;
let mut reader = ion_rs::Reader::new(AnyEncoding.with_catalog(ctx.build_catalog()), input)?;

let mut is_equal = true;
let mut elem_iter = self.elems.iter();

while is_equal {
let (actual_value, expected_elem) = (reader.next()?, elem_iter.next());
let (actual_value, expected_elem) = (reader.read_next_element()?, elem_iter.next());
println!("actual={actual_value:?} expected={expected_elem:?}");
match (actual_value, expected_elem) {
(None, None) => break,
(Some(actual_value), Some(expected_elem)) => {
is_equal &= super::fragment::ProxyElement(expected_elem, ctx) == actual_value
// is_equal &= super::fragment::ProxyElement(expected_elem, ctx) == actual_value
is_equal &= expected_elem.eq(&actual_value);
}
_ => is_equal = false,
}
Expand All @@ -253,17 +254,19 @@ pub(crate) struct Denotes {

impl Denotes {
pub fn evaluate(&self, ctx: &Context) -> InnerResult<()> {
use ion_rs::{Decoder, AnyEncoding};
use ion_rs::{AnyEncoding, Decoder};
let (input, _encoding) = ctx.input(ctx.encoding())?;
println!("input: {input:02x?}");
let mut reader = ion_rs::Reader::new(AnyEncoding.with_catalog(ctx.build_catalog()), input)?;
let mut elem_iter = self.model.iter();

let mut is_equal = true;
while is_equal {
let (read_value, expected_element) = (reader.next()?, elem_iter.next());
is_equal = match (read_value, expected_element) {
(Some(actual), Some(expected)) =>
is_equal && compare_values(ctx, expected, &actual)?,
(Some(actual), Some(expected)) => {
is_equal && compare_values(ctx, expected, &actual)?
}
(None, None) => break,
_ => false,
}
Expand Down Expand Up @@ -299,7 +302,10 @@ impl Then {

/// Determine the encoding (text/binary) of the fragments contained within this Then clause.
fn fragment_encoding(&self) -> IonEncoding {
let enc = self.fragments.iter().find(|f| matches!(f, Fragment::Text(_) | Fragment::Binary(_)));
let enc = self
.fragments
.iter()
.find(|f| matches!(f, Fragment::Text(_) | Fragment::Binary(_)));
match enc {
Some(Fragment::Text(_)) => IonEncoding::Text,
Some(Fragment::Binary(_)) => IonEncoding::Binary,
Expand Down
45 changes: 23 additions & 22 deletions tests/conformance_dsl/fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@
//! so that symbols from the Produces continuation can be evaluated for unknown symbol notation as
//! well.
use super::context::Context;
use super::*;
use ion_rs::{ion_seq, v1_0, v1_1, Encoding, WriteConfig};
use ion_rs::{Element, SExp, Sequence, Struct, Symbol};
use ion_rs::{RawSymbolRef, SequenceWriter, StructWriter, ValueWriter, WriteAsIon, Writer};

use super::context::Context;
use super::*;

/// Shared functionality for Fragments.
trait FragmentImpl {
/// Encode the current fragment into ion given the provided `WriteConfig`
Expand Down Expand Up @@ -193,8 +192,7 @@ pub(crate) struct ProxyElement<'a>(pub &'a Element, pub &'a Context<'a>);

impl ProxyElement<'_> {
fn write_struct<V: ValueWriter>(&self, val: &Struct, writer: V) -> ion_rs::IonResult<()> {
let annotations: Vec<&Symbol> = self.0.annotations().iter().collect();
let annot_writer = writer.with_annotations(annotations)?;
let annot_writer = writer.with_annotations(self.0.annotations())?;
let mut strukt = annot_writer.struct_writer()?;

for (name, value) in val.fields() {
Expand Down Expand Up @@ -342,30 +340,33 @@ impl<T: ion_rs::Decoder> PartialEq<ion_rs::LazyValue<'_, T>> for ProxyElement<'_

impl WriteAsIon for ProxyElement<'_> {
fn write_as_ion<V: ValueWriter>(&self, writer: V) -> ion_rs::IonResult<()> {
match self.0.ion_type() {
IonType::Symbol => self.write_symbol(writer),
IonType::Struct => {
if !self.0.is_null() {
self.write_struct(self.0.as_struct().unwrap(), writer)
} else {
writer.write(self.0)
}
}
IonType::List => {
let annotations: Vec<&Symbol> = self.0.annotations().iter().collect();
let annot_writer = writer.with_annotations(annotations)?;
use ion_rs::Value::*;
match self.0.value() {
Symbol(_) => self.write_symbol(writer),
Struct(strukt) => self.write_struct(strukt, writer),
List(list) => {
let annot_writer = writer.with_annotations(self.0.annotations())?;
let mut list_writer = annot_writer.list_writer()?;
for elem in self.0.as_sequence().unwrap() {
for elem in list {
list_writer.write(ProxyElement(elem, self.1))?;
}
list_writer.close()?;
Ok(())
}
IonType::SExp => {
let annotations: Vec<&Symbol> = self.0.annotations().iter().collect();
let annot_writer = writer.with_annotations(annotations)?;
SExp(sexp) => {
match sexp.get(0).map(Element::value) {
Some(Symbol(symbol)) if symbol.text().is_some() => {
let text = symbol.text().unwrap();
if text.starts_with("#$:") {
todo!("e-expression transcription")
}
}
_ => {}
}

let annot_writer = writer.with_annotations(self.0.annotations())?;
let mut sexp_writer = annot_writer.sexp_writer()?;
for elem in self.0.as_sequence().unwrap() {
for elem in sexp {
sexp_writer.write(ProxyElement(elem, self.1))?;
}
sexp_writer.close()?;
Expand Down
Loading

0 comments on commit f6392b4

Please sign in to comment.