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

JIT support for match expressions. #1838

Merged
merged 69 commits into from
Oct 2, 2024
Merged

JIT support for match expressions. #1838

merged 69 commits into from
Oct 2, 2024

Conversation

chriseth
Copy link
Member

@chriseth chriseth commented Sep 24, 2024

This PR supports match expression, while most of the work regards patterns.

Unfortunately, we cannot use rust patterns directly: The types are too incompatible. For example a match ("abc", 7) { ("abc", 7) => ...} cannot be directly translated, since the rust types here are String and ibig::IBig and they cannot be used with these literals like that, at least not directly and in all circumstances.

The way it is implemented here is that each pattern is compiled to code that is supposed to evaluate to an Option. If the pattern matches, the Option is a Some-value that contains the values that are assigned to the variables in the pattern. The function also returns a string containing the variable names. The function calls itself recursively on recursive data structures.

@chriseth chriseth marked this pull request as ready for review September 30, 2024 14:15
@@ -283,6 +284,26 @@ impl<'a, T: FieldElement> CodeGenerator<'a, T> {
.unwrap_or_default()
)
}
Expression::MatchExpression(_, MatchExpression { scrutinee, arms }) => {
// TODO try to find a solution where we do not introduce a variable
Copy link
Member Author

Choose a reason for hiding this comment

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

Not to be done in this PR.

if let Ok(n) = BigUint::try_from(n) {
format_unsigned_integer(&n)
} else {
format_signed_integer(&-(n.clone()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is the sign "ignored" here when formatting? also, is there some test using negative integers?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it's a bug! :)

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this function should be recursive.

@@ -283,6 +284,26 @@ impl<'a, T: FieldElement> CodeGenerator<'a, T> {
.unwrap_or_default()
)
}
Expression::MatchExpression(_, MatchExpression { scrutinee, arms }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe a small comment describing what it compiles to? just sth like "compiles the match arms into a sequence of if let Some(arm_vars) = arm_test { arm_expr } else ..."

.map(|MatchArm { pattern, value }| {
let (vars, code) = check_pattern(var_name, pattern)?;
Ok(format!(
"if let Some({vars}) = ({code}) {{\n{}\n}}",
Copy link
Collaborator

Choose a reason for hiding this comment

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

code could have a more specific name like arm_test

///
/// So if `let (vars, code) = check_pattern("x", pattern)?;`, then the return value
/// can be used like this: `if let Some({vars}) = ({code}) {{ .. }}`
fn check_pattern(value_name: &str, pattern: &Pattern) -> Result<(String, String), String> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

idk about the name, maybe match_arm_pattern?

Copy link
Member Author

Choose a reason for hiding this comment

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

It will also be used in let statements.

(format!("{value_name}[{i}]"), item)
})
})
.map(|(access_name, item)| {
Copy link
Collaborator

Choose a reason for hiding this comment

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

i wonder if this map being merged into the preceding filter_map makes it easier to read?

Copy link
Member Author

Choose a reason for hiding this comment

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

The issue is that the first is a filter, i.e. returns Option and the second one returns Result. I think it's too complicate to combine both.

Pattern::Array(_, items) => {
let mut vars = vec![];
let mut ellipsis_seen = false;
let inner_code = items
Copy link
Collaborator

Choose a reason for hiding this comment

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

small comment saying what inner_code will be?

pacheco
pacheco previously approved these changes Oct 1, 2024
georgwiese
georgwiese previously approved these changes Oct 2, 2024
Copy link
Collaborator

@georgwiese georgwiese left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -436,7 +441,7 @@ fn format_signed_integer(n: &BigInt) -> String {
if let Ok(n) = BigUint::try_from(n) {
format_unsigned_integer(&n)
} else {
format_signed_integer(&-(n.clone()))
format!("-{}", format_signed_integer(&-(n.clone())))
Copy link
Member

Choose a reason for hiding this comment

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

Is clone really necessary?

Anyway, maybe it is better to avoid recursion:

Suggested change
format!("-{}", format_signed_integer(&-(n.clone())))
format!("-{}", format_unsigned_integer(&BigUint::try_from(-n).unwrap())

@chriseth chriseth added this pull request to the merge queue Oct 2, 2024
Merged via the queue into main with commit eebbe5f Oct 2, 2024
14 checks passed
@chriseth chriseth deleted the match_expr branch October 2, 2024 13:29
@chriseth chriseth restored the match_expr branch October 2, 2024 13:57
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.

4 participants