diff options
Diffstat (limited to 'js/src/tests/ecma_6/Comprehensions')
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/arguments.js | 14 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/array-yield.js | 23 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/error-messages.js | 172 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/generator-semantics.js | 52 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/nested-for-if.js | 20 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/scope.js | 18 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/shell.js | 0 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/sudoku.js | 168 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/syntax.js | 6 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Comprehensions/toSource.js | 14 |
10 files changed, 487 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/Comprehensions/arguments.js b/js/src/tests/ecma_6/Comprehensions/arguments.js new file mode 100644 index 000000000..082374778 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/arguments.js @@ -0,0 +1,14 @@ + + +function values(g) { + return [for (x of g) x]; +} + +function argumentsTest() { + return values((for (i of [0,1,2]) arguments[i])); +} + +assertDeepEq(argumentsTest('a', 'b', 'c'), ['a', 'b', 'c']); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Comprehensions/array-yield.js b/js/src/tests/ecma_6/Comprehensions/array-yield.js new file mode 100644 index 000000000..69e699522 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/array-yield.js @@ -0,0 +1,23 @@ +// Interactions between yield and array comprehensions. + + +function assertIteratorResult(result, value, done) { + assertDeepEq(result.value, value); + assertEq(result.done, done); +} + +function* t1() { return [for (x of yield 0) x*2] } + +var o = t1(); +assertIteratorResult(o.next(), 0, false); +assertIteratorResult(o.next([0, 1, 2]), [0, 2, 4], true); + +function* t2() { return [for (x of [1,2,3]) yield x] } + +o = t2(); +assertIteratorResult(o.next(), 1, false); +assertIteratorResult(o.next(5), 2, false); +assertIteratorResult(o.next(6), 3, false); +assertIteratorResult(o.next(7), [5, 6, 7], true); + +reportCompare(null, null, "test"); diff --git a/js/src/tests/ecma_6/Comprehensions/error-messages.js b/js/src/tests/ecma_6/Comprehensions/error-messages.js new file mode 100644 index 000000000..aeacfde27 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/error-messages.js @@ -0,0 +1,172 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +// This file tests contextual restrictions for yield and arguments, and is +// derived from js1_8/genexps/regress-634472.js. + +function error(str) { + var base; + try { + // the following line must not be broken up into multiple lines + base = (function(){try{eval('throw new Error()')}catch(e){return e.lineNumber}})(); eval(str); + return null; + } catch (e) { + e.lineNumber = e.lineNumber - base + 1; + return e; + } +} + +const YIELD_PAREN = error("(function*(){(for (y of (yield 1, 2)) y)})").message; +const GENEXP_YIELD = error("(function*(){(for (x of yield 1) x)})").message; +const TOP_YIELD = error("yield").message; +const GENERIC = error("(for)").message; +const BAD_GENERATOR_SYNTAX = error("(for (x of []) x, 1)").message; +const MISSING_SEMI = error("yield 1").message; +const PAREN_PAREN = error("(foo").message; +const FOR_OF_PAREN = error("(for (x of y, z) w)").message; + +const cases = [ +// Expressions involving yield without a value, not currently implemented. Many +// of these errors would need to be updated. (Note: line numbers below might be +// mere placeholders, not actually the expected correct behavior -- check before +// blindly uncommenting.) +//{ expr: "yield", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield" }, +//{ expr: "1, yield", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list" }, +//{ expr: "yield, 1", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list" }, +//{ expr: "(yield)", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized" }, +//{ expr: "(1, yield)", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized" }, +//{ expr: "(yield, 1)", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized" }, +//{ expr: "((((yield))))", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "deeply nested yield" }, +//{ expr: "(for (x of []) yield)", top: [TOP_YIELD, 777], fun: [GENERIC, 777], gen: [GENERIC, 777], desc: "simple yield in genexp" }, +//{ expr: "(for (x of []) yield, 1)", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list in genexp" }, +//{ expr: "(for (x of []) 1, yield)", top: [TOP_YIELD, 777], fun: [GENERIC, 777], gen: [GENERIC, 777], desc: "simple yield at end of list in genexp" }, +//{ expr: "(for (x of []) (yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in genexp" }, +//{ expr: "(for (x of []) 1, (yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in list in genexp" }, +//{ expr: "(for (x of []) (1, yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in genexp" }, +//{ expr: "(for (x of []) 1, (2, yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in list in genexp" }, +//{ expr: "(for (x of []) (yield, 1))", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized in genexp" }, +//{ expr: "(for (x of []) 1, (yield, 2))", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized in list in genexp" }, +//{ expr: "(for (x of []) (function*() { yield }))", top: null, fun: null, gen: null, desc: "legal yield in nested function" }, + + // yield expressions + { expr: "yield 1", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg" }, + { expr: "1, yield 2", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [FOR_OF_PAREN, 1], desc: "yield w/ arg at end of list" }, + { expr: "yield 1, 2", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [FOR_OF_PAREN, 3], desc: "yield w/ arg in list" }, + { expr: "(yield 1)", top: [PAREN_PAREN, 2], fun: [PAREN_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized" }, + { expr: "(1, yield 2)", top: [PAREN_PAREN, 2], fun: [PAREN_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized" }, + { expr: "(yield 1, 2)", top: [PAREN_PAREN, 2], fun: [PAREN_PAREN, 2], gen: null, genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized" }, + + // deeply nested yield expressions + { expr: "((((yield 1))))", top: [PAREN_PAREN, 2], fun: [PAREN_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield w/ arg" }, + + // arguments + { expr: "arguments", top: null, fun: null, gen: null, genexp: null, desc: "arguments in list" }, + { expr: "1, arguments", top: null, fun: null, gen: null, genexp: [FOR_OF_PAREN, 1], desc: "arguments in list" }, + + // yield in generator expressions + { expr: "(for (x of []) yield 1)", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in genexp" }, + { expr: "(for (x of []) yield 1, 2)", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in list in genexp" }, + { expr: "(for (x of []) 1, yield 2)", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list in genexp" }, + { expr: "(for (x of []) (yield 1))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized in genexp" }, + { expr: "(for (x of []) 1, (yield 2))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg, parenthesized in list in genexp" }, + { expr: "(for (x of []) (1, yield 2))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized in genexp" }, + { expr: "(for (x of []) 1, (2, yield 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list, parenthesized in list in genexp" }, + { expr: "(for (x of []) (yield 1, 2))", top: [YIELD_PAREN, 2], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized in genexp" }, + { expr: "(for (x of []) 1, (yield 2, 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg in list, parenthesized in list in genexp" }, + + // deeply nested yield in generator expressions + { expr: "(for (x of []) (((1, yield 2))))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in genexp" }, + { expr: "(for (y of []) (for (x of []) ((1, yield 2))))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in multiple genexps" }, + + // arguments in generator expressions + { expr: "(for (x of []) arguments)", top: null, fun: null, gen: null, genexp: null, desc: "simple arguments in genexp" }, + { expr: "(for (x of []) 1, arguments)", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list in genexp" }, + { expr: "(for (x of []) (arguments))", top: null, fun: null, gen: null, genexp: null, desc: "arguments, parenthesized in genexp" }, + { expr: "(for (x of []) 1, (arguments))", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments, parenthesized in list in genexp" }, + { expr: "(for (x of []) (1, arguments))", top: null, fun: null, gen: null, genexp: null, desc: "arguments in list, parenthesized in genexp" }, + { expr: "(for (x of []) 1, (2, arguments))", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list, parenthesized in list in genexp" }, + + // deeply nested arguments in generator expressions + { expr: "(for (x of []) (((1, arguments))))", top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in genexp" }, + { expr: "(for (y of []) (for (x of []) ((1, arguments))))", top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in multiple genexps" }, + + // legal yield/arguments in nested function + { expr: "(for (x of []) (function*() { yield 1 }))", top: null, fun: null, gen: null, genexp: null, desc: "legal yield in nested function" }, + { expr: "(for (x of []) (function() { arguments }))", top: null, fun: null, gen: null, genexp: null, desc: "legal arguments in nested function" }, + { expr: "(for (x of []) (function() arguments))", top: null, fun: null, gen: null, genexp: null, desc: "legal arguments in nested expression-closure" } +]; + +//----------------------------------------------------------------------------- +test(); +//----------------------------------------------------------------------------- + +function splitKeyword(str) { + return str. +// replace(/[)] yield/, ')\nyield\n'). + replace(/yield ([0-9])/, '\nyield $1\n'). + replace(/yield([^ ]|$)/, '\nyield\n$1'). + replace(/arguments/, '\narguments\n'); +} + +function expectError1(err, ctx, msg, lineNumber) { + reportCompare('object', typeof err, 'exn for: ' + msg); + reportCompare(ctx, err.message, 'exn message for: ' + msg); + reportCompare(lineNumber, err.lineNumber, 'exn token for: ' + msg); +} + +function expectError(expr, wrapCtx, [expect, lineNumber], msg) { + expectError1(error(wrapCtx(expr)), expect, msg, lineNumber); +} + +function expectSuccess(err, msg) { + reportCompare(null, err, 'parse: ' + msg); +} + +function atTop(str) { return str } +function inFun(str) { return '(function(){' + str + '})' } +function inGen(str) { return '(function*(){' + str + '})' } +function inGenExp(str) { return '(for (y of ' + str + ') y)' } + +function test() +{ + enterFunc ('test'); + printBugNumber(BUGNUMBER); + printStatus (summary); + + for (var i = 0, len = cases.length; i < len; i++) { + var expr, top, fun, gen, genexp, desc; + expr = cases[i].expr; + top = cases[i].top; + fun = cases[i].fun; + gen = cases[i].gen; + genexp = cases[i].genexp; + desc = cases[i].desc; + + expr = splitKeyword(expr); + + if (top) + expectError(expr, atTop, top, 'top-level context, ' + desc); + else + expectSuccess(error(expr), 'top-level context, ' + desc); + + if (fun) + expectError(expr, inFun, fun, 'function context, ' + desc); + else + expectSuccess(error(inFun(expr)), 'function context, ' + desc); + + if (gen) + expectError(expr, inGen, gen, 'generator context, ' + desc); + else + expectSuccess(error(inGen(expr)), 'generator context, ' + desc); + + if (genexp) + expectError(expr, inGenExp, genexp, 'genexp context, ' + desc); + else + expectSuccess(error(inGenExp(expr)), 'genexp context, ' + desc); + } + + exitFunc ('test'); +} diff --git a/js/src/tests/ecma_6/Comprehensions/generator-semantics.js b/js/src/tests/ecma_6/Comprehensions/generator-semantics.js new file mode 100644 index 000000000..52426115f --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/generator-semantics.js @@ -0,0 +1,52 @@ +// Interaction of eval with generator expressions. +function a1() { + var a = 10; + var g = (for (y of [0]) eval('var a=42;')); + g.next(); + return a; +} +assertEq(a1(), 10); + +function a2() { + var a = 10; + (for (y of [0]) eval('a=42')).next(); + return a; +} +assertEq(a2(), 42) + +// Arguments and this. +function b1() { + return [for (arg of (for (i of [0, 1, 2]) arguments[i])) arg]; +} +assertDeepEq(b1('a', 'b', 'c'), ['a', 'b', 'c']); + +function b2() { + return [for (x of (for (i of [0]) this)) x]; +} +var b2o = { b2: b2 } +assertDeepEq(b2o.b2(), [b2o]) + +// Assignment to eval or arguments. +function c1() { + return [for (arg of (for (i of [0, 1, 2]) arguments = i)) arg]; +} +assertDeepEq(c1(), [0, 1, 2]); + +function c2() { + "use strict"; + return eval('[for (arg of (for (i of [0, 1, 2]) arguments = i)) arg]'); +} +assertThrows(c2, SyntaxError); + +function c3() { + return [for (arg of (for (i of [0, 1, 2]) eval = i)) arg]; +} +assertDeepEq(c3(), [0, 1, 2]); + +function c4() { + "use strict"; + return eval('[for (arg of (for (i of [0, 1, 2]) eval = i)) arg]'); +} +assertThrows(c4, SyntaxError); + +reportCompare(null, null, "test"); diff --git a/js/src/tests/ecma_6/Comprehensions/nested-for-if.js b/js/src/tests/ecma_6/Comprehensions/nested-for-if.js new file mode 100644 index 000000000..4e3291182 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/nested-for-if.js @@ -0,0 +1,20 @@ +// For and if clauses can nest without limit in comprehensions. This is +// unlike JS 1.8 comprehensions, which can only have one trailing "if" +// clause. + +function* range(start, end) { + for (var n = start; n < end; n++) + yield n; +} + +function primesBetween6And25() { + return [for (n of range(6, 25)) if (n % 2) if (n % 3) if (n % 5) n]; +} +assertDeepEq(primesBetween6And25(), [7,11,13,17,19,23]); + +function countUpToEvens(limit) { + return [for (n of range(0, limit)) if (!(n % 2)) for (m of range(0, n)) m] +} +assertDeepEq(countUpToEvens(7), [0,1,0,1,2,3,0,1,2,3,4,5]); + +reportCompare(null, null, "test"); diff --git a/js/src/tests/ecma_6/Comprehensions/scope.js b/js/src/tests/ecma_6/Comprehensions/scope.js new file mode 100644 index 000000000..e9083d552 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/scope.js @@ -0,0 +1,18 @@ +// The identifier of a ComprehensionFor is only bound within its tail. + +function t() { + var x = [0, 1, 2]; + return [for (x of x) x*2] +} +assertDeepEq(t(), [0, 2, 4]); + +// Each iteration should create a fresh binding. Unfortunately this is +// not currently the case, but bug 449811 will fix this. +function t2() { + var x = [0, 1, 2]; + return [for (x of x) ()=>x] +} +// FIXME: Should be [0, 1, 2]. +assertDeepEq([for (x of t2()) x()], [2, 2, 2]); + +reportCompare(null, null, "test"); diff --git a/js/src/tests/ecma_6/Comprehensions/shell.js b/js/src/tests/ecma_6/Comprehensions/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/shell.js diff --git a/js/src/tests/ecma_6/Comprehensions/sudoku.js b/js/src/tests/ecma_6/Comprehensions/sudoku.js new file mode 100644 index 000000000..680f55f64 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/sudoku.js @@ -0,0 +1,168 @@ +/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +function copy(obj) { + var o = {}; + for (var i in obj) + o[i] = obj[i]; + return o; +} + +Array.prototype.repeat = function (n) { + var s = this.constructor(); + for (var i = 0; i < n; i++) + s = s.concat(this); + return s; +} + +String.prototype.center = function (w) { + var n = this.length; + if (w <= n) + return this; + var m = Math.floor((w - n) / 2); + return ' '.repeat(m) + this + ' '.repeat(w - n - m); +} + +Array.prototype.toString = Array.prototype.toSource +Object.prototype.toString = Object.prototype.toSource + +function all(seq) { + for (var e of seq) + if (!e) + return false; + return true; +} + +function some(seq) { + for (var e of seq) + if (e) + return e; + return false; +} + +function cross(A, B) { + return [for (a of A) for (b of B) a+b]; +} + +function dict(A) { + var d = {}; + for (var e of A) + d[e[0]] = e[1]; + return d; +} + +function set(A) { + var s = []; + for (var e of A) + if (!s.includes(e)) + s.push(e); + return s; +} + +function zip(A, B) { + var z = []; + var n = Math.min(A.length, B.length); + for (var i = 0; i < n; i++) + z.push([A[i], B[i]]); + return z; +} + +rows = 'ABCDEFGHI'; +cols = '123456789'; +digits = '123456789'; +squares = cross(rows, cols); +unitlist = [for (c of cols) cross(rows, c)] + .concat([for (r of rows) cross(r, cols)]) + .concat([for (rs of ['ABC','DEF','GHI']) for (cs of ['123','456','789']) cross(rs, cs)]); +units = dict((for (s of squares) + [s, [for (u of unitlist) if (u.includes(s)) u]])); + +peers = dict((for (s of squares) + [s, set([for (u of units[s]) for (s2 of u) if (s2 != s) s2])])); + +// Given a string of 81 digits (or . or 0 or -), return a dict of {cell:values}. +function parse_grid(grid) { + grid = [for (c of grid) if ('0.-123456789'.includes(c)) c]; + var values = dict((for (s of squares) [s, digits])); + + for (var pair of zip(squares, grid)) { + var s = pair[0], d = pair[1]; + if (digits.includes(d) && !assign(values, s, d)) + return false; + } + return values; +} + +// Eliminate all the other values (except d) from values[s] and propagate. +function assign(values, s, d) { + if (all((for (d2 of values[s]) if (d2 != d) eliminate(values, s, d2)))) + return values; + return false; +} + +// Eliminate d from values[s]; propagate when values or places <= 2. +function eliminate(values, s, d) { + if (!values[s].includes(d)) + return values; // Already eliminated + values[s] = values[s].replace(d, ''); + if (values[s].length == 0) + return false; // Contradiction: removed last value + if (values[s].length == 1) { + // If there is only one value (d2) left in square, remove it from peers + var d2 = values[s][0]; + if (!all((for (s2 of peers[s]) eliminate(values, s2, d2)))) + return false; + } + // Now check the places where d appears in the units of s + for (var u of units[s]) { + var dplaces = [for (s of u) if (values[s].includes(d)) s]; + if (dplaces.length == 0) + return false; + if (dplaces.length == 1) + // d can only be in one place in unit; assign it there + if (!assign(values, dplaces[0], d)) + return false; + } + return values; +} + +// Used for debugging. +function print_board(values) { + var width = 1 + Math.max.apply(Math, [for (s of squares) values[s].length]); + var line = '\n' + ['-'.repeat(width*3)].repeat(3).join('+'); + for (var r of rows) + print([for (c of cols) + values[r+c].center(width) + ('36'.includes(c) && '|' || '')] + .join('') + ('CF'.includes(r) && line || '')); + print('\n'); +} + +easy = "..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3.."; + +print_board(parse_grid(easy)); + +// Using depth-first search and constraint propagation, try all possible values. +function search(values) { + if (!values) + return false; // Failed earlier + if (all((for (s of squares) values[s].length == 1))) + return values; // Solved! + + // Choose the unfilled square s with the fewest possibilities + // XXX Math.min etc. should work with generator expressions and other iterators + // XXX Math.min etc. should work on arrays (lists or tuples in Python) as well as numbers + var a = [for (s of squares) if (values[s].length > 1) values[s].length + s].sort(); + var s = a[0].slice(-2); + + return some((for (d of values[s]) search(assign(copy(values), s, d)))); +} + +hard = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......'; + +print_board(search(parse_grid(hard))) + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Comprehensions/syntax.js b/js/src/tests/ecma_6/Comprehensions/syntax.js new file mode 100644 index 000000000..a57b1e6dd --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/syntax.js @@ -0,0 +1,6 @@ +// "let" is not allowed as an identifier. + +assertThrowsInstanceOf(function () { eval('[for (let of y) foo]') }, SyntaxError); +assertThrowsInstanceOf(function () { eval('(for (let of y) foo)') }, SyntaxError); + +reportCompare(null, null, "test"); diff --git a/js/src/tests/ecma_6/Comprehensions/toSource.js b/js/src/tests/ecma_6/Comprehensions/toSource.js new file mode 100644 index 000000000..5ce1db172 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/toSource.js @@ -0,0 +1,14 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +assertEq( function () { g = (for (d of [0]) d); g.next(); }.toSource(), + '(function () { g = (for (d of [0]) d); g.next(); })'); + + +assertEq( function () { return [for (d of [0]) d]; }.toSource(), + '(function () { return [for (d of [0]) d]; })'); + +if (typeof reportCompare === "function") + reportCompare(true, true); |