fuzzilli
fuzzilli copied to clipboard
Nicer `FunctionSignature` literals
In https://github.com/googleprojectzero/fuzzilli/commit/c1a3848b0cdc713b40a326bb76f791066128837e we had to change FunctionSignature literals to look like this:
let sig = [.plain(.integer), .opt(.string), .rest(.anything)] => .integer
since they now contain a Parameter struct instead of just a Type.
However, it would be nice if we found some way (that isn't a terrible hack) to be able to write FunctionSignature literals like this again (or something similar):
let sig = [.integer, .opt(.string), .anything...] => .integer
This is just a "nice to have" though.
Well, I've looked into this, but the only feasible way to do this is with classes. If you're ok with that then I'll have this implemented asap
Oh cool, do you have a short code snippet to explain what you mean (i.e. what would have to become a class, etc.)? Thanks!
I actually found a way to do it using structs. I think I tried this before and was caught up with an issue that could have been solved by making my own init(rawValue:) initializer.
struct BaseType: OptionSet, Hashable {
fileprivate var _parameterKind: ParameterKind
var rawValue: UInt32 = 0
static let integer = BaseType(rawValue: 1 << 1)
static let bigint = BaseType(rawValue: 1 << 9)
static let anything = BaseType([.integer, .bigint])
init(rawValue: UInt32) {
self._parameterKind = .plain
self.rawValue = rawValue
}
}
extension BaseType {
enum ParameterKind {
case plain
case optional
case variadic
}
var parameterKind: ParameterKind { _parameterKind }
init(rawValue: UInt32, parameterKind: ParameterKind) {
self.init(rawValue: rawValue)
self._parameterKind = parameterKind
}
static func opt(_ _type: BaseType) -> BaseType {
var _type = _type
_type._parameterKind = .optional
return _type
}
static func variadic(_ _type: BaseType) -> BaseType {
var _type = _type
_type._parameterKind = .variadic
return _type
}
}
typealias Parameter = BaseType
struct FunctionSignature {
var parameters: [Parameter]
var retVal: BaseType
}
infix operator =>: AdditionPrecedence
func => (paramTypes: [Parameter], returnType: BaseType) -> FunctionSignature {
return FunctionSignature(parameters: paramTypes, retVal: returnType)
}
postfix operator ...
postfix func ...(_type: BaseType) -> BaseType {
var _type = _type
_type._parameterKind = .variadic
return _type
}
let signature: FunctionSignature = [.integer, .opt(.bigint), .anything...] => .bigint
With that out of the way, my initial concern of needing to make the BaseType struct a class has been alleviated.
Having this set up as-is would be great, but the printing functions on the ParameterType struct should be moved to the BaseType within an extension to make everything come full circle as there's really no need to have a separate struct/enum representing it.
Edit: I've updated it to include all the good postfix/infix operator goodies in there ;)
As a suggestion as well, maybe instead of wrapping an optional parameter in opt(_:), maybe we could define an "extend to optional" postfix operator -?. Ex:
postfix operator -?
postfix func -?(_type: BaseType) -> BaseType {
var _type = _type
_type._parameterKind = .optional
return _type
}
let signature: FunctionSignature = [.integer, .bigint-?, .anything...] => .bigint
It was an idea that popped into my head when adding the operators into my snippet, and I think it would be good for unifying the style as being declarative instead of functional.
This is now fixed as a drive-by in https://github.com/googleprojectzero/fuzzilli/commit/7f2c432232c620fd5f0bdf5ea243b72ad49a1db6
This way of doing it now has some redundancy with the duplicated constructors, but this also makes it possible to forbid certain parameter types completely, e.g. .unknown, which is nice. It also still allows using union types as parameters, which is required in the JavaScriptEnvironment.swift. So probably this is good enough...
It'd be nice to just have ? to express optional parameters, but I think that's impossible, and probably .opt is intuitive enough.