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

Includes various small fixes for tagless parameters, expression groups, and system macro invocations. #975

Merged
merged 1 commit into from
Oct 16, 2024

Conversation

tgregg
Copy link
Contributor

@tgregg tgregg commented Oct 16, 2024

Description of changes:

Includes various small fixes for tagless parameters, expression groups, and system macro invocations. See comments inline for a guide.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@@ -3361,6 +3361,10 @@ private void setCheckpointAfterValueHeader() {
case START_CONTAINER:
setCheckpoint(CheckpointLocation.AFTER_CONTAINER_HEADER);
break;
case NEEDS_INSTRUCTION:
// A macro invocation header has just been read.
setCheckpoint(CheckpointLocation.BEFORE_UNANNOTATED_TYPE_ID);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This moves the cursor past the macro invocation header, positioning it on the first argument (if any). This method is called when parsing expression groups.

@@ -1449,7 +1449,7 @@ private void readGroupExpression(Macro.Parameter parameter, List<Expression.EExp
int startIndex = expressions.size();
expressions.add(Expression.Placeholder.INSTANCE);
boolean isSingleton = true;
while (nextGroupedValue() != Event.NEEDS_INSTRUCTION) {
while (nextGroupedValue() != Event.NEEDS_INSTRUCTION || isMacroInvocation()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NEEDS_INSTRUCTION is used either when the end of the group has been reached, or when a macro invocation header has been encountered. When it's the latter, we need to read the invocation as an expression to continue progressing through the group.

@@ -1560,7 +1560,7 @@ protected PresenceBitmap loadPresenceBitmapIfNecessary(List<Macro.Parameter> sig

@Override
protected boolean isMacroInvocation() {
return valueTid.isMacroInvocation;
return valueTid != null && valueTid.isMacroInvocation;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is now called when the cursor may be at the end of the group, at which point valueTid will be null.

Comment on lines +1214 to +1215
List<SymbolToken> annotations = getAnnotations();
boolean isSystemMacro = !annotations.isEmpty() && SystemSymbols_1_1.ION.getText().equals(annotations.get(0).getText());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added macroInvocationInTaggedExpressionGroup test exercises this because it invokes the values macro from a context that does not export the Ion 1.1 system macros. The invocation looks like (:$ion::values ...)

@@ -859,12 +859,12 @@ class IonRawBinaryWriter_1_1 internal constructor(
thisContainerTotalLength++
} else if (isTagless) {
// End tagless group -- write the number of expressions, end with FlexUInt 0
thisContainerTotalLength += writeCurrentContainerLength(lengthPrefixPreallocation)
thisContainerTotalLength += writeCurrentContainerLength(maxOf(1, lengthPrefixPreallocation))
Copy link
Contributor Author

@tgregg tgregg Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now symmetrical with stepInExpressionGroup for this case, which always reserves at least one byte for the length. Without this fix, the byte is reserved in the buffer and a patch point is added, resulting in an erroneous extra byte in the final output. The same can be said for the other change in this file.

This change is verified by the added taglessExpressionGroup test.

buffer.writeByte(FlexInt.ZERO)
thisContainerTotalLength++
} else if (currentContainer.isLengthPrefixed) {
// Length-prefixed, tagged -- write the number of bytes
thisContainerTotalLength += writeCurrentContainerLength(lengthPrefixPreallocation)
thisContainerTotalLength += writeCurrentContainerLength(maxOf(1, lengthPrefixPreallocation))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exercised by the added macroInvocationInTaggedExpressionGroup test.

Comment on lines +88 to +101
val parameterEncoding = when (annotations.size) {
0 -> Macro.ParameterEncoding.Tagged
1 -> {
val encodingText = annotations[0].text
val encoding = Macro.ParameterEncoding.entries.singleOrNull { it.ionTextName == encodingText }
if (encoding == null) {
// TODO: Check for macro-shaped parameter encodings, and only if it's still null, we throw.
throw IonException("unsupported parameter encoding $annotations")
}
encoding
}
2 -> TODO("Qualified references for macro-shaped parameters")
else -> throw IonException("unsupported parameter encoding $annotations")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This patch is contributed by @popematt, and is exercised by the added taglessExpressionGroup test.

@@ -136,6 +141,30 @@ private static void writeMacroSignature(IonRawWriter_1_1 writer, Map<String, Int
writer.stepOut();
}

private static void writeMacroSignatureFromDatagram(IonRawWriter_1_1 writer, Map<String, Integer> symbols, IonDatagram... signature) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows us to specify tagless encodings. The other variant just takes a String, without a way to add an encoding annotation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fascinating use of IonDatagram for "unmodeled sequence of values". I did a double-take.

Copy link
Contributor

@popematt popematt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@tgregg tgregg merged commit d402b46 into ion-11-encoding Oct 16, 2024
17 checks passed
@tgregg tgregg deleted the ion-11-encoding-invocation-in-group branch October 16, 2024 21:36
@@ -136,6 +141,30 @@ private static void writeMacroSignature(IonRawWriter_1_1 writer, Map<String, Int
writer.stepOut();
}

private static void writeMacroSignatureFromDatagram(IonRawWriter_1_1 writer, Map<String, Integer> symbols, IonDatagram... signature) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fascinating use of IonDatagram for "unmodeled sequence of values". I did a double-take.

Comment on lines +147 to +149
if (parameter.size() > 2) {
throw new IllegalStateException("Parameters can only have two components: a name and a cardinality.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (parameter.size() > 2) {
throw new IllegalStateException("Parameters can only have two components: a name and a cardinality.");
}
if (parameter.size() > 2) {
throw new IllegalStateException("Parameters can only have two components: a name and a cardinality.");
}
if (parameter.size() < 1) {
throw new IllegalStateException("Parameters must have at least one component: a name.");
}

Comment on lines +1085 to +1091
writer.stepInEExp(0, false, expectedMacro); {
writer.stepInExpressionGroup(true); {
writer.stepInEExp(SystemMacro.Values); {
writer.writeString("bar");
} writer.stepOut();
} writer.stepOut();
} writer.stepOut();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you're also using the stepIn/Out idiom from old IonJava tests :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants