-
Notifications
You must be signed in to change notification settings - Fork 13
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
Turn Datum into an enum #105
base: master
Are you sure you want to change the base?
Conversation
Using an enum instead of a struct makes it impossible to use the wrong field, and allows us to couple the tag-based dispatch with uses of those fields. This pays off significantly in type coercions for each operator, where some new helper functions have been used to unify the coercion and evaluation blocks.
According to the language reference, >> is guaranteed to be an arithmetic (sign-preserving) shift. https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
flt: 0.0, | ||
str: String::new(), | ||
} | ||
Datum::String("".to_owned()) |
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.
Datum::String("".to_owned()) | |
Datum::String(String::new()) |
pub(crate) fn int(int: MoltInt) -> Self { | ||
Self { | ||
vtype: Type::Int, | ||
int, | ||
flt: 0.0, | ||
str: String::new(), | ||
} | ||
Datum::Int(int) | ||
} | ||
|
||
pub(crate) fn float(flt: MoltFloat) -> Self { | ||
Self { | ||
vtype: Type::Float, | ||
int: 0, | ||
flt, | ||
str: String::new(), | ||
} | ||
Datum::Float(flt) | ||
} |
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.
These methods don't really contain any useful functionality anymore, it might be a good idea to replace any calls to them with direct invocations of the enum variant constructors
match value { | ||
Datum::Int(v) => molt_ok!(Value::from(v)), | ||
Datum::Float(v) => molt_ok!(Value::from(v)), | ||
Datum::String(v) => molt_ok!(Value::from(v)), | ||
} |
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.
I'm not sure if this would work, but it might be worth trying
match value { | |
Datum::Int(v) => molt_ok!(Value::from(v)), | |
Datum::Float(v) => molt_ok!(Value::from(v)), | |
Datum::String(v) => molt_ok!(Value::from(v)), | |
} | |
molt_ok!(match value { | |
Datum::Int(v) => Value::from(v), | |
Datum::Float(v) => Value::from(v), | |
Datum::String(v) => Value::from(v), | |
}) |
if value.int < 0 { | ||
value.int = !((!value.int) >> value2.int) | ||
} else { | ||
value.int >>= value2.int; | ||
} | ||
value = Datum::Int(v1 >> v2) |
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.
It might be a good idea to create a unit test which checks this assumption.
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.
oh, if it is explicitly mentioned in the rust manual that won't be necessary.
value = match coerce_pair(operator, &value, &value2)? { | ||
DatumPair::Ints(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | ||
DatumPair::Floats(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | ||
DatumPair::Strings(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | ||
}; |
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.
value = match coerce_pair(operator, &value, &value2)? { | |
DatumPair::Ints(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | |
DatumPair::Floats(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | |
DatumPair::Strings(v1, v2) => Datum::Int((v1 < v2) as MoltInt), | |
}; | |
value = Datum::Int(match coerce_pair(operator, &value, &value2)? { | |
DatumPair::Ints(v1, v2) => v1 < v2, | |
DatumPair::Floats(v1, v2) => v1 < v2, | |
DatumPair::Strings(v1, v2) => v1 < v2, | |
} as MoltInt); |
value = match coerce_pair(operator, &value, &value2)? { | ||
DatumPair::Ints(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | ||
DatumPair::Floats(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | ||
DatumPair::Strings(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | ||
}; |
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.
value = match coerce_pair(operator, &value, &value2)? { | |
DatumPair::Ints(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | |
DatumPair::Floats(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | |
DatumPair::Strings(v1, v2) => Datum::Int((v1 > v2) as MoltInt), | |
}; | |
value = Datum::Int(match coerce_pair(operator, &value, &value2)? { | |
DatumPair::Ints(v1, v2) => v1 > v2, | |
DatumPair::Floats(v1, v2) => v1 > v2, | |
DatumPair::Strings(v1, v2) => v1 > v2, | |
} as MoltInt); |
if v < 0.0 { | ||
Ok(Datum::Int((v - 0.5) as MoltInt)) | ||
} else { | ||
Ok(Datum::Int((v + 0.5) as MoltInt)) | ||
} |
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.
if v < 0.0 { | |
Ok(Datum::Int((v - 0.5) as MoltInt)) | |
} else { | |
Ok(Datum::Int((v + 0.5) as MoltInt)) | |
} | |
Ok(Datum::Int(if v < 0.0 { | |
v - 0.5 | |
} else { | |
v + 0.5 | |
} as MoltInt)) |
Hi Will -- it's Jonathan! This weekend, I'm making good on my years-old promise to check out Molt. Feel free to take or leave the changes in this PR; I had an idea to try out and it seems to have worked fairly nicely, but it's up to your discretion in the end.
This PR turns the existing
struct Datum
into a more Rust-yenum Datum
, and propagates those changes throughoutexpr.rs
. In the process, I ended up unifying the type coercion sections for each operator with their respective evaluation sections. I especially noticed an inconsistency between the assumptions made by execution forAND
andOR
and what the respective coercion was doing; I think the approach in this PR scopes the relevant assumptions much more tightly, so it'll be much more difficult for things to get out of sync like that.This PR also contains minor contributions for the shift-right operator and absolute value function, which can both be simplified by using core Rust functionality. (Yes, as an arithmetic shift,
>>
is guaranteed to preserve sign!)Lastly, I ran
rustfmt
on my changes to keep things consistent. I find some of the formatting choices it made to be less readable, but I defer to convention :)