| Index: test/mjsunit/harmony/typesystem/testgen.js
 | 
| diff --git a/test/mjsunit/harmony/typesystem/testgen.js b/test/mjsunit/harmony/typesystem/testgen.js
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..740530d545b9baed76a42e11d51cb311ecb0da7b
 | 
| --- /dev/null
 | 
| +++ b/test/mjsunit/harmony/typesystem/testgen.js
 | 
| @@ -0,0 +1,122 @@
 | 
| +// Copyright 2016 the V8 project authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +var debug = false;
 | 
| +
 | 
| +function CheckValid(type) {
 | 
| +  if (debug) { print("V:", type); }
 | 
| +  assertDoesNotThrow("'use types'; var x: " + type + ";");
 | 
| +}
 | 
| +
 | 
| +function CheckInvalid(type) {
 | 
| +  if (debug) { print("I:", type); }
 | 
| +  assertThrows("'use types'; var x: " + type + ";", SyntaxError);
 | 
| +}
 | 
| +
 | 
| +// Parameters:
 | 
| +//   multiplicity: positive integer
 | 
| +//   generator: (size: positive integer, ...params: any[]) => Iterator<SomeType>
 | 
| +//   transformations: [false | ((t: SomeType) => OtherType)]
 | 
| +//   params: any[]
 | 
| +//
 | 
| +// A "test generator" object will have its "generator" generate tests,
 | 
| +// will transform each generated test with all of its "transformations"
 | 
| +// and will yield the results.  false transformations will be ignored.
 | 
| +class TestGen {
 | 
| +  constructor(multiplicity, generator, transformations, ...params) {
 | 
| +    // Determines how often this generator will run, compared to other ones.
 | 
| +    this.multiplicity = multiplicity;
 | 
| +    // The generator function.  It will be called with (size, ...params),
 | 
| +    // for an appropriate size provided externally to method initialize.
 | 
| +    this.generator = generator;
 | 
| +    // The list of transformation functions, excluding false ones.
 | 
| +    this.transformations = transformations.filter(f => f !== false);
 | 
| +    // The optional parameters to be passed to the generator function.
 | 
| +    this.params = params;
 | 
| +  }
 | 
| +  // Returns how many tests this test generator is expected to yield
 | 
| +  // in a row.
 | 
| +  weight() {
 | 
| +    return this.multiplicity * this.transformations.length;
 | 
| +  }
 | 
| +  // Initialize the generator function.
 | 
| +  initialize(size) {
 | 
| +    this.factory = this.generator(size, ...this.params);
 | 
| +  }
 | 
| +  // Is the test generator exhausted?
 | 
| +  exhausted() {
 | 
| +    return this.factory === null;
 | 
| +  }
 | 
| +  // Return a generator that will yield up to weight tests.
 | 
| +  // It returns an Iterator<OtherType>.
 | 
| +  * [Symbol.iterator]() {
 | 
| +    for (let i = 0; i < this.multiplicity; i++) {
 | 
| +      let element = this.factory.next();
 | 
| +      if (element.done) {
 | 
| +        this.factory = null;
 | 
| +        return;
 | 
| +      }
 | 
| +      for (let f of this.transformations) yield f(element.value);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Parameters:
 | 
| +//   size:       positive integer
 | 
| +//   generators: [false | string | TestGen]
 | 
| +//
 | 
| +// This generator function will yield up to size tests.  It will iterate
 | 
| +// cyclically through the list of test generators.  A string in this list
 | 
| +// behaves as a simple generator yielding just one test; a false value
 | 
| +// behaves as a generator yielding nothing.  For every test generator in
 | 
| +// the list, this function will generate as many tests as its weight
 | 
| +// before proceeding to the next test generator.  Once a generator is
 | 
| +// exhausted, it is ignored in subsequent iterations.
 | 
| +function* Generate(size, generators) {
 | 
| +  let fixed = 0, flexible = 0;
 | 
| +  for (let gen of generators) {
 | 
| +    if (gen === false) continue;
 | 
| +    if (typeof gen === "string") fixed++;
 | 
| +    else flexible += gen.weight();
 | 
| +  }
 | 
| +  if (fixed + flexible == 0) throw "Empty list of test generators";
 | 
| +  let remaining = 0;
 | 
| +  for (let gen of generators) {
 | 
| +    if (gen === false) continue;
 | 
| +    if (typeof gen !== "string") {
 | 
| +      let weight = 1 + gen.weight();
 | 
| +      gen.initialize(Math.ceil(size * weight / flexible));
 | 
| +      remaining++;
 | 
| +    }
 | 
| +  }
 | 
| +  for (let once = true; true; once = false) {
 | 
| +    if (remaining == 0) return;
 | 
| +    for (let gen of generators) {
 | 
| +      if (gen === false) continue;
 | 
| +      if (typeof gen === "string") {
 | 
| +        if (once) {
 | 
| +          if (size-- <= 0) return; else yield gen;
 | 
| +        }
 | 
| +        continue;
 | 
| +      }
 | 
| +      if (gen.exhausted()) continue;
 | 
| +      for (let test of gen) {
 | 
| +        if (size-- <= 0) return; else yield test;
 | 
| +      }
 | 
| +      if (gen.exhausted()) remaining--;
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Parameters:
 | 
| +//   size:       positive integer
 | 
| +//   generators: [string | TestGen]
 | 
| +//
 | 
| +// This function will generate all tests yielded by Generate and will
 | 
| +// discard the results.  It will normally be called with test generators
 | 
| +// whose transformation functions test for validity (e.g. CheckValid or
 | 
| +// CheckInvalid) and do not return anything interesting.
 | 
| +function Test(size, generators) {
 | 
| +  for (let attempt of Generate(size, generators)) continue;
 | 
| +}
 | 
| 
 |