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

Add stubs for macro evaluator #923

Merged
merged 3 commits into from
Aug 15, 2024
Merged

Conversation

popematt
Copy link
Contributor

Issue #, if available:

#729, #730

Description of changes:

  • Refactors TemplateBodyExpression into Expression, a generalized form that is useful for macro evaluation
  • Updates MacroCompiler to use the correct syntax for expression groups
  • Adds stubs of MacroEvaluator, MacroExpressionizer (not a great name, I know), and an example of how to bridge between the macro evaluator and an IonReader.
  • ...and a few other minor changes/improvements.

There are some comments in the PR.

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

Copy link

codecov bot commented Aug 14, 2024

Codecov Report

Attention: Patch coverage is 36.04651% with 110 lines in your changes missing coverage. Please review.

Please upload report for BASE (ion-11-encoding@507c51f). Learn more about missing BASE report.

Files Patch % Lines
...amazon/ion/impl/macro/MacroEvaluatorAsIonReader.kt 0.00% 69 Missing ⚠️
.../main/java/com/amazon/ion/impl/macro/Expression.kt 53.22% 21 Missing and 8 partials ⚠️
...n/java/com/amazon/ion/impl/macro/MacroEvaluator.kt 0.00% 6 Missing ⚠️
.../java/com/amazon/ion/impl/macro/EncodingContext.kt 0.00% 3 Missing ⚠️
...a/com/amazon/ion/impl/macro/MacroExpressionizer.kt 0.00% 2 Missing ⚠️
...in/java/com/amazon/ion/impl/macro/MacroCompiler.kt 95.65% 1 Missing ⚠️
Additional details and impacted files
@@                Coverage Diff                 @@
##             ion-11-encoding     #923   +/-   ##
==================================================
  Coverage                   ?   69.52%           
  Complexity                 ?     6589           
==================================================
  Files                      ?      189           
  Lines                      ?    26057           
  Branches                   ?     4691           
==================================================
  Hits                       ?    18115           
  Misses                     ?     6537           
  Partials                   ?     1405           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor Author

@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.

I probably have a bunch of small things that I've overlooked here. I've been staring at this code for too long, and I just need another set of eyes on it at this point.

@@ -0,0 +1,15 @@
package com.amazon.ion.impl.macro
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
package com.amazon.ion.impl.macro
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package com.amazon.ion.impl.macro

ExactlyOne('!'),
OneOrMore('+'),
ZeroOrMore('*');
enum class ParameterCardinality(@JvmField val sigil: Char, @JvmField val canBeVoid: Boolean, @JvmField val canBeMulti: Boolean) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ Added these because as I was working on the macro evaluator, I came across situations where I wanted to simply check "can this be void" or "can this be multiple expressions".

is Expression.BigIntValue -> intExpression.value
}

override fun doubleValue(): Double = (currentValueExpression as Expression.FloatValue).value
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️

Error handling is inconsistent with other [IonReader] implementations

This is one specific instance here. If the reader is on e.g. a StringValue expression, and you call doubleValue(), this will throw a ClassCastException. This will get fixed up in subsequent PRs once I have the macro evaluator and I'm able to more easily run tests on this class.

MacroInvocation(ByName("values"), startInclusive = 1, endInclusive = 2),
Variable(0),
SExpValue(emptyList(), startInclusive = 3, endInclusive = 5),
MacroInvocation(ByName("values"), selfIndex = 0, endExclusive = 6),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ It's not easily noticeable in the diff (because the file was renamed), but I changed the start and end fields in the list, sexp, etc. expressions. I found that I needed the exclusive end rather than the inclusive end in the macro evaluator, and I also found that the "start" I needed was actually startInclusive + 1, so I renamed startInclusive to be selfIndex (since it is the index of this expression instance), and redefined startInclusive to specifically refer to the children of the expression.

(ktlint complained that Expression should be in a file named Expression.kt, otherwise I probably would have left it to make the diff smaller.)

NullValue(emptyList(), IonType.NULL),
BoolValue(emptyList(), true),
IntValue(emptyList(), 1),
LongIntValue(emptyList(), 1),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ Another change that's not particularly noticeable in Expression.kt. I thought that LongIntValue and BigIntValue was a little more descriptive, and then I was able to use IntValue as a sealed supertype of those two.

}

/** Marker interface representing expressions that can be present in E-Expressions. */
sealed interface EncodingExpression : Expression
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 name EncodingExpression is a little confusing because it is not an EExpression (that's further down), but I haven't been able to come up with a better name yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

EExpressionBodyExpression?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

EExpressionBodyExpression

I like it.

@popematt popematt requested a review from tgregg August 14, 2024 22:30
Copy link
Contributor

@tgregg tgregg left a comment

Choose a reason for hiding this comment

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

I think this basically looks good. A few questions:

  1. Can you provide more detail about the relationship between the MacroExpressionizer and the MacroEvaluator? How will the two interact in order to expand an invocation? Do both of them interact with a lower-level IonReader or cursor, or just the Expressionizer?
  2. Where is the multiplexing between the encoding and the template body performed?
  3. It sounds like the MacroExpressionizer is supposed to recursively handle the case where an argument is an e-expression. Does it return a list containing all e-expression arguments at all depths?

@popematt
Copy link
Contributor Author

Can you provide more detail about the relationship between the MacroExpressionizer and the MacroEvaluator? How will the two interact in order to expand an invocation? Do both of them interact with a lower-level IonReader or cursor, or just the Expressionizer?

The "expressionizer" is somewhat of a placeholder because it is too much for me to, at the same time, implement lazily evaluated containers. Essentially...

  1. IonCursor encounters an e-expression
  2. IonReaderContinuableCore, using the current macro table, calls MacroExpressionizer to eagerly read the entirety of the arguments for that e-expression.
  3. IonReaderContinuableCore can pass the List<EExpressionBodyExpression> to MacroEvaluator, and then pull values out of MacroEvaluator (possibly through MacroEvaluatorAsIonReader).

My expectation is that all of this logic will eventually have to move into IonReaderContinuableCoreBinary in the name of performance, but I am starting with things segregated this way to make it easier to test things independently and ensure that they are correct.

I've also kept things in separate classes for now because I am hopeful that the core macro evaluator might be reusable for both binary and text.

Where is the multiplexing between the encoding and the template body performed?

That is performed in the evaluator.

It sounds like the MacroExpressionizer is supposed to recursively handle the case where an argument is an e-expression. Does it return a list containing all e-expression arguments at all depths?

At this point, yes. Everything is eagerly read at all depths. However, I do think that my approach is fundamentally compatible with iterators that are backed by lazy-parsing in the low-level reader.

Copy link
Contributor

@tgregg tgregg left a comment

Choose a reason for hiding this comment

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

Let's merge this and iterate on it if/when we need it to be lazier for performance reasons.

@popematt popematt merged commit b235531 into amazon-ion:ion-11-encoding Aug 15, 2024
20 of 36 checks passed
@popematt popematt deleted the model-pr branch August 15, 2024 21:10
tgregg pushed a commit that referenced this pull request Sep 9, 2024
tgregg pushed a commit that referenced this pull request Dec 13, 2024
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.

2 participants