diff --git a/src/constants.rs b/src/constants.rs index d5688e41c..fea5ac564 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -59,7 +59,7 @@ pub(crate) mod v1_1 { "symbols", // $7 "max_id", // $8 "$ion_shared_symbol_table", // $9 - "$ion_encoding", // $10 + "encoding", // $10 "$ion_literal", // $11 "$ion_shared_module", // $12 "macro", // $13 @@ -120,7 +120,8 @@ pub(crate) mod v1_1 { pub mod system_symbols { use crate::raw_symbol_ref::SystemSymbol_1_1; - pub const ION_ENCODING: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(10); + pub const ION: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(1); + pub const ENCODING: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(10); pub const SYMBOL_TABLE: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(15); pub const EMPTY_TEXT: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(21); pub const ADD_SYMBOLS: SystemSymbol_1_1 = SystemSymbol_1_1::new_unchecked(45); diff --git a/src/lazy/binary/raw/v1_1/immutable_buffer.rs b/src/lazy/binary/raw/v1_1/immutable_buffer.rs index 78ba7c17c..5f8e28721 100644 --- a/src/lazy/binary/raw/v1_1/immutable_buffer.rs +++ b/src/lazy/binary/raw/v1_1/immutable_buffer.rs @@ -1269,15 +1269,15 @@ mod tests { RawSymbolRef::SymbolId(5) ])] #[case::one_flex_syms_with_system_symbol(AnnotationsEncoding::FlexSym, &[0xE7, 0x01, 0x6A], 1, 2, &[ - RawSymbolRef::Text("$ion_encoding"), + RawSymbolRef::Text("encoding"), ])] #[case::two_flex_syms_with_system_symbols(AnnotationsEncoding::FlexSym, &[0xE8, 0x01, 0x60, 0x01, 0x6A], 1, 4, &[ RawSymbolRef::SymbolId(0), - RawSymbolRef::Text("$ion_encoding"), + RawSymbolRef::Text("encoding"), ])] #[case::three_flex_syms_with_system_symbols(AnnotationsEncoding::FlexSym, &[0xE9, 0x0D, 0x01, 0x60, 0x01, 0x6A, 0x01, 0xA1], 2, 6, &[ RawSymbolRef::SymbolId(0), - RawSymbolRef::Text("$ion_encoding"), + RawSymbolRef::Text("encoding"), RawSymbolRef::Text("make_field"), ])] fn read_annotations_sequence( @@ -1623,8 +1623,7 @@ mod tests { // Construct an encoding directive that defines this number of macros. Each macro will expand // to its own address. - let mut macro_definitions = - String::from("$ion_encoding::(\n (macro_table $ion_encoding\n"); + let mut macro_definitions = String::from("$ion::\n(module _\n (macro_table _\n"); for address in MacroTable::FIRST_USER_MACRO_ID..MAX_TEST_MACRO_ADDRESS { writeln!(macro_definitions, " (macro m{address} () {address})")?; } diff --git a/src/lazy/binary/raw/v1_1/reader.rs b/src/lazy/binary/raw/v1_1/reader.rs index 684447b18..b684a79f5 100644 --- a/src/lazy/binary/raw/v1_1/reader.rs +++ b/src/lazy/binary/raw/v1_1/reader.rs @@ -347,7 +347,7 @@ mod tests { 0xE3, 0x01, 0x00, 0x00, // System symbols - 0xEE, 0x0A, // $ion_encoding + 0xEE, 0x0A, // encoding 0xEE, 0x0E, // macro_table 0xEE, 0x15, // empty text 0xEE, 0x41, // make_field @@ -364,7 +364,7 @@ mod tests { RawSymbolRef::SymbolId(1), RawSymbolRef::SymbolId(257), RawSymbolRef::SymbolId(65_793), - RawSymbolRef::Text("$ion_encoding"), + RawSymbolRef::Text("encoding"), RawSymbolRef::Text("macro_table"), RawSymbolRef::Text(""), RawSymbolRef::Text("make_field"), diff --git a/src/lazy/binary/raw/v1_1/struct.rs b/src/lazy/binary/raw/v1_1/struct.rs index 293cbb5fc..9e75ce1fb 100644 --- a/src/lazy/binary/raw/v1_1/struct.rs +++ b/src/lazy/binary/raw/v1_1/struct.rs @@ -335,10 +335,11 @@ mod tests { let mut writer = Writer::new(v1_1::Binary, Vec::new())?; let encoding_directive = Element::read_one( r#" - $ion_encoding::( - (symbol_table $ion_encoding) + $ion:: + (module _ + (symbol_table _) (macro_table - $ion_encoding + _ (macro greet (name) (.make_string "hello, " (%name))) ) ) diff --git a/src/lazy/encoder/writer.rs b/src/lazy/encoder/writer.rs index 766d313ed..8ee1944e6 100644 --- a/src/lazy/encoder/writer.rs +++ b/src/lazy/encoder/writer.rs @@ -165,9 +165,11 @@ impl Writer { let mut directive = directive_writer .value_writer() - .with_annotations(v1_1::system_symbols::ION_ENCODING)? + .with_annotations(v1_1::system_symbols::ION)? .sexp_writer()?; + directive.write_symbol("module")?.write_symbol("_")?; + let pending_symbols = context .symbol_table .symbols_tail(context.num_pending_symbols) @@ -177,7 +179,7 @@ impl Writer { let mut symbol_table = directive.sexp_writer()?; symbol_table .write_symbol(v1_1::system_symbols::SYMBOL_TABLE)? - .write_symbol(v1_1::system_symbols::ION_ENCODING)? + .write_symbol("_")? .write_list(pending_symbols)?; symbol_table.close()?; directive.close() diff --git a/src/lazy/expanded/compiler.rs b/src/lazy/expanded/compiler.rs index 73456aba1..6c8d5495e 100644 --- a/src/lazy/expanded/compiler.rs +++ b/src/lazy/expanded/compiler.rs @@ -460,11 +460,9 @@ impl TemplateCompiler { match module_name { // If the module is `$ion`, this refers to the system module. "$ion" => ION_1_1_SYSTEM_MACROS.clone_macro_with_id(macro_id), - // If the module is `$ion_encoding`, this refers to the active encoding module. - "$ion_encoding" => context.macro_table().clone_macro_with_id(macro_id), - _ => todo!( - "qualified references to modules other than $ion_encoding (found {module_name}" - ), + // If the module is `_`, this refers to the active encoding module. + "_" => context.macro_table().clone_macro_with_id(macro_id), + _ => todo!("qualified references to modules other than `_` (found `{module_name}`"), } } @@ -1725,9 +1723,10 @@ mod tests { let ion = r#" $ion_1_1 - $ion_encoding::( + $ion:: + (module _ (macro_table - $ion_encoding + _ (macro hello (name) (.make_string "hello " (%name))) (macro hello_world () (.hello "world")) // Depends on macro 'hello' ) diff --git a/src/lazy/expanded/macro_evaluator.rs b/src/lazy/expanded/macro_evaluator.rs index 8f629a176..bd270af59 100644 --- a/src/lazy/expanded/macro_evaluator.rs +++ b/src/lazy/expanded/macro_evaluator.rs @@ -1350,7 +1350,8 @@ mod tests { stream_eq( r#" // Define macro `double` - $ion_encoding::( + $ion:: + (module _ (macro_table $ion (macro double (x) (.$ion::values (%x) (%x))) @@ -1359,7 +1360,8 @@ mod tests { // `double` exists until the *end* of the encoding directive below. Define a new // macro that depends on `double`. - $ion_encoding::( + $ion:: + (module _ (macro_table (macro quadruple (y) (.$ion::values @@ -1367,7 +1369,7 @@ mod tests { // to it without qualification. (.double (%y)) // We could also refer to it with a qualification. - (.$ion_encoding::double (%y)))) + (._::double (%y)))) ) ) @@ -1388,23 +1390,25 @@ mod tests { stream_eq( r#" // Define macro `double` - $ion_encoding::( + $ion:: + (module _ (macro_table - $ion_encoding + _ (macro double (x) (.values (%x) (%x))) ) ) - $ion_encoding::( + $ion:: + (module _ (macro_table - $ion_encoding // Re-export the active encoding module's macros + _ // Re-export the active encoding module's macros (macro quadruple (y) (.$ion::values // Because `double` has been added to the local namespace, // we can refer to it without a qualified reference. (.double (%y)) // However, we can also refer to it using a qualified reference. - (.$ion_encoding::double (%y)))) + (._::double (%y)))) ) ) @@ -1456,7 +1460,8 @@ mod tests { fn multiple_arg_expr_groups() -> IonResult<()> { stream_eq( r#" - $ion_encoding::( + $ion:: + (module _ (macro_table (macro foo (x+ y* z+) (.make_string (.. (%x) "-" (%y) "-" (%z)))) @@ -1540,7 +1545,8 @@ mod tests { stream_eq( r#" // Define some symbols - $ion_encoding::( + $ion:: + (module _ (symbol_table ["foo", "bar"]) // $1, $2 ) // Use them @@ -1608,7 +1614,8 @@ mod tests { // TODO: update symbol IDs when reading and writing system symbols are implemented stream_eq( r#" - $ion_encoding::( + $ion:: + (module _ (symbol_table ["foo", "bar", "baz"]) // $1, $2, $3 ) $1 @@ -1686,7 +1693,8 @@ mod tests { // TODO: update symbol IDs when reading and writing system symbols are implemented stream_eq( r#" - $ion_encoding::( + $ion:: + (module _ (symbol_table ["foo", "bar", "baz"]) // $1, $2, $3 ) $1 @@ -1727,7 +1735,8 @@ mod tests { eval_template_invocation( r#" (macro def_macros (macros*) - $ion_encoding::( + $ion:: + (module _ (macro_table (%macros)) ) )"#, diff --git a/src/lazy/expanded/macro_table.rs b/src/lazy/expanded/macro_table.rs index f51920310..4885dc89b 100644 --- a/src/lazy/expanded/macro_table.rs +++ b/src/lazy/expanded/macro_table.rs @@ -292,11 +292,12 @@ impl MacroTable { template( r#" (macro set_symbols (symbols*) - $ion_encoding::( + $ion:: + (module _ // Set a new symbol table (symbol_table [(%symbols)]) // Include the active encoding module macros - (macro_table $ion_encoding) + (macro_table _) ) ) "#, @@ -304,11 +305,12 @@ impl MacroTable { template( r#" (macro add_symbols (symbols*) - $ion_encoding::( + $ion:: + (module _ // Set a new symbol table - (symbol_table $ion_encoding [(%symbols)]) + (symbol_table _ [(%symbols)]) // Include the active encoding module macros - (macro_table $ion_encoding) + (macro_table _) ) ) "#, @@ -316,9 +318,10 @@ impl MacroTable { template( r#" (macro set_macros (macro_definitions*) - $ion_encoding::( + $ion:: + (module _ // Include the active encoding module symbols - (symbol_table $ion_encoding) + (symbol_table _) // Set a new macro table (macro_table (%macro_definitions)) ) @@ -328,11 +331,12 @@ impl MacroTable { template( r#" (macro add_macros (macro_definitions*) - $ion_encoding::( + $ion:: + (module _ // Include the active encoding module symbols - (symbol_table $ion_encoding) + (symbol_table _) // Set a new macro table - (macro_table $ion_encoding (%macro_definitions)) + (macro_table _ (%macro_definitions)) ) ) "#, diff --git a/src/lazy/system_reader.rs b/src/lazy/system_reader.rs index 81bbe59db..d10df8dfc 100644 --- a/src/lazy/system_reader.rs +++ b/src/lazy/system_reader.rs @@ -164,8 +164,8 @@ impl SystemReader { Ok(false) } - /// Returns `true` if the provided `LazyRawValue` is an s-expression whose first annotation - /// is `$ion_encoding`. Caller is responsible for confirming the sexp appeared at the top + /// Returns `true` if the provided `LazyRawValue` is an s-expression whose only annotation + /// is `$ion`. Caller is responsible for confirming the sexp appeared at the top /// level AND that this stream is encoded using Ion 1.1. pub(crate) fn is_encoding_directive_sexp( lazy_value: &'_ LazyExpandedValue<'_, Encoding>, @@ -176,11 +176,13 @@ impl SystemReader { if !lazy_value.has_annotations() { return Ok(false); } - // At this point, we've confirmed it's an annotated s-expression. We need to see if its - // first annotation has the text `$ion_encoding`, which may involve a lookup in the - // encoding context. We'll promote this LazyExpandedValue to a LazyValue to enable that. + // At this point, we've confirmed it's an annotated s-expression. We need to see if: + // 1. It only has one annotation + // 2. That annotation is `$ion` + // This may involve a lookup in the encoding context. + // We'll promote this LazyExpandedValue to a LazyValue to facilitate that. let lazy_value = LazyValue::new(*lazy_value); - lazy_value.annotations().starts_with(["$ion_encoding"]) + lazy_value.annotations().are(["$ion"]) } pub fn symbol_table(&self) -> &SymbolTable { @@ -225,8 +227,33 @@ impl SystemReader { directive: LazyExpandedValue<'_, Encoding>, ) -> IonResult<()> { // We've already confirmed this is an annotated sexp - let directive = directive.read()?.expect_sexp()?; - for step in directive.iter() { + let directive = LazyValue::new(directive).read()?.expect_sexp()?; + let mut exprs = directive.iter(); + let operation = Self::expect_next_sexp_value("operation name", &mut exprs)?; + let operation_name = Self::expect_symbol_text("operation name", operation)?; + // For now, the only supported directive is `$ion::(module _ /*...*/)`. + match operation_name { + "module" => {} + todo_operation @ ("encoding" | "import") => { + return IonResult::decoding_error(format!( + "directive operation `{todo_operation}` is not yet supported" + )); + } + invalid_operation => { + return IonResult::decoding_error(format!( + "unrecognized directive operation `{invalid_operation}`" + )); + } + } + + let module_name = Self::expect_next_sexp_value("module name", &mut exprs)?; + let module_name = Self::expect_symbol_text("module name", module_name)?; + + if module_name != "_" { + return IonResult::decoding_error("only the default module `_` is currently supported"); + } + + for step in exprs { Self::process_encoding_directive_operation(pending_changes, step?)?; } Ok(()) @@ -234,9 +261,9 @@ impl SystemReader { pub(crate) fn process_encoding_directive_operation( pending_changes: &mut PendingContextChanges, - value: LazyExpandedValue<'_, Encoding>, + value: LazyValue<'_, Encoding>, ) -> IonResult<()> { - let operation_sexp = LazyValue::new(value).read()?.expect_sexp().map_err(|_| { + let operation_sexp = value.read()?.expect_sexp().map_err(|_| { IonError::decoding_error(format!( "found an encoding directive step that was not an s-expression: {value:?}" )) @@ -254,7 +281,7 @@ impl SystemReader { let symbol_table = Self::process_symbol_table_definition(operation_sexp)?; let new_encoding_module = match pending_changes.take_new_active_module() { None => EncodingModule::new( - "$ion_encoding".to_owned(), + "_".to_owned(), MacroTable::with_system_macros(IonVersion::v1_1), symbol_table, ), @@ -269,7 +296,7 @@ impl SystemReader { let macro_table = Self::process_macro_table_definition(operation_sexp)?; let new_encoding_module = match pending_changes.take_new_active_module() { None => EncodingModule::new( - "$ion_encoding".to_owned(), + "_".to_owned(), macro_table, SymbolTable::empty(IonVersion::v1_1), ), @@ -334,14 +361,14 @@ impl SystemReader { let mut symbol_table = SymbolTable::empty(IonVersion::v1_1); for arg in args { match arg?.read()? { - ValueRef::Symbol(symbol) if symbol == "$ion_encoding" => { + ValueRef::Symbol(symbol) if symbol == "_" => { let active_symtab = operation.expanded().context.symbol_table(); for symbol in active_symtab.application_symbols() { symbol_table.add_symbol(symbol.clone()); } } ValueRef::Symbol(symbol) => { - todo!("modules other than $ion_encoding (found symbol '{symbol:?}')") + todo!("modules other than _ (found symbol '{symbol:?}')") } ValueRef::List(symbol_list) => { for value in symbol_list { @@ -387,7 +414,7 @@ impl SystemReader { TemplateCompiler::compile_from_sexp(context, ¯o_table, macro_def_sexp)?; macro_table.add_macro(new_macro)?; } - ValueRef::Symbol(module_name) if module_name == "$ion_encoding" => { + ValueRef::Symbol(module_name) if module_name == "_" => { let active_mactab = operation.expanded().context.macro_table(); macro_table.append_all_macros_from(active_mactab)?; } @@ -395,7 +422,7 @@ impl SystemReader { macro_table.append_all_macros_from(&ION_1_1_SYSTEM_MACROS)?; } ValueRef::Symbol(_module_name) => { - todo!("re-exporting macros from a module other than $ion_encoding") + todo!("re-exporting macros from a module other than _") } _other => { return IonResult::decoding_error(format!( @@ -1008,7 +1035,9 @@ mod tests { fn detect_encoding_directive_text() -> IonResult<()> { let text = r#" $ion_1_1 - $ion_encoding::((symbol_table ["foo", "bar", "baz"])) + $ion:: + (module _ + (symbol_table ["foo", "bar", "baz"])) "#; let mut reader = SystemReader::new(AnyEncoding, text); @@ -1024,8 +1053,10 @@ mod tests { let mut writer = LazyRawBinaryWriter_1_1::new(Vec::new())?; let mut directive = writer .value_writer() - .with_annotations("$ion_encoding")? + .with_annotations("$ion")? .sexp_writer()?; + directive.write_symbol("module")?.write_symbol("_")?; + let mut symbol_table = directive.sexp_writer()?; symbol_table.write_symbol("symbol_table")?; symbol_table.write_list(["foo", "bar", "baz"])?; @@ -1044,13 +1075,15 @@ mod tests { let text = r#" $ion_1_0 // In Ion 1.0, this is just an annotated s-expression. - $ion_encoding::((symbol_table ["foo", "bar", "baz"])) + $ion:: + (encoding _ + (symbol_table ["foo", "bar", "baz"])) "#; let mut reader = SystemReader::new(AnyEncoding, text); assert_eq!(reader.next_item()?.expect_ivm()?.major_minor(), (1, 0)); let sexp = reader.next_item()?.expect_value()?.read()?.expect_sexp()?; - assert!(sexp.annotations().are(["$ion_encoding"])?); + assert!(sexp.annotations().are(["$ion"])?); Ok(()) } @@ -1059,8 +1092,9 @@ mod tests { let mut writer = Writer::new(v1_0::Binary, Vec::new())?; let mut directive = writer .value_writer() - .with_annotations("$ion_encoding")? + .with_annotations("$ion")? .sexp_writer()?; + directive.write_symbol("module")?.write_symbol("_")?; let mut symbol_table = directive.sexp_writer()?; symbol_table.write_symbol("symbol_table")?; symbol_table.write_list(["foo", "bar", "baz"])?; @@ -1072,7 +1106,7 @@ mod tests { assert_eq!(reader.next_item()?.expect_ivm()?.major_minor(), (1, 0)); let _ = reader.next_item()?.expect_symbol_table()?; let sexp = reader.next_item()?.expect_value()?.read()?.expect_sexp()?; - assert!(sexp.annotations().are(["$ion_encoding"])?); + assert!(sexp.annotations().are(["$ion"])?); Ok(()) } @@ -1081,10 +1115,11 @@ mod tests { fn read_encoding_directive_new_active_module() -> IonResult<()> { let ion = r#" $ion_1_1 - $ion_encoding::( + $ion:: + (module _ (symbol_table ["foo", "bar", "baz"]) (macro_table - $ion_encoding + _ (macro seventeen () 17) (macro twelve () 12))) (:seventeen) diff --git a/src/lazy/system_stream_item.rs b/src/lazy/system_stream_item.rs index b7cf2da3f..4d00ec3a1 100644 --- a/src/lazy/system_stream_item.rs +++ b/src/lazy/system_stream_item.rs @@ -15,7 +15,7 @@ pub enum SystemStreamItem<'top, D: Decoder> { VersionMarker(D::VersionMarker<'top>), /// An Ion 1.0-style symbol table encoded as a struct annotated with `$ion_symbol_table`. SymbolTable(LazyStruct<'top, D>), - /// An Ion 1.1 encoding directive; an s-expression annotated with `$ion_encoding`. + /// An Ion 1.1 encoding directive; an s-expression annotated with `$ion`. EncodingDirective(LazySExp<'top, D>), /// An application-level Ion value Value(LazyValue<'top, D>), diff --git a/tests/conformance_dsl/fragment.rs b/tests/conformance_dsl/fragment.rs index 356c75719..f681e492e 100644 --- a/tests/conformance_dsl/fragment.rs +++ b/tests/conformance_dsl/fragment.rs @@ -96,9 +96,7 @@ impl Fragment { Ok(bytes.to_owned()) } Fragment::Binary(_) => unreachable!(), - Fragment::Ivm(maj, min) => { - Ok(format!("$ion_{}_{}", maj, min).as_bytes().to_owned()) - } + Fragment::Ivm(maj, min) => Ok(format!("$ion_{}_{}", maj, min).as_bytes().to_owned()), } } @@ -151,7 +149,7 @@ impl TryFrom for Fragment { // Rather than treat Encoding special, we expand it to a (toplevel ..) as described // in the spec. let inner: Element = SExp(Sequence::new(other.body)).into(); - let inner = inner.with_annotations(["$ion_encoding"]); + let inner = inner.with_annotations(["$ion"]); Fragment::TopLevel(TopLevel { elems: vec![inner] }) } ClauseType::MacTab => { diff --git a/tests/conformance_tests.rs b/tests/conformance_tests.rs index b529fcb2a..2937e32fb 100644 --- a/tests/conformance_tests.rs +++ b/tests/conformance_tests.rs @@ -62,7 +62,7 @@ mod implementation { fn test_encoding() { let test: &str = r#" (ion_1_1 - (encoding (macro_table (macro m () 1))) + (encoding module _ (macro_table (macro m () 1))) (text "(:m)") (produces 1) )"#;