首页 > 代码库 > 用Windjs画圆
用Windjs画圆
无意中接触了jscex,也就是Wind.js的前身,深深被它和它的作者老赵吸引。该轻量级js库是为了实现异步编程所设计的,可能因为eval的种种不安全因素或者应用不是很广的原因至今也没很大程度上的推广,从github上来看代码也已经两年多没更新了,但是还是有必要写几个小的demo的,毕竟下份需要阅读的代码中有用到该类库。
先写个canvas上画圆的demo。
等等,画圆?开玩笑,arc简单搞定!那么,要是不用h5的api自己来写这个函数呢?动手画了下感觉还是蛮easy的:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <link rel="stylesheet" href="reset.css"> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <title> </title> 7 <script src="jquery.js"></script> 8 <script src="wind-all-0.7.3.js"></script> 9 <script>10 window.onload = function() {11 var canvas = document.getElementById("canvas");12 var ctx = canvas.getContext("2d");13 var x = 250;14 var y = 250;15 var r = 100;16 var frontX = x - r;17 var frontY = y;18 19 for(var i = x - r; i <= x + r; i++) {20 var tempY = Math.sqrt(r * r - (x - i) * (x - i));21 ctx.beginPath();22 ctx.moveTo(frontX, frontY);23 ctx.lineTo(i, y+ tempY);24 ctx.stroke();25 frontX = i;26 frontY = y + tempY;27 }28 29 for(var i = x + r; i >= x - r; i--) {30 var tempY = Math.sqrt(r * r - (x - i) * (x - i));31 ctx.beginPath();32 ctx.moveTo(frontX, frontY);33 ctx.lineTo(i, y - tempY);34 ctx.stroke();35 frontX = i;36 frontY = y - tempY;37 }38 };39 </script>40 </head>41 <body>42 <canvas id=‘canvas‘ width=500 height=500 style=‘border:1px solid red‘>43 </canvas>44 </body>45 </html>
这里为了写的规范点,用了beginPath。不用beginPath有时会出现些莫名其妙的错误,值得注意。
那么,进步一想,能不能在画布上显示绘制过程呢?
what?开玩笑吧,我们都知道js这样的解释型语言,解释完了也就画完了,咋可能显示绘制过程?
等等,let me have a try,看看能不能用setTimeout?将stroke函数设置个定时器,约定1s后执行,那么能不能出现1s绘制一帧的效果呢?
很遗憾,事实上是没有的,实际的效果是1s后全部绘图一瞬间完成,因为for循环就在一瞬间,然后所有的setTimeout同时累计起来了,what a pity!
这时我们祭出大杀器Windjs!改写后的代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <link rel="stylesheet" href="reset.css"> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <title> </title> 7 <script src="jquery.js"></script> 8 <script src="wind-all-0.7.3.js"></script> 9 <script>10 window.onload = function() {11 var canvas = document.getElementById("canvas");12 var ctx = canvas.getContext("2d");13 var x = 250;14 var y = 250;15 var r = 100;16 var frontX = x - r;17 var frontY = y;18 19 var drawAsync = eval(Wind.compile(‘async‘, function() {20 for(var i = x - r; i <= x + r; i++) {21 var tempY = Math.sqrt(r * r - (x - i) * (x - i));22 ctx.beginPath();23 ctx.moveTo(frontX, frontY);24 ctx.lineTo(i, y+ tempY);25 $await(Wind.Async.sleep(10));26 ctx.stroke();27 frontX = i;28 frontY = y + tempY;29 }30 31 for(var i = x + r; i >= x - r; i--) {32 var tempY = Math.sqrt(r * r - (x - i) * (x - i));33 ctx.beginPath();34 ctx.moveTo(frontX, frontY);35 ctx.lineTo(i, y - tempY);36 $await(Wind.Async.sleep(10));37 ctx.stroke();38 frontX = i;39 frontY = y - tempY;40 }41 }));42 43 drawAsync().start();44 };45 </script>46 </head>47 <body>48 <canvas id=‘canvas‘ width=500 height=500 style=‘border:1px solid red‘>49 </canvas>50 </body>51 </html>
what a pass!来自Windjs的助攻成功地完成了不可能完成的任务!
ps:Wind.js备份
1 /*********************************************************************** 2 wind-core-0.7.0.js 3 ***********************************************************************/ 4 5 (function () { 6 "use strict"; 7 8 var Wind; 9 10 var _ = (function () { 11 12 var isArray = function (obj) { 13 return Object.prototype.toString.call(obj) === ‘[object Array]‘; 14 } 15 16 var each = function (obj, action) { 17 if (isArray(obj)) { 18 for (var i = 0, len = obj.length; i < len; i++) { 19 var value = http://www.mamicode.com/action.length === 1 ? action(obj[i]) : action(i, obj[i]); 20 if (value !== undefined) 21 return value; 22 } 23 } else { 24 for (var key in obj) { 25 if (obj.hasOwnProperty(key)) { 26 var value = http://www.mamicode.com/action.length === 1 ? action(obj[key]) : action(key, obj[key]); 27 if (value !== undefined) 28 return value; 29 } 30 } 31 } 32 } 33 34 var isEmpty = function (obj) { 35 if (isArray(obj)) { 36 return obj.length === 0; 37 } 38 39 return !(_.each(obj, function (v) { return true; })); 40 } 41 42 var map = function (obj, mapper, valueMapper) { 43 if (isArray(obj)) { 44 var array = new Array(obj.length); 45 for (var i = 0, len = obj.length; i < len; i++) { 46 array[i] = mapper(obj[i]); 47 } 48 return array; 49 } else { 50 var keyMapper = valueMapper ? mapper : null; 51 valueMapper = valueMapper || mapper; 52 53 var newObj = {}; 54 for (var key in obj) { 55 if (obj.hasOwnProperty(key)) { 56 var value =http://www.mamicode.com/ obj[key]; 57 var newKey = keyMapper ? keyMapper(key) : key; 58 var newValue = http://www.mamicode.com/valueMapper ? valueMapper(value) : value; 59 newObj[newKey] = newValue; 60 } 61 } 62 63 return newObj; 64 } 65 } 66 67 var clone = function (obj) { 68 return map(obj); 69 } 70 71 var v2n = function (version) { 72 var value = http://www.mamicode.com/0; 73 74 var parts = version.split("."); 75 for (var i = 0; i < 3; i++) { 76 value *= 100; 77 if (i < parts.length) { 78 value += parseInt(parts[i], 10); 79 } 80 } 81 82 return value; 83 } 84 85 var testVersion = function (expected, version) { 86 var expectedMinVersion = expected.substring(1); // remove leading "~" 87 88 var expectedMaxParts = expectedMinVersion.split("."); 89 expectedMaxParts[expectedMaxParts.length - 1] = "0"; 90 expectedMaxParts[expectedMaxParts.length - 2] = (parseInt(expectedMaxParts[expectedMaxParts.length - 2], 10) + 1).toString(); 91 var expectedMaxVersion = expectedMaxParts.join("."); 92 93 var versionNumber = v2n(version); 94 return v2n(expectedMinVersion) <= versionNumber && versionNumber < v2n(expectedMaxVersion); 95 } 96 97 var format = function (f, args) { 98 // support _.format(f, a0, a1, ...); 99 if (!isArray(args)) { 100 var newArgs = new Array(arguments.length - 1); 101 for (var i = 1; i < arguments.length; i++) { 102 newArgs[i - 1] = arguments[i]; 103 } 104 105 return format(f, newArgs); 106 } 107 108 return f.replace(/\{{1,2}\d+\}{1,2}/g, function (ph) { 109 if (ph.indexOf("{{") == 0 && ph.indexOf("}}") == ph.length - 2) { 110 return ph.substring(1, ph.length - 1); 111 } 112 113 var left = 0; 114 while (ph[left] == "{") left++; 115 116 var right = ph.length - 1; 117 while (ph[right] == "}") right--; 118 119 var index = parseInt(ph.substring(left, right + 1), 10); 120 return ph.replace("{" + index + "}", args[index]); 121 }); 122 } 123 124 var once = function (fn) { 125 var called = false; 126 return function () { 127 if (called) return; 128 fn.apply(this, arguments); 129 called = true; 130 } 131 }; 132 133 return { 134 isArray: isArray, 135 each: each, 136 isEmpty: isEmpty, 137 map: map, 138 clone: clone, 139 v2n: v2n, 140 testVersion: testVersion, 141 format: format, 142 once: once 143 }; 144 })(); 145 146 var Level = { 147 ALL: 0, 148 TRACE: 1, 149 DEBUG: 2, 150 INFO: 3, 151 WARN: 4, 152 ERROR: 5, 153 OFF: 100 154 }; 155 156 var Logger = function () { 157 this.level = Level.DEBUG; 158 }; 159 Logger.prototype = { 160 log: function (level, msg) { 161 if (this.level <= level) { 162 try { console.log(msg); } catch (ex) { } 163 } 164 }, 165 166 trace: function (msg) { 167 this.log(Level.TRACE, msg); 168 }, 169 170 debug: function (msg) { 171 this.log(Level.DEBUG, msg); 172 }, 173 174 info: function (msg) { 175 this.log(Level.INFO, msg); 176 }, 177 178 warn: function (msg) { 179 this.log(Level.WARN, msg); 180 }, 181 182 error: function (msg) { 183 this.log(Level.ERROR, msg); 184 } 185 }; 186 187 var exportBasicOptions = function (exports, options) { 188 exports.name = options.name; 189 exports.version = options.version; 190 191 if (options.autoloads) { 192 exports.autoloads = options.autoloads; 193 } 194 195 if (options.dependencies) { 196 exports.dependencies = options.dependencies; 197 } 198 } 199 200 var initModule = function (options) { 201 var existingModule = Wind.modules[options.name]; 202 if (existingModule && existingModule.version != options.version) { 203 Wind.logger.warn(_.format( 204 ‘The module "{0}" with version "{1}" has already been initialized, skip version "{2}".‘, 205 options.name, 206 existingModule.version, 207 options.version)); 208 } 209 210 checkDependencies(options); 211 options.init(); 212 213 var module = {}; 214 exportBasicOptions(module, options); 215 Wind.modules[options.name] = module; 216 } 217 218 var checkDependencies = function (options) { 219 _.each(options.dependencies || [], function (name, expectedVersion) { 220 var module = Wind.modules[name]; 221 if (!module) { 222 throw new Error(_.format( 223 ‘Missing required module: "{0}" (expected version: "{1}").‘, 224 name, 225 expectedVersion)); 226 } 227 228 if (!_.testVersion(expectedVersion, module.version)) { 229 throw new Error(_.format( 230 ‘Version of module "{0}" mismatched, expected: "{1}", actual: "{2}".‘, 231 name, 232 expectedVersion, 233 module.version)); 234 } 235 }); 236 } 237 238 // CommonJS 239 var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports); 240 // CommonJS AMD 241 var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd); 242 243 var defineModule = function (options) { 244 var autoloads = options.autoloads || []; 245 246 if (isCommonJS) { 247 var require = options.require; 248 _.each(autoloads, function (name) { 249 try { 250 require("./wind-" + name); 251 } catch (ex) { 252 require("wind-" + name); 253 } 254 }); 255 256 initModule(options); 257 } else if (isAmd) { 258 var dependencies = _.map(autoloads, function (name) { return "wind-" + name; }); 259 define("wind-" + options.name, dependencies, function () { 260 if (options.onerror) { 261 try { 262 initModule(options); 263 } catch (ex) { 264 options.onerror(ex); 265 } 266 } else { 267 initModule(options); 268 } 269 }); 270 } else { 271 initModule(options); 272 } 273 } 274 275 var init = function () { 276 Wind.logger = new Logger(); 277 Wind.Logging = { 278 Logger: Logger, 279 Level: Level 280 }; 281 282 Wind._ = _; 283 Wind.modules = { core: { name: "core", version: "0.7.0" } }; 284 Wind.binders = { }; 285 Wind.builders = { }; 286 Wind.define = defineModule; 287 }; 288 289 if (isCommonJS) { 290 Wind = module.exports; 291 init(); 292 } else if (isAmd) { 293 define("wind-core", function () { 294 Wind = { }; 295 init(); 296 return Wind; 297 }); 298 } else { 299 // Get the global object. 300 var Fn = Function, global = Fn(‘return this‘)(); 301 302 if (global.Wind) { 303 throw new Error("There‘s already a Wind root here, please load the component only once."); 304 } 305 306 Wind = global.Wind = { }; 307 init(); 308 } 309 })(); 310 311 /*********************************************************************** 312 wind-compiler-0.7.2.js 313 ***********************************************************************/ 314 315 (function () { 316 "use strict"; 317 318 var parse = (function () { 319 320 /*********************************************************************** 321 322 A JavaScript tokenizer / parser / beautifier / compressor. 323 324 This version is suitable for Node.js. With minimal changes (the 325 exports stuff) it should work on any JS platform. 326 327 This file contains the tokenizer/parser. It is a port to JavaScript 328 of parse-js [1], a JavaScript parser library written in Common Lisp 329 by Marijn Haverbeke. Thank you Marijn! 330 331 [1] http://marijn.haverbeke.nl/parse-js/ 332 333 Exported functions: 334 335 - tokenizer(code) -- returns a function. Call the returned 336 function to fetch the next token. 337 338 - parse(code) -- returns an AST of the given JavaScript code. 339 340 -------------------------------- (C) --------------------------------- 341 342 Author: Mihai Bazon 343 <mihai.bazon@gmail.com> 344 http://mihai.bazon.net/blog 345 346 Distributed under the BSD license: 347 348 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com> 349 Based on parse-js (http://marijn.haverbeke.nl/parse-js/). 350 351 Redistribution and use in source and binary forms, with or without 352 modification, are permitted provided that the following conditions 353 are met: 354 355 * Redistributions of source code must retain the above 356 copyright notice, this list of conditions and the following 357 disclaimer. 358 359 * Redistributions in binary form must reproduce the above 360 copyright notice, this list of conditions and the following 361 disclaimer in the documentation and/or other materials 362 provided with the distribution. 363 364 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY 365 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 366 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 367 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 368 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 369 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 370 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 371 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 373 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 374 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 375 SUCH DAMAGE. 376 377 ***********************************************************************/ 378 379 /* -----[ Tokenizer (constants) ]----- */ 380 381 var KEYWORDS = array_to_hash([ 382 "break", 383 "case", 384 "catch", 385 "const", 386 "continue", 387 "default", 388 "delete", 389 "do", 390 "else", 391 "finally", 392 "for", 393 "function", 394 "if", 395 "in", 396 "instanceof", 397 "new", 398 "return", 399 "switch", 400 "throw", 401 "try", 402 "typeof", 403 "var", 404 "void", 405 "while", 406 "with" 407 ]); 408 409 var RESERVED_WORDS = array_to_hash([ 410 "abstract", 411 "boolean", 412 "byte", 413 "char", 414 "class", 415 "debugger", 416 "double", 417 "enum", 418 "export", 419 "extends", 420 "final", 421 "float", 422 "goto", 423 "implements", 424 "import", 425 "int", 426 "interface", 427 "long", 428 "native", 429 "package", 430 "private", 431 "protected", 432 "public", 433 "short", 434 "static", 435 "super", 436 "synchronized", 437 "throws", 438 "transient", 439 "volatile" 440 ]); 441 442 var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ 443 "return", 444 "new", 445 "delete", 446 "throw", 447 "else", 448 "case" 449 ]); 450 451 var KEYWORDS_ATOM = array_to_hash([ 452 "false", 453 "null", 454 "true", 455 "undefined" 456 ]); 457 458 var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); 459 460 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; 461 var RE_OCT_NUMBER = /^0[0-7]+$/; 462 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; 463 464 var OPERATORS = array_to_hash([ 465 "in", 466 "instanceof", 467 "typeof", 468 "new", 469 "void", 470 "delete", 471 "++", 472 "--", 473 "+", 474 "-", 475 "!", 476 "~", 477 "&", 478 "|", 479 "^", 480 "*", 481 "/", 482 "%", 483 ">>", 484 "<<", 485 ">>>", 486 "<", 487 ">", 488 "<=", 489 ">=", 490 "==", 491 "===", 492 "!=", 493 "!==", 494 "?", 495 "=", 496 "+=", 497 "-=", 498 "/=", 499 "*=", 500 "%=", 501 ">>=", 502 "<<=", 503 ">>>=", 504 "|=", 505 "^=", 506 "&=", 507 "&&", 508 "||" 509 ]); 510 511 var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t\u200b")); 512 513 var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); 514 515 var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); 516 517 var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); 518 519 /* -----[ Tokenizer ]----- */ 520 521 // regexps adapted from http://xregexp.com/plugins/#unicode 522 var UNICODE = { 523 letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), 524 non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), 525 space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), 526 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") 527 }; 528 529 function is_letter(ch) { 530 return UNICODE.letter.test(ch); 531 }; 532 533 function is_digit(ch) { 534 ch = ch.charCodeAt(0); 535 return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 536 }; 537 538 function is_alphanumeric_char(ch) { 539 return is_digit(ch) || is_letter(ch); 540 }; 541 542 function is_unicode_combining_mark(ch) { 543 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); 544 }; 545 546 function is_unicode_connector_punctuation(ch) { 547 return UNICODE.connector_punctuation.test(ch); 548 }; 549 550 function is_identifier_start(ch) { 551 return ch == "$" || ch == "_" || is_letter(ch); 552 }; 553 554 function is_identifier_char(ch) { 555 return is_identifier_start(ch) 556 || is_unicode_combining_mark(ch) 557 || is_digit(ch) 558 || is_unicode_connector_punctuation(ch) 559 || ch == "\u200c" // zero-width non-joiner <ZWNJ> 560 || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c) 561 ; 562 }; 563 564 function parse_js_number(num) { 565 if (RE_HEX_NUMBER.test(num)) { 566 return parseInt(num.substr(2), 16); 567 } else if (RE_OCT_NUMBER.test(num)) { 568 return parseInt(num.substr(1), 8); 569 } else if (RE_DEC_NUMBER.test(num)) { 570 return parseFloat(num); 571 } 572 }; 573 574 function JS_Parse_Error(message, line, col, pos) { 575 this.message = message; 576 this.line = line; 577 this.col = col; 578 this.pos = pos; 579 try { 580 ({})(); 581 } catch(ex) { 582 this.stack = ex.stack; 583 }; 584 }; 585 586 JS_Parse_Error.prototype.toString = function() { 587 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; 588 }; 589 590 function js_error(message, line, col, pos) { 591 throw new JS_Parse_Error(message, line, col, pos); 592 }; 593 594 function is_token(token, type, val) { 595 return token.type == type && (val == null || token.value =http://www.mamicode.com/= val); 596 }; 597 598 var EX_EOF = {}; 599 600 function tokenizer($TEXT) { 601 602 var S = { 603 text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ‘‘), 604 pos : 0, 605 tokpos : 0, 606 line : 0, 607 tokline : 0, 608 col : 0, 609 tokcol : 0, 610 newline_before : false, 611 regex_allowed : false, 612 comments_before : [] 613 }; 614 615 function peek() { return S.text.charAt(S.pos); }; 616 617 function next(signal_eof) { 618 var ch = S.text.charAt(S.pos++); 619 if (signal_eof && !ch) 620 throw EX_EOF; 621 if (ch == "\n") { 622 S.newline_before = true; 623 ++S.line; 624 S.col = 0; 625 } else { 626 ++S.col; 627 } 628 return ch; 629 }; 630 631 function eof() { 632 return !S.peek(); 633 }; 634 635 function find(what, signal_eof) { 636 var pos = S.text.indexOf(what, S.pos); 637 if (signal_eof && pos == -1) throw EX_EOF; 638 return pos; 639 }; 640 641 function start_token() { 642 S.tokline = S.line; 643 S.tokcol = S.col; 644 S.tokpos = S.pos; 645 }; 646 647 function token(type, value, is_comment) { 648 S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || 649 (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || 650 (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); 651 var ret = { 652 type : type, 653 value : value, 654 line : S.tokline, 655 col : S.tokcol, 656 pos : S.tokpos, 657 nlb : S.newline_before 658 }; 659 if (!is_comment) { 660 ret.comments_before = S.comments_before; 661 S.comments_before = []; 662 } 663 S.newline_before = false; 664 return ret; 665 }; 666 667 function skip_whitespace() { 668 while (HOP(WHITESPACE_CHARS, peek())) 669 next(); 670 }; 671 672 function read_while(pred) { 673 var ret = "", ch = peek(), i = 0; 674 while (ch && pred(ch, i++)) { 675 ret += next(); 676 ch = peek(); 677 } 678 return ret; 679 }; 680 681 function parse_error(err) { 682 js_error(err, S.tokline, S.tokcol, S.tokpos); 683 }; 684 685 function read_num(prefix) { 686 var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; 687 var num = read_while(function(ch, i){ 688 if (ch == "x" || ch == "X") { 689 if (has_x) return false; 690 return has_x = true; 691 } 692 if (!has_x && (ch == "E" || ch == "e")) { 693 if (has_e) return false; 694 return has_e = after_e = true; 695 } 696 if (ch == "-") { 697 if (after_e || (i == 0 && !prefix)) return true; 698 return false; 699 } 700 if (ch == "+") return after_e; 701 after_e = false; 702 if (ch == ".") { 703 if (!has_dot && !has_x) 704 return has_dot = true; 705 return false; 706 } 707 return is_alphanumeric_char(ch); 708 }); 709 if (prefix) 710 num = prefix + num; 711 var valid = parse_js_number(num); 712 if (!isNaN(valid)) { 713 return token("num", valid); 714 } else { 715 parse_error("Invalid syntax: " + num); 716 } 717 }; 718 719 function read_escaped_char() { 720 var ch = next(true); 721 switch (ch) { 722 case "n" : return "\n"; 723 case "r" : return "\r"; 724 case "t" : return "\t"; 725 case "b" : return "\b"; 726 case "v" : return "\v"; 727 case "f" : return "\f"; 728 case "0" : return "\0"; 729 case "x" : return String.fromCharCode(hex_bytes(2)); 730 case "u" : return String.fromCharCode(hex_bytes(4)); 731 default : return ch; 732 } 733 }; 734 735 function hex_bytes(n) { 736 var num = 0; 737 for (; n > 0; --n) { 738 var digit = parseInt(next(true), 16); 739 if (isNaN(digit)) 740 parse_error("Invalid hex-character pattern in string"); 741 num = (num << 4) | digit; 742 } 743 return num; 744 }; 745 746 function read_string() { 747 return with_eof_error("Unterminated string constant", function(){ 748 var quote = next(), ret = ""; 749 for (;;) { 750 var ch = next(true); 751 if (ch == "\\") ch = read_escaped_char(); 752 else if (ch == quote) break; 753 ret += ch; 754 } 755 return token("string", ret); 756 }); 757 }; 758 759 function read_line_comment() { 760 next(); 761 var i = find("\n"), ret; 762 if (i == -1) { 763 ret = S.text.substr(S.pos); 764 S.pos = S.text.length; 765 } else { 766 ret = S.text.substring(S.pos, i); 767 S.pos = i; 768 } 769 return token("comment1", ret, true); 770 }; 771 772 function read_multiline_comment() { 773 next(); 774 return with_eof_error("Unterminated multiline comment", function(){ 775 var i = find("*/", true), 776 text = S.text.substring(S.pos, i), 777 tok = token("comment2", text, true); 778 S.pos = i + 2; 779 S.line += text.split("\n").length - 1; 780 S.newline_before = text.indexOf("\n") >= 0; 781 782 // https://github.com/mishoo/UglifyJS/issues/#issue/100 783 if (/^@cc_on/i.test(text)) { 784 warn("WARNING: at line " + S.line); 785 warn("*** Found \"conditional comment\": " + text); 786 warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); 787 } 788 789 return tok; 790 }); 791 }; 792 793 function read_name() { 794 var backslash = false, name = "", ch; 795 while ((ch = peek()) != null) { 796 if (!backslash) { 797 if (ch == "\\") backslash = true, next(); 798 else if (is_identifier_char(ch)) name += next(); 799 else break; 800 } 801 else { 802 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); 803 ch = read_escaped_char(); 804 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); 805 name += ch; 806 backslash = false; 807 } 808 } 809 return name; 810 }; 811 812 function read_regexp() { 813 return with_eof_error("Unterminated regular expression", function(){ 814 var prev_backslash = false, regexp = "", ch, in_class = false; 815 while ((ch = next(true))) if (prev_backslash) { 816 regexp += "\\" + ch; 817 prev_backslash = false; 818 } else if (ch == "[") { 819 in_class = true; 820 regexp += ch; 821 } else if (ch == "]" && in_class) { 822 in_class = false; 823 regexp += ch; 824 } else if (ch == "/" && !in_class) { 825 break; 826 } else if (ch == "\\") { 827 prev_backslash = true; 828 } else { 829 regexp += ch; 830 } 831 var mods = read_name(); 832 return token("regexp", [ regexp, mods ]); 833 }); 834 }; 835 836 function read_operator(prefix) { 837 function grow(op) { 838 if (!peek()) return op; 839 var bigger = op + peek(); 840 if (HOP(OPERATORS, bigger)) { 841 next(); 842 return grow(bigger); 843 } else { 844 return op; 845 } 846 }; 847 return token("operator", grow(prefix || next())); 848 }; 849 850 function handle_slash() { 851 next(); 852 var regex_allowed = S.regex_allowed; 853 switch (peek()) { 854 case "/": 855 S.comments_before.push(read_line_comment()); 856 S.regex_allowed = regex_allowed; 857 return next_token(); 858 case "*": 859 S.comments_before.push(read_multiline_comment()); 860 S.regex_allowed = regex_allowed; 861 return next_token(); 862 } 863 return S.regex_allowed ? read_regexp() : read_operator("/"); 864 }; 865 866 function handle_dot() { 867 next(); 868 return is_digit(peek()) 869 ? read_num(".") 870 : token("punc", "."); 871 }; 872 873 function read_word() { 874 var word = read_name(); 875 return !HOP(KEYWORDS, word) 876 ? token("name", word) 877 : HOP(OPERATORS, word) 878 ? token("operator", word) 879 : HOP(KEYWORDS_ATOM, word) 880 ? token("atom", word) 881 : token("keyword", word); 882 }; 883 884 function with_eof_error(eof_error, cont) { 885 try { 886 return cont(); 887 } catch(ex) { 888 if (ex === EX_EOF) parse_error(eof_error); 889 else throw ex; 890 } 891 }; 892 893 function next_token(force_regexp) { 894 if (force_regexp) 895 return read_regexp(); 896 skip_whitespace(); 897 start_token(); 898 var ch = peek(); 899 if (!ch) return token("eof"); 900 if (is_digit(ch)) return read_num(); 901 if (ch == ‘"‘ || ch == "‘") return read_string(); 902 if (HOP(PUNC_CHARS, ch)) return token("punc", next()); 903 if (ch == ".") return handle_dot(); 904 if (ch == "/") return handle_slash(); 905 if (HOP(OPERATOR_CHARS, ch)) return read_operator(); 906 if (ch == "\\" || is_identifier_start(ch)) return read_word(); 907 parse_error("Unexpected character ‘" + ch + "‘"); 908 }; 909 910 next_token.context = function(nc) { 911 if (nc) S = nc; 912 return S; 913 }; 914 915 return next_token; 916 917 }; 918 919 /* -----[ Parser (constants) ]----- */ 920 921 var UNARY_PREFIX = array_to_hash([ 922 "typeof", 923 "void", 924 "delete", 925 "--", 926 "++", 927 "!", 928 "~", 929 "-", 930 "+" 931 ]); 932 933 var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); 934 935 var ASSIGNMENT = (function(a, ret, i){ 936 while (i < a.length) { 937 ret[a[i]] = a[i].substr(0, a[i].length - 1); 938 i++; 939 } 940 return ret; 941 })( 942 ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], 943 { "=": true }, 944 0 945 ); 946 947 var PRECEDENCE = (function(a, ret){ 948 for (var i = 0, n = 1; i < a.length; ++i, ++n) { 949 var b = a[i]; 950 for (var j = 0; j < b.length; ++j) { 951 ret[b[j]] = n; 952 } 953 } 954 return ret; 955 })( 956 [ 957 ["||"], 958 ["&&"], 959 ["|"], 960 ["^"], 961 ["&"], 962 ["==", "===", "!=", "!=="], 963 ["<", ">", "<=", ">=", "in", "instanceof"], 964 [">>", "<<", ">>>"], 965 ["+", "-"], 966 ["*", "/", "%"] 967 ], 968 {} 969 ); 970 971 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); 972 973 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); 974 975 /* -----[ Parser ]----- */ 976 977 function NodeWithToken(str, start, end) { 978 this.name = str; 979 this.start = start; 980 this.end = end; 981 }; 982 983 NodeWithToken.prototype.toString = function() { return this.name; }; 984 985 function parse($TEXT, exigent_mode, embed_tokens) { 986 987 var S = { 988 input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, 989 token : null, 990 prev : null, 991 peeked : null, 992 in_function : 0, 993 in_loop : 0, 994 labels : [] 995 }; 996 997 S.token = next(); 998 999 function is(type, value) {1000 return is_token(S.token, type, value);1001 };1002 1003 function peek() { return S.peeked || (S.peeked = S.input()); };1004 1005 function next() {1006 S.prev = S.token;1007 if (S.peeked) {1008 S.token = S.peeked;1009 S.peeked = null;1010 } else {1011 S.token = S.input();1012 }1013 return S.token;1014 };1015 1016 function prev() {1017 return S.prev;1018 };1019 1020 function croak(msg, line, col, pos) {1021 var ctx = S.input.context();1022 js_error(msg,1023 line != null ? line : ctx.tokline,1024 col != null ? col : ctx.tokcol,1025 pos != null ? pos : ctx.tokpos);1026 };1027 1028 function token_error(token, msg) {1029 croak(msg, token.line, token.col);1030 };1031 1032 function unexpected(token) {1033 if (token == null)1034 token = S.token;1035 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");1036 };1037 1038 function expect_token(type, val) {1039 if (is(type, val)) {1040 return next();1041 }1042 token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);1043 };1044 1045 function expect(punc) { return expect_token("punc", punc); };1046 1047 function can_insert_semicolon() {1048 return !exigent_mode && (1049 S.token.nlb || is("eof") || is("punc", "}")1050 );1051 };1052 1053 function semicolon() {1054 if (is("punc", ";")) next();1055 else if (!can_insert_semicolon()) unexpected();1056 };1057 1058 function as() {1059 return slice(arguments);1060 };1061 1062 function parenthesised() {1063 expect("(");1064 var ex = expression();1065 expect(")");1066 return ex;1067 };1068 1069 function add_tokens(str, start, end) {1070 return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);1071 };1072 1073 var statement = embed_tokens ? function() {1074 var start = S.token;1075 var ast = $statement.apply(this, arguments);1076 ast[0] = add_tokens(ast[0], start, prev());1077 return ast;1078 } : $statement;1079 1080 function $statement() {1081 if (is("operator", "/")) {1082 S.peeked = null;1083 S.token = S.input(true); // force regexp1084 }1085 switch (S.token.type) {1086 case "num":1087 case "string":1088 case "regexp":1089 case "operator":1090 case "atom":1091 return simple_statement();1092 1093 case "name":1094 return is_token(peek(), "punc", ":")1095 ? labeled_statement(prog1(S.token.value, next, next))1096 : simple_statement();1097 1098 case "punc":1099 switch (S.token.value) {1100 case "{":1101 return as("block", block_());1102 case "[":1103 case "(":1104 return simple_statement();1105 case ";":1106 next();1107 return as("block");1108 default:1109 unexpected();1110 }1111 1112 case "keyword":1113 switch (prog1(S.token.value, next)) {1114 case "break":1115 return break_cont("break");1116 1117 case "continue":1118 return break_cont("continue");1119 1120 case "debugger":1121 semicolon();1122 return as("debugger");1123 1124 case "do":1125 return (function(body){1126 expect_token("keyword", "while");1127 return as("do", prog1(parenthesised, semicolon), body);1128 })(in_loop(statement));1129 1130 case "for":1131 return for_();1132 1133 case "function":1134 return function_(true);1135 1136 case "if":1137 return if_();1138 1139 case "return":1140 if (S.in_function == 0)1141 croak("‘return‘ outside of function");1142 return as("return",1143 is("punc", ";")1144 ? (next(), null)1145 : can_insert_semicolon()1146 ? null1147 : prog1(expression, semicolon));1148 1149 case "switch":1150 return as("switch", parenthesised(), switch_block_());1151 1152 case "throw":1153 return as("throw", prog1(expression, semicolon));1154 1155 case "try":1156 return try_();1157 1158 case "var":1159 return prog1(var_, semicolon);1160 1161 case "const":1162 return prog1(const_, semicolon);1163 1164 case "while":1165 return as("while", parenthesised(), in_loop(statement));1166 1167 case "with":1168 return as("with", parenthesised(), statement());1169 1170 default:1171 unexpected();1172 }1173 }1174 };1175 1176 function labeled_statement(label) {1177 S.labels.push(label);1178 var start = S.token, stat = statement();1179 if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))1180 unexpected(start);1181 S.labels.pop();1182 return as("label", label, stat);1183 };1184 1185 function simple_statement() {1186 return as("stat", prog1(expression, semicolon));1187 };1188 1189 function break_cont(type) {1190 var name = is("name") ? S.token.value : null;1191 if (name != null) {1192 next();1193 if (!member(name, S.labels))1194 croak("Label " + name + " without matching loop or statement");1195 }1196 else if (S.in_loop == 0)1197 croak(type + " not inside a loop or switch");1198 semicolon();1199 return as(type, name);1200 };1201 1202 function for_() {1203 expect("(");1204 var init = null;1205 if (!is("punc", ";")) {1206 init = is("keyword", "var")1207 ? (next(), var_(true))1208 : expression(true, true);1209 if (is("operator", "in"))1210 return for_in(init);1211 }1212 return regular_for(init);1213 };1214 1215 function regular_for(init) {1216 expect(";");1217 var test = is("punc", ";") ? null : expression();1218 expect(";");1219 var step = is("punc", ")") ? null : expression();1220 expect(")");1221 return as("for", init, test, step, in_loop(statement));1222 };1223 1224 function for_in(init) {1225 var lhs = init[0] == "var" ? as("name", init[1][0]) : init;1226 next();1227 var obj = expression();1228 expect(")");1229 return as("for-in", init, lhs, obj, in_loop(statement));1230 };1231 1232 var function_ = embed_tokens ? function() {1233 var start = prev();1234 var ast = $function_.apply(this, arguments);1235 ast[0] = add_tokens(ast[0], start, prev());1236 return ast;1237 } : $function_;1238 1239 function $function_(in_statement) {1240 var name = is("name") ? prog1(S.token.value, next) : null;1241 if (in_statement && !name)1242 unexpected();1243 expect("(");1244 return as(in_statement ? "defun" : "function",1245 name,1246 // arguments1247 (function(first, a){1248 while (!is("punc", ")")) {1249 if (first) first = false; else expect(",");1250 if (!is("name")) unexpected();1251 a.push(S.token.value);1252 next();1253 }1254 next();1255 return a;1256 })(true, []),1257 // body1258 (function(){1259 ++S.in_function;1260 var loop = S.in_loop;1261 S.in_loop = 0;1262 var a = block_();1263 --S.in_function;1264 S.in_loop = loop;1265 return a;1266 })());1267 };1268 1269 function if_() {1270 var cond = parenthesised(), body = statement(), belse;1271 if (is("keyword", "else")) {1272 next();1273 belse = statement();1274 }1275 return as("if", cond, body, belse);1276 };1277 1278 function block_() {1279 expect("{");1280 var a = [];1281 while (!is("punc", "}")) {1282 if (is("eof")) unexpected();1283 a.push(statement());1284 }1285 next();1286 return a;1287 };1288 1289 var switch_block_ = curry(in_loop, function(){1290 expect("{");1291 var a = [], cur = null;1292 while (!is("punc", "}")) {1293 if (is("eof")) unexpected();1294 if (is("keyword", "case")) {1295 next();1296 cur = [];1297 a.push([ expression(), cur ]);1298 expect(":");1299 }1300 else if (is("keyword", "default")) {1301 next();1302 expect(":");1303 cur = [];1304 a.push([ null, cur ]);1305 }1306 else {1307 if (!cur) unexpected();1308 cur.push(statement());1309 }1310 }1311 next();1312 return a;1313 });1314 1315 function try_() {1316 var body = block_(), bcatch, bfinally;1317 if (is("keyword", "catch")) {1318 next();1319 expect("(");1320 if (!is("name"))1321 croak("Name expected");1322 var name = S.token.value;1323 next();1324 expect(")");1325 bcatch = [ name, block_() ];1326 }1327 if (is("keyword", "finally")) {1328 next();1329 bfinally = block_();1330 }1331 if (!bcatch && !bfinally)1332 croak("Missing catch/finally blocks");1333 return as("try", body, bcatch, bfinally);1334 };1335 1336 function vardefs(no_in) {1337 var a = [];1338 for (;;) {1339 if (!is("name"))1340 unexpected();1341 var name = S.token.value;1342 next();1343 if (is("operator", "=")) {1344 next();1345 a.push([ name, expression(false, no_in) ]);1346 } else {1347 a.push([ name ]);1348 }1349 if (!is("punc", ","))1350 break;1351 next();1352 }1353 return a;1354 };1355 1356 function var_(no_in) {1357 return as("var", vardefs(no_in));1358 };1359 1360 function const_() {1361 return as("const", vardefs());1362 };1363 1364 function new_() {1365 var newexp = expr_atom(false), args;1366 if (is("punc", "(")) {1367 next();1368 args = expr_list(")");1369 } else {1370 args = [];1371 }1372 return subscripts(as("new", newexp, args), true);1373 };1374 1375 function expr_atom(allow_calls) {1376 if (is("operator", "new")) {1377 next();1378 return new_();1379 }1380 if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {1381 return make_unary("unary-prefix",1382 prog1(S.token.value, next),1383 expr_atom(allow_calls));1384 }1385 if (is("punc")) {1386 switch (S.token.value) {1387 case "(":1388 next();1389 return subscripts(prog1(expression, curry(expect, ")")), allow_calls);1390 case "[":1391 next();1392 return subscripts(array_(), allow_calls);1393 case "{":1394 next();1395 return subscripts(object_(), allow_calls);1396 }1397 unexpected();1398 }1399 if (is("keyword", "function")) {1400 next();1401 return subscripts(function_(false), allow_calls);1402 }1403 if (HOP(ATOMIC_START_TOKEN, S.token.type)) {1404 var atom = S.token.type == "regexp"1405 ? as("regexp", S.token.value[0], S.token.value[1])1406 : as(S.token.type, S.token.value);1407 return subscripts(prog1(atom, next), allow_calls);1408 }1409 unexpected();1410 };1411 1412 function expr_list(closing, allow_trailing_comma, allow_empty) {1413 var first = true, a = [];1414 while (!is("punc", closing)) {1415 if (first) first = false; else expect(",");1416 if (allow_trailing_comma && is("punc", closing)) break;1417 if (is("punc", ",") && allow_empty) {1418 a.push([ "atom", "undefined" ]);1419 } else {1420 a.push(expression(false));1421 }1422 }1423 next();1424 return a;1425 };1426 1427 function array_() {1428 return as("array", expr_list("]", !exigent_mode, true));1429 };1430 1431 function object_() {1432 var first = true, a = [];1433 while (!is("punc", "}")) {1434 if (first) first = false; else expect(",");1435 if (!exigent_mode && is("punc", "}"))1436 // allow trailing comma1437 break;1438 var type = S.token.type;1439 var name = as_property_name();1440 if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {1441 a.push([ as_name(), function_(false), name ]);1442 } else {1443 expect(":");1444 a.push([ name, expression(false) ]);1445 }1446 }1447 next();1448 return as("object", a);1449 };1450 1451 function as_property_name() {1452 switch (S.token.type) {1453 case "num":1454 case "string":1455 return prog1(S.token.value, next);1456 }1457 return as_name();1458 };1459 1460 function as_name() {1461 switch (S.token.type) {1462 case "name":1463 case "operator":1464 case "keyword":1465 case "atom":1466 return prog1(S.token.value, next);1467 default:1468 unexpected();1469 }1470 };1471 1472 function subscripts(expr, allow_calls) {1473 if (is("punc", ".")) {1474 next();1475 return subscripts(as("dot", expr, as_name()), allow_calls);1476 }1477 if (is("punc", "[")) {1478 next();1479 return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);1480 }1481 if (allow_calls && is("punc", "(")) {1482 next();1483 return subscripts(as("call", expr, expr_list(")")), true);1484 }1485 if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) {1486 return prog1(curry(make_unary, "unary-postfix", S.token.value, expr),1487 next);1488 }1489 return expr;1490 };1491 1492 function make_unary(tag, op, expr) {1493 if ((op == "++" || op == "--") && !is_assignable(expr))1494 croak("Invalid use of " + op + " operator");1495 return as(tag, op, expr);1496 };1497 1498 function expr_op(left, min_prec, no_in) {1499 var op = is("operator") ? S.token.value : null;1500 if (op && op == "in" && no_in) op = null;1501 var prec = op != null ? PRECEDENCE[op] : null;1502 if (prec != null && prec > min_prec) {1503 next();1504 var right = expr_op(expr_atom(true), prec, no_in);1505 return expr_op(as("binary", op, left, right), min_prec, no_in);1506 }1507 return left;1508 };1509 1510 function expr_ops(no_in) {1511 return expr_op(expr_atom(true), 0, no_in);1512 };1513 1514 function maybe_conditional(no_in) {1515 var expr = expr_ops(no_in);1516 if (is("operator", "?")) {1517 next();1518 var yes = expression(false);1519 expect(":");1520 return as("conditional", expr, yes, expression(false, no_in));1521 }1522 return expr;1523 };1524 1525 function is_assignable(expr) {1526 if (!exigent_mode) return true;1527 switch (expr[0]) {1528 case "dot":1529 case "sub":1530 case "new":1531 case "call":1532 return true;1533 case "name":1534 return expr[1] != "this";1535 }1536 };1537 1538 function maybe_assign(no_in) {1539 var left = maybe_conditional(no_in), val = S.token.value;1540 if (is("operator") && HOP(ASSIGNMENT, val)) {1541 if (is_assignable(left)) {1542 next();1543 return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));1544 }1545 croak("Invalid assignment");1546 }1547 return left;1548 };1549 1550 function expression(commas, no_in) {1551 if (arguments.length == 0)1552 commas = true;1553 var expr = maybe_assign(no_in);1554 if (commas && is("punc", ",")) {1555 next();1556 return as("seq", expr, expression(true, no_in));1557 }1558 return expr;1559 };1560 1561 function in_loop(cont) {1562 try {1563 ++S.in_loop;1564 return cont();1565 } finally {1566 --S.in_loop;1567 }1568 };1569 1570 return as("toplevel", (function(a){1571 while (!is("eof"))1572 a.push(statement());1573 return a;1574 })([]));1575 1576 };1577 1578 /* -----[ Utilities ]----- */1579 1580 function curry(f) {1581 var args = slice(arguments, 1);1582 return function() { return f.apply(this, args.concat(slice(arguments))); };1583 };1584 1585 function prog1(ret) {1586 if (ret instanceof Function)1587 ret = ret();1588 for (var i = 1, n = arguments.length; --n > 0; ++i)1589 arguments[i]();1590 return ret;1591 };1592 1593 function array_to_hash(a) {1594 var ret = {};1595 for (var i = 0; i < a.length; ++i)1596 ret[a[i]] = true;1597 return ret;1598 };1599 1600 function slice(a, start) {1601 return Array.prototype.slice.call(a, start == null ? 0 : start);1602 };1603 1604 function characters(str) {1605 return str.split("");1606 };1607 1608 function member(name, array) {1609 for (var i = array.length; --i >= 0;)1610 if (array[i] === name)1611 return true;1612 return false;1613 };1614 1615 function HOP(obj, prop) {1616 return Object.prototype.hasOwnProperty.call(obj, prop);1617 };1618 1619 var warn = function() {};1620 1621 return parse;1622 1623 })();1624 1625 var Wind;1626 1627 var codeGenerator = (typeof eval("(function () {})") == "function") ?1628 function (code) { return code; } :1629 function (code) { return "false || " + code; };1630 1631 // support string type only.1632 var stringify = (typeof JSON !== "undefined" && JSON.stringify) ?1633 function (s) { return JSON.stringify(s); } :1634 (function () {1635 // Implementation comes from JSON2 (http://www.json.org/js.html)1636 1637 var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;1638 1639 var meta = { // table of character substitutions1640 ‘\b‘: ‘\\b‘,1641 ‘\t‘: ‘\\t‘,1642 ‘\n‘: ‘\\n‘,1643 ‘\f‘: ‘\\f‘,1644 ‘\r‘: ‘\\r‘,1645 ‘"‘ : ‘\\"‘,1646 ‘\\‘: ‘\\\\‘1647 }1648 1649 return function (s) {1650 // If the string contains no control characters, no quote characters, and no1651 // backslash characters, then we can safely slap some quotes around it.1652 // Otherwise we must also replace the offending characters with safe escape1653 // sequences.1654 1655 escapable.lastIndex = 0;1656 return escapable.test(s) ? ‘"‘ + s.replace(escapable, function (a) {1657 var c = meta[a];1658 return typeof c === ‘s‘ ? c :1659 ‘\\u‘ + (‘0000‘ + a.charCodeAt(0).toString(16)).slice(-4);1660 }) + ‘"‘ : ‘"‘ + s + ‘"‘;1661 };1662 })();1663 1664 function sprintf(format) {1665 var args = arguments;1666 return format.toString().replace(new RegExp("{\\d+}", "g"), function (p) {1667 var n = parseInt(p.substring(1, p.length - 1), 10);1668 return args[n + 1];1669 });1670 }1671 1672 function trim(s) {1673 return s.replace(/ +/g, "");1674 }1675 1676 function getPrecedence(ast) {1677 var type = ast[0];1678 switch (type) {1679 case "dot": // .1680 case "sub": // []1681 case "call": // ()1682 return 1;1683 case "unary-postfix": // ++ -- - ~ ! delete new typeof void1684 case "unary-prefix":1685 return 2;1686 case "var":1687 case "binary":1688 switch (ast[1]) {1689 case "*":1690 case "/":1691 case "%":1692 return 3;1693 case "+":1694 case "-":1695 return 4;1696 case "<<":1697 case ">>":1698 case ">>>":1699 return 5;1700 case "<":1701 case "<=":1702 case ">":1703 case ">=":1704 case "instanceof":1705 return 6;1706 case "==":1707 case "!=":1708 case "===":1709 case "!==":1710 return 7;1711 case "&":1712 return 8;1713 case "^":1714 return 9;1715 case "|":1716 return 10;1717 case "&&":1718 return 11;1719 case "||":1720 return 12;1721 }1722 case "conditional":1723 return 13;1724 case "assign":1725 return 14;1726 case "new":1727 return 15;1728 case "seq":1729 case "stat":1730 case "name":1731 case "object":1732 case "array":1733 case "num":1734 case "regexp":1735 case "string":1736 case "function":1737 case "defun":1738 case "for":1739 case "for-in":1740 case "block":1741 case "while":1742 case "do":1743 case "if":1744 case "break":1745 case "continue":1746 case "return":1747 case "throw":1748 case "try":1749 case "switch": 1750 return 0;1751 default:1752 return 100; // the lowest1753 }1754 }1755 1756 var CodeWriter = function (indent) {1757 this._indent = indent || " ";1758 this._indentLevel = 0;1759 1760 this.lines = [];1761 }1762 CodeWriter.prototype = {1763 write: function (str) {1764 if (str === undefined) return;1765 1766 if (this.lines.length == 0) {1767 this.lines.push("");1768 }1769 1770 this.lines[this.lines.length - 1] += str;1771 return this;1772 },1773 1774 writeLine: function () {1775 this.write.apply(this, arguments);1776 this.lines.push("");1777 return this;1778 },1779 1780 writeIndents: function () {1781 var indents = new Array(this._indentLevel);1782 for (var i = 0; i < this._indentLevel; i++) {1783 indents[i] = this._indent;1784 }1785 1786 this.write(indents.join(""));1787 return this;1788 }, 1789 1790 addIndentLevel: function (diff) {1791 this._indentLevel += diff;1792 return this;1793 }1794 };1795 1796 var SeedProvider = function () {1797 this._seeds = {};1798 }1799 SeedProvider.prototype.next = function (key) {1800 var value = http://www.mamicode.com/this._seeds[key];1801 if (value =http://www.mamicode.com/= undefined) {1802 this._seeds[key] = 0;1803 return 0;1804 } else {1805 this._seeds[key] = ++value;1806 return value;1807 }1808 }1809 1810 function isWindPattern(ast) {1811 if (ast[0] != "call") return false;1812 1813 var evalName = ast[1];1814 if (evalName[0] != "name" || evalName[1] != "eval") return false;1815 1816 var compileCall = ast[2][0];1817 if (!compileCall || compileCall[0] != "call") return false;1818 1819 var compileMethod = compileCall[1];1820 if (!compileMethod || compileMethod[0] != "dot" || compileMethod[2] != "compile") return false;1821 1822 var windName = compileMethod[1];1823 if (!windName || windName[0] != "name" || windName[1] != compile.rootName) return false;1824 1825 var builder = compileCall[2][0];1826 if (!builder || builder[0] != "string") return false;1827 1828 var func = compileCall[2][1];1829 if (!func || func[0] != "function") return false;1830 1831 return true;1832 }1833 1834 function compileWindPattern(ast, seedProvider, codeWriter, commentWriter) {1835 1836 var builderName = ast[2][0][2][0][1];1837 var funcAst = ast[2][0][2][1];1838 1839 var windTreeGenerator = new WindTreeGenerator(builderName, seedProvider);1840 var windAst = windTreeGenerator.generate(funcAst);1841 1842 commentWriter.write(builderName + " << ");1843 var codeGenerator = new CodeGenerator(builderName, seedProvider, codeWriter, commentWriter);1844 1845 var funcName = funcAst[1] || "";1846 codeGenerator.generate(funcName, funcAst[2], windAst);1847 1848 return funcName;1849 }1850 1851 var WindTreeGenerator = function (builderName, seedProvider) {1852 this._binder = Wind.binders[builderName];1853 this._seedProvider = seedProvider;1854 }1855 WindTreeGenerator.prototype = {1856 1857 generate: function (ast) {1858 1859 var params = ast[2], statements = ast[3];1860 1861 var rootAst = { type: "delay", stmts: [] };1862 1863 this._visitStatements(statements, rootAst.stmts);1864 1865 return rootAst;1866 },1867 1868 _getBindInfo: function (stmt) {1869 1870 var type = stmt[0];1871 if (type == "stat") {1872 var expr = stmt[1];1873 if (expr[0] == "call") {1874 var callee = expr[1];1875 if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {1876 return {1877 expression: expr[2][0],1878 argName: "",1879 assignee: null1880 };1881 }1882 } else if (expr[0] == "assign") {1883 var assignee = expr[2];1884 expr = expr[3];1885 if (expr[0] == "call") {1886 var callee = expr[1];1887 if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {1888 return {1889 expression: expr[2][0],1890 argName: "_result_$",1891 assignee: assignee1892 };1893 }1894 }1895 }1896 } else if (type == "var") {1897 var defs = stmt[1];1898 if (defs.length == 1) {1899 var item = defs[0];1900 var name = item[0];1901 var expr = item[1];1902 if (expr && expr[0] == "call") {1903 var callee = expr[1];1904 if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {1905 return {1906 expression: expr[2][0],1907 argName: name,1908 assignee: null1909 }; 1910 }1911 }1912 }1913 } else if (type == "return") {1914 var expr = stmt[1];1915 if (expr && expr[0] == "call") {1916 var callee = expr[1];1917 if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {1918 return {1919 expression: expr[2][0],1920 argName: "_result_$",1921 assignee: "return"1922 };1923 }1924 }1925 }1926 1927 return null;1928 },1929 1930 _visitStatements: function (statements, stmts, index) {1931 if (arguments.length <= 2) index = 0;1932 1933 if (index >= statements.length) {1934 stmts.push({ type: "normal" });1935 return this;1936 }1937 1938 var currStmt = statements[index];1939 var bindInfo = this._getBindInfo(currStmt);1940 1941 if (bindInfo) {1942 var bindStmt = { type: "bind", info: bindInfo };1943 stmts.push(bindStmt);1944 1945 if (bindInfo.assignee != "return") {1946 bindStmt.stmts = [];1947 this._visitStatements(statements, bindStmt.stmts, index + 1);1948 }1949 1950 } else {1951 var type = currStmt[0];1952 if (type == "return" || type == "break" || type == "continue" || type == "throw") {1953 1954 stmts.push({ type: type, stmt: currStmt });1955 1956 } else if (type == "if" || type == "try" || type == "for" || type == "do"1957 || type == "while" || type == "switch" || type == "for-in") {1958 1959 var newStmt = this._visit(currStmt);1960 1961 if (newStmt.type == "raw") {1962 stmts.push(newStmt);1963 this._visitStatements(statements, stmts, index + 1);1964 } else {1965 var isLast = (index == statements.length - 1);1966 if (isLast) {1967 stmts.push(newStmt);1968 } else {1969 1970 var combineStmt = {1971 type: "combine",1972 first: { type: "delay", stmts: [newStmt] },1973 second: { type: "delay", stmts: [] }1974 };1975 stmts.push(combineStmt);1976 1977 this._visitStatements(statements, combineStmt.second.stmts, index + 1);1978 }1979 }1980 1981 } else {1982 1983 stmts.push({ type: "raw", stmt: currStmt });1984 1985 this._visitStatements(statements, stmts, index + 1);1986 }1987 }1988 1989 return this;1990 },1991 1992 _visit: function (ast) {1993 1994 var type = ast[0];1995 1996 function throwUnsupportedError() {1997 throw new Error(‘"‘ + type + ‘" is not currently supported.‘);1998 }1999 2000 var visitor = this._visitors[type];2001 2002 if (visitor) {2003 return visitor.call(this, ast);2004 } else {2005 throwUnsupportedError();2006 }2007 },2008 2009 _visitBody: function (ast, stmts) {2010 if (ast[0] == "block") {2011 this._visitStatements(ast[1], stmts);2012 } else {2013 this._visitStatements([ast], stmts);2014 }2015 },2016 2017 _noBinding: function (stmts) {2018 switch (stmts[stmts.length - 1].type) {2019 case "normal":2020 case "return":2021 case "break":2022 case "throw":2023 case "continue":2024 return true;2025 }2026 2027 return false;2028 },2029 2030 _collectCaseStatements: function (cases, index) {2031 var res = [];2032 2033 for (var i = index; i < cases.length; i++) {2034 var rawStmts = cases[i][1];2035 for (var j = 0; j < rawStmts.length; j++) {2036 if (rawStmts[j][0] == "break") {2037 return res2038 }2039 2040 res.push(rawStmts[j]);2041 }2042 }2043 2044 return res;2045 },2046 2047 _visitors: {2048 2049 "for": function (ast) {2050 var bodyStmts = [];2051 var body = ast[4];2052 this._visitBody(body, bodyStmts);2053 2054 if (this._noBinding(bodyStmts)) {2055 return { type: "raw", stmt: ast };2056 }2057 2058 var delayStmt = { type: "delay", stmts: [] };2059 2060 var setup = ast[1];2061 if (setup) {2062 delayStmt.stmts.push({ type: "raw", stmt: setup });2063 }2064 2065 var forStmt = { type: "for", bodyStmt: { type: "delay", stmts: bodyStmts } };2066 delayStmt.stmts.push(forStmt);2067 2068 var condition = ast[2];2069 if (condition) {2070 forStmt.condition = condition;2071 }2072 2073 var update = ast[3];2074 if (update) {2075 forStmt.update = update;2076 }2077 2078 return delayStmt;2079 },2080 2081 "for-in": function (ast) {2082 2083 var body = ast[4];2084 2085 var bodyStmts = [];2086 this._visitBody(body, bodyStmts);2087 2088 if (this._noBinding(bodyStmts)) {2089 return { type: "raw", stmt: ast };2090 }2091 2092 var forInStmt = { type: "for-in", bodyStmts: bodyStmts, obj: ast[3] };2093 2094 var argName = ast[2][1]; // ast[2] == ["name", m]2095 if (ast[1][0] == "var") {2096 forInStmt.argName = argName;2097 } else {2098 var keyVar = "_forInKey_$" + this._seedProvider.next("forInKey");2099 forInStmt.argName = keyVar;2100 forInStmt.bodyStmts.unshift({2101 type: "raw",2102 stmt: parse(argName + " = " + keyVar + ";")[1][0]2103 });2104 }2105 2106 return forInStmt;2107 },2108 2109 "while": function (ast) {2110 2111 var bodyStmts = [];2112 var body = ast[2];2113 this._visitBody(body, bodyStmts);2114 2115 if (this._noBinding(bodyStmts)) {2116 return { type: "raw", stmt: ast }2117 }2118 2119 var loopStmt = { type: "while", bodyStmt: { type: "delay", stmts: bodyStmts } };2120 2121 var condition = ast[1];2122 loopStmt.condition = condition;2123 2124 return loopStmt;2125 },2126 2127 "do": function (ast) {2128 2129 var bodyStmts = [];2130 var body = ast[2];2131 this._visitBody(body, bodyStmts);2132 2133 if (this._noBinding(bodyStmts)) {2134 return { type: "raw", stmt: ast };2135 }2136 2137 var doStmt = {2138 type: "do",2139 bodyStmt: { type: "delay", stmts: bodyStmts },2140 condition: ast[1]2141 };2142 2143 return doStmt;2144 },2145 2146 "switch": function (ast) {2147 var noBinding = true;2148 2149 var switchStmt = { type: "switch", item: ast[1], caseStmts: [] };2150 2151 var cases = ast[2];2152 for (var i = 0; i < cases.length; i++) { 2153 var caseStmt = { item: cases[i][0], stmts: [] };2154 switchStmt.caseStmts.push(caseStmt);2155 2156 var statements = this._collectCaseStatements(cases, i);2157 this._visitStatements(statements, caseStmt.stmts);2158 noBinding = noBinding && this._noBinding(caseStmt.stmts);2159 }2160 2161 if (noBinding) {2162 return { type: "raw", stmt: ast };2163 } else {2164 return switchStmt;2165 }2166 },2167 2168 "if": function (ast) {2169 2170 var noBinding = true;2171 2172 var ifStmt = { type: "if", conditionStmts: [] };2173 2174 var currAst = ast;2175 while (true) {2176 var condition = currAst[1];2177 var condStmt = { cond: condition, stmts: [] };2178 ifStmt.conditionStmts.push(condStmt);2179 2180 var thenPart = currAst[2];2181 this._visitBody(thenPart, condStmt.stmts);2182 2183 noBinding = noBinding && this._noBinding(condStmt.stmts);2184 2185 var elsePart = currAst[3];2186 if (elsePart && elsePart[0] == "if") {2187 currAst = elsePart;2188 } else {2189 break;2190 }2191 }2192 2193 var elsePart = currAst[3];2194 if (elsePart) {2195 ifStmt.elseStmts = [];2196 2197 this._visitBody(elsePart, ifStmt.elseStmts);2198 2199 noBinding = noBinding && this._noBinding(ifStmt.elseStmts);2200 }2201 2202 if (noBinding) {2203 return { type: "raw", stmt: ast };2204 } else {2205 return ifStmt;2206 }2207 },2208 2209 "try": function (ast, stmts) {2210 2211 var bodyStmts = [];2212 var bodyStatements = ast[1];2213 this._visitStatements(bodyStatements, bodyStmts);2214 2215 var noBinding = this._noBinding(bodyStmts)2216 2217 var tryStmt = { type: "try", bodyStmt: { type: "delay", stmts: bodyStmts } };2218 2219 var catchClause = ast[2];2220 if (catchClause) {2221 var exVar = catchClause[0];2222 tryStmt.exVar = exVar;2223 tryStmt.catchStmts = [];2224 2225 this._visitStatements(catchClause[1], tryStmt.catchStmts);2226 2227 noBinding = noBinding && this._noBinding(tryStmt.catchStmts);2228 }2229 2230 var finallyStatements = ast[3];2231 if (finallyStatements) {2232 tryStmt.finallyStmt = { type: "delay", stmts: [] };2233 2234 this._visitStatements(finallyStatements, tryStmt.finallyStmt.stmts);2235 2236 noBinding = noBinding && this._noBinding(tryStmt.finallyStmt.stmts);2237 }2238 2239 if (noBinding) {2240 return { type: "raw", stmt: ast };2241 } else {2242 return tryStmt;2243 }2244 }2245 }2246 }2247 2248 var CodeGenerator = function (builderName, seedProvider, codeWriter, commentWriter) {2249 this._builderName = builderName;2250 this._binder = Wind.binders[builderName];2251 this._seedProvider = seedProvider;2252 2253 this._codeWriter = codeWriter;2254 this._commentWriter = commentWriter;2255 }2256 CodeGenerator.prototype = {2257 2258 _code: function () {2259 this._codeWriter.write.apply(this._codeWriter, arguments);2260 return this;2261 },2262 2263 _codeLine: function () {2264 this._codeWriter.writeLine.apply(this._codeWriter, arguments);2265 return this;2266 },2267 2268 _codeIndents: function () {2269 this._codeWriter.writeIndents();2270 return this;2271 },2272 2273 _codeIndentLevel: function (diff) {2274 this._codeWriter.addIndentLevel(diff);2275 return this;2276 },2277 2278 _comment: function () {2279 this._commentWriter.write.apply(this._commentWriter, arguments);2280 return this;2281 },2282 2283 _commentLine: function () {2284 this._commentWriter.writeLine.apply(this._commentWriter, arguments);2285 return this;2286 },2287 2288 _commentIndents: function () {2289 this._commentWriter.writeIndents();2290 return this;2291 },2292 2293 _commentIndentLevel: function (diff) {2294 this._commentWriter.addIndentLevel(diff);2295 return this;2296 },2297 2298 _both: function () {2299 this._codeWriter.write.apply(this._codeWriter, arguments);2300 this._commentWriter.write.apply(this._commentWriter, arguments);2301 2302 return this;2303 },2304 2305 _bothLine: function () {2306 this._codeWriter.writeLine.apply(this._codeWriter, arguments);2307 this._commentWriter.writeLine.apply(this._commentWriter, arguments);2308 2309 return this;2310 },2311 2312 _bothIndents: function () {2313 this._codeWriter.writeIndents();2314 this._commentWriter.writeIndents();2315 2316 return this;2317 },2318 2319 _bothIndentLevel: function (diff) {2320 this._codeWriter.addIndentLevel(diff);2321 this._commentWriter.addIndentLevel(diff);2322 2323 return this;2324 },2325 2326 _newLine: function () {2327 this._codeWriter.writeLine.apply(this._codeWriter, arguments);2328 this._commentWriter.writeLine(); // To Remove2329 return this;2330 },2331 2332 generate: function (name, params, windAst) {2333 this._normalMode = false;2334 this._builderVar = "_builder_$" + this._seedProvider.next("builderId");2335 2336 this._codeLine("(function " + name + "(" + params.join(", ") + ") {")._commentLine("function (" + params.join(", ") + ") {");2337 this._bothIndentLevel(1);2338 2339 this._codeIndents()._newLine("var " + this._builderVar + " = " + compile.rootName + ".builders[" + stringify(this._builderName) + "];");2340 2341 this._codeIndents()._newLine("return " + this._builderVar + ".Start(this,");2342 this._codeIndentLevel(1);2343 2344 this._pos = { };2345 2346 this._bothIndents()._visitWind(windAst)._newLine();2347 this._codeIndentLevel(-1);2348 2349 this._codeIndents()._newLine(");");2350 this._bothIndentLevel(-1);2351 2352 this._bothIndents()._code("})")._comment("}");2353 },2354 2355 _visitWind: function (ast) {2356 this._windVisitors[ast.type].call(this, ast);2357 return this;2358 },2359 2360 _visitRaw: function (ast) {2361 var type = ast[0];2362 2363 var visitor = this._rawVisitors[type];2364 if (visitor) {2365 visitor.call(this, ast);2366 } else {2367 throw new Error(‘"‘ + type + ‘" is not currently supported.‘);2368 }2369 2370 return this;2371 },2372 2373 _visitWindStatements: function (statements) {2374 for (var i = 0; i < statements.length; i++) {2375 var stmt = statements[i];2376 2377 if (stmt.type == "raw" || stmt.type == "if" || stmt.type == "switch") {2378 this._bothIndents()._visitWind(stmt)._newLine();2379 } else if (stmt.type == "delay") {2380 this._visitWindStatements(stmt.stmts);2381 } else {2382 this._bothIndents()._code("return ")._visitWind(stmt)._newLine(";");2383 }2384 }2385 },2386 2387 _visitRawStatements: function (statements) {2388 for (var i = 0; i < statements.length; i++) {2389 var s = statements[i];2390 2391 this._bothIndents()._visitRaw(s)._bothLine();2392 2393 switch (s[0]) {2394 case "break":2395 case "return":2396 case "continue":2397 case "throw":2398 return;2399 }2400 }2401 },2402 2403 _visitRawBody: function (body) {2404 if (body[0] == "block") {2405 this._visitRaw(body);2406 } else {2407 this._bothLine();2408 this._bothIndentLevel(1);2409 2410 this._bothIndents()._visitRaw(body);2411 this._bothIndentLevel(-1);2412 }2413 2414 return this;2415 },2416 2417 _visitRawFunction: function (ast) {2418 var funcName = ast[1] || "";2419 var args = ast[2];2420 var statements = ast[3];2421 2422 this._bothLine("function " + funcName + "(" + args.join(", ") + ") {")2423 this._bothIndentLevel(1);2424 2425 var currInFunction = this._pos.inFunction;2426 this._pos.inFunction = true;2427 2428 this._visitRawStatements(statements);2429 this._bothIndentLevel(-1);2430 2431 this._pos.inFunction = currInFunction;2432 2433 this._bothIndents()._both("}");2434 },2435 2436 _windVisitors: {2437 "delay": function (ast) {2438 if (ast.stmts.length == 1) {2439 var subStmt = ast.stmts[0];2440 switch (subStmt.type) {2441 case "delay":2442 case "combine":2443 case "normal":2444 case "break":2445 case "continue":2446 case "for":2447 case "for-in":2448 case "while":2449 case "do":2450 case "try":2451 this._visitWind(subStmt);2452 return;2453 case "return":2454 if (!subStmt.stmt[1]) {2455 this._visitWind(subStmt);2456 return;2457 }2458 }2459 }2460 2461 this._newLine(this._builderVar + ".Delay(function () {");2462 this._codeIndentLevel(1);2463 2464 this._visitWindStatements(ast.stmts);2465 this._codeIndentLevel(-1);2466 2467 this._codeIndents()._code("})");2468 },2469 2470 "combine": function (ast) {2471 this._newLine(this._builderVar + ".Combine(");2472 this._codeIndentLevel(1);2473 2474 this._bothIndents()._visitWind(ast.first)._newLine(",");2475 this._bothIndents()._visitWind(ast.second)._newLine();2476 this._codeIndentLevel(-1);2477 2478 this._codeIndents()._code(")");2479 },2480 2481 "for": function (ast) { 2482 if (ast.condition) {2483 this._codeLine(this._builderVar + ".For(function () {")2484 ._commentLine("for (");2485 this._codeIndentLevel(1);2486 2487 this._bothIndents()2488 ._code("return ")2489 ._comment("; ")2490 ._visitRaw(ast.condition)2491 ._newLine(";");2492 this._codeIndentLevel(-1);2493 2494 this._bothIndents()._code("}, ");2495 } else {2496 this._code(this._builderVar + ".For(null, ")2497 ._comment("for (; ");2498 }2499 2500 if (ast.update) {2501 this._newLine("function () {");2502 this._codeIndentLevel(1);2503 2504 this._bothIndents()2505 ._comment("; ")2506 ._visitRaw(ast.update)2507 ._codeLine(";")2508 ._commentLine(") {");2509 this._codeIndentLevel(-1);2510 2511 this._codeIndents()._newLine("},");2512 } else {2513 this._codeLine("null,")._commentLine("; ) {");2514 }2515 this._bothIndentLevel(1);2516 2517 this._bothIndents()._visitWind(ast.bodyStmt)._newLine();2518 this._bothIndentLevel(-1);2519 2520 this._bothIndents()._code(")")._comment("}");2521 },2522 2523 "for-in": function (ast) {2524 this._code(this._builderVar + ".ForIn(")2525 ._comment("for (var " + ast.argName + " in ")2526 ._visitRaw(ast.obj)2527 ._codeLine(", function (" + ast.argName + ") {")2528 ._commentLine(") {");2529 this._bothIndentLevel(1);2530 2531 this._visitWindStatements(ast.bodyStmts);2532 this._bothIndentLevel(-1);2533 2534 this._bothIndents()._code("})")._comment("}");2535 },2536 2537 "while": function (ast) {2538 this._newLine(this._builderVar + ".While(function () {");2539 this._codeIndentLevel(1);2540 2541 this._bothIndents()2542 ._code("return ")2543 ._comment("while (")2544 ._visitRaw(ast.condition)2545 ._codeLine(";")2546 ._commentLine(") {");2547 this._codeIndentLevel(-1);2548 2549 this._codeIndents()._newLine("},");2550 this._bothIndentLevel(1);2551 2552 this._bothIndents()._visitWind(ast.bodyStmt)._newLine();2553 this._bothIndentLevel(-1);2554 2555 this._bothIndents()._code(")")._comment("}");2556 },2557 2558 "do": function (ast) {2559 this._codeLine(this._builderVar + ".Do(")._commentLine("do {");2560 this._bothIndentLevel(1);2561 2562 this._bothIndents()._visitWind(ast.bodyStmt)._newLine(",");2563 this._commentIndentLevel(-1);2564 2565 this._codeIndents()._newLine("function () {");2566 this._codeIndentLevel(1);2567 2568 this._bothIndents()2569 ._code("return ")2570 ._comment("} while (")2571 ._visitRaw(ast.condition)2572 ._codeLine(";")2573 ._commentLine(");");2574 this._codeIndentLevel(-1);2575 2576 this._codeIndents()._newLine("}");2577 this._codeIndentLevel(-1);2578 2579 this._codeIndents()._code(")");2580 },2581 2582 "raw": function (ast) {2583 this._visitRaw(ast.stmt, true);2584 },2585 2586 "bind": function (ast) {2587 var info = ast.info;2588 2589 var commentPrefix = "";2590 if (info.assignee == "return") {2591 commentPrefix = "return ";2592 } else if (info.argName != "") {2593 commentPrefix = "var " + info.argName + " = ";2594 }2595 2596 this._code(this._builderVar + ".Bind(")._comment(commentPrefix + this._binder + "(")._visitRaw(info.expression)._comment(");")._newLine(", function (" + info.argName + ") {");2597 this._codeIndentLevel(1);2598 2599 if (info.assignee == "return") {2600 this._codeIndents()2601 ._newLine("return " + this._builderVar + ".Return(" + info.argName + ");");2602 } else {2603 if (info.assignee) {2604 this._bothIndents()2605 ._visitRaw(info.assignee)._bothLine(" = " + info.argName + ";");2606 }2607 2608 this._visitWindStatements(ast.stmts);2609 }2610 this._codeIndentLevel(-1);2611 2612 this._codeIndents()2613 ._code("})");2614 },2615 2616 "if": function (ast) {2617 2618 for (var i = 0; i < ast.conditionStmts.length; i++) {2619 var stmt = ast.conditionStmts[i];2620 2621 this._both("if (")._visitRaw(stmt.cond)._bothLine(") {");2622 this._bothIndentLevel(1);2623 2624 this._visitWindStatements(stmt.stmts);2625 this._bothIndentLevel(-1);2626 2627 if (i < ast.conditionStmts.length - 1 || ast.elseStmts) {2628 this._bothIndents()._both("} else ");2629 } else {2630 this._bothIndents()._code("} else ")._comment("}");2631 }2632 }2633 2634 if (ast.elseStmts) {2635 this._bothLine("{");2636 this._bothIndentLevel(1);2637 } else {2638 this._newLine("{");2639 this._codeIndentLevel(1);2640 }2641 2642 if (ast.elseStmts) {2643 this._visitWindStatements(ast.elseStmts);2644 } else {2645 this._codeIndents()2646 ._newLine("return " + this._builderVar + ".Normal();");2647 }2648 2649 if (ast.elseStmts) {2650 this._bothIndentLevel(-1);2651 } else {2652 this._codeIndentLevel(-1);2653 }2654 2655 if (ast.elseStmts) {2656 this._bothIndents()2657 ._both("}");2658 } else {2659 this._codeIndents()2660 ._code("}");2661 }2662 },2663 2664 "switch": function (ast) {2665 this._both("switch (")._visitRaw(ast.item)._bothLine(") {");2666 this._bothIndentLevel(1);2667 2668 for (var i = 0; i < ast.caseStmts.length; i++) {2669 var caseStmt = ast.caseStmts[i];2670 2671 if (caseStmt.item) {2672 this._bothIndents()2673 ._both("case ")._visitRaw(caseStmt.item)._bothLine(":");2674 } else {2675 this._bothIndents()._bothLine("default:");2676 }2677 this._bothIndentLevel(1);2678 2679 this._visitWindStatements(caseStmt.stmts); 2680 this._bothIndentLevel(-1);2681 }2682 2683 this._bothIndents()._code("}");2684 },2685 2686 "try": function (ast) {2687 this._codeLine(this._builderVar + ".Try(")._commentLine("try {");2688 this._bothIndentLevel(1);2689 2690 this._bothIndents()._visitWind(ast.bodyStmt)._newLine(",");2691 this._commentIndentLevel(-1);2692 2693 if (ast.catchStmts) {2694 this._bothIndents()2695 ._codeLine("function (" + ast.exVar + ") {")2696 ._commentLine("} catch (" + ast.exVar + ") {");2697 this._bothIndentLevel(1);2698 2699 this._visitWindStatements(ast.catchStmts);2700 this._bothIndentLevel(-1);2701 2702 this._bothIndents()._codeLine("},");2703 if (ast.finallyStmt) {2704 this._commentLine("} finally {");2705 } else {2706 this._commentLine("}");2707 }2708 } else {2709 this._bothIndents()._codeLine("null,")._commentLine("} finally {");2710 }2711 2712 if (ast.finallyStmt) {2713 this._commentIndentLevel(1);2714 this._bothIndents()._visitWind(ast.finallyStmt)._newLine();2715 this._commentIndentLevel(-1);2716 } else {2717 this._codeIndents()._newLine("null");2718 }2719 this._codeIndentLevel(-1);2720 2721 this._codeIndents()._code(")");2722 if (ast.finallyStmt) {2723 this._commentIndents()._comment("}");2724 }2725 },2726 2727 "normal": function (ast) {2728 this._code(this._builderVar + ".Normal()");2729 },2730 2731 "throw": function (ast) {2732 this2733 ._code(this._builderVar + ".Throw(")2734 ._comment("throw ")2735 ._visitRaw(ast.stmt[1])2736 ._code(")")._comment(";");2737 },2738 2739 "break": function (ast) {2740 this._code(this._builderVar + ".Break()")._comment("break;");2741 },2742 2743 "continue": function (ast) {2744 this._code(this._builderVar + ".Continue()")._comment("continue;");2745 },2746 2747 "return": function (ast) {2748 this._code(this._builderVar + ".Return(")._comment("return");2749 if (ast.stmt[1]) {2750 this._comment(" ")._visitRaw(ast.stmt[1]);2751 }2752 2753 this._code(")")._comment(";");2754 }2755 },2756 2757 _rawVisitors: {2758 "var": function (ast) {2759 this._both("var ");2760 2761 var items = ast[1];2762 for (var i = 0; i < items.length; i++) {2763 this._both(items[i][0]);2764 if (items[i].length > 1) {2765 this._both(" = ")._visitRaw(items[i][1]);2766 }2767 if (i < items.length - 1) this._both(", ");2768 }2769 2770 this._both(";");2771 },2772 2773 "seq": function (ast, noBracket) {2774 var left = ast[1];2775 var right = ast[2];2776 2777 if (!noBracket) this._both("(");2778 2779 this._visitRaw(left);2780 this._both(", ");2781 2782 if (right[0] == "seq") {2783 arguments.callee.call(this, right, true);2784 } else {2785 this._visitRaw(right);2786 }2787 2788 if (!noBracket) this._both(")");2789 },2790 2791 "binary": function (ast) {2792 var op = ast[1], left = ast[2], right = ast[3];2793 2794 if (getPrecedence(ast) < getPrecedence(left)) {2795 this._both("(")._visitRaw(left)._both(") ");2796 } else {2797 this._visitRaw(left)._both(" ");2798 }2799 2800 this._both(op);2801 2802 if (getPrecedence(ast) <= getPrecedence(right)) {2803 this._both(" (")._visitRaw(right)._both(")");2804 } else {2805 this._both(" ")._visitRaw(right);2806 }2807 },2808 2809 "sub": function (ast) {2810 var prop = ast[1], index = ast[2];2811 2812 if (getPrecedence(ast) < getPrecedence(prop)) {2813 this._both("(")._visitRaw(prop)._both(")[")._visitRaw(index)._both("]");2814 } else {2815 this._visitRaw(prop)._both("[")._visitRaw(index)._both("]");2816 }2817 },2818 2819 "unary-postfix": function (ast) {2820 var op = ast[1];2821 var item = ast[2];2822 2823 if (getPrecedence(ast) <= getPrecedence(item)) {2824 this._both("(")._visitRaw(item)._both(")");2825 } else {2826 this._visitRaw(item);2827 }2828 2829 this._both(" " + op);2830 },2831 2832 "unary-prefix": function (ast) {2833 var op = ast[1];2834 var item = ast[2];2835 2836 this._both(op + " ");2837 2838 if (getPrecedence(ast) < getPrecedence(item)) {2839 this._both("(")._visitRaw(item)._both(")");2840 } else {2841 this._visitRaw(item);2842 }2843 },2844 2845 "assign": function (ast) {2846 var op = ast[1];2847 var name = ast[2];2848 var value = http://www.mamicode.com/ast[3];2849 2850 if (name[0] == "assign") {2851 this._both("(")._visitRaw(name)._both(")");2852 } else {2853 this._visitRaw(name);2854 }2855 2856 if ((typeof op) == "string") {2857 this._both(" " + op + "= ");2858 } else {2859 this._both(" = ");2860 }2861 2862 this._visitRaw(value);2863 },2864 2865 "stat": function (ast) {2866 this._visitRaw(ast[1])._both(";");2867 },2868 2869 "dot": function (ast) {2870 var left = ast[1];2871 var right = ast[2];2872 2873 if (getPrecedence(ast) < getPrecedence(left)) {2874 this._both("(")._visitRaw(left)._both(").")._both(right);2875 } else {2876 this._visitRaw(left)._both(".")._both(right);2877 }2878 },2879 2880 "new": function (ast) {2881 var ctor = ast[1];2882 2883 this._both("new ")._visitRaw(ctor)._both("(");2884 2885 var args = ast[2];2886 for (var i = 0, len = args.length; i < len; i++) {2887 this._visitRaw(args[i]);2888 if (i < len - 1) this._both(", ");2889 }2890 2891 this._both(")");2892 },2893 2894 "call": function (ast) {2895 2896 if (isWindPattern(ast)) {2897 compileWindPattern(ast, this._seedProvider, this._codeWriter, this._commentWriter);2898 } else {2899 var caller = ast[1];2900 2901 var invalidBind = (caller[0] == "name") && (caller[1] == this._binder);2902 // throw?2903 2904 if (getPrecedence(ast) < getPrecedence(caller)) {2905 this._both("(")._visitRaw(caller)._both(")");2906 } else {2907 this._visitRaw(caller);2908 }2909 2910 this._both("(");2911 2912 var args = ast[2];2913 for (var i = 0; i < args.length; i++) {2914 this._visitRaw(args[i]);2915 if (i < args.length - 1) this._both(", ");2916 }2917 2918 this._both(")");2919 }2920 },2921 2922 "name": function (ast) {2923 this._both(ast[1]);2924 },2925 2926 "object": function (ast) {2927 var items = ast[1];2928 if (items.length <= 0) {2929 this._both("{ }");2930 } else {2931 this._bothLine("{");2932 this._bothIndentLevel(1);2933 2934 for (var i = 0; i < items.length; i++) {2935 this._bothIndents()2936 ._both(stringify(items[i][0]) + ": ")2937 ._visitRaw(items[i][1]);2938 2939 if (i < items.length - 1) {2940 this._bothLine(",");2941 } else {2942 this._bothLine("");2943 }2944 }2945 2946 this._bothIndentLevel(-1);2947 this._bothIndents()._both("}");2948 }2949 },2950 2951 "array": function (ast) {2952 this._both("[");2953 2954 var items = ast[1];2955 for (var i = 0; i < items.length; i++) {2956 this._visitRaw(items[i]);2957 if (i < items.length - 1) this._both(", ");2958 }2959 2960 this._both("]");2961 },2962 2963 "num": function (ast) {2964 this._both(ast[1]);2965 },2966 2967 "regexp": function (ast) {2968 this._both("/" + ast[1] + "/" + ast[2]);2969 },2970 2971 "string": function (ast) {2972 this._both(stringify(ast[1]));2973 },2974 2975 "function": function (ast) {2976 this._visitRawFunction(ast);2977 },2978 2979 "defun": function (ast) {2980 this._visitRawFunction(ast);2981 },2982 2983 "for": function (ast) {2984 this._both("for (");2985 2986 var setup = ast[1];2987 if (setup) {2988 this._visitRaw(setup);2989 if (setup[0] != "var") {2990 this._both("; ");2991 } else {2992 this._both(" ");2993 }2994 } else {2995 this._both("; ");2996 }2997 2998 var condition = ast[2];2999 if (condition) this._visitRaw(condition);3000 this._both("; ");3001 3002 var update = ast[3];3003 if (update) this._visitRaw(update);3004 this._both(") ");3005 3006 var currInLoop = this._pos.inLoop;3007 this._pos.inLoop = true;3008 3009 var body = ast[4];3010 this._visitRawBody(body);3011 3012 this._pos.inLoop = currInLoop;3013 },3014 3015 "for-in": function (ast) {3016 this._both("for (");3017 3018 var declare = ast[1];3019 if (declare[0] == "var") { // declare == ["var", [["m"]]]3020 this._both("var " + declare[1][0][0]);3021 } else {3022 this._visitRaw(declare);3023 }3024 3025 this._both(" in ")._visitRaw(ast[3])._both(") ");3026 3027 var currInLoop = this._pos.inLoop;3028 this._pos.inLoop = true;3029 3030 var body = ast[4];3031 this._visitRawBody(body);3032 3033 this._pos.inLoop = currInLoop;3034 },3035 3036 "block": function (ast) {3037 if (ast.length > 1) { 3038 this._bothLine("{")3039 this._bothIndentLevel(1);3040 3041 this._visitRawStatements(ast[1]);3042 this._bothIndentLevel(-1);3043 3044 this._bothIndents()3045 ._both("}");3046 } else {3047 this._both(";");3048 }3049 },3050 3051 "while": function (ast) {3052 var condition = ast[1];3053 var body = ast[2];3054 3055 var currInLoop = this._pos.inLoop;3056 this._pos.inLoop = true;3057 3058 this._both("while (")._visitRaw(condition)._both(") ")._visitRawBody(body);3059 3060 this._pos.inLoop = currInLoop;3061 },3062 3063 "do": function (ast) {3064 var condition = ast[1];3065 var body = ast[2];3066 3067 var currInLoop = this._pos.inLoop;3068 this._pos.inLoop = true;3069 3070 this._both("do ")._visitRawBody(body);3071 3072 this._pos.inLoop = currInLoop;3073 3074 if (body[0] == "block") {3075 this._both(" ");3076 } else {3077 this._bothLine()3078 ._bothIndents();3079 }3080 3081 this._both("while (")._visitRaw(condition)._both(");");3082 },3083 3084 "if": function (ast) {3085 var condition = ast[1];3086 var thenPart = ast[2];3087 3088 this._both("if (")._visitRaw(condition)._both(") ")._visitRawBody(thenPart);3089 3090 var elsePart = ast[3];3091 if (elsePart) {3092 if (thenPart[0] == "block") {3093 this._both(" ");3094 } else {3095 this._bothLine("")3096 ._bothIndents();3097 }3098 3099 if (elsePart[0] == "if") {3100 this._both("else ")._visitRaw(elsePart);3101 } else {3102 this._both("else ")._visitRawBody(elsePart);3103 }3104 }3105 },3106 3107 "break": function (ast) {3108 if (this._pos.inLoop || this._pos.inSwitch) {3109 this._both("break;");3110 } else {3111 this._code("return ")._visitWind({ type: "break", stmt: ast })._code(";");3112 }3113 },3114 3115 "continue": function (ast) {3116 if (this._pos.inLoop) {3117 this._both("continue;");3118 } else {3119 this._code("return ")._visitWind({ type: "continue", stmt: ast })._code(";");3120 }3121 },3122 3123 "return": function (ast) {3124 if (this._pos.inFunction) {3125 this._both("return");3126 var value = http://www.mamicode.com/ast[1];3127 if (value) this._both(" ")._visitRaw(value);3128 this._both(";");3129 } else {3130 this._code("return ")._visitWind({ type: "return", stmt: ast })._code(";");3131 }3132 },3133 3134 "throw": function (ast) {3135 var pos = this._pos;3136 if (pos.inTry || pos.inFunction) {3137 this._both("throw ")._visitRaw(ast[1])._both(";");3138 } else {3139 this._code("return ")._visitWind({ type: "throw", stmt: ast })._code(";");3140 }3141 },3142 3143 "conditional": function (ast) {3144 this._both("(")._visitRaw(ast[1])._both(") ? (")._visitRaw(ast[2])._both(") : (")._visitRaw(ast[3])._both(")");3145 },3146 3147 "try": function (ast) {3148 3149 this._bothLine("try {");3150 this._bothIndentLevel(1);3151 3152 var currInTry = this._pos.inTry;3153 this._pos.inTry = true;3154 3155 this._visitRawStatements(ast[1]);3156 this._bothIndentLevel(-1);3157 3158 this._pos.inTry = currInTry;3159 3160 var catchClause = ast[2];3161 var finallyStatements = ast[3];3162 3163 if (catchClause) {3164 this._bothIndents()3165 ._bothLine("} catch (" + catchClause[0] + ") {")3166 this._bothIndentLevel(1);3167 3168 this._visitRawStatements(catchClause[1]);3169 this._bothIndentLevel(-1);3170 }3171 3172 if (finallyStatements) {3173 this._bothIndents()3174 ._bothLine("} finally {");3175 this._bothIndentLevel(1);3176 3177 this._visitRawStatements(finallyStatements);3178 this._bothIndentLevel(-1);3179 } 3180 3181 this._bothIndents()3182 ._both("}");3183 },3184 3185 "switch": function (ast) {3186 this._both("switch (")._visitRaw(ast[1])._bothLine(") {");3187 this._bothIndentLevel(1);3188 3189 var currInSwitch = this._pos.inSwitch;3190 this._pos.inSwitch = true;3191 3192 var cases = ast[2];3193 for (var i = 0; i < cases.length; i++) {3194 var c = cases[i];3195 this._bothIndents();3196 3197 if (c[0]) {3198 this._both("case ")._visitRaw(c[0])._bothLine(":");3199 } else {3200 this._bothLine("default:");3201 }3202 this._bothIndentLevel(1);3203 3204 this._visitRawStatements(c[1]);3205 this._bothIndentLevel(-1);3206 }3207 this._bothIndentLevel(-1);3208 3209 this._pos.inSwitch = currInSwitch;3210 3211 this._bothIndents()3212 ._both("}");3213 }3214 }3215 };3216 3217 var merge = function (commentLines, codeLines) {3218 var length = commentLines.length;3219 3220 var maxShift = 0;3221 3222 for (var i = 0; i < length; i++) {3223 var matches = codeLines[i].match(" +");3224 var spaceLength = matches ? matches[0].length : 0;3225 3226 var shift = commentLines[i].length - spaceLength + 10;3227 if (shift > maxShift) {3228 maxShift = shift;3229 }3230 }3231 3232 var shiftBuffer = new Array(maxShift);3233 for (var i = 0; i < maxShift; i++) {3234 shiftBuffer[i] = " ";3235 }3236 3237 var shiftSpaces = shiftBuffer.join("");3238 3239 var buffer = [];3240 for (var i = 0; i < length; i++) {3241 var comment = commentLines[i]; 3242 if (comment.replace(/ +/g, "").length > 0) {3243 comment = "/* " + comment + " */ ";3244 }3245 3246 var code = shiftSpaces + codeLines[i];3247 3248 buffer.push(comment);3249 buffer.push(code.substring(comment.length));3250 3251 if (i != length - 1) {3252 buffer.push("\n");3253 }3254 }3255 3256 return buffer.join("");3257 }3258 3259 var sourceUrlSeed = 0;3260 3261 var getOptions = function (options) {3262 options = options || { };3263 options.root = options.root || "Wind";3264 options.noSourceUrl = options.noSourceUrl || false;3265 3266 return options;3267 }3268 3269 var compile = function (builderName, func, options) {3270 options = getOptions(options);3271 3272 var funcCode = func.toString();3273 var evalCode = "eval(" + compile.rootName + ".compile(" + stringify(builderName) + ", " + funcCode + "))"3274 var evalCodeAst = parse(evalCode);3275 3276 var codeWriter = new CodeWriter();3277 var commentWriter = new CodeWriter();3278 3279 // [ "toplevel", [ [ "stat", [ "call", ... ] ] ] ]3280 var evalAst = evalCodeAst[1][0][1];3281 var funcName = compileWindPattern(evalAst, new SeedProvider(), codeWriter, commentWriter);3282 3283 var newCode = merge(commentWriter.lines, codeWriter.lines);3284 if (!options.noSourceUrl) {3285 newCode += ("\n//@ sourceURL=wind/" + (sourceUrlSeed++) + "_" + (funcName || "anonymous") + ".js");3286 }3287 3288 Wind.logger.debug("// Original: \r\n" + funcCode + "\r\n\r\n// Compiled: \r\n" + newCode + "\r\n");3289 3290 return codeGenerator(newCode);3291 }3292 3293 compile.rootName = "Wind";3294 3295 // CommonJS3296 var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);3297 // CommonJS AMD3298 var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);3299 3300 var defineModule = function () {3301 Wind.define({3302 name: "compiler",3303 version: "0.7.2",3304 require: isCommonJS && require,3305 dependencies: { core: "~0.7.0" },3306 init: function () {3307 Wind.parse = parse;3308 Wind.compile = compile;3309 }3310 });3311 }3312 3313 if (isCommonJS) {3314 try {3315 Wind = require("./wind-core");3316 } catch (ex) {3317 Wind = require("wind-core");3318 }3319 3320 defineModule();3321 } else if (isAmd) {3322 require(["wind-core"], function (wind) {3323 Wind = wind;3324 defineModule();3325 });3326 } else {3327 var Fn = Function, global = Fn(‘return this‘)();3328 if (!global.Wind) {3329 throw new Error(‘Missing the root object, please load "wind" component first.‘);3330 }3331 3332 Wind = global.Wind;3333 defineModule();3334 }3335 })();3336 3337 /***********************************************************************3338 wind-builderbase-0.7.0.js3339 ***********************************************************************/3340 3341 (function () {3342 "use strict";3343 3344 var BuilderBase = function () { }3345 BuilderBase.prototype = {3346 For: function (condition, update, body) {3347 return {3348 next: function (_this, callback) {3349 3350 var loop = function (skipUpdate) {3351 try {3352 if (update && !skipUpdate) {3353 update.call(_this);3354 }3355 3356 if (!condition || condition.call(_this)) {3357 body.next(_this, function (type, value, target) {3358 if (type == "normal" || type == "continue") {3359 loop(false);3360 } else if (type == "throw" || type == "return") {3361 callback(type, value);3362 } else if (type == "break") {3363 callback("normal");3364 } else {3365 throw new Error(‘Invalid type for "Loop": ‘ + type);3366 }3367 });3368 } else {3369 callback("normal");3370 }3371 } catch (ex) {3372 callback("throw", ex);3373 }3374 }3375 3376 loop(true);3377 }3378 };3379 },3380 3381 ForIn: function (obj, bodyGenerator) {3382 return {3383 next: function (_this, callback) {3384 3385 var keys = [];3386 for (var k in obj) {3387 keys.push(k);3388 }3389 3390 var loop = function (i) {3391 try {3392 if (i < keys.length) {3393 var body = bodyGenerator(keys[i]);3394 body.next(_this, function (type, value, target) {3395 if (type == "normal" || type == "continue") {3396 loop(i + 1);3397 } else if (type == "throw" || type == "return") {3398 callback(type, value);3399 } else if (type == "break") {3400 callback("normal");3401 } else {3402 throw new Error(‘Invalid type for "Loop": ‘ + type);3403 }3404 });3405 } else {3406 callback("normal");3407 }3408 } catch (ex) {3409 callback("throw", ex);3410 }3411 }3412 3413 loop(0);3414 }3415 };3416 },3417 3418 While: function (condition, body) {3419 return {3420 next: function (_this, callback) {3421 var loop = function () {3422 try {3423 if (condition.call(_this)) {3424 body.next(_this, function (type, value, target) {3425 if (type == "normal" || type == "continue") {3426 loop();3427 } else if (type == "throw" || type == "return") {3428 callback(type, value);3429 } else if (type == "break") {3430 callback("normal");3431 } else {3432 throw new Error(‘Invalid type for "Loop": ‘ + type);3433 }3434 });3435 } else {3436 callback("normal");3437 }3438 } catch (ex) {3439 callback("throw", ex);3440 }3441 }3442 3443 loop();3444 }3445 };3446 },3447 3448 Do: function (body, condition) {3449 return {3450 next: function (_this, callback) {3451 3452 var loop = function () {3453 body.next(_this, function (type, value, target) {3454 if (type == "normal" || type == "continue") {3455 try {3456 if (condition.call(_this)) {3457 loop();3458 } else {3459 callback("normal");3460 }3461 } catch (ex) {3462 callback("throw", ex);3463 }3464 } else if (type == "throw" || type == "return") {3465 callback(type, value);3466 } else if (type == "break") {3467 callback("normal");3468 } else {3469 throw new Error(‘Invalid type for "Loop": ‘ + type);3470 }3471 });3472 };3473 3474 loop();3475 }3476 };3477 },3478 3479 Delay: function (generator) {3480 return {3481 next: function (_this, callback) {3482 try {3483 var step = generator.call(_this);3484 step.next(_this, callback);3485 } catch (ex) {3486 callback("throw", ex);3487 }3488 }3489 };3490 },3491 3492 Combine: function (s1, s2) {3493 return {3494 next: function (_this, callback) {3495 s1.next(_this, function (type, value, target) {3496 if (type == "normal") {3497 try {3498 s2.next(_this, callback);3499 } catch (ex) {3500 callback("throw", ex);3501 }3502 } else {3503 callback(type, value, target);3504 }3505 });3506 }3507 };3508 },3509 3510 Return: function (result) {3511 return {3512 next: function (_this, callback) {3513 callback("return", result);3514 }3515 };3516 },3517 3518 Normal: function () {3519 return {3520 next: function (_this, callback) {3521 callback("normal");3522 }3523 };3524 },3525 3526 Break: function () {3527 return {3528 next: function (_this, callback) {3529 callback("break");3530 }3531 };3532 },3533 3534 Continue: function () {3535 return {3536 next: function (_this, callback) {3537 callback("continue");3538 }3539 };3540 },3541 3542 Throw: function (ex) {3543 return {3544 next: function (_this, callback) {3545 callback("throw", ex);3546 }3547 };3548 },3549 3550 Try: function (tryTask, catchGenerator, finallyStep) {3551 return {3552 next: function (_this, callback) {3553 tryTask.next(_this, function (type, value, target) {3554 if (type != "throw" || !catchGenerator) {3555 if (!finallyStep) {3556 callback(type, value, target);3557 } else {3558 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {3559 if (finallyType == "normal") {3560 callback(type, value, target);3561 } else {3562 callback(finallyType, finallyValue, finallyTarget);3563 }3564 });3565 }3566 } else {3567 3568 if (catchGenerator) {3569 3570 var catchTask;3571 try {3572 catchTask = catchGenerator.call(_this, value);3573 } catch (ex) {3574 if (finallyStep) {3575 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {3576 if (finallyType == "normal") {3577 callback("throw", ex);3578 } else {3579 callback(finallyType, finallyValue, finallyTarget);3580 }3581 });3582 } else {3583 callback("throw", ex);3584 }3585 }3586 3587 if (catchTask) {3588 catchTask.next(_this, function (catchType, catchValue, catchTarget) {3589 if (catchType == "throw") {3590 if (finallyStep) {3591 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {3592 if (finallyType == "normal") {3593 callback(catchType, catchValue, catchTarget);3594 } else {3595 callback(finallyType, finallyValue, finallyTarget);3596 }3597 });3598 } else {3599 callback(catchType, catchValue, catchTarget);3600 }3601 } else {3602 if (finallyStep) {3603 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {3604 if (finallyType == "normal") {3605 callback(catchType, catchValue, catchTarget);3606 } else {3607 callback(finallyType, finallyValue, finallyTarget);3608 }3609 });3610 } else {3611 callback(catchType, catchValue, catchTarget);3612 }3613 } 3614 });3615 }3616 } else {3617 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {3618 if (finallyType == "normal") {3619 callback(type, value, target);3620 } else {3621 callback(finallyType, finallyValue, finallyTarget);3622 }3623 });3624 }3625 }3626 });3627 }3628 };3629 }3630 }3631 3632 // CommonJS3633 var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);3634 // CommonJS AMD3635 var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);3636 3637 var Wind;3638 3639 var defineModule = function () {3640 Wind.define({3641 name: "builderbase",3642 version: "0.7.0",3643 require: isCommonJS && require,3644 dependencies: { core: "~0.7.0" },3645 init: function () {3646 Wind.BuilderBase = BuilderBase;3647 }3648 });3649 }3650 3651 if (isCommonJS) {3652 try {3653 Wind = require("./wind-core");3654 } catch (ex) {3655 Wind = require("wind-core");3656 }3657 3658 defineModule();3659 } else if (isAmd) {3660 require(["wind-core"], function (wind) {3661 Wind = wind;3662 defineModule();3663 });3664 } else {3665 var Fn = Function, global = Fn(‘return this‘)();3666 if (!global.Wind) {3667 throw new Error(‘Missing the root object, please load "wind" component first.‘);3668 }3669 3670 Wind = global.Wind;3671 defineModule();3672 }3673 })();3674 3675 /***********************************************************************3676 wind-async-0.7.1.js3677 ***********************************************************************/3678 3679 (function () {3680 "use strict";3681 3682 var supportDefineProperty = (function () {3683 var i = 0;3684 var getter = function () {3685 if (i === 0) {3686 throw new Error("Execute too soon.");3687 }3688 3689 return i;3690 };3691 3692 var obj = {};3693 3694 try {3695 Object.defineProperty(obj, "value", { get: getter });3696 3697 i = 1;3698 return obj.value =http://www.mamicode.com/== 1;3699 } catch (ex) {3700 return false;3701 }3702 })();3703 3704 var Wind, _;3705 3706 var Async = { };3707 3708 /***********************************************************************3709 Errors3710 ***********************************************************************/3711 3712 var CanceledErrorTypeID = "670a1076-712b-4edd-9b70-64b152fe1cd9";3713 var isCanceledError = function (ex) { return ex._typeId == CanceledErrorTypeID; }3714 var CanceledError = Async.CanceledError = function () { }3715 CanceledError.prototype = {3716 isTypeOf: isCanceledError,3717 _typeId: CanceledErrorTypeID,3718 message: "The task has been cancelled."3719 }3720 3721 var AggregateErrorTypeID = "4a73efb8-c2e2-4305-a05c-72385288650a";3722 var AggregateError = Async.AggregateError = function (errors) {3723 this.children = [];3724 3725 if (errors) {3726 for (var i = 0; i < errors.length; i++) {3727 this.children.push(errors[i]);3728 }3729 }3730 }3731 AggregateError.prototype = {3732 _typeId: AggregateErrorTypeID,3733 message: "This is an error contains sub-errors, please check the ‘children‘ collection for more details.",3734 isTypeOf: function (ex) {3735 return ex._typeId == AggregateErrorTypeID;3736 }3737 }3738 3739 /***********************************************************************3740 CancellationToken3741 ***********************************************************************/3742 3743 var CancellationToken = Async.CancellationToken = function () { }3744 CancellationToken.prototype = {3745 register: function (handler) {3746 if (this.isCancellationRequested) {3747 handler();3748 }3749 3750 if (!this._handlers) {3751 this._handlers = [];3752 }3753 3754 this._handlers.push(handler);3755 },3756 3757 unregister: function (handler) {3758 if (!this._handlers) {3759 return;3760 }3761 3762 var index = this._handlers.indexOf(handler);3763 if (index >= 0) {3764 this._handlers.splice(index, 1);3765 }3766 },3767 3768 cancel: function () {3769 if (this.isCancellationRequested) {3770 return;3771 }3772 3773 this.isCancellationRequested = true;3774 3775 var handlers = this._handlers;3776 delete this._handlers;3777 3778 for (var i = 0; i < handlers.length; i++) {3779 try {3780 handlers[i]();3781 } catch (ex) {3782 Wind.logger.warn("Cancellation handler threw an error: " + ex);3783 }3784 }3785 },3786 3787 throwIfCancellationRequested: function () {3788 if (this.isCancellationRequested) {3789 throw new CanceledError();3790 }3791 }3792 };3793 3794 /***********************************************************************3795 Task3796 ***********************************************************************/3797 3798 var EventManager = function () {3799 this._listeners = {};3800 this._firing = null;3801 }3802 EventManager.prototype = {3803 add: function (name, listener) {3804 if (this._firing === name) {3805 var self = this;3806 setTimeout(function () {3807 self.add(name, listener);3808 }, 0);3809 3810 return;3811 }3812 3813 var eventListeners = this._listeners[name];3814 if (!eventListeners) {3815 eventListeners = this._listeners[name] = [];3816 }3817 3818 eventListeners.push(listener);3819 },3820 3821 remove: function (name, listener) {3822 if (this._firing === name) {3823 var self = this;3824 setTimeout(function () {3825 self.remove(name, listener);3826 }, 0);3827 3828 return;3829 }3830 3831 var eventListeners = this._listeners[name];3832 if (!eventListeners) return;3833 3834 var index = eventListeners.indexOf(listener);3835 if (index >= 0) {3836 eventListeners.splice(index, 1);3837 }3838 },3839 3840 fire: function (name, self, args) {3841 var listeners = this._listeners[name];3842 if (!listeners) return;3843 3844 this._firing = name;3845 3846 for (var i = 0; i < listeners.length; i++) {3847 try {3848 listeners[i].call(self, args);3849 } catch (ex) {3850 Wind.logger.warn(‘An error occurred in "‘ + name + ‘ listener": ‘ + ex);3851 }3852 }3853 3854 this._firing = null;3855 }3856 };3857 3858 var taskEventManager = new EventManager();3859 3860 var Task = Async.Task = function (delegate) {3861 this._delegate = delegate;3862 this._eventManager = new EventManager();3863 this.status = "ready";3864 }3865 Task.prototype = {3866 start: function () {3867 if (this.status != "ready") {3868 throw new Error(‘Task can only be started in "ready" status.‘);3869 }3870 3871 this.status = "running";3872 3873 try {3874 this._delegate(this);3875 } catch (ex) {3876 if (this.status == "running") {3877 this.complete("failure", ex);3878 } else {3879 Wind.logger.warn("An unexpected error occurred after the task is completed: " + ex);3880 }3881 }3882 3883 return this;3884 },3885 3886 complete: function (type, value) {3887 if (type !== "success" && type !== "failure") {3888 throw new Error("Unsupported type: " + type);3889 }3890 3891 if (this.status != "running") {3892 throw new Error(‘The "complete" method can only be called in "running" status.‘);3893 }3894 3895 var eventManager = this._eventManager;3896 this._eventManager = null;3897 3898 if (type === "success") {3899 this.status = "succeeded";3900 3901 if (supportDefineProperty) {3902 this._result = value;3903 } else {3904 this.result = value;3905 }3906 3907 eventManager.fire("success", this);3908 } else {3909 if (isCanceledError(value)) {3910 this.status = "canceled";3911 } else {3912 this.status = "faulted";3913 }3914 3915 if (supportDefineProperty) {3916 this._error = value;3917 } else {3918 this.error = value;3919 }3920 3921 eventManager.fire("failure", this);3922 }3923 3924 eventManager.fire("complete", this);3925 3926 if (type !== "failure") return;3927 if (!supportDefineProperty) return;3928 if (this._errorObserved) return;3929 3930 var self = this;3931 this._unobservedTimeoutToken = setTimeout(function () {3932 self._handleUnobservedError(value);3933 }, Task.unobservedTimeout);3934 },3935 3936 observeError: function () {3937 if (this.status === "ready" || this.status === "running") {3938 throw new Error("The method could only be called when it‘s completed.");3939 }3940 3941 if (!supportDefineProperty) return this.error;3942 3943 var token = this._unobservedTimeoutToken;3944 if (token) {3945 clearTimeout(token);3946 this._unobservedTimeoutToken = null;3947 }3948 3949 this._errorObserved = true;3950 return this._error;3951 },3952 3953 _handleUnobservedError: function (error) {3954 this._unobservedTimeoutToken = null;3955 3956 var args = {3957 task: this,3958 error: error,3959 observed: false3960 };3961 3962 taskEventManager.fire("unobservedError", Task, args);3963 3964 if (!args.observed) {3965 throw error;3966 }3967 },3968 3969 then: function (nextGenerator) {3970 var firstTask = this;3971 3972 return Task.create(function (t) {3973 3974 var nextOnComplete = function () {3975 if (this.error) {3976 t.complete("failure", this.error);3977 } else {3978 t.complete("success", this.result);3979 }3980 };3981 3982 var processNext = function (nextTask) {3983 if (nextTask.status == "ready") {3984 nextTask.start();3985 }3986 3987 if (nextTask.status == "running") {3988 nextTask.on("complete", nextOnComplete);3989 } else {3990 nextOnComplete.call(nextTask);3991 }3992 };3993 3994 var firstOnComplete = function () {3995 if (this.error) {3996 return t.complete("failure", this.error);3997 }3998 3999 var nextTask;4000 try {4001 nextTask = nextGenerator(this.result);4002 } catch (ex) {4003 return t.complete("failure", ex);4004 }4005 4006 processNext(nextTask);4007 };4008 4009 if (firstTask.status == "ready") {4010 firstTask.start();4011 }4012 4013 if (firstTask.status == "running") {4014 firstTask.on("complete", firstOnComplete);4015 } else {4016 firstOnComplete.call(firstTask);4017 }4018 });4019 }4020 };4021 4022 Task.prototype.on = Task.prototype.addEventListener = function () {4023 var eventManager = this._eventManager;4024 if (!eventManager) {4025 throw new Error("Cannot add event listeners when the task is complete.");4026 }4027 4028 eventManager.add.apply(eventManager, arguments);4029 return this;4030 };4031 4032 Task.prototype.off = Task.prototype.removeEventListener = function () {4033 var eventManager = this._eventManager;4034 if (!eventManager) {4035 throw new Error("All the event listeners have been removed when the task was complete.");4036 }4037 4038 eventManager.remove.apply(eventManager, arguments);4039 return this;4040 };4041 4042 if (supportDefineProperty) {4043 Object.defineProperty(Task.prototype, "error", {4044 get: function () {4045 return this.observeError();4046 }4047 });4048 4049 Object.defineProperty(Task.prototype, "result", {4050 get: function () {4051 var error = this.observeError();4052 if (error) throw error;4053 4054 return this._result;4055 }4056 });4057 }4058 4059 var observeErrorListener = function () { this.observeError(); };4060 4061 Task.on = Task.addEventListener = function () {4062 taskEventManager.add.apply(taskEventManager, arguments);4063 }4064 4065 Task.off = Task.removeEventListener = function (name, listener) {4066 taskEventManager.remove.apply(taskEventManager, arguments);4067 }4068 4069 Task.unobservedTimeout = 10 * 1000;4070 4071 var isTask = Task.isTask = function (t) {4072 return t && (typeof t.start === "function") && (typeof t.addEventListener) === "function" && (typeof t.removeEventListener) === "function" && (typeof t.complete) === "function";4073 };4074 4075 var create = Task.create = function (delegate) {4076 return new Task(delegate);4077 }4078 4079 /***********************************************************************4080 Task helpers4081 ***********************************************************************/4082 4083 var whenAll = Task.whenAll = function () {4084 var inputTasks;4085 4086 if (arguments.length == 1) {4087 var arg = arguments[0];4088 if (isTask(arg)) { // a single task4089 inputTasks = [arg];4090 } else {4091 inputTasks = arg;4092 }4093 } else {4094 inputTasks = new Array(arguments.length);4095 for (var i = 0; i < arguments.length; i++) {4096 inputTasks[i] = arguments[i];4097 }4098 }4099 4100 return create(function (taskWhenAll) {4101 4102 var errors;4103 4104 var done = function () {4105 if (errors) {4106 taskWhenAll.complete("failure", new AggregateError(errors));4107 } else {4108 var results = _.map(inputTasks, function (t) {4109 return t.result;4110 });4111 4112 taskWhenAll.complete("success", results);4113 }4114 }4115 4116 var runningNumber = 0;4117 4118 _.each(inputTasks, function (key, task) {4119 if (!task) return;4120 4121 if (!isTask(task)) {4122 inputTasks[key] = task = whenAll(task);4123 }4124 4125 if (task.status === "ready") {4126 task.start();4127 }4128 4129 if (task.status === "running") {4130 runningNumber++;4131 task.addEventListener("complete", function () {4132 if (this.status !== "succeeded") {4133 if (!errors) errors = [];4134 errors.push(this.error);4135 }4136 4137 if (--runningNumber == 0) {4138 done();4139 }4140 });4141 } else if (task.status === "faulted" || task.status === "canceled") {4142 if (!errors) errors = [];4143 errors.push(task.error);4144 }4145 });4146 4147 if (runningNumber == 0) {4148 done();4149 }4150 });4151 };4152 4153 var whenAny = Task.whenAny = function () {4154 4155 var inputTasks = { };4156 var isArray = true;4157 4158 if (arguments.length == 1) {4159 var arg = arguments[0];4160 if (isTask(arg)) {4161 inputTasks[0] = arg;4162 } else {4163 isArray = _.isArray(arg);4164 _.each(arg, function (key, task) {4165 if (isTask(task)) {4166 inputTasks[key] = task;4167 }4168 });4169 }4170 } else {4171 for (var i = 0; i < arguments.length; i++) {4172 var task = arguments[i];4173 if (isTask(task)) {4174 inputTasks[i] = task;4175 }4176 }4177 }4178 4179 var processKey = isArray4180 ? function (key) { return parseInt(key, 10); }4181 : function (key) { return key; }4182 4183 return create(function (taskWhenAny) {4184 if (_.isEmpty(inputTasks)) {4185 return taskWhenAny.complete("failure", "There‘s no valid input tasks.");4186 }4187 4188 var result;4189 4190 _.each(inputTasks, function (key, task) {4191 if (task.status === "ready") {4192 task.start();4193 }4194 4195 if (task.status !== "running") {4196 task.observeError();4197 4198 if (!result) {4199 result = { key: processKey(key), task: task };4200 }4201 }4202 });4203 4204 if (result) {4205 _.each(inputTasks, function (key, task) {4206 if (task.status === "running") {4207 task.on("failure", observeErrorListener);4208 }4209 });4210 4211 return taskWhenAny.complete("success", result);4212 }4213 4214 var onComplete = function () {4215 this.observeError();4216 4217 var taskCompleted = this;4218 var keyCompleted;4219 4220 _.each(inputTasks, function (key, task) {4221 if (taskCompleted === task) {4222 keyCompleted = key;4223 return;4224 }4225 4226 task.off("complete", onComplete);4227 task.on("failure", observeErrorListener);4228 });4229 4230 taskWhenAny.complete("success", { key: processKey(keyCompleted), task: this });4231 }4232 4233 _.each(inputTasks, function (task) {4234 task.addEventListener("complete", onComplete);4235 });4236 });4237 }4238 4239 /***********************************************************************4240 Async helpers4241 ***********************************************************************/4242 4243 var sleep = Async.sleep = function (delay, /* CancellationToken */ ct) {4244 return Task.create(function (t) {4245 if (ct && ct.isCancellationRequested) {4246 t.complete("failure", new CanceledError());4247 }4248 4249 var seed;4250 var cancelHandler;4251 4252 if (ct) {4253 cancelHandler = function () {4254 clearTimeout(seed);4255 t.complete("failure", new CanceledError());4256 }4257 }4258 4259 var seed = setTimeout(function () {4260 if (ct) {4261 ct.unregister(cancelHandler);4262 }4263 4264 t.complete("success");4265 }, delay);4266 4267 if (ct) {4268 ct.register(cancelHandler);4269 }4270 });4271 }4272 4273 var onEvent = Async.onEvent = function (target, eventName, /* CancellationToken*/ ct) {4274 return Task.create(function (t) {4275 if (ct && ct.isCancellationRequested) {4276 t.complete("failure", new CanceledError());4277 }4278 4279 var cleanUp = function () {4280 if (target.removeEventListener) {4281 target.removeEventListener(eventName, eventHandler);4282 } else if (target.removeListener) {4283 target.removeListener(eventName, eventHandler);4284 } else {4285 target.detachEvent(eventName, eventHandler);4286 }4287 }4288 4289 var eventHandler;4290 var cancelHandler;4291 4292 if (ct) {4293 cancelHandler = function () {4294 cleanUp();4295 t.complete("failure", new CanceledError());4296 }4297 }4298 4299 var eventHandler = function (ev) {4300 if (ct) {4301 ct.unregister(cancelHandler);4302 }4303 4304 cleanUp();4305 t.complete("success", ev);4306 }4307 4308 if (target.addEventListener) {4309 target.addEventListener(eventName, eventHandler);4310 } else if (target.addListener) {4311 target.addListener(eventName, eventHandler);4312 } else {4313 target.attachEvent(eventName, eventHandler);4314 }4315 4316 if (ct) {4317 ct.register(cancelHandler);4318 }4319 });4320 }4321 4322 /***********************************************************************4323 AsyncBuilder4324 ***********************************************************************/4325 4326 var AsyncBuilder = Async.AsyncBuilder = function () { }4327 AsyncBuilder.prototype = {4328 Start: function (_this, task) {4329 return Task.create(function (t) {4330 task.next(_this, function (type, value, target) {4331 if (type == "normal" || type == "return") {4332 t.complete("success", value);4333 } else if (type == "throw") {4334 t.complete("failure", value);4335 } else {4336 throw new Error("Unsupported type: " + type);4337 }4338 });4339 });4340 },4341 4342 Bind: function (task, generator) {4343 return {4344 next: function (_this, callback) {4345 4346 var onComplete = function () {4347 if (this.error) {4348 callback("throw", this.error);4349 } else {4350 var nextTask;4351 try {4352 nextTask = generator.call(_this, this.result);4353 } catch (ex) {4354 callback("throw", ex);4355 return;4356 }4357 4358 nextTask.next(_this, callback);4359 }4360 }4361 4362 if (task.status == "ready") {4363 task.addEventListener("complete", onComplete);4364 task.start();4365 } else if (task.status == "running") {4366 task.addEventListener("complete", onComplete);4367 } else {4368 onComplete.call(task);4369 }4370 }4371 };4372 }4373 }4374 4375 var Binding = Async.Binding = { };4376 4377 var collectArgs = function (args, requiredArgs) {4378 var result = [];4379 for (var i = 0; i < args.length; i++) {4380 result.push(args[i]);4381 }4382 4383 while (result.length < requiredArgs) {4384 result.push(undefined);4385 }4386 4387 return result;4388 }4389 4390 var collectCallbackArgNames = function (args) {4391 if (args.length <= 1) return null;4392 4393 var result = [];4394 for (var i = 1; i < args.length; i++) {4395 result.push(args[i]);4396 }4397 4398 return result;4399 }4400 4401 var fromStandard = Binding.fromStandard = function (fn) {4402 var callbackArgNames = collectCallbackArgNames(arguments);4403 4404 return function () {4405 var _this = this;4406 var args = collectArgs(arguments, fn.length - 1);4407 4408 return Task.create(function (t) {4409 args.push(function (error, result) {4410 if (error) {4411 t.complete("failure", error);4412 } else if (!callbackArgNames) {4413 t.complete("success", result);4414 } else {4415 var data =http://www.mamicode.com/ {};4416 for (var i = 0; i < callbackArgNames.length; i++) {4417 data[callbackArgNames[i]] = arguments[i + 1];4418 }4419 4420 return t.complete("success", data);4421 }4422 });4423 4424 fn.apply(_this, args);4425 });4426 };4427 };4428 4429 var fromCallback = Binding.fromCallback = function (fn) {4430 var callbackArgNames = collectCallbackArgNames(arguments);4431 4432 return function () {4433 var _this = this;4434 var args = collectArgs(arguments, fn.length - 1);4435 4436 return Task.create(function (t) {4437 args.push(function (result) {4438 if (callbackArgNames) {4439 var data =http://www.mamicode.com/ {};4440 for (var i = 0; i < callbackArgNames.length; i++) {4441 data[callbackArgNames[i]] = arguments[i];4442 }4443 4444 t.complete("success", data);4445 } else {4446 t.complete("success", result);4447 }4448 });4449 4450 fn.apply(_this, args);4451 });4452 };4453 };4454 4455 // CommonJS4456 var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);4457 // CommonJS AMD4458 var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);4459 4460 var defineModule = function () {4461 Wind.define({4462 name: "async",4463 version: "0.7.1",4464 require: isCommonJS && require,4465 autoloads: [ "builderbase" ],4466 dependencies: { builderbase: "~0.7.0" },4467 init: function () {4468 4469 _ = Wind._;4470 4471 _.each(Wind.BuilderBase.prototype, function (m, fn) {4472 AsyncBuilder.prototype[m] = fn;4473 });4474 4475 Wind.Async = Async;4476 4477 Wind.binders["async"] = "$await";4478 Wind.builders["async"] = new AsyncBuilder();4479 }4480 });4481 }4482 4483 if (isCommonJS) {4484 try {4485 Wind = require("./wind-core");4486 } catch (ex) {4487 Wind = require("wind-core");4488 }4489 4490 defineModule();4491 } else if (isAmd) {4492 require(["wind-core"], function (wind) {4493 Wind = wind;4494 defineModule();4495 });4496 } else {4497 var Fn = Function, global = Fn(‘return this‘)();4498 4499 if (!global.Wind) {4500 throw new Error(‘Missing the root object, please load "wind" component first.‘);4501 }4502 4503 Wind = global.Wind;4504 defineModule();4505 }4506 })();4507 4508 4509 /***********************************************************************4510 wind-promise-0.7.0.js4511 ***********************************************************************/4512 4513 (function () {4514 "use strict";4515 4516 var Wind;4517 4518 var defaultCreate = function () {4519 throw new Error(‘Please set "Wind.Promise.create" to provide a factory method for creating a promise object.‘);4520 }4521 4522 var PromiseBuilder = function () { }4523 PromiseBuilder.prototype = {4524 Start: function (_this, task) {4525 return Wind.Promise.create(function (complete, error) {4526 task.next(_this, function (type, value, target) {4527 if (type == "normal" || type == "return") {4528 complete(value);4529 } else if (type == "throw") {4530 error(value);4531 } else {4532 throw new Error("Unsupported type: " + type);4533 }4534 });4535 });4536 },4537 4538 Bind: function (promise, generator) {4539 return {4540 next: function (_this, callback) {4541 promise.then(function (result) {4542 var nextTask;4543 try {4544 nextTask = generator.call(_this, result);4545 } catch (ex) {4546 return callback("throw", ex);4547 }4548 4549 nextTask.next(_this, callback);4550 }, function (error) {4551 callback("throw", error);4552 });4553 }4554 };4555 }4556 }4557 4558 // CommonJS4559 var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);4560 // CommonJS AMD4561 var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);4562 4563 var defineModule = function () {4564 Wind.define({4565 name: "promise",4566 version: "0.7.0",4567 require: isCommonJS && require,4568 autoloads: [ "builderbase" ],4569 dependencies: { builderbase: "~0.7.0" },4570 init: function () {4571 Wind._.each(Wind.BuilderBase.prototype, function (m, fn) {4572 PromiseBuilder.prototype[m] = fn;4573 });4574 4575 if (!Wind.Promise) {4576 Wind.Promise = {};4577 }4578 4579 Wind.Promise.create = defaultCreate;4580 4581 Wind.binders["promise"] = "$await";4582 Wind.builders["promise"] = new PromiseBuilder();4583 }4584 });4585 }4586 4587 if (isCommonJS) {4588 try {4589 Wind = require("./wind-core");4590 } catch (ex) {4591 Wind = require("wind-core");4592 }4593 4594 defineModule();4595 } else if (isAmd) {4596 require(["wind-core"], function (wind) {4597 Wind = wind;4598 defineModule();4599 });4600 } else {4601 var Fn = Function, global = Fn(‘return this‘)();4602 4603 if (!global.Wind) {4604 throw new Error(‘Missing the root object, please load "wind" component first.‘);4605 }4606 4607 Wind = global.Wind;4608 defineModule();4609 }4610 })();
用Windjs画圆
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。