Skip to content

Commit cea391f

Browse files
Feature/with statement js compiler (#439)
* Implements the step JS->FuzzIL for the With-Statement * Implements two unit tests for the With-Statement
1 parent 7cb027f commit cea391f

File tree

6 files changed

+175
-0
lines changed

6 files changed

+175
-0
lines changed

Sources/Fuzzilli/Compiler/Compiler.swift

+7
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,13 @@ public class JavaScriptCompiler {
479479
let value = try compileExpression(throwStatement.argument)
480480
emit(ThrowException(), withInputs: [value])
481481

482+
case .withStatement(let withStatement):
483+
let object = try compileExpression(withStatement.object)
484+
emit(BeginWith(), withInputs: [object])
485+
try enterNewScope {
486+
try compileBody(withStatement.body)
487+
}
488+
emit(EndWith())
482489
}
483490
}
484491

Sources/Fuzzilli/Compiler/Parser/parser.js

+6
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@ function parse(script, proto) {
320320
case 'ThrowStatement': {
321321
return makeStatement('ThrowStatement', { argument: visitExpression(node.argument) });
322322
}
323+
case 'WithStatement': {
324+
let withStatement = {};
325+
withStatement.object = visitExpression(node.object);
326+
withStatement.body = visitStatement(node.body);
327+
return makeStatement('WithStatement', withStatement);
328+
}
323329
default: {
324330
throw "Unhandled node type " + node.type;
325331
}

Sources/Fuzzilli/Protobuf/ast.pb.swift

+141
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,36 @@ public struct Compiler_Protobuf_ThrowStatement: @unchecked Sendable {
875875
fileprivate var _storage = _StorageClass.defaultInstance
876876
}
877877

878+
public struct Compiler_Protobuf_WithStatement: @unchecked Sendable {
879+
// SwiftProtobuf.Message conformance is added in an extension below. See the
880+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
881+
// methods supported on all messages.
882+
883+
public var object: Compiler_Protobuf_Expression {
884+
get {return _storage._object ?? Compiler_Protobuf_Expression()}
885+
set {_uniqueStorage()._object = newValue}
886+
}
887+
/// Returns true if `object` has been explicitly set.
888+
public var hasObject: Bool {return _storage._object != nil}
889+
/// Clears the value of `object`. Subsequent reads from it will return its default value.
890+
public mutating func clearObject() {_uniqueStorage()._object = nil}
891+
892+
public var body: Compiler_Protobuf_Statement {
893+
get {return _storage._body ?? Compiler_Protobuf_Statement()}
894+
set {_uniqueStorage()._body = newValue}
895+
}
896+
/// Returns true if `body` has been explicitly set.
897+
public var hasBody: Bool {return _storage._body != nil}
898+
/// Clears the value of `body`. Subsequent reads from it will return its default value.
899+
public mutating func clearBody() {_uniqueStorage()._body = nil}
900+
901+
public var unknownFields = SwiftProtobuf.UnknownStorage()
902+
903+
public init() {}
904+
905+
fileprivate var _storage = _StorageClass.defaultInstance
906+
}
907+
878908
public struct Compiler_Protobuf_Statement: @unchecked Sendable {
879909
// SwiftProtobuf.Message conformance is added in an extension below. See the
880910
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -1021,6 +1051,14 @@ public struct Compiler_Protobuf_Statement: @unchecked Sendable {
10211051
set {_uniqueStorage()._statement = .throwStatement(newValue)}
10221052
}
10231053

1054+
public var withStatement: Compiler_Protobuf_WithStatement {
1055+
get {
1056+
if case .withStatement(let v)? = _storage._statement {return v}
1057+
return Compiler_Protobuf_WithStatement()
1058+
}
1059+
set {_uniqueStorage()._statement = .withStatement(newValue)}
1060+
}
1061+
10241062
public var unknownFields = SwiftProtobuf.UnknownStorage()
10251063

10261064
public enum OneOf_Statement: Equatable, Sendable {
@@ -1041,6 +1079,7 @@ public struct Compiler_Protobuf_Statement: @unchecked Sendable {
10411079
case continueStatement(Compiler_Protobuf_ContinueStatement)
10421080
case tryStatement(Compiler_Protobuf_TryStatement)
10431081
case throwStatement(Compiler_Protobuf_ThrowStatement)
1082+
case withStatement(Compiler_Protobuf_WithStatement)
10441083

10451084
}
10461085

@@ -3896,6 +3935,90 @@ extension Compiler_Protobuf_ThrowStatement: SwiftProtobuf.Message, SwiftProtobuf
38963935
}
38973936
}
38983937

3938+
extension Compiler_Protobuf_WithStatement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3939+
public static let protoMessageName: String = _protobuf_package + ".WithStatement"
3940+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
3941+
1: .same(proto: "object"),
3942+
2: .same(proto: "body"),
3943+
]
3944+
3945+
fileprivate class _StorageClass {
3946+
var _object: Compiler_Protobuf_Expression? = nil
3947+
var _body: Compiler_Protobuf_Statement? = nil
3948+
3949+
#if swift(>=5.10)
3950+
// This property is used as the initial default value for new instances of the type.
3951+
// The type itself is protecting the reference to its storage via CoW semantics.
3952+
// This will force a copy to be made of this reference when the first mutation occurs;
3953+
// hence, it is safe to mark this as `nonisolated(unsafe)`.
3954+
static nonisolated(unsafe) let defaultInstance = _StorageClass()
3955+
#else
3956+
static let defaultInstance = _StorageClass()
3957+
#endif
3958+
3959+
private init() {}
3960+
3961+
init(copying source: _StorageClass) {
3962+
_object = source._object
3963+
_body = source._body
3964+
}
3965+
}
3966+
3967+
fileprivate mutating func _uniqueStorage() -> _StorageClass {
3968+
if !isKnownUniquelyReferenced(&_storage) {
3969+
_storage = _StorageClass(copying: _storage)
3970+
}
3971+
return _storage
3972+
}
3973+
3974+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3975+
_ = _uniqueStorage()
3976+
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
3977+
while let fieldNumber = try decoder.nextFieldNumber() {
3978+
// The use of inline closures is to circumvent an issue where the compiler
3979+
// allocates stack space for every case branch when no optimizations are
3980+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
3981+
switch fieldNumber {
3982+
case 1: try { try decoder.decodeSingularMessageField(value: &_storage._object) }()
3983+
case 2: try { try decoder.decodeSingularMessageField(value: &_storage._body) }()
3984+
default: break
3985+
}
3986+
}
3987+
}
3988+
}
3989+
3990+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3991+
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
3992+
// The use of inline closures is to circumvent an issue where the compiler
3993+
// allocates stack space for every if/case branch local when no optimizations
3994+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
3995+
// https://github.com/apple/swift-protobuf/issues/1182
3996+
try { if let v = _storage._object {
3997+
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
3998+
} }()
3999+
try { if let v = _storage._body {
4000+
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
4001+
} }()
4002+
}
4003+
try unknownFields.traverse(visitor: &visitor)
4004+
}
4005+
4006+
public static func ==(lhs: Compiler_Protobuf_WithStatement, rhs: Compiler_Protobuf_WithStatement) -> Bool {
4007+
if lhs._storage !== rhs._storage {
4008+
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
4009+
let _storage = _args.0
4010+
let rhs_storage = _args.1
4011+
if _storage._object != rhs_storage._object {return false}
4012+
if _storage._body != rhs_storage._body {return false}
4013+
return true
4014+
}
4015+
if !storagesAreEqual {return false}
4016+
}
4017+
if lhs.unknownFields != rhs.unknownFields {return false}
4018+
return true
4019+
}
4020+
}
4021+
38994022
extension Compiler_Protobuf_Statement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
39004023
public static let protoMessageName: String = _protobuf_package + ".Statement"
39014024
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
@@ -3916,6 +4039,7 @@ extension Compiler_Protobuf_Statement: SwiftProtobuf.Message, SwiftProtobuf._Mes
39164039
15: .same(proto: "continueStatement"),
39174040
16: .same(proto: "tryStatement"),
39184041
17: .same(proto: "throwStatement"),
4042+
18: .same(proto: "withStatement"),
39194043
]
39204044

39214045
fileprivate class _StorageClass {
@@ -4174,6 +4298,19 @@ extension Compiler_Protobuf_Statement: SwiftProtobuf.Message, SwiftProtobuf._Mes
41744298
_storage._statement = .throwStatement(v)
41754299
}
41764300
}()
4301+
case 18: try {
4302+
var v: Compiler_Protobuf_WithStatement?
4303+
var hadOneofValue = false
4304+
if let current = _storage._statement {
4305+
hadOneofValue = true
4306+
if case .withStatement(let m) = current {v = m}
4307+
}
4308+
try decoder.decodeSingularMessageField(value: &v)
4309+
if let v = v {
4310+
if hadOneofValue {try decoder.handleConflictingOneOf()}
4311+
_storage._statement = .withStatement(v)
4312+
}
4313+
}()
41774314
default: break
41784315
}
41794316
}
@@ -4255,6 +4392,10 @@ extension Compiler_Protobuf_Statement: SwiftProtobuf.Message, SwiftProtobuf._Mes
42554392
guard case .throwStatement(let v)? = _storage._statement else { preconditionFailure() }
42564393
try visitor.visitSingularMessageField(value: v, fieldNumber: 17)
42574394
}()
4395+
case .withStatement?: try {
4396+
guard case .withStatement(let v)? = _storage._statement else { preconditionFailure() }
4397+
try visitor.visitSingularMessageField(value: v, fieldNumber: 18)
4398+
}()
42584399
case nil: break
42594400
}
42604401
}

Sources/Fuzzilli/Protobuf/ast.proto

+6
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ message ThrowStatement {
202202
Expression argument = 1;
203203
}
204204

205+
message WithStatement {
206+
Expression object = 1;
207+
Statement body = 2;
208+
}
209+
205210
message Statement {
206211
oneof statement {
207212
EmptyStatement emptyStatement = 1;
@@ -221,6 +226,7 @@ message Statement {
221226
ContinueStatement continueStatement = 15;
222227
TryStatement tryStatement = 16;
223228
ThrowStatement throwStatement = 17;
229+
WithStatement withStatement = 18;
224230
}
225231
}
226232

Tests/FuzzilliTests/CompilerTests/basic_object_access.js

+8
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ o[2] = o[1] + o[0];
1212
o[3] = o[2] + o[1];
1313

1414
output(JSON.stringify(o));
15+
16+
with(o) {
17+
a = 3;
18+
b = 4;
19+
c = a + b;
20+
}
21+
22+
output(JSON.stringify(o));

Tests/FuzzilliTests/CompilerTests/basic_scoping.js

+7
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,12 @@ function foo(x) {
1616
}
1717
output(x);
1818
output(y);
19+
let obj = { x: 45, y: 9001 };
20+
with (obj) {
21+
output(x);
22+
output(y);
23+
}
24+
output(x);
25+
output(y);
1926
}
2027
foo(44);

0 commit comments

Comments
 (0)