[es6] Implement completion value reform (--harmony-completion).
This CL depends on #1362363002. R=rossberg BUG= Review URL: https://codereview.chromium.org/1361403003 Cr-Commit-Position: refs/heads/master@{#31180}
This commit is contained in:
parent
3feba64470
commit
7a0a682083
@ -1880,6 +1880,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_concat_spreadable)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexps)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_unicode_regexps)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tostring)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_completion)
|
||||
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_tolength() {
|
||||
@ -2606,6 +2607,7 @@ bool Genesis::InstallExperimentalNatives() {
|
||||
static const char* harmony_simd_natives[] = {"native harmony-simd.js",
|
||||
nullptr};
|
||||
static const char* harmony_tolength_natives[] = {nullptr};
|
||||
static const char* harmony_completion_natives[] = {nullptr};
|
||||
|
||||
for (int i = ExperimentalNatives::GetDebuggerCount();
|
||||
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
||||
|
@ -199,7 +199,8 @@ DEFINE_BOOL(legacy_const, true, "legacy semantics for const in sloppy mode")
|
||||
V(harmony_destructuring, "harmony destructuring") \
|
||||
V(harmony_default_parameters, "harmony default parameters") \
|
||||
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
||||
V(harmony_simd, "harmony simd")
|
||||
V(harmony_simd, "harmony simd") \
|
||||
V(harmony_completion, "harmony completion value semantics")
|
||||
|
||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||
#define HARMONY_STAGED(V) \
|
||||
|
@ -3339,16 +3339,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
|
||||
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
|
||||
Statement* body, bool* ok) {
|
||||
// ES6 13.6.3.4 specifies that on each loop iteration the let variables are
|
||||
// copied into a new environment. After copying, the "next" statement of the
|
||||
// loop is executed to update the loop variables. The loop condition is
|
||||
// checked and the loop body is executed.
|
||||
// ES6 13.7.4.8 specifies that on each loop iteration the let variables are
|
||||
// copied into a new environment. Moreover, the "next" statement must be
|
||||
// evaluated not in the environment of the just completed iteration but in
|
||||
// that of the upcoming one. We achieve this with the following desugaring.
|
||||
// Extra care is needed to preserve the completion value of the original loop.
|
||||
//
|
||||
// We rewrite a for statement of the form
|
||||
// We are given a for statement of the form
|
||||
//
|
||||
// labels: for (let/const x = i; cond; next) body
|
||||
//
|
||||
// into
|
||||
// and rewrite it as follows. Here we write {{ ... }} for init-blocks, ie.,
|
||||
// blocks whose ignore_completion_value_ flag is set.
|
||||
//
|
||||
// {
|
||||
// let/const x = i;
|
||||
@ -3356,29 +3358,21 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
// first = 1;
|
||||
// undefined;
|
||||
// outer: for (;;) {
|
||||
// { // This block's only function is to ensure that the statements it
|
||||
// // contains do not affect the normal completion value. This is
|
||||
// // accomplished by setting its ignore_completion_value bit.
|
||||
// // No new lexical scope is introduced, so lexically scoped variables
|
||||
// // declared here will be scoped to the outer for loop.
|
||||
// let/const x = temp_x;
|
||||
// if (first == 1) {
|
||||
// first = 0;
|
||||
// } else {
|
||||
// next;
|
||||
// }
|
||||
// flag = 1;
|
||||
// }
|
||||
// let/const x = temp_x;
|
||||
// {{ if (first == 1) {
|
||||
// first = 0;
|
||||
// } else {
|
||||
// next;
|
||||
// }
|
||||
// flag = 1;
|
||||
// if (!cond) break;
|
||||
// }}
|
||||
// labels: for (; flag == 1; flag = 0, temp_x = x) {
|
||||
// if (cond) {
|
||||
// body
|
||||
// } else {
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// if (flag == 1) {
|
||||
// break;
|
||||
// body
|
||||
// }
|
||||
// {{ if (flag == 1) // Body used break.
|
||||
// break;
|
||||
// }}
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -3386,7 +3380,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
Scope* for_scope = scope_;
|
||||
ZoneList<Variable*> temps(names->length(), zone());
|
||||
|
||||
Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
|
||||
Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
|
||||
RelocInfo::kNoPosition);
|
||||
|
||||
// Add statement: let/const x = i.
|
||||
@ -3443,7 +3437,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
Block* inner_block =
|
||||
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
|
||||
Block* ignore_completion_block = factory()->NewBlock(
|
||||
NULL, names->length() + 2, true, RelocInfo::kNoPosition);
|
||||
NULL, names->length() + 3, true, RelocInfo::kNoPosition);
|
||||
ZoneList<Variable*> inner_vars(names->length(), zone());
|
||||
// For each let variable x:
|
||||
// make statement: let/const x = temp_x.
|
||||
@ -3502,6 +3496,16 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
|
||||
ignore_completion_block->statements()->Add(assignment_statement, zone());
|
||||
}
|
||||
|
||||
// Make statement: if (!cond) break.
|
||||
if (cond) {
|
||||
Statement* stop =
|
||||
factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
|
||||
Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||
ignore_completion_block->statements()->Add(
|
||||
factory()->NewIfStatement(cond, noop, stop, cond->position()), zone());
|
||||
}
|
||||
|
||||
inner_block->statements()->Add(ignore_completion_block, zone());
|
||||
// Make cond expression for main loop: flag == 1.
|
||||
Expression* flag_cond = NULL;
|
||||
@ -3540,23 +3544,14 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
compound_next, RelocInfo::kNoPosition);
|
||||
}
|
||||
|
||||
// Make statement: if (cond) { body; } else { break outer; }
|
||||
Statement* body_or_stop = body;
|
||||
if (cond) {
|
||||
Statement* stop =
|
||||
factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
|
||||
body_or_stop =
|
||||
factory()->NewIfStatement(cond, body, stop, cond->position());
|
||||
}
|
||||
|
||||
// Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
|
||||
// Note that we re-use the original loop node, which retains its labels
|
||||
// and ensures that any break or continue statements in body point to
|
||||
// the right place.
|
||||
loop->Initialize(NULL, flag_cond, compound_next_statement, body_or_stop);
|
||||
loop->Initialize(NULL, flag_cond, compound_next_statement, body);
|
||||
inner_block->statements()->Add(loop, zone());
|
||||
|
||||
// Make statement: if (flag == 1) { break; }
|
||||
// Make statement: {{if (flag == 1) break;}}
|
||||
{
|
||||
Expression* compare = NULL;
|
||||
// Make compare expresion: flag == 1.
|
||||
@ -3571,7 +3566,10 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||
Statement* if_flag_break =
|
||||
factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
|
||||
inner_block->statements()->Add(if_flag_break, zone());
|
||||
Block* ignore_completion_block =
|
||||
factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
|
||||
ignore_completion_block->statements()->Add(if_flag_break, zone());
|
||||
inner_block->statements()->Add(ignore_completion_block, zone());
|
||||
}
|
||||
|
||||
inner_scope->set_end_position(scanner()->location().end_pos);
|
||||
|
@ -62,6 +62,9 @@ class Processor: public AstVisitor {
|
||||
Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition);
|
||||
}
|
||||
|
||||
// Inserts '.result = undefined' in front of the given statement.
|
||||
Statement* AssignUndefinedBefore(Statement* s);
|
||||
|
||||
// Node visitors.
|
||||
#define DEF_VISIT(type) virtual void Visit##type(type* node) override;
|
||||
AST_NODE_LIST(DEF_VISIT)
|
||||
@ -73,6 +76,20 @@ class Processor: public AstVisitor {
|
||||
};
|
||||
|
||||
|
||||
Statement* Processor::AssignUndefinedBefore(Statement* s) {
|
||||
Expression* result_proxy = factory()->NewVariableProxy(result_);
|
||||
Expression* undef = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
|
||||
Expression* assignment = factory()->NewAssignment(
|
||||
Token::ASSIGN, result_proxy, undef, RelocInfo::kNoPosition);
|
||||
Block* b = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
|
||||
b->statements()->Add(
|
||||
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
||||
zone());
|
||||
b->statements()->Add(s, zone());
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
void Processor::Process(ZoneList<Statement*>* statements) {
|
||||
for (int i = statements->length() - 1; i >= 0; --i) {
|
||||
Visit(statements->at(i));
|
||||
@ -116,6 +133,11 @@ void Processor::VisitIfStatement(IfStatement* node) {
|
||||
node->set_else_statement(replacement_);
|
||||
is_set_ = is_set_ && set_in_then;
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -127,6 +149,11 @@ void Processor::VisitIterationStatement(IterationStatement* node) {
|
||||
node->set_body(replacement_);
|
||||
is_set_ = is_set_ && set_after;
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -166,6 +193,11 @@ void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
|
||||
node->set_catch_block(static_cast<Block*>(replacement_));
|
||||
is_set_ = is_set_ && set_in_try;
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -198,6 +230,11 @@ void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
|
||||
Visit(node->try_block());
|
||||
node->set_try_block(replacement_->AsBlock());
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -211,6 +248,11 @@ void Processor::VisitSwitchStatement(SwitchStatement* node) {
|
||||
}
|
||||
is_set_ = is_set_ && set_after;
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -230,6 +272,11 @@ void Processor::VisitWithStatement(WithStatement* node) {
|
||||
Visit(node->statement());
|
||||
node->set_statement(replacement_);
|
||||
replacement_ = node;
|
||||
|
||||
if (FLAG_harmony_completion && !is_set_) {
|
||||
is_set_ = true;
|
||||
replacement_ = AssignUndefinedBefore(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,10 +189,10 @@ assertEquals(undefined, eval("for (let i = 0; i < 10; i++) { continue; i; }"));
|
||||
assertEquals(0, eval("for (let i = 0; true;) { i; break; }"));
|
||||
assertEquals(0, eval("for (const i = 0; true;) { i; break; }"));
|
||||
assertEquals(9, eval("for (let i = 0; i < 10; i++) { i; continue; }"));
|
||||
assertEquals(3, eval("for (let i = 0; true; i++) { i; if (i >= 3) break; }"));
|
||||
assertEquals(2, eval("for (let i = 0; true; i++) { if (i >= 3) break; i; }"));
|
||||
assertEquals(3, eval("for (let i = 0; true; i++) { i; if (i >= 3) break; }")); // --harmony-completion: undefined
|
||||
assertEquals(2, eval("for (let i = 0; true; i++) { if (i >= 3) break; i; }")); // --harmony-completion: undefined
|
||||
assertEquals(
|
||||
2, eval("for (let i = 0; i < 10; i++) { if (i >= 3) continue; i; }"));
|
||||
2, eval("for (let i = 0; i < 10; i++) { if (i >= 3) continue; i; }")); // --harmony-completion: undefined
|
||||
assertEquals(undefined, eval("foo: for (let i = 0; true;) { break foo; }"));
|
||||
assertEquals(undefined, eval("foo: for (const i = 0; true;) { break foo; }"));
|
||||
assertEquals(3, eval("foo: for (let i = 3; true;) { i; break foo; }"));
|
||||
|
@ -26,6 +26,7 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --no-legacy-const --harmony-sloppy --harmony-sloppy-let
|
||||
// Flags: --harmony-completion
|
||||
|
||||
function props(x) {
|
||||
var array = [];
|
||||
@ -190,10 +191,12 @@ assertEquals(undefined, eval("for (let i = 0; i < 10; i++) { continue; i; }"));
|
||||
assertEquals(0, eval("for (let i = 0; true;) { i; break; }"));
|
||||
assertEquals(0, eval("for (const i = 0; true;) { i; break; }"));
|
||||
assertEquals(9, eval("for (let i = 0; i < 10; i++) { i; continue; }"));
|
||||
assertEquals(3, eval("for (let i = 0; true; i++) { i; if (i >= 3) break; }"));
|
||||
assertEquals(2, eval("for (let i = 0; true; i++) { if (i >= 3) break; i; }"));
|
||||
assertEquals(
|
||||
2, eval("for (let i = 0; i < 10; i++) { if (i >= 3) continue; i; }"));
|
||||
undefined, eval("for (let i = 0; true; i++) { i; if (i >= 3) break; }"));
|
||||
assertEquals(
|
||||
undefined, eval("for (let i = 0; true; i++) { if (i >= 3) break; i; }"));
|
||||
assertEquals(
|
||||
undefined, eval("for (let i = 0; i < 10; i++) { if (i >= 3) continue; i; }"));
|
||||
assertEquals(undefined, eval("foo: for (let i = 0; true;) { break foo; }"));
|
||||
assertEquals(undefined, eval("foo: for (const i = 0; true;) { break foo; }"));
|
||||
assertEquals(3, eval("foo: for (let i = 3; true;) { i; break foo; }"));
|
||||
|
150
test/mjsunit/harmony/completion.js
Normal file
150
test/mjsunit/harmony/completion.js
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Flags: --harmony-completion --harmony-sloppy-let --no-legacy-const
|
||||
|
||||
|
||||
function assertUndef(x) {
|
||||
assertEquals(undefined, x);
|
||||
}
|
||||
|
||||
|
||||
// IfStatement [13.6.7]
|
||||
|
||||
assertUndef(eval('42; if (true) ; else 0;')); // ES5: 42
|
||||
assertUndef(eval('42; if (true) ;')); // ES5: 42
|
||||
assertUndef(eval('42; if (false) 0;')); // ES5: 42
|
||||
|
||||
assertEquals(1, eval('42; if (true) 1;'));
|
||||
assertEquals(1, eval('42; if (true) 1; else 0;'));
|
||||
assertEquals(0, eval('42; if (false) 1; else 0;'));
|
||||
|
||||
|
||||
// IterationStatement [13.7]
|
||||
|
||||
assertUndef(eval('42; do ; while (false);')); // ES5: 42
|
||||
assertUndef(eval('42; var x = 1; do ; while (x--);')); // ES5: 42
|
||||
assertUndef(eval('42; while (false) 0;')); // ES5: 42
|
||||
assertUndef(eval('42; while (true) break;')); // ES5: 42
|
||||
assertUndef(eval('42; bla: while (true) break bla;')); // ES5: 42
|
||||
assertUndef(eval('42; var x = 1; while (x--) ;')); // ES5: 42
|
||||
assertUndef(eval('42; for (; false; ) 0;')); // ES5: 42
|
||||
assertUndef(eval('42; for (var x = 1; x; x--) ;')); // ES5: 42
|
||||
assertUndef(eval('42; for (var x in ["foo", "bar"]) ;'));
|
||||
assertUndef(eval('42; for (var x of ["foo", "bar"]) ;'));
|
||||
assertUndef(eval('42; for (let x = 1; x; x--) ;'));
|
||||
assertUndef(eval('42; for (let x in ["foo", "bar"]) ;'));
|
||||
assertUndef(eval('42; for (let x of ["foo", "bar"]) ;'));
|
||||
assertUndef(eval('42; for (const x in ["foo", "bar"]) ;'));
|
||||
assertUndef(eval('42; for (const x of ["foo", "bar"]) ;'));
|
||||
|
||||
assertEquals(1, eval('42; var x = 10; do x--; while (x);'));
|
||||
assertEquals(1, eval('42; var x = 10; while (x) x--;'));
|
||||
assertEquals(1, eval('42; for (var x = 10; x; x--) x;'));
|
||||
assertEquals(1, eval('42; for (var x = 10; x; --x) x;'));
|
||||
assertEquals(1, eval('42; for (let x = 10; x; --x) x;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (var x in ["foo", "bar"]) y--;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (const x in ["foo", "bar"]) y--;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (let x in ["foo", "bar"]) y--;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (var x of ["foo", "bar"]) y--;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (const x of ["foo", "bar"]) y--;'));
|
||||
assertEquals(1, eval('42; var y = 2; for (let x of ["foo", "bar"]) y--;'));
|
||||
|
||||
|
||||
// WithStatement [13.11.7]
|
||||
|
||||
assertUndef(eval('42; with ({}) ;')); // ES5: 42
|
||||
|
||||
assertEquals(1, eval('42; with ({}) 1;'));
|
||||
|
||||
|
||||
// SwitchStatement [13.12.11]
|
||||
|
||||
assertUndef(eval('42; switch (0) {};')); // ES5: 42
|
||||
assertUndef(eval('42; switch (0) { case 1: 1; };')); // ES5: 42
|
||||
assertUndef(eval('42; switch (0) { case 0: ; };')); // ES5: 42
|
||||
assertUndef(eval('42; switch (0) { default: ; };')); // ES5: 42
|
||||
assertUndef(eval('42; switch (0) { case 0: break; }')); // ES5: 42
|
||||
|
||||
assertEquals(1, eval('42; switch (0) { case 0: 1; }'));
|
||||
assertEquals(1, eval('42; switch (0) { case 0: 1; break; }'));
|
||||
assertEquals(1, eval('42; switch (0) { case 0: 1; case 666: break; }'));
|
||||
assertEquals(2, eval('42; switch (0) { case 0: 1; case 666: 2; break; }'));
|
||||
|
||||
|
||||
// TryStatement [13.15.8]
|
||||
|
||||
assertUndef(eval('42; try { } catch(e) { };')); // ES5: 42
|
||||
assertUndef(eval('42; try { } catch(e) { 0; };')); // ES5: 42
|
||||
assertUndef(eval('42; try { throw "" } catch(e) { };')); // ES5: 42
|
||||
assertUndef(eval('42; try { throw "" } catch(e) { } finally { };')); // ES5: 42
|
||||
assertUndef(eval('42; try { } finally { 666 };')); // ES5: 42
|
||||
|
||||
|
||||
// Some combinations
|
||||
|
||||
assertUndef(eval('42; switch (0) { case 0: if (true) break; }')); // ES5: 42
|
||||
assertUndef(eval('42; switch (0) { case 0: 1; if (true) ; }')); // ES5: 1
|
||||
assertUndef(eval('42; switch (0) { case 0: 1; try { break } catch(e) { }; }')); // ES5: 1
|
||||
|
||||
assertEquals(0, eval('42; switch (0) { case 0: 0; case 1: break; }'));
|
||||
assertEquals(0, eval('42; while (1) { 0; break; }'))
|
||||
assertEquals(0, eval('42; bla: while (1) { 0; break bla; }'))
|
||||
assertEquals(0, eval('42; while (1) { with ({}) { 0; break; } }'))
|
||||
assertEquals(0, eval('42; while (1) { try { 0; break } catch(e) {666} }'))
|
||||
assertEquals(0, eval(
|
||||
'42; while (1) { try { 0; break } catch(e) {666} finally {666} }'))
|
||||
assertEquals(0, eval(
|
||||
'42; while (1) { try { throw "" } catch(e) {666} finally {0; break} }'))
|
||||
assertEquals(0, eval(
|
||||
'42; while (1) { try { throw "" } catch(e) {0; break} finally {666} }'))
|
||||
assertEquals(0, eval(
|
||||
'42; while (1) { try { 666 } finally {0; break} }'));
|
||||
assertEquals(0, eval(
|
||||
'42; while (1) { try { 666; break } finally {0; break} }'));
|
||||
assertEquals(0, eval(
|
||||
'42; lab: try { 666; break lab } finally {0; break lab}'));
|
||||
assertEquals(undefined, eval(
|
||||
'var b = 1; ' +
|
||||
'outer: while (1) { while (1) { if (b--) 42; else break outer; }; 666 }'));
|
||||
|
||||
// The following is not what ES6 says, but see ES bug 4540.
|
||||
assertUndef(eval('42; switch (0) { case 0: 1; if (true) break; }')); // ES5: 1
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following are copied from webkit/eval-throw-return and adapted.
|
||||
|
||||
function throwFunc() {
|
||||
throw "";
|
||||
}
|
||||
|
||||
function throwOnReturn(){
|
||||
1;
|
||||
return throwFunc();
|
||||
}
|
||||
|
||||
function twoFunc() {
|
||||
2;
|
||||
}
|
||||
|
||||
assertEquals(1, eval("1;"));
|
||||
assertUndef(eval("1; try { foo = [2,3,throwFunc(), 4]; } catch (e){}"));
|
||||
assertUndef(eval("1; try { 2; throw ''; } catch (e){}"));
|
||||
assertUndef(eval("1; try { 2; throwFunc(); } catch (e){}"));
|
||||
assertEquals(3, eval("1; try { 2; throwFunc(); } catch (e){3;} finally {}"));
|
||||
assertEquals(3, eval("1; try { 2; throwFunc(); } catch (e){3;} finally {4;}"));
|
||||
assertUndef(eval("function blah() { 1; }; blah();"));
|
||||
assertUndef(eval("var x = 1;"));
|
||||
assertEquals(1, eval("if (true) { 1; } else { 2; }"));
|
||||
assertEquals(2, eval("if (false) { 1; } else { 2; }"));
|
||||
assertUndef(eval("try{1; if (true) { 2; throw ''; } else { 2; }} catch(e){}"));
|
||||
assertEquals(2, eval("1; var i = 0; do { ++i; 2; } while(i!=1);"));
|
||||
assertUndef(eval(
|
||||
"try{1; var i = 0; do { ++i; 2; throw ''; } while (i!=1);} catch(e){}"));
|
||||
assertUndef(eval("1; try{2; throwOnReturn();} catch(e){}"));
|
||||
assertUndef(eval("1; twoFunc();"));
|
||||
assertEquals(2, eval("1; with ( { a: 0 } ) { 2; }"));
|
Loading…
Reference in New Issue
Block a user