text: /*
   *  Development test for avoiding relying on a register bound variable
   *  as a final expression result for assignment: it's incorrect if the
   *  value is used as an input for further expressions because it may
   *  change before it's eventually read.
   *
   *  Exercise all code paths of duk_js_compiler 'assign:' handling.
   *  Generated bytecode should also be inspected manually using e.g.
   *  the debugger web UI.
   */
  
  /*===
  slow path
  true
  123
  123.1
  5
  99
  100
  223
  346.1
  351.1
  450.1
  true
  123
  123.1
  5
  99
  100
  223
  346.1
  351.1
  450.1
  post: true
  post: 123
  post: 123.1
  post: 5
  post: 99
  post: 100
  post: 223
  post: 346.1
  post: 351.1
  post: 450.1
  pre: 450.1
  post: true
  pre: true
  post: 123
  pre: 123
  post: 123.1
  pre: 123.1
  post: 5
  pre: 5
  post: 99
  pre: 99
  post: 100
  pre: 100
  post: 223
  pre: 223
  post: 346.1
  pre: 346.1
  post: 351.1
  pre: 351.1
  post: 450.1
  true
  true
  123
  123
  123.1
  123.1
  5
  5
  99
  99
  100
  100
  223
  223
  346.1
  346.1
  351.1
  351.1
  450.1
  450.1
  100
  100
  600
  1000
  100
  650
  30
  100
  3
  3
  arg1
  arg2
  357
  30
  100
  ===*/
  
  var glob;
  
  /* Test assignment cases where LHS is handled using slow path PUTVAR. */
  
  function slowPathAssignTest() {
      var four = 4;
      var y = 99;
      var y1 = 10;
      var y2 = 20;
      var y3 = 30;
      var y4 = 40;
  
      // Top-level assignment cases.
      //  plain: true, 123
      //  const: 123.1, 'foo'
      //  temp reg: four + 1
      //  reg-bound var: y
  
      glob = true; print(glob);
      glob = 123; print(glob);
      glob = 123.1; print(glob);
      glob = four + 1; print(glob);
      glob = y; print(glob);
  
      glob += true; print(glob);
      glob += 123; print(glob);
      glob += 123.1; print(glob);
      glob += four + 1; print(glob);
      glob += y; print(glob);
  
      // Parenthesis don't affect the top level status.
  
      (glob = true); print(glob);
      (glob = 123); print(glob);
      (glob = 123.1); print(glob);
      (glob = four + 1); print(glob);
      (glob = y); print(glob);
  
      (glob += true); print(glob);
      (glob += 123); print(glob);
      (glob += 123.1); print(glob);
      (glob += four + 1); print(glob);
      (glob += y); print(glob);
  
      // Comma expression doesn't affect top level status.
  
      glob = true, print('post: ' + glob);
      glob = 123, print('post: ' + glob);
      glob = 123.1, print('post: ' + glob);
      glob = four + 1, print('post: ' + glob);
      glob = y, print('post: ' + glob);
  
      glob += true, print('post: ' + glob);
      glob += 123, print('post: ' + glob);
      glob += 123.1, print('post: ' + glob);
      glob += four + 1, print('post: ' + glob);
      glob += y, print('post: ' + glob);
  
      print('pre: ' + glob), glob = true, print('post: ' + glob);
      print('pre: ' + glob), glob = 123, print('post: ' + glob);
      print('pre: ' + glob), glob = 123.1, print('post: ' + glob);
      print('pre: ' + glob), glob = four + 1, print('post: ' + glob);
      print('pre: ' + glob), glob = y, print('post: ' + glob);
  
      print('pre: ' + glob), glob += true, print('post: ' + glob);
      print('pre: ' + glob), glob += 123, print('post: ' + glob);
      print('pre: ' + glob), glob += 123.1, print('post: ' + glob);
      print('pre: ' + glob), glob += four + 1, print('post: ' + glob);
      print('pre: ' + glob), glob += y, print('post: ' + glob);
  
      // Being inside a function call (or any other expression type)
      // removes top level status.
  
      print(glob = true); print(glob);
      print(glob = 123); print(glob);
      print(glob = 123.1); print(glob);
      print(glob = four + 1); print(glob);
      print(glob = y); print(glob);
  
      print(glob += true); print(glob);
      print(glob += 123); print(glob);
      print(glob += 123.1); print(glob);
      print(glob += four + 1); print(glob);
      print(glob += y); print(glob);
  
      // Intermediate values must be independent of 'glob'.
  
      print( ((glob = 10) + (glob = 20)) + ((glob = 30) + (glob = 40)) );
      print( ((glob = y1) + (glob = y2)) + ((glob = y3) + (glob = y4)) );
  
      glob = 100;
      print( ((glob += 10) + (glob += 20)) + ((glob += 30) + (glob += 40)) );
      print( ((glob += y1) + (glob += y2)) + ((glob += y3) + (glob += y4)) );
  
      // Both LHS and RHS are mutated so an actual temp is mandatory.
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( ((glob = y1) + (glob = y1 = y2)) + ((glob = y1 = y2 = y3) + (glob = y1 = y2 = y3 = y4)) );
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( ((glob += y1) + (glob += y1 += y2)) + ((glob += y1 += y2 += y3) + (glob += y1 += y2 += y3 += y4)) );
  
      // Unresolved addition as RHS.
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      glob = y1 + y2; print(glob);
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( (glob = y1 + y2) + (glob = y3 + y4) );
  
      // Unresolved addition as RHS.  Must be computed exactly once
      // so that side effects are not repeated.
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print(glob = 1 + 2); print(glob);
  
      var obj1 = {valueOf: function() { print('arg1'); return 123; }};
      var obj2 = {valueOf: function() { print('arg2'); return 234; }};
      print(glob = obj1 + obj2);
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      glob = y1 + y2; print(glob);
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( (glob = y1 + y2) + (glob = y3 + y4) );
  }
  
  try {
      print('slow path');
      slowPathAssignTest();
  } catch (e) {
      print(e.stack || e);
  }
  
  /*===
  fast path
  true
  123
  123.1
  5
  99
  100
  223
  346.1
  351.1
  450.1
  true
  123
  123.1
  5
  99
  100
  223
  346.1
  351.1
  450.1
  post: true
  post: 123
  post: 123.1
  post: 5
  post: 99
  post: 100
  post: 223
  post: 346.1
  post: 351.1
  post: 450.1
  pre: 450.1
  post: true
  pre: true
  post: 123
  pre: 123
  post: 123.1
  pre: 123.1
  post: 5
  pre: 5
  post: 99
  pre: 99
  post: 100
  pre: 100
  post: 223
  pre: 223
  post: 346.1
  pre: 346.1
  post: 351.1
  pre: 351.1
  post: 450.1
  true
  true
  123
  123
  123.1
  123.1
  5
  5
  99
  99
  100
  100
  223
  223
  346.1
  346.1
  351.1
  351.1
  450.1
  450.1
  100
  100
  600
  1000
  100
  650
  3
  3
  arg1
  arg2
  357
  30
  100
  ===*/
  
  /* Test assignment cases where LHS is handled using the fast path, i.e.
   * a register load to a register-bound identifier.
   */
  
  function fastPathAssignTest() {
      var four = 4;
      var x;
      var y = 99;
      var y1 = 10;
      var y2 = 20;
      var y3 = 30;
      var y4 = 40;
  
      // Top-level assignment cases.
      //  plain: true, 123
      //  const: 123.1, 'foo'
      //  temp reg: four + 1
      //  reg-bound var: y
  
      x = true; print(x);
      x = 123; print(x);
      x = 123.1; print(x);
      x = four + 1; print(x);
      x = y; print(x);
  
      x += true; print(x);
      x += 123; print(x);
      x += 123.1; print(x);
      x += four + 1; print(x);
      x += y; print(x);
  
      // Parenthesis don't affect the top level status.
  
      (x = true); print(x);
      (x = 123); print(x);
      (x = 123.1); print(x);
      (x = four + 1); print(x);
      (x = y); print(x);
  
      (x += true); print(x);
      (x += 123); print(x);
      (x += 123.1); print(x);
      (x += four + 1); print(x);
      (x += y); print(x);
  
      // Comma expression doesn't affect top level status.
  
      x = true, print('post: ' + x);
      x = 123, print('post: ' + x);
      x = 123.1, print('post: ' + x);
      x = four + 1, print('post: ' + x);
      x = y, print('post: ' + x);
  
      x += true, print('post: ' + x);
      x += 123, print('post: ' + x);
      x += 123.1, print('post: ' + x);
      x += four + 1, print('post: ' + x);
      x += y, print('post: ' + x);
  
      print('pre: ' + x), x = true, print('post: ' + x);
      print('pre: ' + x), x = 123, print('post: ' + x);
      print('pre: ' + x), x = 123.1, print('post: ' + x);
      print('pre: ' + x), x = four + 1, print('post: ' + x);
      print('pre: ' + x), x = y, print('post: ' + x);
  
      print('pre: ' + x), x += true, print('post: ' + x);
      print('pre: ' + x), x += 123, print('post: ' + x);
      print('pre: ' + x), x += 123.1, print('post: ' + x);
      print('pre: ' + x), x += four + 1, print('post: ' + x);
      print('pre: ' + x), x += y, print('post: ' + x);
  
      // Being inside a function call (or any other expression type)
      // removes top level status.
  
      print(x = true); print(x);
      print(x = 123); print(x);
      print(x = 123.1); print(x);
      print(x = four + 1); print(x);
      print(x = y); print(x);
  
      print(x += true); print(x);
      print(x += 123); print(x);
      print(x += 123.1); print(x);
      print(x += four + 1); print(x);
      print(x += y); print(x);
  
      // Intermediate values must be independent of 'x'.
  
      print( ((x = 10) + (x = 20)) + ((x = 30) + (x = 40)) );
      print( ((x = y1) + (x = y2)) + ((x = y3) + (x = y4)) );
  
      x = 100;
      print( ((x += 10) + (x += 20)) + ((x += 30) + (x += 40)) );
      print( ((x += y1) + (x += y2)) + ((x += y3) + (x += y4)) );
  
      // Both LHS and RHS are mutated so an actual temp is mandatory.
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( ((x = y1) + (x = y1 = y2)) + ((x = y1 = y2 = y3) + (x = y1 = y2 = y3 = y4)) );
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( ((x += y1) + (x += y1 += y2)) + ((x += y1 += y2 += y3) + (x += y1 += y2 += y3 += y4)) );
  
      // Unresolved addition as RHS.  Must be computed exactly once
      // so that side effects are not repeated.
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print(x = 1 + 2); print(x);
  
      var obj1 = {valueOf: function() { print('arg1'); return 123; }};
      var obj2 = {valueOf: function() { print('arg2'); return 234; }};
      print(x = obj1 + obj2);
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      x = y1 + y2; print(x);
  
      y1 = 10; y2 = 20; y3 = 30; y4 = 40;
      print( (x = y1 + y2) + (x = y3 + y4) );
  }
  
  try {
      print('fast path');
      fastPathAssignTest();
  } catch (e) {
      print(e.stack || e);
  }
  
  /*===
  misc assign test
  50
  70
  120
  50
  70
  120
  50
  70
  120
  50
  70
  120
  50
  70
  120
  50
  70
  120
  17.1
  30
  123
  123.1
  30
  123
  123.1
  30 123 123.1
  ===*/
  
  function miscAssignTest() {
      var x = 10;
      var y = 20;
      var z = 30;
      var w;
      var obj = { foo: 0 };
  
      // On the top level these should not use a temporary, and e.g.
      // x = y + z should compile to a single ADD.
      x = y + z; print(x);
      x += y; print(x);
      x += y + z; print(x);
  
      // Outside of top level a temporary must be used.
      w = x = y + z; print(x);
      w = x += y; print(x);
      w = x += y + z; print(x);
  
      // Same tests for a non-reg-bound variable.
      glob = y + z; print(glob);
      glob += y; print(glob);
      glob += y + z; print(glob);
      w = glob = y + z; print(glob);
      w = glob += y; print(glob);
      w = glob += y + z; print(glob);
  
      // And for a property LHS.
      obj.foo = y + z; print(obj.foo);
      obj.foo += y; print(obj.foo);
      obj.foo += y + z; print(obj.foo);
      w = obj.foo = y + z; print(obj.foo);
      w = obj.foo += y; print(obj.foo);
      w = obj.foo += y + z; print(obj.foo);
  
      // Bytecode tests (inspect manually)
      x = 10;
      x += 3;
      x += 3.1;
      x += true;
      print(x);
  
      x = 10; y = 20;
      glob = +(x + y); print(glob);
      glob = 123; print(glob);
      glob = 123.1; print(glob);
      w = glob = +(x + y); print(glob);
      w = glob = 123; print(glob);
      w = glob = 123.1; print(glob);
      print(glob = +(x + y), glob = 123, glob = 123.1);
  }
  
  try {
      print('misc assign test');
      miscAssignTest();
  } catch (e) {
      print(e.stack || e);
  }
  