-
Notifications
You must be signed in to change notification settings - Fork 38
Recursive macro expansion in TDL containers #647
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
Changes from all commits
2185cc3
222bcb2
fb37931
22ca798
871205e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ use crate::lazy::binary::raw::value::LazyRawBinaryValue; | |
use crate::lazy::decoder::private::{LazyContainerPrivate, LazyRawValuePrivate}; | ||
use crate::lazy::decoder::{ | ||
LazyDecoder, LazyRawFieldExpr, LazyRawReader, LazyRawSequence, LazyRawStruct, LazyRawValue, | ||
LazyRawValueExpr, | ||
LazyRawValueExpr, RawFieldExpr, RawValueExpr, | ||
}; | ||
use crate::lazy::encoding::{BinaryEncoding_1_0, Never, TextEncoding_1_0, TextEncoding_1_1}; | ||
use crate::lazy::expanded::macro_evaluator::MacroInvocation; | ||
|
@@ -114,11 +114,11 @@ impl<'data> Iterator for LazyRawAnyMacroArgsIterator<'data> { | |
fn next(&mut self) -> Option<Self::Item> { | ||
match self.encoding { | ||
LazyRawAnyMacroArgsIteratorKind::Text_1_1(mut iter) => match iter.next() { | ||
Some(Ok(LazyRawValueExpr::ValueLiteral(value))) => Some(Ok( | ||
LazyRawValueExpr::ValueLiteral(LazyRawAnyValue::from(value)), | ||
)), | ||
Some(Ok(LazyRawValueExpr::MacroInvocation(invocation))) => Some(Ok( | ||
LazyRawValueExpr::MacroInvocation(LazyRawAnyMacroInvocation { | ||
Some(Ok(RawValueExpr::ValueLiteral(value))) => { | ||
Some(Ok(RawValueExpr::ValueLiteral(LazyRawAnyValue::from(value)))) | ||
} | ||
Some(Ok(RawValueExpr::MacroInvocation(invocation))) => Some(Ok( | ||
RawValueExpr::MacroInvocation(LazyRawAnyMacroInvocation { | ||
Comment on lines
-117
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗺️ Now that // Before:
LazyRawValueExpr::ValueLiteral(v)
// After:
LazyRawValueExpr::<'data, D>::ValueLiteral(v) However, the compiler is able to infer the correct types for Unfortunately, that change makes up the lion's share of the line count in this diff. x_x An analogous change has been made for the |
||
encoding: LazyRawAnyMacroInvocationKind::Text_1_1(invocation), | ||
}), | ||
)), | ||
|
@@ -217,12 +217,12 @@ impl<'data> From<LazyRawValueExpr<'data, TextEncoding_1_0>> | |
{ | ||
fn from(value: LazyRawValueExpr<'data, TextEncoding_1_0>) -> Self { | ||
match value { | ||
LazyRawValueExpr::ValueLiteral(v) => LazyRawValueExpr::ValueLiteral(v.into()), | ||
LazyRawValueExpr::MacroInvocation(m) => { | ||
RawValueExpr::ValueLiteral(v) => RawValueExpr::ValueLiteral(v.into()), | ||
RawValueExpr::MacroInvocation(m) => { | ||
let invocation = LazyRawAnyMacroInvocation { | ||
encoding: LazyRawAnyMacroInvocationKind::Text_1_0(m), | ||
}; | ||
LazyRawValueExpr::MacroInvocation(invocation) | ||
RawValueExpr::MacroInvocation(invocation) | ||
} | ||
} | ||
} | ||
|
@@ -233,12 +233,12 @@ impl<'data> From<LazyRawValueExpr<'data, BinaryEncoding_1_0>> | |
{ | ||
fn from(value: LazyRawValueExpr<'data, BinaryEncoding_1_0>) -> Self { | ||
match value { | ||
LazyRawValueExpr::ValueLiteral(v) => LazyRawValueExpr::ValueLiteral(v.into()), | ||
LazyRawValueExpr::MacroInvocation(m) => { | ||
RawValueExpr::ValueLiteral(v) => RawValueExpr::ValueLiteral(v.into()), | ||
RawValueExpr::MacroInvocation(m) => { | ||
let invocation = LazyRawAnyMacroInvocation { | ||
encoding: LazyRawAnyMacroInvocationKind::Binary_1_0(m), | ||
}; | ||
LazyRawValueExpr::MacroInvocation(invocation) | ||
RawValueExpr::MacroInvocation(invocation) | ||
} | ||
} | ||
} | ||
|
@@ -249,12 +249,12 @@ impl<'data> From<LazyRawValueExpr<'data, TextEncoding_1_1>> | |
{ | ||
fn from(value: LazyRawValueExpr<'data, TextEncoding_1_1>) -> Self { | ||
match value { | ||
LazyRawValueExpr::ValueLiteral(v) => LazyRawValueExpr::ValueLiteral(v.into()), | ||
LazyRawValueExpr::MacroInvocation(m) => { | ||
RawValueExpr::ValueLiteral(v) => RawValueExpr::ValueLiteral(v.into()), | ||
RawValueExpr::MacroInvocation(m) => { | ||
let invocation = LazyRawAnyMacroInvocation { | ||
encoding: LazyRawAnyMacroInvocationKind::Text_1_1(m), | ||
}; | ||
LazyRawValueExpr::MacroInvocation(invocation) | ||
RawValueExpr::MacroInvocation(invocation) | ||
} | ||
} | ||
} | ||
|
@@ -731,11 +731,13 @@ impl<'data> From<LazyRawFieldExpr<'data, TextEncoding_1_0>> | |
{ | ||
fn from(text_field: LazyRawFieldExpr<'data, TextEncoding_1_0>) -> Self { | ||
let (name, value) = match text_field { | ||
LazyRawFieldExpr::NameValuePair(name, value) => (name, value), | ||
LazyRawFieldExpr::MacroInvocation(_) => unreachable!("macro invocation in Ion 1.0"), | ||
RawFieldExpr::NameValuePair(name, value) => (name, value), | ||
RawFieldExpr::MacroInvocation(_) => { | ||
unreachable!("macro invocation in Ion 1.0") | ||
} | ||
}; | ||
// Convert the text-encoded value into an any-encoded value | ||
LazyRawFieldExpr::NameValuePair(name, value.into()) | ||
RawFieldExpr::NameValuePair(name, value.into()) | ||
} | ||
} | ||
|
||
|
@@ -744,20 +746,22 @@ impl<'data> From<LazyRawFieldExpr<'data, BinaryEncoding_1_0>> | |
{ | ||
fn from(binary_field: LazyRawFieldExpr<'data, BinaryEncoding_1_0>) -> Self { | ||
let (name, value) = match binary_field { | ||
LazyRawFieldExpr::NameValuePair(name, value) => (name, value), | ||
LazyRawFieldExpr::MacroInvocation(_) => unreachable!("macro invocation in Ion 1.0"), | ||
RawFieldExpr::NameValuePair(name, value) => (name, value), | ||
RawFieldExpr::MacroInvocation(_) => { | ||
unreachable!("macro invocation in Ion 1.0") | ||
} | ||
}; | ||
// Convert the binary-encoded value into an any-encoded value | ||
LazyRawFieldExpr::NameValuePair(name, value.into()) | ||
RawFieldExpr::NameValuePair(name, value.into()) | ||
} | ||
} | ||
|
||
impl<'data> From<LazyRawFieldExpr<'data, TextEncoding_1_1>> | ||
for LazyRawFieldExpr<'data, AnyEncoding> | ||
{ | ||
fn from(text_field: LazyRawFieldExpr<'data, TextEncoding_1_1>) -> Self { | ||
use LazyRawFieldExpr::{MacroInvocation as FieldMacroInvocation, NameValuePair}; | ||
use LazyRawValueExpr::{MacroInvocation as ValueMacroInvocation, ValueLiteral}; | ||
use RawFieldExpr::{MacroInvocation as FieldMacroInvocation, NameValuePair}; | ||
use RawValueExpr::{MacroInvocation as ValueMacroInvocation, ValueLiteral}; | ||
match text_field { | ||
NameValuePair(name, ValueLiteral(value)) => { | ||
NameValuePair(name, ValueLiteral(value.into())) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,35 +35,45 @@ where | |
type MacroInvocation: MacroInvocation<'data, Self>; | ||
} | ||
|
||
/// An item found in value position within an Ion data stream. | ||
/// This item may be either a value literal or a macro invocation. | ||
/// An expression found in value position in either serialized Ion or a template. | ||
/// If it is a value literal, it is considered a stream with exactly one Ion value. | ||
/// If it is a macro invocation, it is a stream with zero or more Ion values. | ||
#[derive(Copy, Clone, Debug)] | ||
pub enum LazyRawValueExpr<'data, D: LazyDecoder<'data>> { | ||
/// A text Ion 1.1 value literal. For example: `5`, `foo`, or `"hello"` | ||
ValueLiteral(D::Value), | ||
/// A text Ion 1.1 macro invocation. For example: `(:employee 12345 "Sarah" "Gonzalez")` | ||
MacroInvocation(D::MacroInvocation), | ||
pub enum RawValueExpr<V, M> { | ||
/// A value literal. For example: `5`, `foo`, or `"hello"` in text. | ||
ValueLiteral(V), | ||
/// An Ion 1.1+ macro invocation. For example: `(:employee 12345 "Sarah" "Gonzalez")` in text. | ||
MacroInvocation(M), | ||
} | ||
|
||
impl<'data, D: LazyDecoder<'data>> LazyRawValueExpr<'data, D> { | ||
pub fn expect_value(self) -> IonResult<D::Value> { | ||
// `RawValueExpr` above has no ties to a particular encoding. The `LazyRawValueExpr` type alias | ||
// below uses the `Value` and `MacroInvocation` associated types from the decoder `D`. In most | ||
// places, this is a helpful constraint; we can talk about the value expression in terms of the | ||
// LazyDecoder it's associated with. However, in some places (primarily when expanding template | ||
// values that don't have a LazyDecoder) we need to be able to use it without constraints. | ||
Comment on lines
+49
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be moved to the doc comments of one or both of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call, I'll add this to #652. |
||
|
||
/// An item found in value position within an Ion data stream written in the encoding represented | ||
/// by the LazyDecoder `D`. This item may be either a value literal or a macro invocation. | ||
pub type LazyRawValueExpr<'data, D> = | ||
RawValueExpr<<D as LazyDecoder<'data>>::Value, <D as LazyDecoder<'data>>::MacroInvocation>; | ||
|
||
impl<V: Debug, M: Debug> RawValueExpr<V, M> { | ||
pub fn expect_value(self) -> IonResult<V> { | ||
match self { | ||
LazyRawValueExpr::ValueLiteral(v) => Ok(v), | ||
LazyRawValueExpr::MacroInvocation(_m) => { | ||
IonResult::decoding_error("expected a value literal, but found macro invocation") | ||
} | ||
RawValueExpr::ValueLiteral(v) => Ok(v), | ||
RawValueExpr::MacroInvocation(_m) => IonResult::decoding_error( | ||
"expected a value literal, but found a macro invocation ({:?})", | ||
), | ||
} | ||
} | ||
|
||
pub fn expect_macro(self) -> IonResult<D::MacroInvocation> { | ||
pub fn expect_macro(self) -> IonResult<M> { | ||
match self { | ||
LazyRawValueExpr::ValueLiteral(v) => IonResult::decoding_error(format!( | ||
"expected a macro invocation but found a value literal {:?}", | ||
RawValueExpr::ValueLiteral(v) => IonResult::decoding_error(format!( | ||
"expected a macro invocation but found a value literal ({:?})", | ||
v | ||
)), | ||
LazyRawValueExpr::MacroInvocation(m) => Ok(m), | ||
RawValueExpr::MacroInvocation(m) => Ok(m), | ||
} | ||
} | ||
} | ||
|
@@ -74,15 +84,27 @@ impl<'data, D: LazyDecoder<'data>> LazyRawValueExpr<'data, D> { | |
/// * a name/e-expression pair | ||
/// * an e-expression | ||
#[derive(Debug)] | ||
pub enum LazyRawFieldExpr<'data, D: LazyDecoder<'data>> { | ||
NameValuePair(RawSymbolTokenRef<'data>, LazyRawValueExpr<'data, D>), | ||
MacroInvocation(D::MacroInvocation), | ||
pub enum RawFieldExpr<'name, V, M> { | ||
NameValuePair(RawSymbolTokenRef<'name>, RawValueExpr<V, M>), | ||
MacroInvocation(M), | ||
} | ||
|
||
impl<'data, D: LazyDecoder<'data>> LazyRawFieldExpr<'data, D> { | ||
pub fn expect_name_value(self) -> IonResult<(RawSymbolTokenRef<'data>, D::Value)> { | ||
// As with the `RawValueExpr`/`LazyRawValueExpr` type pair, a `RawFieldExpr` has no constraints | ||
// on the types used for values or macros, while the `LazyRawFieldExpr` type alias below uses the | ||
// value and macro types associated with the decoder `D`. | ||
|
||
/// An item found in struct field position an Ion data stream written in the encoding represented | ||
/// by the LazyDecoder `D`. | ||
pub type LazyRawFieldExpr<'data, D> = RawFieldExpr< | ||
'data, | ||
<D as LazyDecoder<'data>>::Value, | ||
<D as LazyDecoder<'data>>::MacroInvocation, | ||
>; | ||
|
||
impl<'name, V: Debug, M: Debug> RawFieldExpr<'name, V, M> { | ||
pub fn expect_name_value(self) -> IonResult<(RawSymbolTokenRef<'name>, V)> { | ||
match self { | ||
LazyRawFieldExpr::NameValuePair(name, LazyRawValueExpr::ValueLiteral(value)) => { | ||
RawFieldExpr::NameValuePair(name, RawValueExpr::ValueLiteral(value)) => { | ||
Ok((name, value)) | ||
} | ||
_ => IonResult::decoding_error(format!( | ||
|
@@ -92,22 +114,21 @@ impl<'data, D: LazyDecoder<'data>> LazyRawFieldExpr<'data, D> { | |
} | ||
} | ||
|
||
pub fn expect_name_macro(self) -> IonResult<(RawSymbolTokenRef<'data>, D::MacroInvocation)> { | ||
pub fn expect_name_macro(self) -> IonResult<(RawSymbolTokenRef<'name>, M)> { | ||
match self { | ||
LazyRawFieldExpr::NameValuePair( | ||
name, | ||
LazyRawValueExpr::MacroInvocation(invocation), | ||
) => Ok((name, invocation)), | ||
RawFieldExpr::NameValuePair(name, RawValueExpr::MacroInvocation(invocation)) => { | ||
Ok((name, invocation)) | ||
} | ||
_ => IonResult::decoding_error(format!( | ||
"expected a name/macro pair but found {:?}", | ||
self | ||
)), | ||
} | ||
} | ||
|
||
pub fn expect_macro(self) -> IonResult<D::MacroInvocation> { | ||
pub fn expect_macro(self) -> IonResult<M> { | ||
match self { | ||
LazyRawFieldExpr::MacroInvocation(invocation) => Ok(invocation), | ||
RawFieldExpr::MacroInvocation(invocation) => Ok(invocation), | ||
_ => IonResult::decoding_error(format!( | ||
"expected a macro invocation but found {:?}", | ||
self | ||
|
@@ -125,6 +146,7 @@ impl<'data, D: LazyDecoder<'data>> LazyRawFieldExpr<'data, D> { | |
// internal code that is defined in terms of `LazyRawField` to call the private `into_value()` | ||
// function while also preventing users from seeing or depending on it. | ||
pub(crate) mod private { | ||
use crate::lazy::encoding::RawValueLiteral; | ||
use crate::{IonResult, RawSymbolTokenRef}; | ||
|
||
use super::LazyDecoder; | ||
|
@@ -143,7 +165,7 @@ pub(crate) mod private { | |
fn from_value(value: D::Value) -> Self; | ||
} | ||
|
||
pub trait LazyRawValuePrivate<'data> { | ||
pub trait LazyRawValuePrivate<'data>: RawValueLiteral { | ||
/// Returns the field name associated with this value. If the value is not inside a struct, | ||
/// returns `IllegalOperation`. | ||
fn field_name(&self) -> IonResult<RawSymbolTokenRef<'data>>; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗺️ The enum
LazyRawValueExpr<'data, D>
can be either a value literal (D::Value
) or a macro invocation (D::MacroInvocation
). Starting with this PR, we needed the ability to talk about value expressions that might have come from templates, which are not a kind of stream encoding and so do not have a corresponding implementationD: LazyDecoder<'data>
.The new enum
RawValueExpr<V, M>
allows any types to be used as the value (V
) and the macro invocation (M
).LazyRawValueExpr<'data, D>
is now a type alias for the most common kind of value expression:An analogous change has been made for the
LazyRawFieldExpr
/RawFieldExpr
pair.