es6-for-of-visitors.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /**
  2. * Copyright 2013-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. /*global exports:true*/
  10. /**
  11. * Implements ES6 for-of loop, making optimization
  12. * for arrays. If an object is not an array, instantiates
  13. * an iterator for this object, assuming the runtime
  14. * support for the iterator is implemented.
  15. *
  16. * ES6:
  17. *
  18. * for (var v of <expr>) <body>
  19. *
  20. * Compiled ES3:
  21. *
  22. * for (var v,
  23. * _iter = <expr>,
  24. * _isArray = Array.isArray(_iter),
  25. * _k = 0,
  26. * _iter = _isArray ? _iter : _iter[Symbol.iterator]();;
  27. * ) {
  28. *
  29. * if (_isArray) {
  30. * if (_k >= _iter.length) break;
  31. * v = _iter[_k++];
  32. * } else {
  33. * _k = _iter.next();
  34. * if (_k.done) break;
  35. * v = _k.value;
  36. * }
  37. *
  38. * <body>
  39. * }
  40. */
  41. var Syntax = require('esprima-fb').Syntax;
  42. var utils = require('../src/utils');
  43. function process(traverse, node, path, state) {
  44. utils.move(node.range[0], state);
  45. traverse(node, path, state);
  46. utils.catchup(node.range[1], state);
  47. }
  48. function visitForOfStatement(traverse, node, path, state) {
  49. var iter = utils.injectTempVar(state);
  50. var isArray = utils.injectTempVar(state);
  51. var k = utils.injectTempVar(state);
  52. var variable;
  53. if (node.left.type === Syntax.VariableDeclaration) {
  54. variable = node.left.declarations[0].id.name;
  55. utils.append('var ' + variable + ';', state);
  56. } else {
  57. variable = node.left.name;
  58. }
  59. utils.append('for(', state);
  60. utils.append(iter + '=', state);
  61. process(traverse, node.right, path, state);
  62. // Setup iterator with optimization for arrays.
  63. utils.append(
  64. ',' + isArray + '=Array.isArray(' + iter + '),' +
  65. k + '=0,' +
  66. iter + '=' + isArray + '?' + iter + ':' +
  67. iter + '[/*global Symbol*/typeof Symbol=="function"' +
  68. '?Symbol.iterator:"@@iterator"]();;',
  69. state
  70. );
  71. // Jump to the body creating block if needed.
  72. if (node.body.type === Syntax.BlockStatement) {
  73. utils.catchup(node.body.range[0] + 1, state);
  74. } else {
  75. utils.catchup(node.body.range[0], state);
  76. utils.append('{', state);
  77. }
  78. // Arrays case.
  79. utils.append(
  80. 'if(' + isArray + '){' +
  81. 'if(' + k + '>=' + iter + '.length) break;',
  82. state
  83. );
  84. utils.append(variable + '=' + iter + '[' + k + '++];', state);
  85. // Iterators case.
  86. utils.append(
  87. '}else{' + k + '=' + iter + '.next();' +
  88. 'if(' + k + '.done) break;',
  89. state
  90. );
  91. utils.append(variable + '=' + k + '.value;}', state);
  92. traverse(node.body, path, state);
  93. utils.catchup(node.body.range[1], state);
  94. if (node.body.type !== Syntax.BlockStatement) {
  95. utils.append('}', state);
  96. }
  97. return false;
  98. }
  99. visitForOfStatement.test = function(node, path, state) {
  100. return node.type === Syntax.ForOfStatement;
  101. };
  102. exports.visitorList = [
  103. visitForOfStatement,
  104. ];