Handle side-effects in expression evaluation #241
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Ensure that expressions with a side-effect, like
rand()
, are evaluated only once even if they're referenced multiple times in a module. Otherwise each evaluation duplicates the side effect, which in the example ofrand()
yields a different value even though the expression is the same.Add
Expr::has_side_effect()
to determine if an expression has any side effect. Currently only expressions returning a random value have a side effect.To ensure a unique evaluation per expression, add an evaluation cache to the implementations of
EvalContext
, saving the evaluated string associated with anExprHandle
.Add to
EvalContext
some helpers:make_local_var()
to create a unique variable name, for storing intermediate evaluations.push_stmt()
to write the statement which actually stores the evaluation of an expression into a local variable before it's referenced.Remove the
module()
andexpr()
fromEvalContext
, and move the mutableModule
reference out of that context, passing it explicitly instead. This allows acquiring a mutable reference to both the context and the module at the same time, which is not possible if the module reference is stored as a context field.Add
EvalContext::make_fn()
to generate a function with a temporary function-local context. This ensures that functions which use expressions with side effects have their local statements emitted inside the body of the function, and not at the call site where they're not available.Fix several bugs in some older modifiers which were using hand-crafted code not properly parenthesized, which could lead to invalid expression evaluation due to operator priorities in WGSL:
SetPositionCircleModifier
SetPositionSphereModifier
SetVelocityCircleModifier
SetVelocitySphereModifier
SetVelocityTangentModifier
Bug: #240