shift-fuzzer
Version:
generate random valid Shift format ASTs
161 lines (141 loc) • 4.55 kB
JavaScript
/**
* Copyright 2014 Shape Security, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const Random = require("./random");
class FuzzerState {
constructor({maxDepth = 7, rng = Math.random} = {}) {
this.maxDepth = maxDepth;
this.rng = new Random(rng);
this.depth = 0;
this.inLoop = false; // allows continue and unlabelled break
this.inSwitch = false; // allows unlabelled break // todo consider collapsing into one allowBreak, one allowContinue
this.strict = false;
this.allowReturn = false;
this.allowNewTarget = false;
this.allowSuperCall = false; // todo generate constructor methods more often
this.allowSuperProp = false; // implied by allowSuperCall
this.allowMissingElse = true;
this.declKind = null; // const requires initializer; const and let prohibit bindings named let.
this.allowYieldIdentifier = true;
this.allowYieldExpr = false; // mutually exclusive with the above, but both can be false, e.g. in formal parameters of or within a generator
this.allowAwaitIdentifier = true;
this.allowAwaitExpr = false; // mutually exclusive with the above, but both can be false, e.g. in formal parameters
this.isModule = false;
this.labels = []; // would use a set, but we need immutibility.
this.loopLabels = []; // is a subset of labels
}
clone() {
let st = Object.create(FuzzerState.prototype);
st.maxDepth = this.maxDepth;
st.rng = this.rng;
st.depth = this.depth;
st.inLoop = this.inLoop;
st.inSwitch = this.inSwitch;
st.strict = this.strict;
st.allowReturn = this.allowReturn;
st.allowNewTarget = this.allowNewTarget;
st.allowSuperCall = this.allowSuperCall;
st.allowSuperProp = this.allowSuperProp;
st.allowMissingElse = this.allowMissingElse;
st.declKind = this.declKind;
st.allowYieldIdentifier = this.allowYieldIdentifier;
st.allowYieldExpr = this.allowYieldExpr;
st.allowAwaitIdentifier = this.allowAwaitIdentifier;
st.allowAwaitExpr = this.allowAwaitExpr;
st.isModule = this.isModule;
st.labels = this.labels;
st.loopLabels = this.loopLabels;
return st;
}
goDeeper() {
let st = this.clone();
++st.depth;
return st;
}
tooDeep() {
return this.depth >= this.maxDepth;
}
allowBreak() {
return this.inLoop || this.inSwitch || this.labels.length !== 0;
}
enableMissingElse() {
let st = this.clone();
st.allowMissingElse = true;
return st;
}
disableMissingElse() {
let st = this.clone();
st.allowMissingElse = false;
return st;
}
disableYieldExpr() {
let st = this.clone();
st.allowYieldExpr = false;
return st;
}
disableAwaitExpr() {
let st = this.clone();
st.allowAwaitExpr = false;
return st;
}
enterFunction({isGenerator = false, isAsync = false, isArrow = false, isMethod = false, hasStrictDirective = false} = {}) {
let st = this.clone();
if (st.declKind !== null) throw 'declKind'; // todo remove this
st.inLoop = false;
st.inSwitch = false;
if (hasStrictDirective) {
st.strict = true;
}
st.allowReturn = true;
if (isArrow) {
st.allowYieldExpr = false;
} else {
st.allowNewTarget = true;
if (isGenerator) {
st.allowYieldIdentifier = false;
st.allowYieldExpr = true;
} else {
st.allowYieldIdentifier = true;
st.allowYieldExpr = false;
}
if (!isMethod) {
st.allowSuperCall = false;
st.allowSuperProp = false;
}
}
if (isAsync) {
st.allowAwaitExpr = true;
st.allowAwaitIdentifier = false;
} else {
st.allowAwaitExpr = false;
st.allowAwaitIdentifier = !st.isModule;
}
st.allowMissingElse = true;
st.labels = [];
st.loopLabels = [];
return st;
}
enterLoop() {
let st = this.clone();
st.inLoop = true;
return st;
}
enterSwitch() {
let st = this.clone();
st.inSwitch = true;
return st;
}
}
module.exports = FuzzerState;