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

Implements compilation of new parameter types #449

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

TobiasWienand
Copy link
Contributor

This initial commit enables compilation of shallow objectPattern and arrayPattern parameters. Shallow means that all elements of the objectPattern and arrayPattern are identifierParameters and particularly not nested object- or arrayPatterns

TODO

  1. Property renaming in object pattern parameters (e.g. {a: b, c: d})
  2. Nested objected/array patterns (e.g. {a: {b, c}, d: [e, f]})
    This also means we need to redesign the Parameters struct again because at the moment the enum can only represent if a parameter opens/closes an array/object, not how many.
  3. Default values for parameters (e.g. function f(a = 42) { ... })
  4. Run Fuzzilli with seeds that are now compilable

Questions

  1. This commit changes the Parameters struct. If I understand correctly, this is performance-critical code. So my concern is if the impact on performance is negligible in this case?
  2. Compilation works with these changes but I realize the changes to the core of Fuzzilli may also necessitate changes to other parts of Fuzzilli that still assume that the Parameters struct has the old form. Which parts of Fuzzilli might be impacted by this change?

This initial commit enables compilation of shallow objectPattern and arrayPattern parameters. Shallow means that all elements of the objectPattern and arrayPattern are identifierParameters and particularly not nested object- or arrayPatterns
Copy link
Collaborator

@saelo saelo left a comment

Choose a reason for hiding this comment

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

Really cool! Left some comments, I hope those answer your questions

@@ -1059,9 +1059,25 @@ public struct Parameters {
return Int(numParameters)
}

init(count: Int, hasRestParameter: Bool = false) {
enum ParameterType {
Copy link
Collaborator

Choose a reason for hiding this comment

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

One other thing that needs to be changed is the logic that infers the signature of a function definition:

private func inferSubroutineParameterList(of op: BeginAnySubroutine, at index: Int) -> ParameterList {
here we now also need to take object and array parameters into account and construct the signature accordingly (i.e. all parameters that are part of an array literal become a single parameter of type .iterable etc.).

Then it would also be good to add some tests. Maybe a special version of the testSubroutineTypes test for complex parameters.

map(identifier.name, to: beginCatch.innerOutput)

default:
throw CompilerError.unsupportedFeatureError("Unsupported parameter type")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: maybe add something like "... in catch block"

@@ -468,7 +468,14 @@ public class JavaScriptCompiler {
try enterNewScope {
let beginCatch = emit(BeginCatch())
if tryStatement.catch.hasParameter {
map(tryStatement.catch.parameter.name, to: beginCatch.innerOutput)
let parameter = tryStatement.catch.parameter
switch parameter.parameter {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I think you could shorten this slightly with an if case let .identifierParameter(identifier) = tryStatement.catch.parameter or so (and throw the exception in an else). However, I'm wondering if it wouldn't be better to change the parameter directly to a IdentifierParameter if that's the only allowed one?

flatParameters.append(element.name)
expectedVariableCount += 1
}
default:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can there be another case? If not, can we omit the default or mark it as unreachable?

@@ -1059,9 +1059,25 @@ public struct Parameters {
return Int(numParameters)
}

init(count: Int, hasRestParameter: Bool = false) {
enum ParameterType {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe this should instead be called ParameterStructure or so since I would otherwise assume that this is the type of the parameter, i.e. something like .object() or .int or so

case standaloneArray
}

var parameterTypes: [ParameterType]
Copy link
Collaborator

Choose a reason for hiding this comment

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

... and then this can just be called structure

case arrayStart
case arrayEnd
case arrayMiddle
case standaloneArray
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm wondering if this is the most efficient representation of the structure of parameters. I guess the common case would be that we only have identifiers, so we could maybe also use a representation where only array- and object parameters need special handling and the default is identifier. For example something like

struct ParameterStructure {
    let type: ParameterStructureType  // .object or .array I guess
    let start: Int32
    let end: Int32
}

And then have a list of those. OTOH I'm not sure this is really performance sensitive since we should only ever have a few of these in a given program. So I guess I would recommend using whichever representation is easiest to work with, in the compiler, the typer, and the lifter.

self.numParameters = UInt32(count)
self.hasRestParameter = hasRestParameter
self.parameterTypes = parameterTypes
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we could add some structure validation here, for example that for every .objectStart we also have a .objectEnd. Alternatively, we could use a different representation (something along the lines of what I suggested above) where structural correctness is guaranteed (because e.g. an array pattern is just a single element in a list instead of two separate elements: a start and an end).

@brookate
Copy link

Can you also support such code:

  1. const [a0, a1] = f0(t);
  2. const { prop1 } = obj.f();

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.

3 participants