-
Notifications
You must be signed in to change notification settings - Fork 310
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
Redesign named variables in FuzzIL #486
base: main
Are you sure you want to change the base?
Conversation
990d884
to
f040756
Compare
Had some time on the train today so I gave the idea from #474 (comment) a try. @carl-smith and @TobiasWienand, could you both take a look at this and see what you think? This should make named variables much more flexible and powerful and I think it should now make it easy to handle issues such as the one we're encountering in PR #474 now. But it's also a somewhat deep change and for example also removes |
eda09b2
to
3e40cbe
Compare
This change replaces the three operations LoadNamedVariable, StoreNamedVariable, and DefineNamedVariable with a single new operation: CreateNamedVariable. This operation now simply creates a new FuzzIL variable that will be assigned a specific identifier during lifting. Optionally, the named variable can be declared using any of the available variable declaration modes: global, var, let, or const. Below is a small example of how CreateNamedVariable can be used: // Make an existing named variable (e.g. a builtin) available v0 <- CreateNamedVariable 'print', declarationMode: .none // Overwrite an existing named variable v1 <- CreateNamedVariable 'foo', declarationMode: .none v2 <- CallFunction v0, v1 v3 <- LoadString 'bar' Reassign v1, v3 // Declare a new named variable v4 <- CreateNamedVariable 'baz', declarationMode: .var, v1 v5 <- LoadString 'bla' Update v4 '+' v5 v5 <- CallFunction v0, v4 This will lift to JavaScript code similar to the following: print(foo); foo = "bar"; var baz = foo; baz += "bla"; print(baz); With this, we now have a single, flexible way of creating variables that have a specific name. We now use this: * For builtins, which are effectively just existing named variables in the global scope. This also now makes it (easily) possible to overwrite builtins. As such, The LoadBuiltin operation was removed. * During code generation, to sometimes create variables with specific names in generated code (we use random property names). * In the compiler. This is the main user of named variables and this is where this change has the most impact: we now compiler _every_ variable declaration to a CreateNamedVariable operation. This now makes it possible to correctly compiler any code that relies on variable names, for example due to using `eval`, with statements, or similar constructs. See some of the added/modified tests for examples. The consequence of this is that compiled code will now often have a lot of CreateNamedVariable operations. However, as these are now just regular FuzzIL variables, this change should not significantly affect mutability of the programs. In the future, we could consider implementing a specific minimizer (that we could also run during corpus import) to remove unneeded CreateNamedVariable operations. However, it will likely be somewhat difficult to determine when such an operation is not needed.
3e40cbe
to
e4dcc6a
Compare
Overall it looks really awesome :) beforefor (const a of ["a"]) {}
for (let b of ["b"]) {}
for (var c of ["c"]) {} afterfor (const v2 of ["a"]) {}
for (const v5 of ["b"]) {}
for (const v8 of ["c"]) {} Apart from that, my small testbench regarding scoping of variables passed. I am currently working on a more comprehensive test bench |
This change replaces the three operations LoadNamedVariable, StoreNamedVariable, and DefineNamedVariable with a single new operation: CreateNamedVariable. This operation now simply creates a new FuzzIL variable that will be assigned a specific identifier during lifting. Optionally, the named variable can be declared using any of the available variable declaration modes: global, var, let, or const.
Below is a small example of how CreateNamedVariable can be used:
This will now lift to the following JavaScript code:
With this, we now have a single, flexible way of creating variables that have a specific name. We now use this:
eval
, with statements, or similar constructs. See some of the added/modified tests for examples. The consequence of this is that compiled code will now often have a lot of CreateNamedVariable operations. However, as these are now just regular FuzzIL variables, this change should not significantly affect mutability of the programs. In the future, we could consider implementing a specific minimizer (that we could also run during corpus import) to remove unneeded CreateNamedVariable operations. However, it will likely be somewhat difficult to determine when such an operation is not needed.