(function (root, mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports); if (typeof define == "function" && define.amd) return define(["exports"] , mod); mod(root.acorn || (root.acorn = { } )); } )(this, function (exports){ "use strict"; exports.version = "0.4.1"; var options, input, inputLen, sourceFile; exports.parse = function (inpt, opts){ input = String(inpt); inputLen = _AN_Read_length("length", input); setOptions(opts); initTokenState(); return parseTopLevel(options.program); } ; var defaultOptions = exports.defaultOptions = { ecmaVersion: 5, strictSemicolons: false , allowTrailingCommas: true , forbidReserved: false , locations: false , onComment: null , ranges: false , program: null , sourceFile: null , directSourceFile: null } ; function setOptions(opts){ options = opts || { } ; for (var opt in defaultOptions)if (!Object.prototype.hasOwnProperty.call(options, opt)) options[opt] = defaultOptions[opt]; sourceFile = options.sourceFile || null ; } var getLineInfo = exports.getLineInfo = function (input, offset){ for (var line = 1, cur = 0; ; ){ lineBreak.lastIndex = cur; var match = lineBreak.exec(input); if (match && match.index < offset) { ++line; cur = match.index + _AN_Read_length("length", match[0]); } else break ; } return { line: line, column: offset - cur} ; } ; exports.tokenize = function (inpt, opts){ input = String(inpt); inputLen = _AN_Read_length("length", input); setOptions(opts); initTokenState(); var t = { } ; function getToken(forceRegexp){ readToken(forceRegexp); t.start = tokStart; t.end = tokEnd; t.startLoc = tokStartLoc; t.endLoc = tokEndLoc; t.type = tokType; t.value = tokVal; return t; } getToken.jumpTo = function (pos, reAllowed){ tokPos = pos; if (options.locations) { tokCurLine = 1; tokLineStart = lineBreak.lastIndex = 0; var match; while ((match = lineBreak.exec(input)) && match.index < pos){ ++tokCurLine; tokLineStart = match.index + _AN_Read_length("length", match[0]); } } tokRegexpAllowed = reAllowed; skipSpace(); } ; return getToken; } ; var tokPos; var tokStart, tokEnd; var tokStartLoc, tokEndLoc; var tokType, tokVal; var tokRegexpAllowed; var tokCurLine, tokLineStart; var lastStart, lastEnd, lastEndLoc; var inFunction, labels, strict; function raise(pos, message){ var loc = getLineInfo(input, pos); message += " (" + loc.line + ":" + loc.column + ")"; var err = new SyntaxError(message); err.pos = pos; err.loc = loc; err.raisedAt = tokPos; throw err } var empty = [] ; var _num = { type: "num"} , _regexp = { type: "regexp"} , _string = { type: "string"} ; var _name = { type: "name"} , _eof = { type: "eof"} ; var _break = { keyword: "break"} , _case = { keyword: "case", beforeExpr: true } , _catch = { keyword: "catch"} ; var _continue = { keyword: "continue"} , _debugger = { keyword: "debugger"} , _default = { keyword: "default"} ; var _do = { keyword: "do", isLoop: true } , _else = { keyword: "else", beforeExpr: true } ; var _finally = { keyword: "finally"} , _for = { keyword: "for", isLoop: true } , _function = { keyword: "function"} ; var _if = { keyword: "if"} , _return = { keyword: "return", beforeExpr: true } , _switch = { keyword: "switch"} ; var _throw = { keyword: "throw", beforeExpr: true } , _try = { keyword: "try"} , _var = { keyword: "var"} ; var _while = { keyword: "while", isLoop: true } , _with = { keyword: "with"} , _new = { keyword: "new", beforeExpr: true } ; var _this = { keyword: "this"} ; var _null = { keyword: "null", atomValue: null } , _true = { keyword: "true", atomValue: true } ; var _false = { keyword: "false", atomValue: false } ; var _in = { keyword: "in", binop: 7, beforeExpr: true } ; var keywordTypes = { "break": _break, "case": _case, "catch": _catch, "continue": _continue, "debugger": _debugger, "default": _default, "do": _do, "else": _else, "finally": _finally, "for": _for, "function": _function, "if": _if, "return": _return, "switch": _switch, "throw": _throw, "try": _try, "var": _var, "while": _while, "with": _with, "null": _null, "true": _true, "false": _false, "new": _new, "in": _in, "instanceof": { keyword: "instanceof", binop: 7, beforeExpr: true } , "this": _this, "typeof": { keyword: "typeof", prefix: true , beforeExpr: true } , "void": { keyword: "void", prefix: true , beforeExpr: true } , "delete": { keyword: "delete", prefix: true , beforeExpr: true } } ; var _bracketL = { type: "[", beforeExpr: true } , _bracketR = { type: "]"} , _braceL = { type: "{", beforeExpr: true } ; var _braceR = { type: "}"} , _parenL = { type: "(", beforeExpr: true } , _parenR = { type: ")"} ; var _comma = { type: ",", beforeExpr: true } , _semi = { type: ";", beforeExpr: true } ; var _colon = { type: ":", beforeExpr: true } , _dot = { type: "."} , _question = { type: "?", beforeExpr: true } ; var _slash = { binop: 10, beforeExpr: true } , _eq = { isAssign: true , beforeExpr: true } ; var _assign = { isAssign: true , beforeExpr: true } ; var _incDec = { postfix: true , prefix: true , isUpdate: true } , _prefix = { prefix: true , beforeExpr: true } ; var _logicalOR = { binop: 1, beforeExpr: true } ; var _logicalAND = { binop: 2, beforeExpr: true } ; var _bitwiseOR = { binop: 3, beforeExpr: true } ; var _bitwiseXOR = { binop: 4, beforeExpr: true } ; var _bitwiseAND = { binop: 5, beforeExpr: true } ; var _equality = { binop: 6, beforeExpr: true } ; var _relational = { binop: 7, beforeExpr: true } ; var _bitShift = { binop: 8, beforeExpr: true } ; var _plusMin = { binop: 9, prefix: true , beforeExpr: true } ; var _multiplyModulo = { binop: 10, beforeExpr: true } ; exports.tokTypes = { bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR, parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon, dot: _dot, question: _question, slash: _slash, eq: _eq, name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string} ; for (var kw in keywordTypes)exports.tokTypes["_" + kw] = keywordTypes[kw]; function makePredicate(words){ words = words.split(" "); var f = "", cats = [] ; out: for (var i = 0; i < _AN_Read_length("length", words); ++i){ for (var j = 0; j < _AN_Read_length("length", cats); ++j)if (_AN_Read_length("length", cats[j][0]) == _AN_Read_length("length", words[i])) { cats[j].push(words[i]); continue out; } cats.push([words[i]] ); } function compareTo(arr){ if (_AN_Read_length("length", arr) == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; f += "switch(str){"; for (var i = 0; i < _AN_Read_length("length", arr); ++i)f += "case " + JSON.stringify(arr[i]) + ":"; f += "return true}return false;"; } if (_AN_Read_length("length", cats) > 3) { cats.sort(function (a, b){ return _AN_Read_length("length", b) - _AN_Read_length("length", a); } ); f += "switch(str.length){"; for (var i = 0; i < _AN_Read_length("length", cats); ++i){ var cat = cats[i]; f += "case " + _AN_Read_length("length", cat[0]) + ":"; compareTo(cat); } f += "}"; } else { compareTo(words); } return new Function("str", f); } var isReservedWord3 = makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"); var isReservedWord5 = makePredicate("class enum extends super const export import"); var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield"); var isStrictBadIdWord = makePredicate("eval arguments"); var isKeyword = makePredicate("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"); var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\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\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\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-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\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-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\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-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\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"; var nonASCIIidentifierChars = "\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); var newline = /[\n\r\u2028\u2029]/; var lineBreak = /\r\n|[\n\r\u2028\u2029]/g; var isIdentifierStart = exports.isIdentifierStart = function (code){ if (code < 65) return code === 36; if (code < 91) return true ; if (code < 97) return code === 95; if (code < 123) return true ; return code >= 170 && nonASCIIidentifierStart.test(String.fromCharCode(code)); } ; var isIdentifierChar = exports.isIdentifierChar = function (code){ if (code < 48) return code === 36; if (code < 58) return true ; if (code < 65) return false ; if (code < 91) return true ; if (code < 97) return code === 95; if (code < 123) return true ; return code >= 170 && nonASCIIidentifier.test(String.fromCharCode(code)); } ; function line_loc_t(){ this.line = tokCurLine; this.column = tokPos - tokLineStart; } function initTokenState(){ tokCurLine = 1; tokPos = tokLineStart = 0; tokRegexpAllowed = true ; skipSpace(); } function finishToken(type, val){ tokEnd = tokPos; if (options.locations) tokEndLoc = new line_loc_t(); tokType = type; skipSpace(); tokVal = val; tokRegexpAllowed = type.beforeExpr; } function skipBlockComment(){ var startLoc = options.onComment && options.locations && new line_loc_t(); var start = tokPos, end = input.indexOf("*/", tokPos += 2); if (end === -1) raise(tokPos - 2, "Unterminated comment"); tokPos = end + 2; if (options.locations) { lineBreak.lastIndex = start; var match; while ((match = lineBreak.exec(input)) && match.index < tokPos){ ++tokCurLine; tokLineStart = match.index + _AN_Read_length("length", match[0]); } } if (options.onComment) options.onComment(true , input.slice(start + 2, end), start, tokPos, startLoc, options.locations && new line_loc_t()); } function skipLineComment(){ var start = tokPos; var startLoc = options.onComment && options.locations && new line_loc_t(); var ch = input.charCodeAt(tokPos += 2); while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233){ ++tokPos; ch = input.charCodeAt(tokPos); } if (options.onComment) options.onComment(false , input.slice(start + 2, tokPos), start, tokPos, startLoc, options.locations && new line_loc_t()); } function skipSpace(){ while (tokPos < inputLen){ var ch = input.charCodeAt(tokPos); if (ch === 32) { ++tokPos; } else if (ch === 13) { ++tokPos; var next = input.charCodeAt(tokPos); if (next === 10) { ++tokPos; } if (options.locations) { ++tokCurLine; tokLineStart = tokPos; } } else if (ch === 10 || ch === 8232 || ch === 8233) { ++tokPos; if (options.locations) { ++tokCurLine; tokLineStart = tokPos; } } else if (ch > 8 && ch < 14) { ++tokPos; } else if (ch === 47) { var next = input.charCodeAt(tokPos + 1); if (next === 42) { skipBlockComment(); } else if (next === 47) { skipLineComment(); } else break ; } else if (ch === 160) { ++tokPos; } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { ++tokPos; } else { break ; } } } function readToken_dot(){ var next = input.charCodeAt(tokPos + 1); if (next >= 48 && next <= 57) return readNumber(true ); ++tokPos; return finishToken(_dot); } function readToken_slash(){ var next = input.charCodeAt(tokPos + 1); if (tokRegexpAllowed) { ++tokPos; return readRegexp(); } if (next === 61) return finishOp(_assign, 2); return finishOp(_slash, 1); } function readToken_mult_modulo(){ var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_multiplyModulo, 1); } function readToken_pipe_amp(code){ var next = input.charCodeAt(tokPos + 1); if (next === code) return finishOp(code === 124? _logicalOR: _logicalAND, 2); if (next === 61) return finishOp(_assign, 2); return finishOp(code === 124? _bitwiseOR: _bitwiseAND, 1); } function readToken_caret(){ var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_bitwiseXOR, 1); } function readToken_plus_min(code){ var next = input.charCodeAt(tokPos + 1); if (next === code) { if (next == 45 && input.charCodeAt(tokPos + 2) == 62 && newline.test(input.slice(lastEnd, tokPos))) { tokPos += 3; skipLineComment(); skipSpace(); return readToken(); } return finishOp(_incDec, 2); } if (next === 61) return finishOp(_assign, 2); return finishOp(_plusMin, 1); } function readToken_lt_gt(code){ var next = input.charCodeAt(tokPos + 1); var size = 1; if (next === code) { size = code === 62 && input.charCodeAt(tokPos + 2) === 62? 3: 2; if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1); return finishOp(_bitShift, size); } if (next == 33 && code == 60 && input.charCodeAt(tokPos + 2) == 45 && input.charCodeAt(tokPos + 3) == 45) { tokPos += 4; skipLineComment(); skipSpace(); return readToken(); } if (next === 61) size = input.charCodeAt(tokPos + 2) === 61? 3: 2; return finishOp(_relational, size); } function readToken_eq_excl(code){ var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_equality, input.charCodeAt(tokPos + 2) === 61? 3: 2); return finishOp(code === 61? _eq: _prefix, 1); } function getTokenFromCode(code){ switch (code){ case 46: return readToken_dot(); case 40: ++tokPos; return finishToken(_parenL); case 41: ++tokPos; return finishToken(_parenR); case 59: ++tokPos; return finishToken(_semi); case 44: ++tokPos; return finishToken(_comma); case 91: ++tokPos; return finishToken(_bracketL); case 93: ++tokPos; return finishToken(_bracketR); case 123: ++tokPos; return finishToken(_braceL); case 125: ++tokPos; return finishToken(_braceR); case 58: ++tokPos; return finishToken(_colon); case 63: ++tokPos; return finishToken(_question); case 48: var next = input.charCodeAt(tokPos + 1); if (next === 120 || next === 88) return readHexNumber(); case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: return readNumber(false ); case 34: case 39: return readString(code); case 47: return readToken_slash(code); case 37: case 42: return readToken_mult_modulo(); case 124: case 38: return readToken_pipe_amp(code); case 94: return readToken_caret(); case 43: case 45: return readToken_plus_min(code); case 60: case 62: return readToken_lt_gt(code); case 61: case 33: return readToken_eq_excl(code); case 126: return finishOp(_prefix, 1); } return false ; } function readToken(forceRegexp){ if (!forceRegexp) tokStart = tokPos; else tokPos = tokStart + 1; if (options.locations) tokStartLoc = new line_loc_t(); if (forceRegexp) return readRegexp(); if (tokPos >= inputLen) return finishToken(_eof); var code = input.charCodeAt(tokPos); if (isIdentifierStart(code) || code === 92) return readWord(); var tok = getTokenFromCode(code); if (tok === false ) { var ch = String.fromCharCode(code); if (ch === "\\" || nonASCIIidentifierStart.test(ch)) return readWord(); raise(tokPos, "Unexpected character '" + ch + "'"); } return tok; } function finishOp(type, size){ var str = input.slice(tokPos, tokPos + size); tokPos += size; finishToken(type, str); } function readRegexp(){ var content = "", escaped, inClass, start = tokPos; for (; ; ){ if (tokPos >= inputLen) raise(start, "Unterminated regular expression"); var ch = input.charAt(tokPos); if (newline.test(ch)) raise(start, "Unterminated regular expression"); if (!escaped) { if (ch === "[") inClass = true ; else if (ch === "]" && inClass) inClass = false ; else if (ch === "/" && !inClass) break ; escaped = ch === "\\"; } else escaped = false ; ++tokPos; } var content = input.slice(start, tokPos); ++tokPos; var mods = readWord1(); if (mods && !/^[gmsiy]*$/.test(mods)) raise(start, "Invalid regexp flag"); try { var value = new RegExp(content, mods); } catch (e) { if (e instanceof SyntaxError) raise(start, e.message); raise(e); } return finishToken(_regexp, value); } function readInt(radix, len){ var start = tokPos, total = 0; for (var i = 0, e = len == null ? Infinity: len; i < e; ++i){ var code = input.charCodeAt(tokPos), val; if (code >= 97) val = code - 97 + 10; else if (code >= 65) val = code - 65 + 10; else if (code >= 48 && code <= 57) val = code - 48; else val = Infinity; if (val >= radix) break ; ++tokPos; total = total * radix + val; } if (tokPos === start || len != null && tokPos - start !== len) return null ; return total; } function readHexNumber(){ tokPos += 2; var val = readInt(16); if (val == null ) raise(tokStart + 2, "Expected hexadecimal number"); if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); return finishToken(_num, val); } function readNumber(startsWithDot){ var start = tokPos, isFloat = false , octal = input.charCodeAt(tokPos) === 48; if (!startsWithDot && readInt(10) === null ) raise(start, "Invalid number"); if (input.charCodeAt(tokPos) === 46) { ++tokPos; readInt(10); isFloat = true ; } var next = input.charCodeAt(tokPos); if (next === 69 || next === 101) { next = input.charCodeAt(++tokPos); if (next === 43 || next === 45) ++tokPos; if (readInt(10) === null ) raise(start, "Invalid number"); isFloat = true ; } if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); var str = input.slice(start, tokPos), val; if (isFloat) val = parseFloat(str); else if (!octal || _AN_Read_length("length", str) === 1) val = parseInt(str, 10); else if (/[89]/.test(str) || strict) raise(start, "Invalid number"); else val = parseInt(str, 8); return finishToken(_num, val); } function readString(quote){ tokPos++ ; var out = ""; for (; ; ){ if (tokPos >= inputLen) raise(tokStart, "Unterminated string constant"); var ch = input.charCodeAt(tokPos); if (ch === quote) { ++tokPos; return finishToken(_string, out); } if (ch === 92) { ch = input.charCodeAt(++tokPos); var octal = /^[0-7]+/.exec(input.slice(tokPos, tokPos + 3)); if (octal) octal = octal[0]; while (octal && parseInt(octal, 8) > 255)octal = octal.slice(0, -1); if (octal === "0") octal = null ; ++tokPos; if (octal) { if (strict) raise(tokPos - 2, "Octal literal in strict mode"); out += String.fromCharCode(parseInt(octal, 8)); tokPos += _AN_Read_length("length", octal) - 1; } else { switch (ch){ case 110: out += "\n"; break ; case 114: out += "\r"; break ; case 120: out += String.fromCharCode(readHexChar(2)); break ; case 117: out += String.fromCharCode(readHexChar(4)); break ; case 85: out += String.fromCharCode(readHexChar(8)); break ; case 116: out += "\t"; break ; case 98: out += "\b"; break ; case 118: out += "\u000b"; break ; case 102: out += "\f"; break ; case 48: out += "\0"; break ; case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; case 10: if (options.locations) { tokLineStart = tokPos; ++tokCurLine; } break ; default : { out += String.fromCharCode(ch); break ; } } } } else { if (ch === 13 || ch === 10 || ch === 8232 || ch === 8233) raise(tokStart, "Unterminated string constant"); out += String.fromCharCode(ch); ++tokPos; } } } function readHexChar(len){ var n = readInt(16, len); if (n === null ) raise(tokStart, "Bad character escape sequence"); return n; } var containsEsc; function readWord1(){ containsEsc = false ; var word, first = true , start = tokPos; for (; ; ){ var ch = input.charCodeAt(tokPos); if (isIdentifierChar(ch)) { if (containsEsc) word += input.charAt(tokPos); ++tokPos; } else if (ch === 92) { if (!containsEsc) word = input.slice(start, tokPos); containsEsc = true ; if (input.charCodeAt(++tokPos) != 117) raise(tokPos, "Expecting Unicode escape sequence \\uXXXX"); ++tokPos; var esc = readHexChar(4); var escStr = String.fromCharCode(esc); if (!escStr) raise(tokPos - 1, "Invalid Unicode escape"); if (!(first? isIdentifierStart(esc): isIdentifierChar(esc))) raise(tokPos - 4, "Invalid Unicode escape"); word += escStr; } else { break ; } first = false ; } return containsEsc? word: input.slice(start, tokPos); } function readWord(){ var word = readWord1(); var type = _name; if (!containsEsc) { if (isKeyword(word)) type = keywordTypes[word]; else if (options.forbidReserved && (options.ecmaVersion === 3? isReservedWord3: isReservedWord5)(word) || strict && isStrictReservedWord(word)) raise(tokStart, "The keyword '" + word + "' is reserved"); } return finishToken(type, word); } function next(){ lastStart = tokStart; lastEnd = tokEnd; lastEndLoc = tokEndLoc; readToken(); } function setStrict(strct){ strict = strct; tokPos = tokStart; if (options.locations) { while (tokPos < tokLineStart){ tokLineStart = input.lastIndexOf("\n", tokLineStart - 2) + 1; --tokCurLine; } } skipSpace(); readToken(); } function node_t(){ this.type = null ; this.start = tokStart; this.end = null ; } function node_loc_t(){ this.start = tokStartLoc; this.end = null ; if (sourceFile !== null ) this.source = sourceFile; } function startNode(){ var node = new node_t(); if (options.locations) node.loc = new node_loc_t(); if (options.directSourceFile) node.sourceFile = options.directSourceFile; if (options.ranges) node.range = [tokStart, 0] ; return node; } function startNodeFrom(other){ var node = new node_t(); node.start = other.start; if (options.locations) { node.loc = new node_loc_t(); node.loc.start = other.loc.start; } if (options.ranges) node.range = [other.range[0], 0] ; return node; } function finishNode(node, type){ node.type = type; node.end = lastEnd; if (options.locations) node.loc.end = lastEndLoc; if (options.ranges) node.range[1] = lastEnd; return node; } function isUseStrict(stmt){ return options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && stmt.expression.value === "use strict"; } function eat(type){ if (tokType === type) { next(); return true ; } } function canInsertSemicolon(){ return !options.strictSemicolons && (tokType === _eof || tokType === _braceR || newline.test(input.slice(lastEnd, tokStart))); } function semicolon(){ if (!eat(_semi) && !canInsertSemicolon()) unexpected(); } function expect(type){ if (tokType === type) next(); else unexpected(); } function unexpected(){ raise(tokStart, "Unexpected token"); } function checkLVal(expr){ if (expr.type !== "Identifier" && expr.type !== "MemberExpression") raise(expr.start, "Assigning to rvalue"); if (strict && expr.type === "Identifier" && isStrictBadIdWord(expr.name)) raise(expr.start, "Assigning to " + expr.name + " in strict mode"); } function parseTopLevel(program){ lastStart = lastEnd = tokPos; if (options.locations) lastEndLoc = new line_loc_t(); inFunction = strict = null ; labels = [] ; readToken(); var node = program || startNode(), first = true ; if (!program) node.body = [] ; while (tokType !== _eof){ var stmt = parseStatement(); node.body.push(stmt); if (first && isUseStrict(stmt)) setStrict(true ); first = false ; } return finishNode(node, "Program"); } var loopLabel = { kind: "loop"} , switchLabel = { kind: "switch"} ; function parseStatement(){ if (tokType === _slash || tokType === _assign && tokVal == "/=") readToken(true ); var starttype = tokType, node = startNode(); switch (starttype){ case _break: case _continue: next(); var isBreak = starttype === _break; if (eat(_semi) || canInsertSemicolon()) node.label = null ; else if (tokType !== _name) unexpected(); else { node.label = parseIdent(); semicolon(); } for (var i = 0; i < _AN_Read_length("length", labels); ++i){ var lab = labels[i]; if (node.label == null || lab.name === node.label.name) { if (lab.kind != null && (isBreak || lab.kind === "loop")) break ; if (node.label && isBreak) break ; } } if (i === _AN_Read_length("length", labels)) raise(node.start, "Unsyntactic " + starttype.keyword); return finishNode(node, isBreak? "BreakStatement": "ContinueStatement"); case _debugger: next(); semicolon(); return finishNode(node, "DebuggerStatement"); case _do: next(); labels.push(loopLabel); node.body = parseStatement(); labels.pop(); expect(_while); node.test = parseParenExpression(); semicolon(); return finishNode(node, "DoWhileStatement"); case _for: next(); labels.push(loopLabel); expect(_parenL); if (tokType === _semi) return parseFor(node, null ); if (tokType === _var) { var init = startNode(); next(); parseVar(init, true ); finishNode(init, "VariableDeclaration"); if (_AN_Read_length("length", init.declarations) === 1 && eat(_in)) return parseForIn(node, init); return parseFor(node, init); } var init = parseExpression(false , true ); if (eat(_in)) { checkLVal(init); return parseForIn(node, init); } return parseFor(node, init); case _function: next(); return parseFunction(node, true ); case _if: next(); node.test = parseParenExpression(); node.consequent = parseStatement(); node.alternate = eat(_else)? parseStatement(): null ; return finishNode(node, "IfStatement"); case _return: if (!inFunction) raise(tokStart, "'return' outside of function"); next(); if (eat(_semi) || canInsertSemicolon()) node.argument = null ; else { node.argument = parseExpression(); semicolon(); } return finishNode(node, "ReturnStatement"); case _switch: next(); node.discriminant = parseParenExpression(); node.cases = [] ; expect(_braceL); labels.push(switchLabel); for (var cur, sawDefault; tokType != _braceR; ){ if (tokType === _case || tokType === _default) { var isCase = tokType === _case; if (cur) finishNode(cur, "SwitchCase"); node.cases.push(cur = startNode()); cur.consequent = [] ; next(); if (isCase) cur.test = parseExpression(); else { if (sawDefault) raise(lastStart, "Multiple default clauses"); sawDefault = true ; cur.test = null ; } expect(_colon); } else { if (!cur) unexpected(); cur.consequent.push(parseStatement()); } } if (cur) finishNode(cur, "SwitchCase"); next(); labels.pop(); return finishNode(node, "SwitchStatement"); case _throw: next(); if (newline.test(input.slice(lastEnd, tokStart))) raise(lastEnd, "Illegal newline after throw"); node.argument = parseExpression(); semicolon(); return finishNode(node, "ThrowStatement"); case _try: next(); node.block = parseBlock(); node.handler = null ; if (tokType === _catch) { var clause = startNode(); next(); expect(_parenL); clause.param = parseIdent(); if (strict && isStrictBadIdWord(clause.param.name)) raise(clause.param.start, "Binding " + clause.param.name + " in strict mode"); expect(_parenR); clause.guard = null ; clause.body = parseBlock(); node.handler = finishNode(clause, "CatchClause"); } node.guardedHandlers = empty; node.finalizer = eat(_finally)? parseBlock(): null ; if (!node.handler && !node.finalizer) raise(node.start, "Missing catch or finally clause"); return finishNode(node, "TryStatement"); case _var: next(); parseVar(node); semicolon(); return finishNode(node, "VariableDeclaration"); case _while: next(); node.test = parseParenExpression(); labels.push(loopLabel); node.body = parseStatement(); labels.pop(); return finishNode(node, "WhileStatement"); case _with: if (strict) raise(tokStart, "'with' in strict mode"); next(); node.object = parseParenExpression(); node.body = parseStatement(); return finishNode(node, "WithStatement"); case _braceL: return parseBlock(); case _semi: next(); return finishNode(node, "EmptyStatement"); default : { var maybeName = tokVal, expr = parseExpression(); if (starttype === _name && expr.type === "Identifier" && eat(_colon)) { for (var i = 0; i < _AN_Read_length("length", labels); ++i)if (labels[i].name === maybeName) raise(expr.start, "Label '" + maybeName + "' is already declared"); var kind = tokType.isLoop? "loop": tokType === _switch? "switch": null ; labels.push({ name: maybeName, kind: kind} ); node.body = parseStatement(); labels.pop(); node.label = expr; return finishNode(node, "LabeledStatement"); } else { node.expression = expr; semicolon(); return finishNode(node, "ExpressionStatement"); } } } } function parseParenExpression(){ expect(_parenL); var val = parseExpression(); expect(_parenR); return val; } function parseBlock(allowStrict){ var node = startNode(), first = true , strict = false , oldStrict; node.body = [] ; expect(_braceL); while (!eat(_braceR)){ var stmt = parseStatement(); node.body.push(stmt); if (first && allowStrict && isUseStrict(stmt)) { oldStrict = strict; setStrict(strict = true ); } first = false ; } if (strict && !oldStrict) setStrict(false ); return finishNode(node, "BlockStatement"); } function parseFor(node, init){ node.init = init; expect(_semi); node.test = tokType === _semi? null : parseExpression(); expect(_semi); node.update = tokType === _parenR? null : parseExpression(); expect(_parenR); node.body = parseStatement(); labels.pop(); return finishNode(node, "ForStatement"); } function parseForIn(node, init){ node.left = init; node.right = parseExpression(); expect(_parenR); node.body = parseStatement(); labels.pop(); return finishNode(node, "ForInStatement"); } function parseVar(node, noIn){ node.declarations = [] ; node.kind = "var"; for (; ; ){ var decl = startNode(); decl.id = parseIdent(); if (strict && isStrictBadIdWord(decl.id.name)) raise(decl.id.start, "Binding " + decl.id.name + " in strict mode"); decl.init = eat(_eq)? parseExpression(true , noIn): null ; node.declarations.push(finishNode(decl, "VariableDeclarator")); if (!eat(_comma)) break ; } return node; } function parseExpression(noComma, noIn){ var expr = parseMaybeAssign(noIn); if (!noComma && tokType === _comma) { var node = startNodeFrom(expr); node.expressions = [expr] ; while (eat(_comma))node.expressions.push(parseMaybeAssign(noIn)); return finishNode(node, "SequenceExpression"); } return expr; } function parseMaybeAssign(noIn){ var left = parseMaybeConditional(noIn); if (tokType.isAssign) { var node = startNodeFrom(left); node.operator = tokVal; node.left = left; next(); node.right = parseMaybeAssign(noIn); checkLVal(left); return finishNode(node, "AssignmentExpression"); } return left; } function parseMaybeConditional(noIn){ var expr = parseExprOps(noIn); if (eat(_question)) { var node = startNodeFrom(expr); node.test = expr; node.consequent = parseExpression(true ); expect(_colon); node.alternate = parseExpression(true , noIn); return finishNode(node, "ConditionalExpression"); } return expr; } function parseExprOps(noIn){ return parseExprOp(parseMaybeUnary(), -1, noIn); } function parseExprOp(left, minPrec, noIn){ var prec = tokType.binop; if (prec != null && (!noIn || tokType !== _in)) { if (prec > minPrec) { var node = startNodeFrom(left); node.left = left; node.operator = tokVal; var op = tokType; next(); node.right = parseExprOp(parseMaybeUnary(), prec, noIn); var exprNode = finishNode(node, (op === _logicalOR || op === _logicalAND)? "LogicalExpression": "BinaryExpression"); return parseExprOp(exprNode, minPrec, noIn); } } return left; } function parseMaybeUnary(){ if (tokType.prefix) { var node = startNode(), update = tokType.isUpdate; node.operator = tokVal; node.prefix = true ; tokRegexpAllowed = true ; next(); node.argument = parseMaybeUnary(); if (update) checkLVal(node.argument); else if (strict && node.operator === "delete" && node.argument.type === "Identifier") raise(node.start, "Deleting local variable in strict mode"); return finishNode(node, update? "UpdateExpression": "UnaryExpression"); } var expr = parseExprSubscripts(); while (tokType.postfix && !canInsertSemicolon()){ var node = startNodeFrom(expr); node.operator = tokVal; node.prefix = false ; node.argument = expr; checkLVal(expr); next(); expr = finishNode(node, "UpdateExpression"); } return expr; } function parseExprSubscripts(){ return parseSubscripts(parseExprAtom()); } function parseSubscripts(base, noCalls){ if (eat(_dot)) { var node = startNodeFrom(base); node.object = base; node.property = parseIdent(true ); node.computed = false ; return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); } else if (eat(_bracketL)) { var node = startNodeFrom(base); node.object = base; node.property = parseExpression(); node.computed = true ; expect(_bracketR); return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); } else if (!noCalls && eat(_parenL)) { var node = startNodeFrom(base); node.callee = base; node.arguments = parseExprList(_parenR, false ); return parseSubscripts(finishNode(node, "CallExpression"), noCalls); } else return base; } function parseExprAtom(){ switch (tokType){ case _this: var node = startNode(); next(); return finishNode(node, "ThisExpression"); case _name: return parseIdent(); case _num: case _string: case _regexp: var node = startNode(); node.value = tokVal; node.raw = input.slice(tokStart, tokEnd); next(); return finishNode(node, "Literal"); case _null: case _true: case _false: var node = startNode(); node.value = tokType.atomValue; node.raw = tokType.keyword; next(); return finishNode(node, "Literal"); case _parenL: var tokStartLoc1 = tokStartLoc, tokStart1 = tokStart; next(); var val = parseExpression(); val.start = tokStart1; val.end = tokEnd; if (options.locations) { val.loc.start = tokStartLoc1; val.loc.end = tokEndLoc; } if (options.ranges) val.range = [tokStart1, tokEnd] ; expect(_parenR); return val; case _bracketL: var node = startNode(); next(); node.elements = parseExprList(_bracketR, true , true ); return finishNode(node, "ArrayExpression"); case _braceL: return parseObj(); case _function: var node = startNode(); next(); return parseFunction(node, false ); case _new: return parseNew(); default : { unexpected(); } } } function parseNew(){ var node = startNode(); next(); node.callee = parseSubscripts(parseExprAtom(), true ); if (eat(_parenL)) node.arguments = parseExprList(_parenR, false ); else node.arguments = empty; return finishNode(node, "NewExpression"); } function parseObj(){ var node = startNode(), first = true , sawGetSet = false ; node.properties = [] ; next(); while (!eat(_braceR)){ if (!first) { expect(_comma); if (options.allowTrailingCommas && eat(_braceR)) break ; } else first = false ; var prop = { key: parsePropertyName()} , isGetSet = false , kind; if (eat(_colon)) { prop.value = parseExpression(true ); kind = prop.kind = "init"; } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set")) { isGetSet = sawGetSet = true ; kind = prop.kind = prop.key.name; prop.key = parsePropertyName(); if (tokType !== _parenL) unexpected(); prop.value = parseFunction(startNode(), false ); } else unexpected(); if (prop.key.type === "Identifier" && (strict || sawGetSet)) { for (var i = 0; i < _AN_Read_length("length", node.properties); ++i){ var other = node.properties[i]; if (other.key.name === prop.key.name) { var conflict = kind == other.kind || isGetSet && other.kind === "init" || kind === "init" && (other.kind === "get" || other.kind === "set"); if (conflict && !strict && kind === "init" && other.kind === "init") conflict = false ; if (conflict) raise(prop.key.start, "Redefinition of property"); } } } node.properties.push(prop); } return finishNode(node, "ObjectExpression"); } function parsePropertyName(){ if (tokType === _num || tokType === _string) return parseExprAtom(); return parseIdent(true ); } function parseFunction(node, isStatement){ if (tokType === _name) node.id = parseIdent(); else if (isStatement) unexpected(); else node.id = null ; node.params = [] ; var first = true ; expect(_parenL); while (!eat(_parenR)){ if (!first) expect(_comma); else first = false ; node.params.push(parseIdent()); } var oldInFunc = inFunction, oldLabels = labels; inFunction = true ; labels = [] ; node.body = parseBlock(true ); inFunction = oldInFunc; labels = oldLabels; if (strict || _AN_Read_length("length", node.body.body) && isUseStrict(node.body.body[0])) { for (var i = node.id? -1: 0; i < _AN_Read_length("length", node.params); ++i){ var id = i < 0? node.id: node.params[i]; if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) raise(id.start, "Defining '" + id.name + "' in strict mode"); if (i >= 0) for (var j = 0; j < i; ++j)if (id.name === node.params[j].name) raise(id.start, "Argument name clash in strict mode"); } } return finishNode(node, isStatement? "FunctionDeclaration": "FunctionExpression"); } function parseExprList(close, allowTrailingComma, allowEmpty){ var elts = [] , first = true ; while (!eat(close)){ if (!first) { expect(_comma); if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break ; } else first = false ; if (allowEmpty && tokType === _comma) elts.push(null ); else elts.push(parseExpression(true )); } return elts; } function parseIdent(liberal){ var node = startNode(); node.name = tokType === _name? tokVal: (liberal && !options.forbidReserved && tokType.keyword) || unexpected(); tokRegexpAllowed = false ; next(); return finishNode(node, "Identifier"); } } ); (function (root, mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./acorn")); if (typeof define == "function" && define.amd) return define(["exports", "./acorn"] , mod); mod(root.acorn || (root.acorn = { } ), root.acorn); } )(this, function (exports, acorn){ "use strict"; var tt = acorn.tokTypes; var options, input, fetchToken, context; exports.parse_dammit = function (inpt, opts){ if (!opts) opts = { } ; input = String(inpt); options = opts; if (!opts.tabSize) opts.tabSize = 4; fetchToken = acorn.tokenize(inpt, opts); sourceFile = options.sourceFile || null ; context = [] ; nextLineStart = 0; ahead.length = 0; next(); return parseTopLevel(); } ; var lastEnd, token = { start: 0, end: 0} , ahead = [] ; var curLineStart, nextLineStart, curIndent, lastEndLoc, sourceFile; function next(){ lastEnd = token.end; if (options.locations) lastEndLoc = token.endLoc; if (ahead.length) token = ahead.shift(); else token = readToken(); if (token.start >= nextLineStart) { while (token.start >= nextLineStart){ curLineStart = nextLineStart; nextLineStart = lineEnd(curLineStart) + 1; } curIndent = indentationAfter(curLineStart); } } function readToken(){ for (; ; ){ try { return fetchToken(); } catch (e) { if (!(e instanceof SyntaxError)) throw e var msg = e.message, pos = e.raisedAt, replace = true ; if (/unterminated/i.test(msg)) { pos = lineEnd(e.pos); if (/string/.test(msg)) { replace = { start: e.pos, end: pos, type: tt.string, value: input.slice(e.pos + 1, pos)} ; } else if (/regular expr/i.test(msg)) { var re = input.slice(e.pos, pos); try { re = new RegExp(re); } catch (e) { } replace = { start: e.pos, end: pos, type: tt.regexp, value: re} ; } else { replace = false ; } } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) { while (pos < _AN_Read_length("length", input) && !isSpace(input.charCodeAt(pos)))++pos; } else if (/character escape|expected hexadecimal/i.test(msg)) { while (pos < _AN_Read_length("length", input)){ var ch = input.charCodeAt(pos++ ); if (ch === 34 || ch === 39 || isNewline(ch)) break ; } } else if (/unexpected character/i.test(msg)) { pos++ ; replace = false ; } else { throw e } resetTo(pos); if (replace === true ) replace = { start: pos, end: pos, type: tt.name, value: "✖"} ; if (replace) { if (options.locations) { replace.startLoc = acorn.getLineInfo(input, replace.start); replace.endLoc = acorn.getLineInfo(input, replace.end); } return replace; } } } } function resetTo(pos){ var ch = input.charAt(pos - 1); var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos)); fetchToken.jumpTo(pos, reAllowed); } function copyToken(token){ var copy = { start: token.start, end: token.end, type: token.type, value: token.value} ; if (options.locations) { copy.startLoc = token.startLoc; copy.endLoc = token.endLoc; } return copy; } function lookAhead(n){ if (!_AN_Read_length("length", ahead)) token = copyToken(token); while (n > _AN_Read_length("length", ahead))ahead.push(copyToken(readToken())); return ahead[n - 1]; } var newline = /[\n\r\u2028\u2029]/; function isNewline(ch){ return ch === 10 || ch === 13 || ch === 8232 || ch === 8329; } function isSpace(ch){ return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewline(ch); } function pushCx(){ context.push(curIndent); } function popCx(){ curIndent = context.pop(); } function lineEnd(pos){ while (pos < _AN_Read_length("length", input) && !isNewline(input.charCodeAt(pos)))++pos; return pos; } function indentationAfter(pos){ for (var count = 0; ; ++pos){ var ch = input.charCodeAt(pos); if (ch === 32) ++count; else if (ch === 9) count += options.tabSize; else return count; } } function closes(closeTok, indent, line, blockHeuristic){ if (token.type === closeTok || token.type === tt.eof) return true ; if (line != curLineStart && curIndent < indent && tokenStartsLine() && (!blockHeuristic || nextLineStart >= _AN_Read_length("length", input) || indentationAfter(nextLineStart) < indent)) return true ; return false ; } function tokenStartsLine(){ for (var p = token.start - 1; p >= curLineStart; --p){ var ch = input.charCodeAt(p); if (ch !== 9 && ch !== 32) return false ; } return true ; } function node_t(start){ this.type = null ; this.start = start; this.end = null ; } function node_loc_t(start){ this.start = start || token.startLoc || { line: 1, column: 0} ; this.end = null ; if (sourceFile !== null ) this.source = sourceFile; } function startNode(){ var node = new node_t(token.start); if (options.locations) node.loc = new node_loc_t(); if (options.directSourceFile) node.sourceFile = options.directSourceFile; return node; } function startNodeFrom(other){ var node = new node_t(other.start); if (options.locations) node.loc = new node_loc_t(other.loc.start); return node; } function finishNode(node, type){ node.type = type; node.end = lastEnd; if (options.locations) node.loc.end = lastEndLoc; return node; } function getDummyLoc(){ if (options.locations) { var loc = new node_loc_t(); loc.end = loc.start; return loc; } } ; function dummyIdent(){ var dummy = new node_t(token.start); dummy.type = "Identifier"; dummy.end = token.start; dummy.name = "✖"; dummy.loc = getDummyLoc(); return dummy; } function isDummy(node){ return node.name == "✖"; } function eat(type){ if (token.type === type) { next(); return true ; } } function canInsertSemicolon(){ return (token.type === tt.eof || token.type === tt.braceR || newline.test(input.slice(lastEnd, token.start))); } function semicolon(){ eat(tt.semi); } function expect(type){ if (eat(type)) return true ; if (lookAhead(1).type == type) { next(); next(); return true ; } if (lookAhead(2).type == type) { next(); next(); next(); return true ; } } function checkLVal(expr){ if (expr.type === "Identifier" || expr.type === "MemberExpression") return expr; return dummyIdent(); } function parseTopLevel(){ var node = startNode(); node.body = [] ; while (token.type !== tt.eof)node.body.push(parseStatement()); return finishNode(node, "Program"); } function parseStatement(){ var starttype = token.type, node = startNode(); switch (starttype){ case tt._break: case tt._continue: next(); var isBreak = starttype === tt._break; node.label = token.type === tt.name? parseIdent(): null ; semicolon(); return finishNode(node, isBreak? "BreakStatement": "ContinueStatement"); case tt._debugger: next(); semicolon(); return finishNode(node, "DebuggerStatement"); case tt._do: next(); node.body = parseStatement(); node.test = eat(tt._while)? parseParenExpression(): dummyIdent(); semicolon(); return finishNode(node, "DoWhileStatement"); case tt._for: next(); pushCx(); expect(tt.parenL); if (token.type === tt.semi) return parseFor(node, null ); if (token.type === tt._var) { var init = startNode(); next(); parseVar(init, true ); if (_AN_Read_length("length", init.declarations) === 1 && eat(tt._in)) return parseForIn(node, init); return parseFor(node, init); } var init = parseExpression(false , true ); if (eat(tt._in)) { return parseForIn(node, checkLVal(init)); } return parseFor(node, init); case tt._function: next(); return parseFunction(node, true ); case tt._if: next(); node.test = parseParenExpression(); node.consequent = parseStatement(); node.alternate = eat(tt._else)? parseStatement(): null ; return finishNode(node, "IfStatement"); case tt._return: next(); if (eat(tt.semi) || canInsertSemicolon()) node.argument = null ; else { node.argument = parseExpression(); semicolon(); } return finishNode(node, "ReturnStatement"); case tt._switch: var blockIndent = curIndent, line = curLineStart; next(); node.discriminant = parseParenExpression(); node.cases = [] ; pushCx(); expect(tt.braceL); for (var cur; !closes(tt.braceR, blockIndent, line, true ); ){ if (token.type === tt._case || token.type === tt._default) { var isCase = token.type === tt._case; if (cur) finishNode(cur, "SwitchCase"); node.cases.push(cur = startNode()); cur.consequent = [] ; next(); if (isCase) cur.test = parseExpression(); else cur.test = null ; expect(tt.colon); } else { if (!cur) { node.cases.push(cur = startNode()); cur.consequent = [] ; cur.test = null ; } cur.consequent.push(parseStatement()); } } if (cur) finishNode(cur, "SwitchCase"); popCx(); eat(tt.braceR); return finishNode(node, "SwitchStatement"); case tt._throw: next(); node.argument = parseExpression(); semicolon(); return finishNode(node, "ThrowStatement"); case tt._try: next(); node.block = parseBlock(); node.handler = null ; if (token.type === tt._catch) { var clause = startNode(); next(); expect(tt.parenL); clause.param = parseIdent(); expect(tt.parenR); clause.guard = null ; clause.body = parseBlock(); node.handler = finishNode(clause, "CatchClause"); } node.finalizer = eat(tt._finally)? parseBlock(): null ; if (!node.handler && !node.finalizer) return node.block; return finishNode(node, "TryStatement"); case tt._var: next(); node = parseVar(node); semicolon(); return node; case tt._while: next(); node.test = parseParenExpression(); node.body = parseStatement(); return finishNode(node, "WhileStatement"); case tt._with: next(); node.object = parseParenExpression(); node.body = parseStatement(); return finishNode(node, "WithStatement"); case tt.braceL: return parseBlock(); case tt.semi: next(); return finishNode(node, "EmptyStatement"); default : { var expr = parseExpression(); if (isDummy(expr)) { next(); if (token.type === tt.eof) return finishNode(node, "EmptyStatement"); return parseStatement(); } else if (starttype === tt.name && expr.type === "Identifier" && eat(tt.colon)) { node.body = parseStatement(); node.label = expr; return finishNode(node, "LabeledStatement"); } else { node.expression = expr; semicolon(); return finishNode(node, "ExpressionStatement"); } } } } function parseBlock(){ var node = startNode(); pushCx(); expect(tt.braceL); var blockIndent = curIndent, line = curLineStart; node.body = [] ; while (!closes(tt.braceR, blockIndent, line, true ))node.body.push(parseStatement()); popCx(); eat(tt.braceR); return finishNode(node, "BlockStatement"); } function parseFor(node, init){ node.init = init; node.test = node.update = null ; if (eat(tt.semi) && token.type !== tt.semi) node.test = parseExpression(); if (eat(tt.semi) && token.type !== tt.parenR) node.update = parseExpression(); popCx(); expect(tt.parenR); node.body = parseStatement(); return finishNode(node, "ForStatement"); } function parseForIn(node, init){ node.left = init; node.right = parseExpression(); popCx(); expect(tt.parenR); node.body = parseStatement(); return finishNode(node, "ForInStatement"); } function parseVar(node, noIn){ node.declarations = [] ; node.kind = "var"; while (token.type === tt.name){ var decl = startNode(); decl.id = parseIdent(); decl.init = eat(tt.eq)? parseExpression(true , noIn): null ; node.declarations.push(finishNode(decl, "VariableDeclarator")); if (!eat(tt.comma)) break ; } if (!_AN_Read_length("length", node.declarations)) { var decl = startNode(); decl.id = dummyIdent(); node.declarations.push(finishNode(decl, "VariableDeclarator")); } return finishNode(node, "VariableDeclaration"); } function parseExpression(noComma, noIn){ var expr = parseMaybeAssign(noIn); if (!noComma && token.type === tt.comma) { var node = startNodeFrom(expr); node.expressions = [expr] ; while (eat(tt.comma))node.expressions.push(parseMaybeAssign(noIn)); return finishNode(node, "SequenceExpression"); } return expr; } function parseParenExpression(){ pushCx(); expect(tt.parenL); var val = parseExpression(); popCx(); expect(tt.parenR); return val; } function parseMaybeAssign(noIn){ var left = parseMaybeConditional(noIn); if (token.type.isAssign) { var node = startNodeFrom(left); node.operator = token.value; node.left = checkLVal(left); next(); node.right = parseMaybeAssign(noIn); return finishNode(node, "AssignmentExpression"); } return left; } function parseMaybeConditional(noIn){ var expr = parseExprOps(noIn); if (eat(tt.question)) { var node = startNodeFrom(expr); node.test = expr; node.consequent = parseExpression(true ); node.alternate = expect(tt.colon)? parseExpression(true , noIn): dummyIdent(); return finishNode(node, "ConditionalExpression"); } return expr; } function parseExprOps(noIn){ var indent = curIndent, line = curLineStart; return parseExprOp(parseMaybeUnary(noIn), -1, noIn, indent, line); } function parseExprOp(left, minPrec, noIn, indent, line){ if (curLineStart != line && curIndent < indent && tokenStartsLine()) return left; var prec = token.type.binop; if (prec != null && (!noIn || token.type !== tt._in)) { if (prec > minPrec) { var node = startNodeFrom(left); node.left = left; node.operator = token.value; next(); if (curLineStart != line && curIndent < indent && tokenStartsLine()) node.right = dummyIdent(); else node.right = parseExprOp(parseMaybeUnary(noIn), prec, noIn, indent, line); var node = finishNode(node, /&&|\|\|/.test(node.operator)? "LogicalExpression": "BinaryExpression"); return parseExprOp(node, minPrec, noIn, indent, line); } } return left; } function parseMaybeUnary(noIn){ if (token.type.prefix) { var node = startNode(), update = token.type.isUpdate; node.operator = token.value; node.prefix = true ; next(); node.argument = parseMaybeUnary(noIn); if (update) node.argument = checkLVal(node.argument); return finishNode(node, update? "UpdateExpression": "UnaryExpression"); } var expr = parseExprSubscripts(); while (token.type.postfix && !canInsertSemicolon()){ var node = startNodeFrom(expr); node.operator = token.value; node.prefix = false ; node.argument = checkLVal(expr); next(); expr = finishNode(node, "UpdateExpression"); } return expr; } function parseExprSubscripts(){ return parseSubscripts(parseExprAtom(), false , curIndent, curLineStart); } function parseSubscripts(base, noCalls, startIndent, line){ for (; ; ){ if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) { if (token.type == tt.dot && curIndent == startIndent) --startIndent; else return base; } if (eat(tt.dot)) { var node = startNodeFrom(base); node.object = base; if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) node.property = dummyIdent(); else node.property = parsePropertyName() || dummyIdent(); node.computed = false ; base = finishNode(node, "MemberExpression"); } else if (token.type == tt.bracketL) { pushCx(); next(); var node = startNodeFrom(base); node.object = base; node.property = parseExpression(); node.computed = true ; popCx(); expect(tt.bracketR); base = finishNode(node, "MemberExpression"); } else if (!noCalls && token.type == tt.parenL) { pushCx(); var node = startNodeFrom(base); node.callee = base; node.arguments = parseExprList(tt.parenR); base = finishNode(node, "CallExpression"); } else { return base; } } } function parseExprAtom(){ switch (token.type){ case tt._this: var node = startNode(); next(); return finishNode(node, "ThisExpression"); case tt.name: return parseIdent(); case tt.num: case tt.string: case tt.regexp: var node = startNode(); node.value = token.value; node.raw = input.slice(token.start, token.end); next(); return finishNode(node, "Literal"); case tt._null: case tt._true: case tt._false: var node = startNode(); node.value = token.type.atomValue; node.raw = token.type.keyword; next(); return finishNode(node, "Literal"); case tt.parenL: var tokStart1 = token.start; next(); var val = parseExpression(); val.start = tokStart1; val.end = token.end; expect(tt.parenR); return val; case tt.bracketL: var node = startNode(); pushCx(); node.elements = parseExprList(tt.bracketR); return finishNode(node, "ArrayExpression"); case tt.braceL: return parseObj(); case tt._function: var node = startNode(); next(); return parseFunction(node, false ); case tt._new: return parseNew(); default : { return dummyIdent(); } } } function parseNew(){ var node = startNode(), startIndent = curIndent, line = curLineStart; next(); node.callee = parseSubscripts(parseExprAtom(), true , startIndent, line); if (token.type == tt.parenL) { pushCx(); node.arguments = parseExprList(tt.parenR); } else { node.arguments = [] ; } return finishNode(node, "NewExpression"); } function parseObj(){ var node = startNode(); node.properties = [] ; pushCx(); next(); var propIndent = curIndent, line = curLineStart; while (!closes(tt.braceR, propIndent, line)){ var name = parsePropertyName(); if (!name) { if (isDummy(parseExpression(true ))) next(); eat(tt.comma); continue ; } var prop = { key: name} , isGetSet = false , kind; if (eat(tt.colon)) { prop.value = parseExpression(true ); kind = prop.kind = "init"; } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set")) { isGetSet = true ; kind = prop.kind = prop.key.name; prop.key = parsePropertyName() || dummyIdent(); prop.value = parseFunction(startNode(), false ); } else { next(); eat(tt.comma); continue ; } node.properties.push(prop); eat(tt.comma); } popCx(); eat(tt.braceR); return finishNode(node, "ObjectExpression"); } function parsePropertyName(){ if (token.type === tt.num || token.type === tt.string) return parseExprAtom(); if (token.type === tt.name || token.type.keyword) return parseIdent(); } function parseIdent(){ var node = startNode(); node.name = token.type === tt.name? token.value: token.type.keyword; next(); return finishNode(node, "Identifier"); } function parseFunction(node, isStatement){ if (token.type === tt.name) node.id = parseIdent(); else if (isStatement) node.id = dummyIdent(); else node.id = null ; node.params = [] ; pushCx(); expect(tt.parenL); while (token.type == tt.name){ node.params.push(parseIdent()); eat(tt.comma); } popCx(); eat(tt.parenR); node.body = parseBlock(); return finishNode(node, isStatement? "FunctionDeclaration": "FunctionExpression"); } function parseExprList(close){ var indent = curIndent, line = curLineStart, elts = [] , continuedLine = nextLineStart; next(); if (curLineStart > continuedLine) continuedLine = curLineStart; while (!closes(close, indent + (curLineStart <= continuedLine? 1: 0), line)){ var elt = parseExpression(true ); if (isDummy(elt)) { if (closes(close, indent, line)) break ; next(); } else { elts.push(elt); } while (eat(tt.comma)){ } } popCx(); eat(close); return elts; } } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(require("infer"), require("tern"), require("comment"), require("walk")); if (typeof define == "function" && define.amd) return define(["infer", "tern", "comment", "walk"] , mod); mod(tern, tern, tern.comment, acorn.walk); } )(function (infer, tern, comment, walk){ "use strict"; tern.registerPlugin("doc_comment", function (){ return { passes: { "postParse": postParse, "postInfer": postInfer} } ; } ); function postParse(ast, text){ function attachComments(node){ comment.ensureCommentsBefore(text, node); } walk.simple(ast, { VariableDeclaration: attachComments, FunctionDeclaration: attachComments, AssignmentExpression: function (node){ if (node.operator == "=") attachComments(node); } , ObjectExpression: function (node){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i)attachComments(node.properties[i].key); } } ); } function postInfer(ast, scope){ walk.simple(ast, { VariableDeclaration: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.declarations[0].id.name)); } , FunctionDeclaration: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.id.name), node.body.scope.fnType); } , AssignmentExpression: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, infer.expressionType({ node: node.left, state: scope} )); } , ObjectExpression: function (node, scope){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i){ var prop = node.properties[i], key = prop.key; if (key.commentsBefore) interpretComments(prop, key.commentsBefore, scope, node.objType.getProp(key.name)); } } } , infer.searchVisitor, scope); } function interpretComments(node, comments, scope, aval, type){ jsdocInterpretComments(node, scope, aval, comments); if (!type && aval instanceof infer.AVal && _AN_Read_length("length", aval.types)) { type = aval.types[_AN_Read_length("length", aval.types) - 1]; if (!(type instanceof infer.Obj) || type.origin != infer.cx().curOrigin || type.doc) type = null ; } var first = comments[0], dot = first.search(/\.\s/); if (dot > 5) first = first.slice(0, dot + 1); first = _AN_Call_replace("replace", first.trim(), /\s*\n\s*\*\s*|\s{1,}/g, " "); if (aval instanceof infer.AVal) aval.doc = first; if (type) type.doc = first; } function skipSpace(str, pos){ while (/\s/.test(str.charAt(pos)))++pos; return pos; } function parseLabelList(scope, str, pos, close){ var labels = [] , types = [] ; for (var first = true ; ; first = false ){ pos = skipSpace(str, pos); if (first && str.charAt(pos) == close) break ; var colon = str.indexOf(":", pos); if (colon < 0) return null ; var label = str.slice(pos, colon); if (!/^[\w$]+$/.test(label)) return null ; labels.push(label); pos = colon + 1; var type = parseType(scope, str, pos); if (!type) return null ; pos = type.end; types.push(type.type); pos = skipSpace(str, pos); var next = str.charAt(pos); ++pos; if (next == close) break ; if (next != ",") return null ; } return { labels: labels, types: types, end: pos} ; } function parseType(scope, str, pos){ pos = skipSpace(str, pos); var type; if (str.indexOf("function(", pos) == pos) { var args = parseLabelList(scope, str, pos + 9, ")"), ret = infer.ANull; if (!args) return null ; pos = skipSpace(str, args.end); if (str.charAt(pos) == ":") { ++pos; var retType = parseType(scope, str, pos + 1); if (!retType) return null ; pos = retType.end; ret = retType.type; } type = new infer.Fn(null , infer.ANull, args.types, args.labels, ret); } else if (str.charAt(pos) == "[") { var inner = parseType(scope, str, pos + 1); if (!inner) return null ; pos = skipSpace(str, inner.end); if (str.charAt(pos) != "]") return null ; ++pos; type = new infer.Arr(inner.type); } else if (str.charAt(pos) == "{") { var fields = parseLabelList(scope, str, pos + 1, "}"); if (!fields) return null ; type = new infer.Obj(true ); for (var i = 0; i < _AN_Read_length("length", fields.types); ++i){ var field = type.defProp(fields.labels[i]); field.initializer = true ; fields.types[i].propagate(field); } pos = fields.end; } else { var start = pos; while (/[\w$]/.test(str.charAt(pos)))++pos; if (start == pos) return null ; var word = str.slice(start, pos); if (/^(number|integer)$/i.test(word)) type = infer.cx().num; else if (/^bool(ean)?$/i.test(word)) type = infer.cx().bool; else if (/^string$/i.test(word)) type = infer.cx().str; else if (/^array$/i.test(word)) { var inner = null ; if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var inAngles = parseType(scope, str, pos + 2); if (!inAngles) return null ; pos = skipSpace(str, inAngles.end); if (str.charAt(pos++ ) != ">") return null ; inner = inAngles.type; } type = new infer.Arr(inner); } else if (/^object$/i.test(word)) { type = new infer.Obj(true ); if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var key = parseType(scope, str, pos + 2); if (!key) return null ; pos = skipSpace(str, key.end); if (str.charAt(pos++ ) != ",") return null ; var val = parseType(scope, str, pos); if (!val) return null ; pos = skipSpace(str, val.end); if (str.charAt(pos++ ) != ">") return null ; val.type.propagate(type.defProp("")); } } else { var found = scope.hasProp(word); if (found) found = found.getType(); if (!found) { type = infer.ANull; } else if (found instanceof infer.Fn && /^[A-Z]/.test(word)) { var proto = found.getProp("prototype").getType(); if (proto instanceof infer.Obj) type = infer.getInstance(proto); else type = found; } else { type = found; } } } var isOptional = false ; if (str.charAt(pos) == "=") { ++pos; isOptional = true ; } return { type: type, end: pos, isOptional: isOptional} ; } function parseTypeOuter(scope, str, pos){ pos = skipSpace(str, pos || 0); if (str.charAt(pos) != "{") return null ; var result = parseType(scope, str, pos + 1); if (!result || str.charAt(result.end) != "}") return null ; ++result.end; return result; } function jsdocInterpretComments(node, scope, aval, comments){ var type, args, ret, foundOne; for (var i = 0; i < _AN_Read_length("length", comments); ++i){ var comment = comments[i]; var decl = /(?:\n|$|\*)\s*@(type|param|arg(?:ument)?|returns?)\s+(.*)/g, m; while (m = decl.exec(comment)){ var parsed = parseTypeOuter(scope, m[2]); if (!parsed) continue ; foundOne = true ; switch (m[1]){ case "returns": case "return": ret = parsed.type; break ; case "type": type = parsed.type; break ; case "param": case "arg": case "argument": var name = m[2].slice(parsed.end).match(/^\s*([\w$]+)/); if (!name) continue ; var argname = name[1] + (parsed.isOptional? "?": ""); (args || (args = Object.create(null )))[argname] = parsed.type; break ; } } } if (foundOne) applyType(type, args, ret, node, aval); } ; function applyType(type, args, ret, node, aval){ var fn; if (node.type == "VariableDeclaration") { var decl = node.declarations[0]; if (decl.init && decl.init.type == "FunctionExpression") fn = decl.init.body.scope.fnType; } else if (node.type == "FunctionDeclaration") { fn = node.body.scope.fnType; } else if (node.type == "AssignmentExpression") { if (node.right.type == "FunctionExpression") fn = node.right.body.scope.fnType; } else { if (node.value.type == "FunctionExpression") fn = node.value.body.scope.fnType; } if (fn && (args || ret)) { if (args) for (var i = 0; i < _AN_Read_length("length", fn.argNames); ++i){ var name = fn.argNames[i], known = args[name]; if (!known && (known = args[name + "?"])) fn.argNames[i] += "?"; if (known) known.propagate(fn.args[i]); } if (ret) ret.propagate(fn.retval); } else if (type) { type.propagate(aval); } } ; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports); if (typeof define == "function" && define.amd) return define(["exports"] , mod); mod(tern.comment || (tern.comment = { } )); } )(function (exports){ function isSpace(ch){ return (ch < 14 && ch > 8) || ch === 32 || ch === 160; } function onOwnLine(text, pos){ for (; pos > 0; --pos){ var ch = text.charCodeAt(pos - 1); if (ch == 10) break ; if (!isSpace(ch)) return false ; } return true ; } exports.commentsBefore = function (text, pos){ var found = null , emptyLines = 0, topIsLineComment; out: while (pos > 0){ var prev = text.charCodeAt(pos - 1); if (prev == 10) { for (var scan = --pos, sawNonWS = false ; scan > 0; --scan){ prev = text.charCodeAt(scan - 1); if (prev == 47 && text.charCodeAt(scan - 2) == 47) { if (!onOwnLine(text, scan - 2)) break out; var content = text.slice(scan, pos); if (!emptyLines && topIsLineComment) found[0] = content + "\n" + found[0]; else (found || (found = [] )).unshift(content); topIsLineComment = true ; emptyLines = 0; pos = scan - 2; break ; } else if (prev == 10) { if (!sawNonWS && ++emptyLines > 1) break out; break ; } else if (!sawNonWS && !isSpace(prev)) { sawNonWS = true ; } } } else if (prev == 47 && text.charCodeAt(pos - 2) == 42) { for (var scan = pos - 2; scan > 1; --scan){ if (text.charCodeAt(scan - 1) == 42 && text.charCodeAt(scan - 2) == 47) { if (!onOwnLine(text, scan - 2)) break out; (found || (found = [] )).unshift(text.slice(scan, pos - 2)); topIsLineComment = false ; emptyLines = 0; break ; } } pos = scan - 2; } else if (isSpace(prev)) { --pos; } else { break ; } } return found; } ; exports.commentAfter = function (text, pos){ while (pos < _AN_Read_length("length", text)){ var next = text.charCodeAt(pos); if (next == 47) { var after = text.charCodeAt(pos + 1), end; if (after == 47) end = text.indexOf("\n", pos + 2); else if (after == 42) end = text.indexOf("*/", pos + 2); else return ; return text.slice(pos + 2, end < 0? _AN_Read_length("length", text): end); } else if (isSpace(next)) { ++pos; } } } ; exports.ensureCommentsBefore = function (text, node){ if (node.hasOwnProperty("commentsBefore")) return node.commentsBefore; return node.commentsBefore = exports.commentsBefore(text, node.start); } ; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return exports.init = mod; if (typeof define == "function" && define.amd) return define({ init: mod} ); tern.def = { init: mod} ; } )(function (exports, infer){ "use strict"; function hop(obj, prop){ return Object.prototype.hasOwnProperty.call(obj, prop); } var TypeParser = exports.TypeParser = function (spec, start, base, forceNew){ this.pos = start || 0; this.spec = spec; this.base = base; this.forceNew = forceNew; } ; TypeParser.prototype = { eat: function (str){ if (_AN_Read_length("length", str) == 1? this.spec.charAt(this.pos) == str: this.spec.indexOf(str, this.pos) == this.pos) { this.pos += _AN_Read_length("length", str); return true ; } } , word: function (re){ var word = "", ch, re = re || /[\w$]/; while ((ch = this.spec.charAt(this.pos)) && re.test(ch)){ word += ch; ++this.pos; } return word; } , error: function (){ throw new Error("Unrecognized type spec: " + this.spec + " (at " + this.pos + ")") } , parseFnType: function (name, top){ var args = [] , names = [] ; if (!this.eat(")")) for (var i = 0; ; ++i){ var colon = this.spec.indexOf(": ", this.pos), argname; if (colon != -1) { argname = this.spec.slice(this.pos, colon); if (/^[$\w?]+$/.test(argname)) this.pos = colon + 2; else argname = null ; } names.push(argname); args.push(this.parseType()); if (!this.eat(", ")) { this.eat(")") || this.error(); break ; } } var retType, computeRet, computeRetStart, fn; if (this.eat(" -> ")) { if (top && this.spec.indexOf("!", this.pos) > -1) { retType = infer.ANull; computeRetStart = this.pos; computeRet = this.parseRetType(); } else retType = this.parseType(); } else retType = infer.ANull; if (top && (fn = this.base)) infer.Fn.call(this.base, name, infer.ANull, args, names, retType); else fn = new infer.Fn(name, infer.ANull, args, names, retType); if (computeRet) fn.computeRet = computeRet; if (computeRetStart != null ) fn.computeRetSource = this.spec.slice(computeRetStart, this.pos); return fn; } , parseType: function (name, top){ if (this.eat("fn(")) { return this.parseFnType(name, top); } else if (this.eat("[")) { var inner = this.parseType(); this.eat("]") || this.error(); if (top && this.base) { infer.Arr.call(this.base, inner); return this.base; } return new infer.Arr(inner); } else if (this.eat("+")) { var path = this.word(/[\w$<>\.!]/); var base = parsePath(path + ".prototype"); if (!(base instanceof infer.Obj)) base = parsePath(path); if (!(base instanceof infer.Obj)) return base; if (top && this.forceNew) return new infer.Obj(base); return infer.getInstance(base); } else if (this.eat("?")) { return infer.ANull; } else { var spec = this.word(/[\w$<>\.!]/), cx = infer.cx(); switch (spec){ case "number": return cx.num; case "string": return cx.str; case "bool": return cx.bool; case "": return cx.topScope; } if (cx.localDefs && spec in cx.localDefs) return cx.localDefs[spec]; return parsePath(spec); } } , parseBaseRetType: function (){ if (this.eat("[")) { var inner = this.parseRetType(); this.eat("]") || this.error(); return function (self, args){ return new infer.Arr(inner(self, args)); } ; } else if (this.eat("+")) { var base = this.parseRetType(); return function (self, args){ return infer.getInstance(base(self, args)); } ; } else if (this.eat("!")) { var arg = this.word(/\d/); if (arg) { arg = Number(arg); return function (_self, args){ return args[arg] || infer.ANull; } ; } else if (this.eat("this")) { return function (self){ return self; } ; } else if (this.eat("custom:")) { var fname = this.word(/[\w$]/); return customFunctions[fname] || function (){ return infer.ANull; } ; } else this.error(); } var t = this.parseType(); return function (){ return t; } ; } , extendRetType: function (base){ var propName = this.word(/[\w<>$!]/) || this.error(); if (propName == "!ret") return function (self, args){ var lhs = base(self, args); if (lhs.retval) return lhs.retval; var rv = new infer.AVal(); lhs.propagate(new infer.IsCallee(infer.ANull, [] , null , rv)); return rv; } ; return function (self, args){ return base(self, args).getProp(propName); } ; } , parseRetType: function (){ var tp = this.parseBaseRetType(); while (this.eat("."))tp = this.extendRetType(tp); return tp; } } ; function parseType(spec, name, base, forceNew){ var type = new TypeParser(spec, null , base, forceNew).parseType(name, true ); if (/^fn\(/.test(spec)) for (var i = 0; i < _AN_Read_length("length", type.args); ++i)(function (i){ var arg = type.args[i]; if (arg instanceof infer.Fn && arg.args && _AN_Read_length("length", arg.args)) addEffect(type, function (_self, fArgs){ var fArg = fArgs[i]; if (fArg) fArg.propagate(new infer.IsCallee(infer.cx().topScope, arg.args, null , infer.ANull)); } ); } )(i); return type; } function addEffect(fn, handler, replaceRet){ var oldCmp = fn.computeRet, rv = fn.retval; fn.computeRet = function (self, args, argNodes){ var handled = handler(self, args, argNodes); var old = oldCmp? oldCmp(self, args, argNodes): rv; return replaceRet? handled: old; } ; } var parseEffect = exports.parseEffect = function (effect, fn){ var m; if (effect.indexOf("propagate ") == 0) { var p = new TypeParser(effect, 10); var getOrigin = p.parseRetType(); if (!p.eat(" ")) p.error(); var getTarget = p.parseRetType(); addEffect(fn, function (self, args){ getOrigin(self, args).propagate(getTarget(self, args)); } ); } else if (effect.indexOf("call ") == 0) { var andRet = effect.indexOf("and return ", 5) == 5; var p = new TypeParser(effect, andRet? 16: 5); var getCallee = p.parseRetType(), getSelf = null , getArgs = [] ; if (p.eat(" this=")) getSelf = p.parseRetType(); while (p.eat(" "))getArgs.push(p.parseRetType()); addEffect(fn, function (self, args){ var callee = getCallee(self, args); var slf = getSelf? getSelf(self, args): infer.ANull, as = [] ; for (var i = 0; i < _AN_Read_length("length", getArgs); ++i)as.push(getArgs[i](self, args)); var result = andRet? new infer.AVal(): infer.ANull; callee.propagate(new infer.IsCallee(slf, as, null , result)); return result; } , andRet); } else if (m = effect.match(/^custom (\S+)\s*(.*)/)) { var customFunc = customFunctions[m[1]]; if (customFunc) addEffect(fn, m[2]? customFunc(m[2]): customFunc); } else if (effect.indexOf("copy ") == 0) { var p = new TypeParser(effect, 5); var getFrom = p.parseRetType(); p.eat(" "); var getTo = p.parseRetType(); addEffect(fn, function (self, args){ var from = getFrom(self, args), to = getTo(self, args); from.forAllProps(function (prop, val, local){ if (local && prop != "") to.propagate(new infer.PropHasSubset(prop, val)); } ); } ); } else { throw new Error("Unknown effect type: " + effect) } } ; var currentTopScope; var parsePath = exports.parsePath = function (path){ var cx = infer.cx(), cached = cx.paths[path], origPath = path; if (cached != null ) return cached; cx.paths[path] = infer.ANull; var base = currentTopScope || cx.topScope; if (cx.localDefs) for (var name in cx.localDefs){ if (path.indexOf(name) == 0) { if (path == name) return cx.paths[path] = cx.localDefs[path]; if (path.charAt(_AN_Read_length("length", name)) == ".") { base = cx.localDefs[name]; path = path.slice(_AN_Read_length("length", name) + 1); break ; } } } var parts = path.split("."); for (var i = 0; i < _AN_Read_length("length", parts) && base != infer.ANull; ++i){ var prop = parts[i]; if (prop.charAt(0) == "!") { if (prop == "!proto") { base = (base instanceof infer.Obj && base.proto) || infer.ANull; } else { var fn = base.getFunctionType(); if (!fn) { base = infer.ANull; } else if (prop == "!ret") { base = fn.retval && fn.retval.getType() || infer.ANull; } else { var arg = fn.args && fn.args[Number(prop.slice(1))]; base = (arg && arg.getType()) || infer.ANull; } } } else if (base instanceof infer.Obj) { var propVal = (prop == "prototype" && base instanceof infer.Fn)? base.getProp(prop): base.props[prop]; if (!propVal || propVal.isEmpty()) base = infer.ANull; else base = propVal.types[0]; } } cx.paths[origPath] = base == infer.ANull? null : base; return base; } ; function emptyObj(ctor){ var empty = Object.create(ctor.prototype); empty.props = Object.create(null ); empty.isShell = true ; return empty; } function isSimpleAnnotation(spec){ if (!spec["!type"] || /^fn\(/.test(spec["!type"] )) return false ; for (var prop in spec)if (prop != "!type" && prop != "!doc" && prop != "!url" && prop != "!span" && prop != "!data") return false ; return true ; } function passOne(base, spec, path){ if (!base) { var tp = spec["!type"] ; if (tp) { if (/^fn\(/.test(tp)) base = emptyObj(infer.Fn); else if (tp.charAt(0) == "[") base = emptyObj(infer.Arr); else throw new Error("Invalid !type spec: " + tp) } else if (spec["!stdProto"] ) { base = infer.cx().protos[spec["!stdProto"] ]; } else { base = emptyObj(infer.Obj); } base.name = path; } for (var name in spec)if (hop(spec, name) && name.charCodeAt(0) != 33) { var inner = spec[name]; if (typeof inner == "string" || isSimpleAnnotation(inner)) continue ; var prop = base.defProp(name); passOne(prop.getType(), inner, path? path + "." + name: name).propagate(prop); } return base; } function passTwo(base, spec, path){ if (base.isShell) { delete base.isShell; var tp = spec["!type"] ; if (tp) { parseType(tp, path, base); } else { var proto = spec["!proto"] && parseType(spec["!proto"] ); infer.Obj.call(base, proto instanceof infer.Obj? proto: true , path); } } var effects = spec["!effects"] ; if (effects && base instanceof infer.Fn) for (var i = 0; i < _AN_Read_length("length", effects); ++i)parseEffect(effects[i], base); copyInfo(spec, base); for (var name in spec)if (hop(spec, name) && name.charCodeAt(0) != 33) { var inner = spec[name], known = base.defProp(name), innerPath = path? path + "." + name: name; var type = known.getType(); if (typeof inner == "string") { if (type) continue ; parseType(inner, innerPath).propagate(known); } else { if (!isSimpleAnnotation(inner)) { passTwo(type, inner, innerPath); } else if (!type) { parseType(inner["!type"] , innerPath, null , true ).propagate(known); type = known.getType(); if (type instanceof infer.Obj) copyInfo(inner, type); } else continue ; if (inner["!doc"] ) known.doc = inner["!doc"] ; if (inner["!url"] ) _AN_Write_url("url", known, false , inner["!url"] ); if (inner["!span"] ) known.span = inner["!span"] ; } } } function copyInfo(spec, type){ if (spec["!doc"] ) type.doc = spec["!doc"] ; if (spec["!url"] ) _AN_Write_url("url", type, false , spec["!url"] ); if (spec["!span"] ) type.span = spec["!span"] ; if (spec["!data"] ) type.metaData = spec["!data"] ; } function runPasses(type, arg){ var parent = infer.cx().parent, pass = parent && parent.passes && parent.passes[type]; if (pass) for (var i = 0; i < _AN_Read_length("length", pass); i++ )pass[i](arg); } function doLoadEnvironment(data, scope){ var cx = infer.cx(); infer.addOrigin(cx.curOrigin = data["!name"] || "env#" + _AN_Read_length("length", cx.origins)); cx.localDefs = cx.definitions[cx.curOrigin] = Object.create(null ); runPasses("preLoadDef", data); passOne(scope, data); var def = data["!define"] ; if (def) { for (var name in def){ var spec = def[name]; cx.localDefs[name] = typeof spec == "string"? parsePath(spec): passOne(null , spec, name); } for (var name in def){ var spec = def[name]; if (typeof spec != "string") passTwo(cx.localDefs[name], def[name], name); } } passTwo(scope, data); runPasses("postLoadDef", data); cx.curOrigin = cx.localDefs = null ; } exports.load = function (data, scope){ if (!scope) scope = infer.cx().topScope; var oldScope = currentTopScope; currentTopScope = scope; try { doLoadEnvironment(data, scope); } finally{ currentTopScope = oldScope; } } ; var customFunctions = Object.create(null ); infer.registerFunction = function (name, f){ customFunctions[name] = f; } ; var IsCreated = infer.constraint("created, target, spec", { addType: function (tp){ if (tp instanceof infer.Obj && this.created++ < 5) { var derived = new infer.Obj(tp), spec = this.spec; if (spec instanceof infer.AVal) spec = spec.getType(); if (spec instanceof infer.Obj) for (var prop in spec.props){ var cur = spec.props[prop].types[0]; var p = derived.defProp(prop); if (cur && cur instanceof infer.Obj && cur.props.value) { var vtp = cur.props.value.getType(); if (vtp) p.addType(vtp); } } _AN_Read_target("target", this).addType(derived); } } } ); infer.registerFunction("Object_create", function (_self, args, argNodes){ if (argNodes && _AN_Read_length("length", argNodes) && argNodes[0].type == "Literal" && argNodes[0].value == null ) return new infer.Obj(); var result = new infer.AVal(); if (args[0]) args[0].propagate(new IsCreated(0, result, args[1])); return result; } ); var IsBound = infer.constraint("self, args, target", { addType: function (tp){ if (!(tp instanceof infer.Fn)) return ; _AN_Read_target("target", this).addType(new infer.Fn(tp.name, tp.self, tp.args.slice(_AN_Read_length("length", this.args)), tp.argNames.slice(_AN_Read_length("length", this.args)), tp.retval)); this.self.propagate(tp.self); for (var i = 0; i < Math.min(_AN_Read_length("length", tp.args), _AN_Read_length("length", this.args)); ++i)this.args[i].propagate(tp.args[i]); } } ); infer.registerFunction("Function_bind", function (self, args){ if (!_AN_Read_length("length", args)) return infer.ANull; var result = new infer.AVal(); self.propagate(new IsBound(args[0], args.slice(1), result)); return result; } ); infer.registerFunction("Array_ctor", function (_self, args){ var arr = new infer.Arr(); if (_AN_Read_length("length", args) != 1 || !args[0].hasType(infer.cx().num)) { var content = arr.getProp(""); for (var i = 0; i < _AN_Read_length("length", args); ++i)args[i].propagate(content); } return arr; } ); return exports; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(require("infer"), require("tern"), require("comment"), require("walk")); if (typeof define == "function" && define.amd) return define(["infer", "tern", "comment", "walk"] , mod); mod(tern, tern, tern.comment, acorn.walk); } )(function (infer, tern, comment, walk){ "use strict"; tern.registerPlugin("doc_comment", function (){ return { passes: { "postParse": postParse, "postInfer": postInfer} } ; } ); function postParse(ast, text){ function attachComments(node){ comment.ensureCommentsBefore(text, node); } walk.simple(ast, { VariableDeclaration: attachComments, FunctionDeclaration: attachComments, AssignmentExpression: function (node){ if (node.operator == "=") attachComments(node); } , ObjectExpression: function (node){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i)attachComments(node.properties[i].key); } } ); } function postInfer(ast, scope){ walk.simple(ast, { VariableDeclaration: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.declarations[0].id.name)); } , FunctionDeclaration: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.id.name), node.body.scope.fnType); } , AssignmentExpression: function (node, scope){ if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, infer.expressionType({ node: node.left, state: scope} )); } , ObjectExpression: function (node, scope){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i){ var prop = node.properties[i], key = prop.key; if (key.commentsBefore) interpretComments(prop, key.commentsBefore, scope, node.objType.getProp(key.name)); } } } , infer.searchVisitor, scope); } function interpretComments(node, comments, scope, aval, type){ jsdocInterpretComments(node, scope, aval, comments); if (!type && aval instanceof infer.AVal && _AN_Read_length("length", aval.types)) { type = aval.types[_AN_Read_length("length", aval.types) - 1]; if (!(type instanceof infer.Obj) || type.origin != infer.cx().curOrigin || type.doc) type = null ; } var first = comments[0], dot = first.search(/\.\s/); if (dot > 5) first = first.slice(0, dot + 1); first = _AN_Call_replace("replace", first.trim(), /\s*\n\s*\*\s*|\s{1,}/g, " "); if (aval instanceof infer.AVal) aval.doc = first; if (type) type.doc = first; } function skipSpace(str, pos){ while (/\s/.test(str.charAt(pos)))++pos; return pos; } function parseLabelList(scope, str, pos, close){ var labels = [] , types = [] ; for (var first = true ; ; first = false ){ pos = skipSpace(str, pos); if (first && str.charAt(pos) == close) break ; var colon = str.indexOf(":", pos); if (colon < 0) return null ; var label = str.slice(pos, colon); if (!/^[\w$]+$/.test(label)) return null ; labels.push(label); pos = colon + 1; var type = parseType(scope, str, pos); if (!type) return null ; pos = type.end; types.push(type.type); pos = skipSpace(str, pos); var next = str.charAt(pos); ++pos; if (next == close) break ; if (next != ",") return null ; } return { labels: labels, types: types, end: pos} ; } function parseType(scope, str, pos){ pos = skipSpace(str, pos); var type; if (str.indexOf("function(", pos) == pos) { var args = parseLabelList(scope, str, pos + 9, ")"), ret = infer.ANull; if (!args) return null ; pos = skipSpace(str, args.end); if (str.charAt(pos) == ":") { ++pos; var retType = parseType(scope, str, pos + 1); if (!retType) return null ; pos = retType.end; ret = retType.type; } type = new infer.Fn(null , infer.ANull, args.types, args.labels, ret); } else if (str.charAt(pos) == "[") { var inner = parseType(scope, str, pos + 1); if (!inner) return null ; pos = skipSpace(str, inner.end); if (str.charAt(pos) != "]") return null ; ++pos; type = new infer.Arr(inner.type); } else if (str.charAt(pos) == "{") { var fields = parseLabelList(scope, str, pos + 1, "}"); if (!fields) return null ; type = new infer.Obj(true ); for (var i = 0; i < _AN_Read_length("length", fields.types); ++i){ var field = type.defProp(fields.labels[i]); field.initializer = true ; fields.types[i].propagate(field); } pos = fields.end; } else { var start = pos; while (/[\w$]/.test(str.charAt(pos)))++pos; if (start == pos) return null ; var word = str.slice(start, pos); if (/^(number|integer)$/i.test(word)) type = infer.cx().num; else if (/^bool(ean)?$/i.test(word)) type = infer.cx().bool; else if (/^string$/i.test(word)) type = infer.cx().str; else if (/^array$/i.test(word)) { var inner = null ; if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var inAngles = parseType(scope, str, pos + 2); if (!inAngles) return null ; pos = skipSpace(str, inAngles.end); if (str.charAt(pos++ ) != ">") return null ; inner = inAngles.type; } type = new infer.Arr(inner); } else if (/^object$/i.test(word)) { type = new infer.Obj(true ); if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var key = parseType(scope, str, pos + 2); if (!key) return null ; pos = skipSpace(str, key.end); if (str.charAt(pos++ ) != ",") return null ; var val = parseType(scope, str, pos); if (!val) return null ; pos = skipSpace(str, val.end); if (str.charAt(pos++ ) != ">") return null ; val.type.propagate(type.defProp("")); } } else { var found = scope.hasProp(word); if (found) found = found.getType(); if (!found) { type = infer.ANull; } else if (found instanceof infer.Fn && /^[A-Z]/.test(word)) { var proto = found.getProp("prototype").getType(); if (proto instanceof infer.Obj) type = infer.getInstance(proto); else type = found; } else { type = found; } } } var isOptional = false ; if (str.charAt(pos) == "=") { ++pos; isOptional = true ; } return { type: type, end: pos, isOptional: isOptional} ; } function parseTypeOuter(scope, str, pos){ pos = skipSpace(str, pos || 0); if (str.charAt(pos) != "{") return null ; var result = parseType(scope, str, pos + 1); if (!result || str.charAt(result.end) != "}") return null ; ++result.end; return result; } function jsdocInterpretComments(node, scope, aval, comments){ var type, args, ret, foundOne; for (var i = 0; i < _AN_Read_length("length", comments); ++i){ var comment = comments[i]; var decl = /(?:\n|$|\*)\s*@(type|param|arg(?:ument)?|returns?)\s+(.*)/g, m; while (m = decl.exec(comment)){ var parsed = parseTypeOuter(scope, m[2]); if (!parsed) continue ; foundOne = true ; switch (m[1]){ case "returns": case "return": ret = parsed.type; break ; case "type": type = parsed.type; break ; case "param": case "arg": case "argument": var name = m[2].slice(parsed.end).match(/^\s*([\w$]+)/); if (!name) continue ; var argname = name[1] + (parsed.isOptional? "?": ""); (args || (args = Object.create(null )))[argname] = parsed.type; break ; } } } if (foundOne) applyType(type, args, ret, node, aval); } ; function applyType(type, args, ret, node, aval){ var fn; if (node.type == "VariableDeclaration") { var decl = node.declarations[0]; if (decl.init && decl.init.type == "FunctionExpression") fn = decl.init.body.scope.fnType; } else if (node.type == "FunctionDeclaration") { fn = node.body.scope.fnType; } else if (node.type == "AssignmentExpression") { if (node.right.type == "FunctionExpression") fn = node.right.body.scope.fnType; } else { if (node.value.type == "FunctionExpression") fn = node.value.body.scope.fnType; } if (fn && (args || ret)) { if (args) for (var i = 0; i < _AN_Read_length("length", fn.argNames); ++i){ var name = fn.argNames[i], known = args[name]; if (!known && (known = args[name + "?"])) fn.argNames[i] += "?"; if (known) known.propagate(fn.args[i]); } if (ret) ret.propagate(fn.retval); } else if (type) { type.propagate(aval); } } ; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports, require("acorn"), require("acorn_loose"), require("walk"), require("./def"), require("./signal")); if (typeof define == "function" && define.amd) return define(["exports", "acorn", "acorn_loose", "walk", "./def", "./signal"] , mod); mod(self.tern || (self.tern = { } ), acorn, acorn, acorn.walk, tern.def, tern.signal); } )(function (exports, acorn, acorn_loose, walk, def, signal){ "use strict"; var toString = exports.toString = function (type, maxDepth, parent){ return !type || type == parent? "?": type.toString(maxDepth); } ; var ANull = exports.ANull = signal.mixin({ addType: function (){ } , propagate: function (){ } , getProp: function (){ return ANull; } , forAllProps: function (){ } , hasType: function (){ return false ; } , isEmpty: function (){ return true ; } , getFunctionType: function (){ } , getType: function (){ } , gatherProperties: function (){ } , propagatesTo: function (){ } , typeHint: function (){ } , propHint: function (){ } } ); function extend(proto, props){ var obj = Object.create(proto); if (props) for (var prop in props)obj[prop] = props[prop]; return obj; } var WG_DEFAULT = 100, WG_NEW_INSTANCE = 90, WG_MADEUP_PROTO = 10, WG_MULTI_MEMBER = 5, WG_CATCH_ERROR = 5, WG_GLOBAL_THIS = 90, WG_SPECULATIVE_THIS = 2; var AVal = exports.AVal = function (){ this.types = [] ; this.forward = null ; this.maxWeight = 0; } ; AVal.prototype = extend(ANull, { addType: function (type, weight){ weight = weight || WG_DEFAULT; if (this.maxWeight < weight) { this.maxWeight = weight; if (_AN_Read_length("length", this.types) == 1 && this.types[0] == type) return ; this.types.length = 0; } else if (this.maxWeight > weight || this.types.indexOf(type) > -1) { return ; } this.signal("addType", type); this.types.push(type); var forward = this.forward; if (forward) withWorklist(function (add){ for (var i = 0; i < _AN_Read_length("length", forward); ++i)add(type, forward[i], weight); } ); } , propagate: function (target, weight){ if (target == ANull || (target instanceof Type)) return ; if (weight && weight < WG_DEFAULT) target = new Muffle(target, weight); (this.forward || (this.forward = [] )).push(target); var types = this.types; if (types.length) withWorklist(function (add){ for (var i = 0; i < _AN_Read_length("length", types); ++i)add(types[i], target, weight); } ); } , getProp: function (prop){ if (prop == "__proto__" || prop == "✖") return ANull; var found = (this.props || (this.props = Object.create(null )))[prop]; if (!found) { found = this.props[prop] = new AVal(); this.propagate(new PropIsSubset(prop, found)); } return found; } , forAllProps: function (c){ this.propagate(new ForAllProps(c)); } , hasType: function (type){ return this.types.indexOf(type) > -1; } , isEmpty: function (){ return _AN_Read_length("length", this.types) == 0; } , getFunctionType: function (){ for (var i = _AN_Read_length("length", this.types) - 1; i >= 0; --i)if (this.types[i] instanceof Fn) return this.types[i]; } , getType: function (guess){ if (_AN_Read_length("length", this.types) == 0 && guess !== false ) return this.makeupType(); if (_AN_Read_length("length", this.types) == 1) return this.types[0]; return canonicalType(this.types); } , makeupType: function (){ if (!this.forward) return null ; for (var i = _AN_Read_length("length", this.forward) - 1; i >= 0; --i){ var hint = this.forward[i].typeHint(); if (hint && !hint.isEmpty()) { guessing = true ; return hint; } } var props = Object.create(null ), foundProp = null ; for (var i = 0; i < _AN_Read_length("length", this.forward); ++i){ var prop = this.forward[i].propHint(); if (prop && prop != "length" && prop != "" && prop != "✖") { props[prop] = true ; foundProp = prop; } } if (!foundProp) return null ; var objs = objsWithProp(foundProp); if (objs) { var matches = [] ; search: for (var i = 0; i < _AN_Read_length("length", objs); ++i){ var obj = objs[i]; for (var prop in props)if (!obj.hasProp(prop)) continue search; if (obj.hasCtor) obj = getInstance(obj); matches.push(obj); } var canon = canonicalType(matches); if (canon) { guessing = true ; return canon; } } } , typeHint: function (){ return _AN_Read_length("length", this.types)? this.getType(): null ; } , propagatesTo: function (){ return this; } , gatherProperties: function (f, depth){ for (var i = 0; i < _AN_Read_length("length", this.types); ++i)this.types[i].gatherProperties(f, depth); } , guessProperties: function (f){ if (this.forward) for (var i = 0; i < _AN_Read_length("length", this.forward); ++i){ var prop = this.forward[i].propHint(); if (prop) f(prop, null , 0); } } } ); function canonicalType(types){ var arrays = 0, fns = 0, objs = 0, prim = null ; for (var i = 0; i < _AN_Read_length("length", types); ++i){ var tp = types[i]; if (tp instanceof Arr) ++arrays; else if (tp instanceof Fn) ++fns; else if (tp instanceof Obj) ++objs; else if (tp instanceof Prim) { if (prim && tp.name != prim.name) return null ; prim = tp; } } var kinds = (arrays && 1) + (fns && 1) + (objs && 1) + (prim && 1); if (kinds > 1) return null ; if (prim) return prim; var maxScore = 0, maxTp = null ; for (var i = 0; i < _AN_Read_length("length", types); ++i){ var tp = types[i], score = 0; if (arrays) { score = tp.getProp("").isEmpty()? 1: 2; } else if (fns) { score = 1; for (var j = 0; j < _AN_Read_length("length", tp.args); ++j)if (!tp.args[j].isEmpty()) ++score; if (!tp.retval.isEmpty()) ++score; } else if (objs) { score = tp.name? 100: 2; } else if (prims) { score = 1; } if (score >= maxScore) { maxScore = score; maxTp = tp; } } return maxTp; } function Constraint(){ } Constraint.prototype = extend(ANull, { init: function (){ this.origin = cx.curOrigin; } } ); var constraint = exports.constraint = function (props, methods){ var body = "this.init();"; props = props? props.split(", "): [] ; for (var i = 0; i < _AN_Read_length("length", props); ++i)body += "this." + props[i] + " = " + props[i] + ";"; var ctor = Function.apply(null , props.concat([body] )); ctor.prototype = Object.create(Constraint.prototype); for (var m in methods)if (methods.hasOwnProperty(m)) ctor.prototype[m] = methods[m]; return ctor; } ; var PropIsSubset = constraint("prop, target", { addType: function (type, weight){ if (type.getProp) type.getProp(this.prop).propagate(_AN_Read_target("target", this), weight); } , propHint: function (){ return this.prop; } , propagatesTo: function (){ return { target: _AN_Read_target("target", this), pathExt: "." + this.prop} ; } } ); var PropHasSubset = exports.PropHasSubset = constraint("prop, type, originNode", { addType: function (type, weight){ if (!(type instanceof Obj)) return ; var prop = type.defProp(this.prop, this.originNode); prop.origin = this.origin; this.type.propagate(prop, weight); } , propHint: function (){ return this.prop; } } ); var ForAllProps = constraint("c", { addType: function (type){ if (!(type instanceof Obj)) return ; type.forAllProps(this.c); } } ); function withDisabledComputing(fn, body){ cx.disabledComputing = { fn: fn, prev: cx.disabledComputing} ; try { return body(); } finally{ cx.disabledComputing = cx.disabledComputing.prev; } } var IsCallee = exports.IsCallee = constraint("self, args, argNodes, retval", { init: function (){ _AN_Call_init("init", Constraint.prototype); this.disabled = cx.disabledComputing; } , addType: function (fn, weight){ if (!(fn instanceof Fn)) return ; for (var i = 0; i < _AN_Read_length("length", this.args); ++i){ if (i < _AN_Read_length("length", fn.args)) this.args[i].propagate(fn.args[i], weight); if (fn.arguments) this.args[i].propagate(fn.arguments, weight); } this.self.propagate(fn.self, this.self == cx.topScope? WG_GLOBAL_THIS: weight); var compute = fn.computeRet; if (compute) for (var d = this.disabled; d; d = d.prev)if (d.fn == fn || fn.name && d.fn.name == fn.name) compute = null ; if (compute) compute(this.self, this.args, this.argNodes).propagate(this.retval, weight); else fn.retval.propagate(this.retval, weight); } , typeHint: function (){ var names = [] ; for (var i = 0; i < _AN_Read_length("length", this.args); ++i)names.push("?"); return new Fn(null , this.self, this.args, names, ANull); } , propagatesTo: function (){ return { target: this.retval, pathExt: ".!ret"} ; } } ); var HasMethodCall = constraint("propName, args, argNodes, retval", { init: function (){ _AN_Call_init("init", Constraint.prototype); this.disabled = cx.disabledComputing; } , addType: function (obj, weight){ var callee = new IsCallee(obj, this.args, this.argNodes, this.retval); callee.disabled = this.disabled; obj.getProp(this.propName).propagate(callee, weight); } , propHint: function (){ return this.propName; } } ); var IsCtor = exports.IsCtor = constraint("target, noReuse", { addType: function (f, weight){ if (!(f instanceof Fn)) return ; f.getProp("prototype").propagate(new IsProto(this.noReuse? false : f, (_AN_Read_target("target", this))), weight); } } ); var getInstance = exports.getInstance = function (obj, ctor){ if (ctor === false ) return new Obj(obj); if (!ctor) ctor = obj.hasCtor; if (!obj.instances) obj.instances = [] ; for (var i = 0; i < _AN_Read_length("length", obj.instances); ++i){ var cur = obj.instances[i]; if (cur.ctor == ctor) return cur.instance; } var instance = new Obj(obj, ctor && ctor.name); instance.origin = obj.origin; obj.instances.push({ ctor: ctor, instance: instance} ); return instance; } ; var IsProto = exports.IsProto = constraint("ctor, target", { addType: function (o, _weight){ if (!(o instanceof Obj)) return ; if ((this.count = (this.count || 0) + 1) > 8) return ; if (o == cx.protos.Array) _AN_Read_target("target", this).addType(new Arr()); else _AN_Read_target("target", this).addType(getInstance(o, this.ctor)); } } ); var FnPrototype = constraint("fn", { addType: function (o, _weight){ if (o instanceof Obj && !o.hasCtor) { o.hasCtor = this.fn; var adder = new SpeculativeThis(o, this.fn); adder.addType(this.fn); o.forAllProps(function (_prop, val, local){ if (local) val.propagate(adder); } ); } } } ); var IsAdded = constraint("other, target", { addType: function (type, weight){ if (type == cx.str) _AN_Read_target("target", this).addType(cx.str, weight); else if (type == cx.num && this.other.hasType(cx.num)) _AN_Read_target("target", this).addType(cx.num, weight); } , typeHint: function (){ return this.other; } } ); var IfObj = constraint("target", { addType: function (t, weight){ if (t instanceof Obj) _AN_Read_target("target", this).addType(t, weight); } , propagatesTo: function (){ return _AN_Read_target("target", this); } } ); var SpeculativeThis = constraint("obj, ctor", { addType: function (tp){ if (tp instanceof Fn && tp.self && tp.self.isEmpty()) tp.self.addType(getInstance(this.obj, this.ctor), WG_SPECULATIVE_THIS); } } ); var Muffle = constraint("inner, weight", { addType: function (tp, weight){ this.inner.addType(tp, Math.min(weight, this.weight)); } , propagatesTo: function (){ return this.inner.propagatesTo(); } , typeHint: function (){ return this.inner.typeHint(); } , propHint: function (){ return this.inner.propHint(); } } ); var Type = exports.Type = function (){ } ; Type.prototype = extend(ANull, { propagate: function (c, w){ c.addType(this, w); } , hasType: function (other){ return other == this; } , isEmpty: function (){ return false ; } , typeHint: function (){ return this; } , getType: function (){ return this; } } ); var Prim = exports.Prim = function (proto, name){ this.name = name; this.proto = proto; } ; Prim.prototype = extend(Type.prototype, { toString: function (){ return this.name; } , getProp: function (prop){ return this.proto.hasProp(prop) || ANull; } , gatherProperties: function (f, depth){ if (this.proto) this.proto.gatherProperties(f, depth); } } ); var Obj = exports.Obj = function (proto, name){ if (!this.props) this.props = Object.create(null ); this.proto = proto === true ? cx.protos.Object: proto; if (proto && !name && proto.name && !(this instanceof Fn)) { var match = /^(.*)\.prototype$/.exec(this.proto.name); if (match) name = match[1]; } this.name = name; this.maybeProps = null ; this.origin = cx.curOrigin; } ; Obj.prototype = extend(Type.prototype, { toString: function (maxDepth){ if (!maxDepth && this.name) return this.name; var props = [] , etc = false ; for (var prop in this.props)if (prop != "") { if (_AN_Read_length("length", props) > 5) { etc = true ; break ; } if (maxDepth) props.push(prop + ": " + toString(this.props[prop].getType(), maxDepth - 1)); else props.push(prop); } props.sort(); if (etc) props.push("..."); return "{" + props.join(", ") + "}"; } , hasProp: function (prop, searchProto){ var found = this.props[prop]; if (searchProto !== false ) for (var p = this.proto; p && !found; p = p.proto)found = p.props[prop]; return found; } , defProp: function (prop, originNode){ var found = this.hasProp(prop, false ); if (found) { if (originNode && !found.originNode) found.originNode = originNode; return found; } if (prop == "__proto__" || prop == "✖") return ANull; var av = this.maybeProps && this.maybeProps[prop]; if (av) { delete this.maybeProps[prop]; this.maybeUnregProtoPropHandler(); } else { av = new AVal(); } this.props[prop] = av; av.originNode = originNode; av.origin = cx.curOrigin; this.broadcastProp(prop, av, true ); return av; } , getProp: function (prop){ var found = this.hasProp(prop, true ) || (this.maybeProps && this.maybeProps[prop]); if (found) return found; if (prop == "__proto__" || prop == "✖") return ANull; return this.ensureMaybeProps()[prop] = new AVal(); } , broadcastProp: function (prop, val, local){ if (local) { this.signal("addProp", prop, val); if (!(this instanceof Scope)) registerProp(prop, this); } if (this.onNewProp) for (var i = 0; i < _AN_Read_length("length", this.onNewProp); ++i){ var h = this.onNewProp[i]; h.onProtoProp? h.onProtoProp(prop, val, local): h(prop, val, local); } } , onProtoProp: function (prop, val, _local){ var maybe = this.maybeProps && this.maybeProps[prop]; if (maybe) { delete this.maybeProps[prop]; this.maybeUnregProtoPropHandler(); this.proto.getProp(prop).propagate(maybe); } this.broadcastProp(prop, val, false ); } , ensureMaybeProps: function (){ if (!this.maybeProps) { if (this.proto) this.proto.forAllProps(this); this.maybeProps = Object.create(null ); } return this.maybeProps; } , removeProp: function (prop){ var av = this.props[prop]; delete this.props[prop]; this.ensureMaybeProps()[prop] = av; } , forAllProps: function (c){ if (!this.onNewProp) { this.onNewProp = [] ; if (this.proto) this.proto.forAllProps(this); } this.onNewProp.push(c); for (var o = this; o; o = o.proto)for (var prop in o.props){ if (c.onProtoProp) c.onProtoProp(prop, o.props[prop], o == this); else c(prop, o.props[prop], o == this); } } , maybeUnregProtoPropHandler: function (){ if (this.maybeProps) { for (var _n in this.maybeProps)return ; this.maybeProps = null ; } if (!this.proto || this.onNewProp && _AN_Read_length("length", this.onNewProp)) return ; this.proto.unregPropHandler(this); } , unregPropHandler: function (handler){ for (var i = 0; i < _AN_Read_length("length", this.onNewProp); ++i)if (this.onNewProp[i] == handler) { this.onNewProp.splice(i, 1); break ; } this.maybeUnregProtoPropHandler(); } , gatherProperties: function (f, depth){ for (var prop in this.props)if (prop != "") f(prop, this, depth); if (this.proto) this.proto.gatherProperties(f, depth + 1); } } ); var Fn = exports.Fn = function (name, self, args, argNames, retval){ Obj.call(this, cx.protos.Function, name); this.self = self; this.args = args; this.argNames = argNames; this.retval = retval; } ; Fn.prototype = extend(Obj.prototype, { toString: function (maxDepth){ if (maxDepth) maxDepth-- ; var str = "fn("; for (var i = 0; i < _AN_Read_length("length", this.args); ++i){ if (i) str += ", "; var name = this.argNames[i]; if (name && name != "?") str += name + ": "; str += toString(this.args[i].getType(), maxDepth, this); } str += ")"; if (!this.retval.isEmpty()) str += " -> " + toString(this.retval.getType(), maxDepth, this); return str; } , getProp: function (prop){ if (prop == "prototype") { var known = this.hasProp(prop, false ); if (!known) { known = this.defProp(prop); var proto = new Obj(true , this.name && this.name + ".prototype"); proto.origin = this.origin; known.addType(proto, WG_MADEUP_PROTO); } return known; } return Obj.prototype.getProp.call(this, prop); } , defProp: function (prop, originNode){ if (prop == "prototype") { var found = this.hasProp(prop, false ); if (found) return found; found = Obj.prototype.defProp.call(this, prop, originNode); found.origin = this.origin; found.propagate(new FnPrototype(this)); return found; } return Obj.prototype.defProp.call(this, prop, originNode); } , getFunctionType: function (){ return this; } } ); var Arr = exports.Arr = function (contentType){ Obj.call(this, cx.protos.Array); var content = this.defProp(""); if (contentType) contentType.propagate(content); } ; Arr.prototype = extend(Obj.prototype, { toString: function (maxDepth){ return "[" + toString(this.getProp("").getType(), maxDepth, this) + "]"; } } ); function registerProp(prop, obj){ var data = cx.props[prop] || (cx.props[prop] = [] ); data.push(obj); } function objsWithProp(prop){ return cx.props[prop]; } exports.Context = function (defs, parent){ this.parent = parent; this.props = Object.create(null ); this.protos = Object.create(null ); this.origins = [] ; this.curOrigin = "ecma5"; this.paths = Object.create(null ); this.definitions = Object.create(null ); this.purgeGen = 0; this.workList = null ; this.disabledComputing = null ; exports.withContext(this, function (){ cx.protos.Object = new Obj(null , "Object.prototype"); cx.topScope = new Scope(); cx.topScope.name = ""; cx.protos.Array = new Obj(true , "Array.prototype"); cx.protos.Function = new Obj(true , "Function.prototype"); cx.protos.RegExp = new Obj(true , "RegExp.prototype"); cx.protos.String = new Obj(true , "String.prototype"); cx.protos.Number = new Obj(true , "Number.prototype"); cx.protos.Boolean = new Obj(true , "Boolean.prototype"); cx.str = new Prim(cx.protos.String, "string"); cx.bool = new Prim(cx.protos.Boolean, "bool"); cx.num = new Prim(cx.protos.Number, "number"); cx.curOrigin = null ; if (defs) for (var i = 0; i < _AN_Read_length("length", defs); ++i)_AN_Call_load("load", def, defs[i]); } ); } ; var cx = null ; exports.cx = function (){ return cx; } ; exports.withContext = function (context, f){ var old = cx; cx = context; try { return f(); } finally{ cx = old; } } ; exports.addOrigin = function (origin){ if (cx.origins.indexOf(origin) < 0) cx.origins.push(origin); } ; var baseMaxWorkDepth = 20, reduceMaxWorkDepth = 0.0001; function withWorklist(f){ if (cx.workList) return f(cx.workList); var list = [] , depth = 0; var add = cx.workList = function (type, target, weight){ if (depth < baseMaxWorkDepth - reduceMaxWorkDepth * _AN_Read_length("length", list)) list.push(type, target, weight, depth); } ; try { var ret = f(add); for (var i = 0; i < _AN_Read_length("length", list); i += 4){ depth = list[i + 3] + 1; list[i + 1].addType(list[i], list[i + 2]); } return ret; } finally{ cx.workList = null ; } } var Scope = exports.Scope = function (prev){ Obj.call(this, prev || true ); this.prev = prev; } ; Scope.prototype = extend(Obj.prototype, { defVar: function (name, originNode){ for (var s = this; ; s = s.proto){ var found = s.props[name]; if (found) return found; if (!s.prev) return s.defProp(name, originNode); } } } ); function maybeInstantiate(scope, score){ if (scope.fnType) scope.fnType.instantiateScore = (scope.fnType.instantiateScore || 0) + score; } var NotSmaller = { } ; function nodeSmallerThan(node, n){ try { walk.simple(node, { Expression: function (){ if (--n <= 0) throw NotSmaller } } ); return true ; } catch (e) { if (e == NotSmaller) return false ; throw e } } function maybeTagAsInstantiated(node, scope){ var score = scope.fnType.instantiateScore; if (!cx.disabledComputing && score && _AN_Read_length("length", scope.fnType.args) && nodeSmallerThan(node, score * 5)) { maybeInstantiate(scope.prev, score / 2); setFunctionInstantiated(node, scope); return true ; } else { scope.fnType.instantiateScore = null ; } } function setFunctionInstantiated(node, scope){ var fn = scope.fnType; for (var i = 0; i < _AN_Read_length("length", fn.args); ++i)fn.args[i] = new AVal(); fn.self = new AVal(); fn.computeRet = function (self, args){ return withDisabledComputing(fn, function (){ var oldOrigin = cx.curOrigin; cx.curOrigin = fn.origin; var scopeCopy = new Scope(scope.prev); for (var v in scope.props){ var local = scopeCopy.defProp(v); for (var i = 0; i < _AN_Read_length("length", args); ++i)if (fn.argNames[i] == v && i < _AN_Read_length("length", args)) args[i].propagate(local); } var argNames = _AN_Read_length("length", fn.argNames) != _AN_Read_length("length", args)? fn.argNames.slice(0, _AN_Read_length("length", args)): fn.argNames; while (_AN_Read_length("length", argNames) < _AN_Read_length("length", args))argNames.push("?"); scopeCopy.fnType = new Fn(fn.name, self, args, argNames, ANull); if (fn.arguments) { var argset = scopeCopy.fnType.arguments = new AVal(); scopeCopy.defProp("arguments").addType(new Arr(argset)); for (var i = 0; i < _AN_Read_length("length", args); ++i)args[i].propagate(argset); } node.body.scope = scopeCopy; walk.recursive(node.body, scopeCopy, null , scopeGatherer); walk.recursive(node.body, scopeCopy, null , inferWrapper); cx.curOrigin = oldOrigin; return scopeCopy.fnType.retval; } ); } ; } function maybeTagAsGeneric(scope){ var fn = scope.fnType, target = fn.retval; if (target == ANull) return ; var targetInner, asArray; if (!target.isEmpty() && (targetInner = target.getType()) instanceof Arr) target = asArray = targetInner.getProp(""); function explore(aval, path, depth){ if (depth > 3 || !aval.forward) return ; for (var i = 0; i < _AN_Read_length("length", aval.forward); ++i){ var prop = aval.forward[i].propagatesTo(); if (!prop) continue ; var newPath = path, dest; if (prop instanceof AVal) { dest = prop; } else if (prop.target instanceof AVal) { newPath += prop.pathExt; dest = _AN_Read_target("target", prop); } else continue ; if (dest == target) return newPath; var found = explore(dest, newPath, depth + 1); if (found) return found; } } var foundPath = explore(fn.self, "!this", 0); for (var i = 0; !foundPath && i < _AN_Read_length("length", fn.args); ++i)foundPath = explore(fn.args[i], "!" + i, 0); if (foundPath) { if (asArray) foundPath = "[" + foundPath + "]"; var p = new def.TypeParser(foundPath); fn.computeRet = p.parseRetType(); fn.computeRetSource = foundPath; return true ; } } function addVar(scope, nameNode){ var val = scope.defProp(nameNode.name, nameNode); if (val.maybePurge) val.maybePurge = false ; return val; } var scopeGatherer = walk.make({ Function: function (node, scope, c){ var inner = node.body.scope = new Scope(scope); inner.node = node; var argVals = [] , argNames = [] ; for (var i = 0; i < _AN_Read_length("length", node.params); ++i){ var param = node.params[i]; argNames.push(param.name); argVals.push(addVar(inner, param)); } inner.fnType = new Fn(node.id && node.id.name, new AVal(), argVals, argNames, ANull); inner.fnType.originNode = node; if (node.id) { var decl = node.type == "FunctionDeclaration"; addVar(decl? scope: inner, node.id); } c(node.body, inner, "ScopeBody"); } , TryStatement: function (node, scope, c){ c(node.block, scope, "Statement"); if (node.handler) { var v = addVar(scope, node.handler.param); c(node.handler.body, scope, "ScopeBody"); var e5 = cx.definitions.ecma5; if (e5 && v.isEmpty()) getInstance(e5["Error.prototype"] ).propagate(v, WG_CATCH_ERROR); } if (node.finalizer) c(node.finalizer, scope, "Statement"); } , VariableDeclaration: function (node, scope, c){ for (var i = 0; i < _AN_Read_length("length", node.declarations); ++i){ var decl = node.declarations[i]; addVar(scope, decl.id); if (decl.init) c(decl.init, scope, "Expression"); } } } ); function propName(node, scope, c){ var prop = node.property; if (!node.computed) return prop.name; if (prop.type == "Literal" && typeof prop.value == "string") return prop.value; if (c) infer(prop, scope, c, ANull); return ""; } function unopResultType(op){ switch (op){ case "+": case "-": case "~": return cx.num; case "!": return cx.bool; case "typeof": return cx.str; case "void": case "delete": return ANull; } } function binopIsBoolean(op){ switch (op){ case "==": case "!=": case "===": case "!==": case "<": case ">": case ">=": case "<=": case "in": case "instanceof": return true ; } } function literalType(val){ switch (typeof val){ case "boolean": return cx.bool; case "number": return cx.num; case "string": return cx.str; case "object": case "function": if (!val) return ANull; return getInstance(cx.protos.RegExp); } } function ret(f){ return function (node, scope, c, out, name){ var r = f(node, scope, c, name); if (out) r.propagate(out); return r; } ; } function fill(f){ return function (node, scope, c, out, name){ if (!out) out = new AVal(); f(node, scope, c, out, name); return out; } ; } var inferExprVisitor = { ArrayExpression: ret(function (node, scope, c){ var eltval = new AVal(); for (var i = 0; i < _AN_Read_length("length", node.elements); ++i){ var elt = node.elements[i]; if (elt) infer(elt, scope, c, eltval); } return new Arr(eltval); } ), ObjectExpression: ret(function (node, scope, c, name){ var obj = node.objType = new Obj(true , name); obj.originNode = node; for (var i = 0; i < _AN_Read_length("length", node.properties); ++i){ var prop = node.properties[i], key = prop.key, name; if (key.type == "Identifier") { name = key.name; } else if (typeof key.value == "string") { name = key.value; } else { infer(prop.value, scope, c, ANull); continue ; } var val = obj.defProp(name, key); val.initializer = true ; infer(prop.value, scope, c, val, name); } return obj; } ), FunctionExpression: ret(function (node, scope, c, name){ var inner = node.body.scope, fn = inner.fnType; if (name && !fn.name) fn.name = name; c(node.body, scope, "ScopeBody"); maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner); if (node.id) inner.getProp(node.id.name).addType(fn); return fn; } ), SequenceExpression: ret(function (node, scope, c){ for (var i = 0, l = _AN_Read_length("length", node.expressions) - 1; i < l; ++i)infer(node.expressions[i], scope, c, ANull); return infer(node.expressions[l], scope, c); } ), UnaryExpression: ret(function (node, scope, c){ infer(node.argument, scope, c, ANull); return unopResultType(node.operator); } ), UpdateExpression: ret(function (node, scope, c){ infer(node.argument, scope, c, ANull); return cx.num; } ), BinaryExpression: ret(function (node, scope, c){ if (node.operator == "+") { var lhs = infer(node.left, scope, c); var rhs = infer(node.right, scope, c); if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; if (lhs.hasType(cx.num) && rhs.hasType(cx.num)) return cx.num; var result = new AVal(); lhs.propagate(new IsAdded(rhs, result)); rhs.propagate(new IsAdded(lhs, result)); return result; } else { infer(node.left, scope, c, ANull); infer(node.right, scope, c, ANull); return binopIsBoolean(node.operator)? cx.bool: cx.num; } } ), AssignmentExpression: ret(function (node, scope, c){ var rhs, name, pName; if (node.left.type == "MemberExpression") { pName = propName(node.left, scope, c); if (node.left.object.type == "Identifier") name = node.left.object.name + "." + pName; } else { name = node.left.name; } if (node.operator != "=" && node.operator != "+=") { infer(node.right, scope, c, ANull); rhs = cx.num; } else { rhs = infer(node.right, scope, c, null , name); } if (node.left.type == "MemberExpression") { var obj = infer(node.left.object, scope, c); if (pName == "prototype") maybeInstantiate(scope, 20); if (pName == "") { var v = node.left.property.name, local = scope.props[v], over = local && local.iteratesOver; if (over) { maybeInstantiate(scope, 20); var fromRight = node.right.type == "MemberExpression" && node.right.computed && node.right.property.name == v; over.forAllProps(function (prop, val, local){ if (local && prop != "prototype" && prop != "") obj.propagate(new PropHasSubset(prop, fromRight? val: ANull)); } ); return rhs; } } obj.propagate(new PropHasSubset(pName, rhs, node.left.property)); } else { var v = scope.defVar(node.left.name, node.left); if (v.maybePurge) v.maybePurge = false ; rhs.propagate(v); } return rhs; } ), LogicalExpression: fill(function (node, scope, c, out){ infer(node.left, scope, c, out); infer(node.right, scope, c, out); } ), ConditionalExpression: fill(function (node, scope, c, out){ infer(node.test, scope, c, ANull); infer(node.consequent, scope, c, out); infer(node.alternate, scope, c, out); } ), NewExpression: fill(function (node, scope, c, out, name){ if (node.callee.type == "Identifier" && node.callee.name in scope.props) maybeInstantiate(scope, 20); for (var i = 0, args = [] ; i < _AN_Read_length("length", node.arguments); ++i)args.push(infer(node.arguments[i], scope, c)); var callee = infer(node.callee, scope, c); var self = new AVal(); callee.propagate(new IsCtor(self, name && /\.prototype$/.test(name))); self.propagate(out, WG_NEW_INSTANCE); callee.propagate(new IsCallee(self, args, node.arguments, new IfObj(out))); } ), CallExpression: fill(function (node, scope, c, out){ for (var i = 0, args = [] ; i < _AN_Read_length("length", node.arguments); ++i)args.push(infer(node.arguments[i], scope, c)); if (node.callee.type == "MemberExpression") { var self = infer(node.callee.object, scope, c); var pName = propName(node.callee, scope, c); if ((pName == "call" || pName == "apply") && scope.fnType && scope.fnType.args.indexOf(self) > -1) maybeInstantiate(scope, 30); self.propagate(new HasMethodCall(pName, args, node.arguments, out)); } else { var callee = infer(node.callee, scope, c); if (scope.fnType && scope.fnType.args.indexOf(callee) > -1) maybeInstantiate(scope, 30); var knownFn = callee.getFunctionType(); if (knownFn && knownFn.instantiateScore && scope.fnType) maybeInstantiate(scope, knownFn.instantiateScore / 5); callee.propagate(new IsCallee(cx.topScope, args, node.arguments, out)); } } ), MemberExpression: fill(function (node, scope, c, out){ var name = propName(node, scope); var obj = infer(node.object, scope, c); var prop = obj.getProp(name); if (name == "") { var propType = infer(node.property, scope, c); if (!propType.hasType(cx.num)) return prop.propagate(out, WG_MULTI_MEMBER); } prop.propagate(out); } ), Identifier: ret(function (node, scope){ if (node.name == "arguments" && scope.fnType && !(node.name in scope.props)) scope.defProp(node.name, scope.fnType.originNode).addType(new Arr(scope.fnType.arguments = new AVal())); return scope.getProp(node.name); } ), ThisExpression: ret(function (_node, scope){ return scope.fnType? scope.fnType.self: cx.topScope; } ), Literal: ret(function (node){ return literalType(node.value); } )} ; function infer(node, scope, c, out, name){ return inferExprVisitor[node.type](node, scope, c, out, name); } var inferWrapper = walk.make({ Expression: function (node, scope, c){ infer(node, scope, c, ANull); } , FunctionDeclaration: function (node, scope, c){ var inner = node.body.scope, fn = inner.fnType; c(node.body, scope, "ScopeBody"); maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner); var prop = scope.getProp(node.id.name); prop.addType(fn); } , VariableDeclaration: function (node, scope, c){ for (var i = 0; i < _AN_Read_length("length", node.declarations); ++i){ var decl = node.declarations[i], prop = scope.getProp(decl.id.name); if (decl.init) infer(decl.init, scope, c, prop, decl.id.name); } } , ReturnStatement: function (node, scope, c){ if (node.argument && scope.fnType) { if (scope.fnType.retval == ANull) scope.fnType.retval = new AVal(); infer(node.argument, scope, c, scope.fnType.retval); } } , ForInStatement: function (node, scope, c){ var source = infer(node.right, scope, c); if ((node.right.type == "Identifier" && node.right.name in scope.props) || (node.right.type == "MemberExpression" && node.right.property.name == "prototype")) { maybeInstantiate(scope, 5); var varName; if (node.left.type == "Identifier") { varName = node.left.name; } else if (node.left.type == "VariableDeclaration") { varName = node.left.declarations[0].id.name; } if (varName && varName in scope.props) scope.getProp(varName).iteratesOver = source; } c(node.body, scope, "Statement"); } , ScopeBody: function (node, scope, c){ c(node, node.scope || scope); } } ); function runPasses(passes, pass){ var arr = passes && passes[pass]; var args = Array.prototype.slice.call(arguments, 2); if (arr) for (var i = 0; i < _AN_Read_length("length", arr); ++i)arr[i].apply(null , args); } var parse = exports.parse = function (text, passes, options){ var ast; try { ast = acorn.parse(text, options); } catch (e) { ast = acorn_loose.parse_dammit(text, options); } runPasses(passes, "postParse", ast, text); return ast; } ; exports.analyze = function (ast, name, scope, passes){ if (typeof ast == "string") ast = parse(ast); if (!name) name = "file#" + _AN_Read_length("length", cx.origins); exports.addOrigin(cx.curOrigin = name); if (!scope) scope = cx.topScope; walk.recursive(ast, scope, null , scopeGatherer); runPasses(passes, "preInfer", ast, scope); walk.recursive(ast, scope, null , inferWrapper); runPasses(passes, "postInfer", ast, scope); cx.curOrigin = null ; } ; exports.purgeTypes = function (origins, start, end){ var test = makePredicate(origins, start, end); ++cx.purgeGen; cx.topScope.purge(test); for (var prop in cx.props){ var list = cx.props[prop]; for (var i = 0; i < _AN_Read_length("length", list); ++i){ var obj = list[i], av = obj.props[prop]; if (!av || test(av, av.originNode)) list.splice(i-- , 1); } if (!_AN_Read_length("length", list)) delete cx.props[prop]; } } ; function makePredicate(origins, start, end){ var arr = Array.isArray(origins); if (arr && _AN_Read_length("length", origins) == 1) { origins = origins[0]; arr = false ; } if (arr) { if (end == null ) return function (n){ return origins.indexOf(n.origin) > -1; } ; return function (n, pos){ return pos && pos.start >= start && pos.end <= end && origins.indexOf(n.origin) > -1; } ; } else { if (end == null ) return function (n){ return n.origin == origins; } ; return function (n, pos){ return pos && pos.start >= start && pos.end <= end && n.origin == origins; } ; } } AVal.prototype.purge = function (test){ if (this.purgeGen == cx.purgeGen) return ; this.purgeGen = cx.purgeGen; for (var i = 0; i < _AN_Read_length("length", this.types); ++i){ var type = this.types[i]; if (test(type, type.originNode)) this.types.splice(i-- , 1); else type.purge(test); } if (this.forward) for (var i = 0; i < _AN_Read_length("length", this.forward); ++i){ var f = this.forward[i]; if (test(f)) { this.forward.splice(i-- , 1); if (this.props) this.props = null ; } else if (f.purge) { f.purge(test); } } } ; ANull.purge = function (){ } ; Obj.prototype.purge = function (test){ if (this.purgeGen == cx.purgeGen) return true ; this.purgeGen = cx.purgeGen; for (var p in this.props){ var av = this.props[p]; if (test(av, av.originNode)) this.removeProp(p); av.purge(test); } } ; Fn.prototype.purge = function (test){ if (Obj.prototype.purge.call(this, test)) return ; this.self.purge(test); this.retval.purge(test); for (var i = 0; i < _AN_Read_length("length", this.args); ++i)this.args[i].purge(test); } ; exports.markVariablesDefinedBy = function (scope, origins, start, end){ var test = makePredicate(origins, start, end); for (var s = scope; s; s = s.prev)for (var p in s.props){ var prop = s.props[p]; if (test(prop, prop.originNode)) { prop.maybePurge = true ; if (start == null && prop.originNode) prop.originNode = null ; } } } ; exports.purgeMarkedVariables = function (scope){ for (var s = scope; s; s = s.prev)for (var p in s.props)if (s.props[p].maybePurge) delete s.props[p]; } ; function findByPropertyName(name){ guessing = true ; var found = objsWithProp(name); if (found) for (var i = 0; i < _AN_Read_length("length", found); ++i){ var val = found[i].getProp(name); if (!val.isEmpty()) return val; } return ANull; } var typeFinder = { ArrayExpression: function (node, scope){ var eltval = new AVal(); for (var i = 0; i < _AN_Read_length("length", node.elements); ++i){ var elt = node.elements[i]; if (elt) findType(elt, scope).propagate(eltval); } return new Arr(eltval); } , ObjectExpression: function (node){ return node.objType; } , FunctionExpression: function (node){ return node.body.scope.fnType; } , SequenceExpression: function (node, scope){ return findType(node.expressions[_AN_Read_length("length", node.expressions) - 1], scope); } , UnaryExpression: function (node){ return unopResultType(node.operator); } , UpdateExpression: function (){ return cx.num; } , BinaryExpression: function (node, scope){ if (binopIsBoolean(node.operator)) return cx.bool; if (node.operator == "+") { var lhs = findType(node.left, scope); var rhs = findType(node.right, scope); if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; } return cx.num; } , AssignmentExpression: function (node, scope){ return findType(node.right, scope); } , LogicalExpression: function (node, scope){ var lhs = findType(node.left, scope); return lhs.isEmpty()? findType(node.right, scope): lhs; } , ConditionalExpression: function (node, scope){ var lhs = findType(node.consequent, scope); return lhs.isEmpty()? findType(node.alternate, scope): lhs; } , NewExpression: function (node, scope){ var f = findType(node.callee, scope).getFunctionType(); var proto = f && f.getProp("prototype").getType(); if (!proto) return ANull; return getInstance(proto, f); } , CallExpression: function (node, scope){ var f = findType(node.callee, scope).getFunctionType(); if (!f) return ANull; if (f.computeRet) { for (var i = 0, args = [] ; i < _AN_Read_length("length", node.arguments); ++i)args.push(findType(node.arguments[i], scope)); var self = ANull; if (node.callee.type == "MemberExpression") self = findType(node.callee.object, scope); return f.computeRet(self, args, node.arguments); } else { return f.retval; } } , MemberExpression: function (node, scope){ var propN = propName(node, scope), obj = findType(node.object, scope).getType(); if (obj) return obj.getProp(propN); if (propN == "") return ANull; return findByPropertyName(propN); } , Identifier: function (node, scope){ return scope.hasProp(node.name) || ANull; } , ThisExpression: function (_node, scope){ return scope.fnType? scope.fnType.self: cx.topScope; } , Literal: function (node){ return literalType(node.value); } } ; function findType(node, scope){ var found = typeFinder[node.type](node, scope); return found; } var searchVisitor = exports.searchVisitor = walk.make({ Function: function (node, _st, c){ var scope = node.body.scope; if (node.id) c(node.id, scope); for (var i = 0; i < _AN_Read_length("length", node.params); ++i)c(node.params[i], scope); c(node.body, scope, "ScopeBody"); } , TryStatement: function (node, st, c){ if (node.handler) c(node.handler.param, st); walk.base.TryStatement(node, st, c); } , VariableDeclaration: function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.declarations); ++i){ var decl = node.declarations[i]; c(decl.id, st); if (decl.init) c(decl.init, st, "Expression"); } } } ); exports.fullVisitor = walk.make({ MemberExpression: function (node, st, c){ c(node.object, st, "Expression"); c(node.property, st, node.computed? "Expression": null ); } , ObjectExpression: function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i){ c(node.properties[i].value, st, "Expression"); c(node.properties[i].key, st); } } } , searchVisitor); exports.findExpressionAt = function (ast, start, end, defaultScope, filter){ var test = filter || function (_t, node){ return typeFinder.hasOwnProperty(node.type); } ; return walk.findNodeAt(ast, start, end, test, searchVisitor, defaultScope || cx.topScope); } ; exports.findExpressionAround = function (ast, start, end, defaultScope, filter){ var test = filter || function (_t, node){ if (start != null && node.start > start) return false ; return typeFinder.hasOwnProperty(node.type); } ; return walk.findNodeAround(ast, end, test, searchVisitor, defaultScope || cx.topScope); } ; exports.expressionType = function (found){ return findType(found.node, found.state); } ; var guessing = false ; exports.resetGuessing = function (val){ guessing = val; } ; exports.didGuess = function (){ return guessing; } ; exports.forAllPropertiesOf = function (type, f){ type.gatherProperties(f, 0); } ; var refFindWalker = walk.make({ } , searchVisitor); exports.findRefs = function (ast, baseScope, name, refScope, f){ refFindWalker.Identifier = function (node, scope){ if (node.name != name) return ; for (var s = scope; s; s = s.prev){ if (s == refScope) f(node, scope); if (name in s.props) return ; } } ; walk.recursive(ast, baseScope, null , refFindWalker); } ; var simpleWalker = walk.make({ Function: function (node, _st, c){ c(node.body, node.body.scope, "ScopeBody"); } } ); exports.findPropRefs = function (ast, scope, objType, propName, f){ walk.simple(ast, { MemberExpression: function (node, scope){ if (node.computed || node.property.name != propName) return ; if (findType(node.object, scope).getType() == objType) f(node.property); } , ObjectExpression: function (node, scope){ if (findType(node, scope).getType() != objType) return ; for (var i = 0; i < _AN_Read_length("length", node.properties); ++i)if (node.properties[i].key.name == propName) f(node.properties[i].key); } } , simpleWalker, scope); } ; var scopeAt = exports.scopeAt = function (ast, pos, defaultScope){ var found = walk.findNodeAround(ast, pos, function (tp, node){ return tp == "ScopeBody" && node.scope; } ); if (found) return found.node.scope; else return defaultScope || cx.topScope; } ; exports.forAllLocalsAt = function (ast, pos, defaultScope, f){ var scope = scopeAt(ast, pos, defaultScope); scope.gatherProperties(f, 0); } ; def = exports.def = _AN_Call_init("init", def, { } , exports); } ); (function (){ Object.create = Object.create || (function (){ if (!({ __proto__: null } instanceof Object)) return function (base){ return { __proto__: base} ; } ; function ctor(){ } var frame = _AN_Call_appendchild("appendChild", document.body, _AN_Call_createelement("createElement", document, "iframe")); _AN_Write_src("src", frame, false , "javascript:"); var empty = frame.contentWindow.Object.prototype; delete empty.hasOwnProperty; delete empty.isPrototypeOf; delete empty.propertyIsEnumerable; delete empty.valueOf; delete empty.toString; delete empty.toLocaleString; delete empty.constructor; return function (base){ ctor.prototype = base || empty; return new ctor(); } ; } )(); var AP = Array.prototype; AP.some = AP.some || function (pred){ for (var i = 0; i < _AN_Read_length("length", this); ++i)if (pred(this[i], i)) return true ; } ; AP.forEach = AP.forEach || function (f){ for (var i = 0; i < _AN_Read_length("length", this); ++i)f(this[i], i); } ; AP.indexOf = AP.indexOf || function (x, start){ for (var i = start || 0; i < _AN_Read_length("length", this); ++i)if (this[i] === x) return i; return -1; } ; AP.lastIndexOf = AP.lastIndexOf || function (x, start){ for (var i = start == null ? _AN_Read_length("length", this) - 1: start; i >= 0; ++i)if (this[i] === x) return i; return -1; } ; AP.map = AP.map || function (f){ for (var r = [] , i = 0; i < _AN_Read_length("length", this); ++i)r.push(f(this[i], i)); return r; } ; Array.isArray = Array.isArray || function (v){ return Object.prototype.toString.call(v) == "[object Array]"; } ; String.prototype.trim = String.prototype.trim || function (){ var from = 0, to = _AN_Read_length("length", this); while (/\s/.test(this.charAt(from)))++from; while (/\s/.test(this.charAt(to - 1)))--to; return this.slice(from, to); } ; ; (function (){ var e = void 0, i = true , k = null , l = { } .toString, m, n, p = "function" === typeof define && define.c, q = !p && "object" == typeof exports && exports; q || p? "object" == typeof JSON && JSON? p? q = JSON: (q.stringify = JSON.stringify, q.parse = JSON.parse): p && (q = this.JSON = { } ): q = this.JSON || (this.JSON = { } ); var r, t, u, x, z, B, C, D, E, F, G, H, I, J = new Date(-3509827334573292), K, O, P; try { J = -109252 == J.getUTCFullYear() && 0 === J.getUTCMonth() && 1 == J.getUTCDate() && 10 == J.getUTCHours() && 37 == J.getUTCMinutes() && 6 == J.getUTCSeconds() && 708 == J.getUTCMilliseconds(); } catch (Q) { } function R(b){ var c, a, d, j = b == "json"; if (j || b == "json-stringify" || b == "json-parse") { if (b == "json-stringify" || j) { if (c = typeof q.stringify == "function" && J) { (d = function (){ return 1; } ).toJSON = d; try { c = q.stringify(0) === "0" && q.stringify(new Number()) === "0" && q.stringify(new String()) == '""' && q.stringify(l) === e && q.stringify(e) === e && q.stringify() === e && q.stringify(d) === "1" && q.stringify([d] ) == "[1]" && q.stringify([e] ) == "[null]" && q.stringify(k) == "null" && q.stringify([e, l, k] ) == "[null,null,null]" && q.stringify({ A: [d, i, false , k, "\x00\u0008\n\u000c\r\t"] } ) == '{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}' && q.stringify(k, d) === "1" && q.stringify([1, 2] , k, 1) == "[\n 1,\n 2\n]" && q.stringify(new Date(-8640000000000000)) == '"-271821-04-20T00:00:00.000Z"' && q.stringify(new Date(8640000000000000)) == '"+275760-09-13T00:00:00.000Z"' && q.stringify(new Date(-62198755200000)) == '"-000001-01-01T00:00:00.000Z"' && q.stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; } catch (f) { c = false ; } } if (!j) return c; } if (b == "json-parse" || j) { if (typeof q.parse == "function") try { if (q.parse("0") === 0 && !q.parse(false )) { d = q.parse('{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'); if (a = _AN_Read_length('length', d.a) == 5 && d.a[0] == 1) { try { a = !q.parse('"\t"'); } catch (o) { } if (a) try { a = q.parse("01") != 1; } catch (g) { } } } } catch (h) { a = false ; } if (!j) return a; } return c && a; } } if (!R("json")) { J || (K = Math.floor, O = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] , P = function (b, c){ return O[c] + 365 * (b - 1970) + K((b - 1969 + (c = + (c > 1))) / 4) - K((b - 1901 + c) / 100) + K((b - 1601 + c) / 400); } ); if (!(m = { } .hasOwnProperty)) m = function (b){ var c = { } , a; if ((c.__proto__ = k, c.__proto__ = { toString: 1} , c).toString != l) m = function (a){ var b = this.__proto__, a = a in (this.__proto__ = k, this); this.__proto__ = b; return a; } ; else { a = c.constructor; m = function (b){ var c = (this.constructor || a).prototype; return b in this && !(b in c && this[b] === c[b]); } ; } c = k; return m.call(this, b); } ; n = function (b, c){ var a = 0, d, j, f; (d = function (){ this.valueOf = 0; } ).prototype.valueOf = 0; j = new d(); for (f in j)m.call(j, f) && a++ ; d = j = k; if (a) a = a == 2? function (a, b){ var c = { } , d = l.call(a) == "[object Function]", f; for (f in a)!(d && f == "prototype") && !m.call(c, f) && (c[f] = 1) && m.call(a, f) && b(f); } : function (a, b){ var c = l.call(a) == "[object Function]", d, f; for (d in a)!(c && d == "prototype") && m.call(a, d) && !(f = d === "constructor") && b(d); (f || m.call(a, d = "constructor")) && b(d); } ; else { j = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"] ; a = function (a, b){ var c = l.call(a) == "[object Function]", d; for (d in a)!(c && d == "prototype") && m.call(a, d) && b(d); for (c = _AN_Read_length("length", j); d = j[--c]; m.call(a, d) && b(d)); } ; } a(b, c); } ; R("json-stringify") || (r = { "\\": "\\\\", '"': '\\"', "\u0008": "\\b", "\u000c": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t"} , t = function (b, c){ return ("000000" + (c || 0)).slice(- b); } , u = function (b){ for (var c = '"', a = 0, d; d = b.charAt(a); a++ )c = c + ('\\"\u0008\u000c\n\r\t'.indexOf(d) > -1? r[d]: r[d] = d < " "? "\\u00" + t(2, d.charCodeAt(0).toString(16)): d); return c + '"'; } , x = function (b, c, a, d, j, f, o){ var g = c[b], h, s, v, w, L, M, N, y, A; if (typeof g == "object" && g) { h = l.call(g); if (h == "[object Date]" && !m.call(g, "toJSON")) if (g > -1 / 0 && g < 1 / 0) { if (P) { v = K(g / 86400000); for (h = K(v / 365.2425) + 1970 - 1; P(h + 1, 0) <= v; h++ ); for (s = K((v - P(h, 0)) / 30.42); P(h, s + 1) <= v; s++ ); v = 1 + v - P(h, s); w = (g % 86400000 + 86400000) % 86400000; L = K(w / 3600000) % 24; M = K(w / 60000) % 60; N = K(w / 1000) % 60; w = w % 1000; } else { h = g.getUTCFullYear(); s = g.getUTCMonth(); v = g.getUTCDate(); L = g.getUTCHours(); M = g.getUTCMinutes(); N = g.getUTCSeconds(); w = g.getUTCMilliseconds(); } g = (h <= 0 || h >= 10000? (h < 0? "-": "+") + t(6, h < 0? - h: h): t(4, h)) + "-" + t(2, s + 1) + "-" + t(2, v) + "T" + t(2, L) + ":" + t(2, M) + ":" + t(2, N) + "." + t(3, w) + "Z"; } else g = k; else if (typeof g.toJSON == "function" && (h != "[object Number]" && h != "[object String]" && h != "[object Array]" || m.call(g, "toJSON"))) g = g.toJSON(b); } a && (g = a.call(c, b, g)); if (g === k) return "null"; h = l.call(g); if (h == "[object Boolean]") return "" + g; if (h == "[object Number]") return g > -1 / 0 && g < 1 / 0? "" + g: "null"; if (h == "[object String]") return u(g); if (typeof g == "object") { for (b = _AN_Read_length("length", o); b-- ; )if (o[b] === g) throw TypeError() o.push(g); y = [] ; c = f; f = f + j; if (h == "[object Array]") { s = 0; for (b = _AN_Read_length("length", g); s < b; A || (A = i), s++ ){ h = x(s, g, a, d, j, f, o); y.push(h === e? "null": h); } b = A? j? "[\n" + f + y.join(",\n" + f) + "\n" + c + "]": "[" + y.join(",") + "]": "[]"; } else { n(d || g, function (b){ var c = x(b, g, a, d, j, f, o); c !== e && y.push(u(b) + ":" + (j? " ": "") + c); A || (A = i); } ); b = A? j? "{\n" + f + y.join(",\n" + f) + "\n" + c + "}": "{" + y.join(",") + "}": "{}"; } o.pop(); return b; } } , q.stringify = function (b, c, a){ var d, j, f, o, g, h; if (typeof c == "function" || typeof c == "object" && c) if (l.call(c) == "[object Function]") j = c; else if (l.call(c) == "[object Array]") { f = { } ; o = 0; for (g = _AN_Read_length("length", c); o < g; h = c[o++ ], (l.call(h) == "[object String]" || l.call(h) == "[object Number]") && (f[h] = 1)); } if (a) if (l.call(a) == "[object Number]") { if ((a = a - a % 1) > 0) { d = ""; for (a > 10 && (a = 10); _AN_Read_length("length", d) < a; d = d + " "); } } else l.call(a) == "[object String]" && (d = _AN_Read_length("length", a) <= 10? a: a.slice(0, 10)); return x("", (h = { } , h[""] = b, h), j, f, d, "", [] ); } ); R("json-parse") || (z = String.fromCharCode, B = { "\\": "\\", '"': '"', "/": "/", b: "\u0008", t: "\t", n: "\n", f: "\u000c", r: "\r"} , C = function (){ H = I = k; throw SyntaxError() } , D = function (){ for (var b = I, c = _AN_Read_length("length", b), a, d, j, f, o; H < c; ){ a = b.charAt(H); if ("\t\r\n ".indexOf(a) > -1) H++ ; else { if ("{}[]:,".indexOf(a) > -1) { H++ ; return a; } if (a == '"') { d = "@"; for (H++ ; H < c; ){ a = b.charAt(H); if (a < " ") C(); else if (a == "\\") { a = b.charAt(++H); if ('\\"/btnfr'.indexOf(a) > -1) { d = d + B[a]; H++ ; } else if (a == "u") { j = ++H; for (f = H + 4; H < f; H++ ){ a = b.charAt(H); a >= "0" && a <= "9" || a >= "a" && a <= "f" || a >= "A" && a <= "F" || C(); } d = d + z("0x" + b.slice(j, H)); } else C(); } else { if (a == '"') break ; d = d + a; H++ ; } } if (b.charAt(H) == '"') { H++ ; return d; } } else { j = H; if (a == "-") { o = i; a = b.charAt(++H); } if (a >= "0" && a <= "9") { for (a == "0" && (a = b.charAt(H + 1), a >= "0" && a <= "9") && C(); H < c && (a = b.charAt(H), a >= "0" && a <= "9"); H++ ); if (b.charAt(H) == ".") { for (f = ++H; f < c && (a = b.charAt(f), a >= "0" && a <= "9"); f++ ); f == H && C(); H = f; } a = b.charAt(H); if (a == "e" || a == "E") { a = b.charAt(++H); (a == "+" || a == "-") && H++ ; for (f = H; f < c && (a = b.charAt(f), a >= "0" && a <= "9"); f++ ); f == H && C(); H = f; } return + b.slice(j, H); } o && C(); if (b.slice(H, H + 4) == "true") { H = H + 4; return i; } if (b.slice(H, H + 5) == "false") { H = H + 5; return false ; } if (b.slice(H, H + 4) == "null") { H = H + 4; return k; } } C(); } } return "$"; } , E = function (b){ var c, a; b == "$" && C(); if (typeof b == "string") { if (b.charAt(0) == "@") return b.slice(1); if (b == "[") { for (c = [] ; ; a || (a = i)){ b = D(); if (b == "]") break ; if (a) if (b == ",") { b = D(); b == "]" && C(); } else C(); b == "," && C(); c.push(E(b)); } return c; } if (b == "{") { for (c = { } ; ; a || (a = i)){ b = D(); if (b == "}") break ; if (a) if (b == ",") { b = D(); b == "}" && C(); } else C(); (b == "," || typeof b != "string" || b.charAt(0) != "@" || D() != ":") && C(); c[b.slice(1)] = E(D()); } return c; } C(); } return b; } , G = function (b, c, a){ a = F(b, c, a); a === e? delete b[c]: b[c] = a; } , F = function (b, c, a){ var d = b[c], j; if (typeof d == "object" && d) if (l.call(d) == "[object Array]") for (j = _AN_Read_length("length", d); j-- ; )G(d, j, a); else n(d, function (b){ G(d, b, a); } ); return a.call(b, c, d); } , q.parse = function (b, c){ var a, d; H = 0; I = b; a = E(D()); D() != "$" && C(); H = I = k; return c && l.call(c) == "[object Function]"? F((d = { } , d[""] = a, d), "", c): a; } ); } p && define(function (){ return q; } ); } ()); } )(); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports); if (typeof define == "function" && define.amd) return define(["exports"] , mod); mod((self.tern || (self.tern = { } )).signal = { } ); } )(function (exports){ function on(type, f){ var handlers = this._handlers || (this._handlers = Object.create(null )); (handlers[type] || (handlers[type] = [] )).push(f); } function off(type, f){ var arr = this._handlers && this._handlers[type]; if (arr) for (var i = 0; i < _AN_Read_length("length", arr); ++i)if (arr[i] == f) { arr.splice(i, 1); break ; } } function signal(type, a1, a2, a3, a4){ var arr = this._handlers && this._handlers[type]; if (arr) for (var i = 0; i < _AN_Read_length("length", arr); ++i)arr[i].call(this, a1, a2, a3, a4); } exports.mixin = function (obj){ obj.on = on; obj.off = off; obj.signal = signal; return obj; } ; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./infer"), require("./signal"), require("acorn"), require("walk")); if (typeof define == "function" && define.amd) return define(["exports", "./infer", "./signal", "acorn", "walk"] , mod); mod(self.tern || (self.tern = { } ), tern, tern.signal, acorn, acorn.walk); } )(function (exports, infer, signal, acorn, walk){ "use strict"; var plugins = Object.create(null ); exports.registerPlugin = function (name, init){ plugins[name] = init; } ; var defaultOptions = { debug: false , async: false , getFile: function (_f, c){ if (this.async) c(null , null ); } , defs: [] , plugins: { } , fetchTimeout: 1000} ; var queryTypes = { completions: { takesFile: true , run: findCompletions} , properties: { run: findProperties} , type: { takesFile: true , run: findTypeAt} , documentation: { takesFile: true , run: findDocs} , definition: { takesFile: true , run: findDef} , refs: { takesFile: true , fullFile: true , run: findRefs} , rename: { takesFile: true , fullFile: true , run: buildRename} , files: { run: listFiles} } ; exports.defineQueryType = function (name, desc){ queryTypes[name] = desc; } ; function File(name){ this.name = name; this.scope = _AN_Write_text("text", this, false , this.ast = this.lineOffsets = null ); } File.prototype.asLineChar = function (pos){ return asLineChar(this, pos); } ; function updateText(file, text, srv){ _AN_Write_text("text", file, false , text); file.ast = infer.parse(text, srv.passes, { directSourceFile: file} ); file.lineOffsets = null ; } var Server = exports.Server = function (options){ this.cx = null ; this.options = options || { } ; for (var o in defaultOptions)if (!options.hasOwnProperty(o)) options[o] = defaultOptions[o]; this.handlers = Object.create(null ); this.files = [] ; this.uses = 0; this.pending = 0; this.asyncError = null ; this.passes = Object.create(null ); this.defs = options.defs.slice(0); for (var plugin in options.plugins)if (options.plugins.hasOwnProperty(plugin) && plugin in plugins) { var init = plugins[plugin](this, options.plugins[plugin]); if (init && init.defs) { if (init.loadFirst) this.defs.unshift(init.defs); else this.defs.push(init.defs); } if (init && init.passes) for (var type in init.passes)if (init.passes.hasOwnProperty(type)) (this.passes[type] || (this.passes[type] = [] )).push(init.passes[type]); } this.reset(); } ; Server.prototype = signal.mixin({ addFile: function (name, text){ ensureFile(this, name, text); } , delFile: function (name){ for (var i = 0, f; i < _AN_Read_length("length", this.files); ++i)if ((f = this.files[i]).name == name) { clearFile(this, f); this.files.splice(i-- , 1); return ; } } , reset: function (){ this.signal("reset"); this.cx = new infer.Context(this.defs, this); this.uses = 0; for (var i = 0; i < _AN_Read_length("length", this.files); ++i){ var file = this.files[i]; file.scope = null ; } } , request: function (doc, c){ var inv = invalidDoc(doc); if (inv) return c(inv); var self = this; doRequest(this, doc, function (err, data){ c(err, data); if (self.uses > 40) { self.reset(); analyzeAll(self, function (){ } ); } } ); } , findFile: function (name){ return findFile(this.files, name); } , flush: function (c){ var cx = this.cx; analyzeAll(this, function (err){ if (err) return c(err); infer.withContext(cx, c); } ); } , startAsyncAction: function (){ ++this.pending; } , finishAsyncAction: function (err){ if (err) this.asyncError = err; if (--this.pending == 0) this.signal("everythingFetched"); } } ); function doRequest(srv, doc, c){ if (doc.query && !queryTypes.hasOwnProperty(doc.query.type)) return c("No query type '" + doc.query.type + "' defined"); var query = doc.query; if (!query) c(null , { } ); var files = doc.files || [] ; if (files.length) ++srv.uses; for (var i = 0; i < _AN_Read_length("length", files); ++i){ var file = files[i]; ensureFile(srv, file.name, file.type == "full"? file.text: null ); } if (!query) { analyzeAll(srv, function (){ } ); return ; } var queryType = queryTypes[query.type]; if (queryType.takesFile) { if (typeof query.file != "string") return c(".query.file must be a string"); if (!/^#/.test(query.file)) ensureFile(srv, query.file); } analyzeAll(srv, function (err){ if (err) return c(err); var file = queryType.takesFile && resolveFile(srv, files, query.file); if (queryType.fullFile && file.type == "part") return c("Can't run a " + query.type + " query on a file fragment"); infer.withContext(srv.cx, function (){ var result; try { result = queryType.run(srv, query, file); } catch (e) { if (srv.options.debug && e.name != "TernError") console.error(e.stack); return c(e); } c(null , result); } ); } ); } function analyzeFile(srv, file){ infer.withContext(srv.cx, function (){ file.scope = srv.cx.topScope; srv.signal("beforeLoad", file); infer.markVariablesDefinedBy(file.scope, file.name); infer.analyze(file.ast, file.name, file.scope, srv.passes); infer.purgeMarkedVariables(file.scope); srv.signal("afterLoad", file); } ); return file; } function ensureFile(srv, name, text){ var known = findFile(srv.files, name); if (known) { if (text) clearFile(srv, known, text); return ; } var file = new File(name); srv.files.push(file); if (text) { updateText(file, text, srv); } else if (srv.options.async) { srv.startAsyncAction(); srv.options.getFile(name, function (err, text){ updateText(file, text || "", srv); srv.finishAsyncAction(err); } ); } else { updateText(file, srv.options.getFile(name) || "", srv); } } function clearFile(srv, file, newText){ if (file.scope) { infer.withContext(srv.cx, function (){ infer.purgeTypes(file.name); infer.markVariablesDefinedBy(file.scope, file.name); infer.purgeMarkedVariables(file.scope); } ); file.scope = null ; } if (newText != null ) updateText(file, newText, srv); } function fetchAll(srv, c){ var done = true , returned = false ; for (var i = 0; i < _AN_Read_length("length", srv.files); ++i){ var file = srv.files[i]; if (file.text != null ) continue ; if (srv.options.async) { done = false ; srv.options.getFile(file.name, function (err, text){ if (err && !returned) { returned = true ; return c(err); } updateText(file, text || "", srv); fetchAll(srv, c); } ); } else { try { updateText(file, srv.options.getFile(file.name) || "", srv); } catch (e) { return c(e); } } } if (done) c(); } function waitOnFetch(srv, c){ var done = function (){ srv.off("everythingFetched", done); clearTimeout(timeout); analyzeAll(srv, c); } ; srv.on("everythingFetched", done); var timeout = _AN_Call_settimeout("setTimeout", window, done, srv.options.fetchTimeout); } function analyzeAll(srv, c){ if (srv.pending) return waitOnFetch(srv, c); var e = srv.fetchError; if (e) { srv.fetchError = null ; return c(e); } var done = true ; for (var i = 0; i < _AN_Read_length("length", srv.files); ++i){ var file = srv.files[i]; if (file.text == null ) done = false ; else if (file.scope == null ) analyzeFile(srv, file); } if (done) c(); else waitOnFetch(srv, c); } function findFile(arr, name){ for (var i = 0; i < _AN_Read_length("length", arr); ++i){ var file = arr[i]; if (file.name == name && file.type != "part") return file; } } function firstLine(str){ var end = str.indexOf("\n"); if (end < 0) return str; return str.slice(0, end); } function findMatchingPosition(line, file, near){ var pos = Math.max(0, near - 500), closest = null ; if (!/^\s*$/.test(line)) for (; ; ){ var found = file.indexOf(line, pos); if (found < 0 || found > near + 500) break ; if (closest == null || Math.abs(closest - near) > Math.abs(found - near)) closest = found; pos = found + _AN_Read_length("length", line); } return closest; } function scopeDepth(s){ for (var i = 0; s; ++i, s = s.prev){ } return i; } function ternError(msg){ var err = new Error(msg); err.name = "TernError"; return err; } function resolveFile(srv, localFiles, name){ var isRef = name.match(/^#(\d+)$/); if (!isRef) return findFile(srv.files, name); var file = localFiles[isRef[1]]; if (!file) throw ternError("Reference to unknown file " + name) if (file.type == "full") return findFile(srv.files, file.name); var realFile = file.backing = findFile(srv.files, file.name); var offset = file.offset; if (file.offsetLines) offset = { line: file.offsetLines, ch: 0} ; file.offset = offset = resolvePos(realFile, file.offsetLines == null ? file.offset: { line: file.offsetLines, ch: 0} , true ); var line = firstLine(file.text); var foundPos = findMatchingPosition(line, realFile.text, offset); var pos = foundPos == null ? Math.max(0, realFile.text.lastIndexOf("\n", offset)): foundPos; infer.withContext(srv.cx, function (){ infer.purgeTypes(file.name, pos, pos + _AN_Read_length("length", file.text)); var text = file.text, m; if (m = text.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/)) { var objNode = walk.findNodeAround(file.backing.ast, pos, "ObjectExpression"); if (objNode && objNode.node.objType) var inObject = { type: objNode.node.objType, prop: m[2] || m[1]} ; } if (foundPos && (m = line.match(/^(.*?)\bfunction\b/))) { var cut = _AN_Read_length("length", m[1]), white = ""; for (var i = 0; i < cut; ++i)white += " "; text = white + text.slice(cut); var atFunction = true ; } var scopeStart = infer.scopeAt(realFile.ast, pos, realFile.scope); var scopeEnd = infer.scopeAt(realFile.ast, pos + _AN_Read_length("length", text), realFile.scope); var scope = file.scope = scopeDepth(scopeStart) < scopeDepth(scopeEnd)? scopeEnd: scopeStart; infer.markVariablesDefinedBy(scopeStart, file.name, pos, pos + _AN_Read_length("length", file.text)); file.ast = infer.parse(file.text, srv.passes, { directSourceFile: file} ); infer.analyze(file.ast, file.name, scope, srv.passes); infer.purgeMarkedVariables(scopeStart); tieTogether: if (inObject || atFunction) { var newInner = infer.scopeAt(file.ast, _AN_Read_length("length", line), scopeStart); if (!newInner.fnType) break tieTogether; if (inObject) { var prop = inObject.type.getProp(inObject.prop); prop.addType(newInner.fnType); } else if (atFunction) { var inner = infer.scopeAt(realFile.ast, pos + _AN_Read_length("length", line), realFile.scope); if (inner == scopeStart || !inner.fnType) break tieTogether; var fOld = inner.fnType, fNew = newInner.fnType; if (!fNew || (fNew.name != fOld.name && fOld.name)) break tieTogether; for (var i = 0, e = Math.min(_AN_Read_length("length", fOld.args), _AN_Read_length("length", fNew.args)); i < e; ++i)fOld.args[i].propagate(fNew.args[i]); fOld.self.propagate(fNew.self); fNew.retval.propagate(fOld.retval); } } } ); return file; } function isPosition(val){ return typeof val == "number" || typeof val == "object" && typeof val.line == "number" && typeof val.ch == "number"; } function invalidDoc(doc){ if (doc.query) { if (typeof doc.query.type != "string") return ".query.type must be a string"; if (doc.query.start && !isPosition(doc.query.start)) return ".query.start must be a position"; if (doc.query.end && !isPosition(doc.query.end)) return ".query.end must be a position"; } if (doc.files) { if (!Array.isArray(doc.files)) return "Files property must be an array"; for (var i = 0; i < _AN_Read_length("length", doc.files); ++i){ var file = doc.files[i]; if (typeof file != "object") return ".files[n] must be objects"; else if (typeof file.text != "string") return ".files[n].text must be a string"; else if (typeof file.name != "string") return ".files[n].name must be a string"; else if (file.type == "part") { if (!isPosition(file.offset) && typeof file.offsetLines != "number") return ".files[n].offset must be a position"; } else if (file.type != "full") return ".files[n].type must be \"full\" or \"part\""; } } } var offsetSkipLines = 25; function findLineStart(file, line){ var text = file.text, offsets = file.lineOffsets || (file.lineOffsets = [0] ); var pos = 0, curLine = 0; var storePos = Math.min(Math.floor(line / offsetSkipLines), _AN_Read_length("length", offsets) - 1); var pos = offsets[storePos], curLine = storePos * offsetSkipLines; while (curLine < line){ ++curLine; pos = text.indexOf("\n", pos) + 1; if (pos == 0) return null ; if (curLine % offsetSkipLines == 0) offsets.push(pos); } return pos; } function resolvePos(file, pos, tolerant){ if (typeof pos != "number") { var lineStart = findLineStart(file, pos.line); if (lineStart == null ) { if (tolerant) pos = _AN_Read_length("length", file.text); else throw ternError("File doesn't contain a line " + pos.line) } else { pos = lineStart + pos.ch; } } if (pos > _AN_Read_length("length", file.text)) { if (tolerant) pos = _AN_Read_length("length", file.text); else throw ternError("Position " + pos + " is outside of file.") } return pos; } function asLineChar(file, pos){ if (!file) return { line: 0, ch: 0} ; var offsets = file.lineOffsets || (file.lineOffsets = [0] ); var text = file.text, line, lineStart; for (var i = _AN_Read_length("length", offsets) - 1; i >= 0; --i)if (offsets[i] <= pos) { line = i * offsetSkipLines; lineStart = offsets[i]; } for (; ; ){ var eol = text.indexOf("\n", lineStart); if (eol >= pos || eol < 0) break ; lineStart = eol + 1; ++line; } return { line: line, ch: pos - lineStart} ; } function outputPos(query, file, pos){ if (query.lineCharPositions) { var out = asLineChar(file, pos); if (file.type == "part") out.line += file.offsetLines != null ? file.offsetLines: asLineChar(file.backing, file.offset).line; return out; } else { return pos + (file.type == "part"? file.offset: 0); } } function clean(obj){ for (var prop in obj)if (obj[prop] == null ) delete obj[prop]; return obj; } function maybeSet(obj, prop, val){ if (val != null ) obj[prop] = val; } function compareCompletions(a, b){ if (typeof a != "string") { a = a.name; b = b.name; } var aUp = /^[A-Z]/.test(a), bUp = /^[A-Z]/.test(b); if (aUp == bUp) return a < b? -1: a == b? 0: 1; else return aUp? 1: -1; } function isStringAround(node, start, end){ return node.type == "Literal" && typeof node.value == "string" && node.start == start - 1 && node.end <= end + 1; } function findCompletions(srv, query, file){ if (query.end == null ) throw ternError("missing .query.end field") var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text; while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1)))--wordStart; if (query.expandWordForward !== false ) while (wordEnd < _AN_Read_length("length", text) && acorn.isIdentifierChar(text.charCodeAt(wordEnd)))++wordEnd; var word = text.slice(wordStart, wordEnd), completions = [] ; if (query.caseInsensitive) word = word.toLowerCase(); var wrapAsObjs = query.types || query.depths || query.docs || query.urls || query.origins; function gather(prop, obj, depth){ if (query.omitObjectPrototype !== false && obj == srv.cx.protos.Object && !word) return ; if (query.filter !== false && word && (query.caseInsensitive? prop.toLowerCase(): prop).indexOf(word) != 0) return ; for (var i = 0; i < _AN_Read_length("length", completions); ++i){ var c = completions[i]; if ((wrapAsObjs? c.name: c) == prop) return ; } var rec = wrapAsObjs? { name: prop} : prop; completions.push(rec); if (query.types || query.docs || query.urls || query.origins) { var val = obj? obj.props[prop]: infer.ANull; infer.resetGuessing(); var type = val.getType(); rec.guess = infer.didGuess(); if (query.types) rec.type = infer.toString(type); if (query.docs) maybeSet(rec, "doc", val.doc || type && type.doc); if (query.urls) maybeSet(rec, "url", _AN_Read_url("url", val) || type && _AN_Read_url("url", type)); if (query.origins) maybeSet(rec, "origin", val.origin || type && type.origin); } if (query.depths) rec.depth = depth; } var memberExpr = infer.findExpressionAround(file.ast, null , wordStart, file.scope, "MemberExpression"); if (memberExpr && (memberExpr.node.computed? isStringAround(memberExpr.node.property, wordStart, wordEnd): memberExpr.node.object.end < wordStart)) { var prop = memberExpr.node.property; prop = prop.type == "Literal"? prop.value.slice(1): prop.name; memberExpr.node = memberExpr.node.object; var tp = infer.expressionType(memberExpr); if (tp) infer.forAllPropertiesOf(tp, gather); if (!_AN_Read_length("length", completions) && query.guess !== false && tp && tp.guessProperties) { tp.guessProperties(function (p, o, d){ if (p != prop && p != "✖") gather(p, o, d); } ); } if (!_AN_Read_length("length", completions) && _AN_Read_length("length", word) >= 2 && query.guess !== false ) for (var prop in srv.cx.props)gather(prop, srv.cx.props[prop][0], 0); } else { infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather); } if (query.sort !== false ) completions.sort(compareCompletions); return { start: outputPos(query, file, wordStart), end: outputPos(query, file, wordEnd), completions: completions} ; } function findProperties(srv, query){ var prefix = query.prefix, found = [] ; for (var prop in srv.cx.props)if (prop != "" && (!prefix || prop.indexOf(prefix) == 0)) found.push(prop); if (query.sort !== false ) found.sort(compareCompletions); return { completions: found} ; } var findExpr = exports.findQueryExpr = function (file, query, wide){ if (query.end == null ) throw ternError("missing .query.end field") if (query.variable) { var scope = infer.scopeAt(file.ast, resolvePos(file, query.end), file.scope); return { node: { type: "Identifier", name: query.variable, start: query.end, end: query.end + 1} , state: scope} ; } else { var start = query.start && resolvePos(file, query.start), end = resolvePos(file, query.end); var expr = infer.findExpressionAt(file.ast, start, end, file.scope); if (expr) return expr; expr = infer.findExpressionAround(file.ast, start, end, file.scope); if (expr && (wide || (start == null ? end: start) - expr.node.start < 20 || expr.node.end - end < 20)) return expr; throw ternError("No expression at the given position.") } } ; function findTypeAt(_srv, query, file){ var expr = findExpr(file, query); infer.resetGuessing(); var type = infer.expressionType(expr); if (query.preferFunction) type = type.getFunctionType() || type.getType(); else type = type.getType(); if (expr.node.type == "Identifier") var exprName = expr.node.name; else if (expr.node.type == "MemberExpression" && !expr.node.computed) var exprName = expr.node.property.name; if (query.depth != null && typeof query.depth != "number") throw ternError(".query.depth must be a number") var result = { guess: infer.didGuess(), type: infer.toString(type, query.depth), name: type && type.name, exprName: exprName} ; if (type) storeTypeDocs(type, result); return clean(result); } function findDocs(_srv, query, file){ var expr = findExpr(file, query); var type = infer.expressionType(expr); var result = { url: _AN_Read_url("url", type), doc: type.doc} ; var inner = type.getType(); if (inner) storeTypeDocs(inner, result); return clean(result); } function storeTypeDocs(type, out){ if (!_AN_Read_url("url", out)) _AN_Write_url("url", out, false , _AN_Read_url("url", type)); if (!out.doc) out.doc = type.doc; if (!out.origin) out.origin = type.origin; var ctor, boring = infer.cx().protos; if (!_AN_Read_url("url", out) && !out.doc && type.proto && (ctor = type.proto.hasCtor) && type.proto != boring.Object && type.proto != boring.Function && type.proto != boring.Array) { _AN_Write_url("url", out, false , _AN_Read_url("url", ctor)); out.doc = ctor.doc; } } var getSpan = exports.getSpan = function (obj){ if (!obj.origin) return ; if (obj.originNode) { var node = obj.originNode; if (/^Function/.test(node.type) && node.id) node = node.id; return { origin: obj.origin, node: node} ; } if (obj.span) return { origin: obj.origin, span: obj.span} ; } ; var storeSpan = exports.storeSpan = function (srv, query, span, target){ target.origin = span.origin; if (span.span) { var m = /^(\d+)\[(\d+):(\d+)\]-(\d+)\[(\d+):(\d+)\]$/.exec(span.span); target.start = query.lineCharPositions? { line: Number(m[2]), ch: Number(m[3])} : Number(m[1]); target.end = query.lineCharPositions? { line: Number(m[5]), ch: Number(m[6])} : Number(m[4]); } else { var file = findFile(srv.files, span.origin); target.start = outputPos(query, file, span.node.start); target.end = outputPos(query, file, span.node.end); } } ; function findDef(srv, query, file){ var expr = findExpr(file, query); infer.resetGuessing(); var type = infer.expressionType(expr); if (infer.didGuess()) return { } ; var span = getSpan(type); var result = { url: _AN_Read_url("url", type), doc: type.doc, origin: type.origin} ; if (type.types) for (var i = _AN_Read_length("length", type.types) - 1; i >= 0; --i){ var tp = type.types[i]; storeTypeDocs(tp, result); if (!span) span = getSpan(tp); } if (span && span.node) { var spanFile = span.node.sourceFile || findFile(srv.files, span.origin); var start = outputPos(query, spanFile, span.node.start), end = outputPos(query, spanFile, span.node.end); result.start = start; result.end = end; result.file = span.origin; var cxStart = Math.max(0, span.node.start - 50); result.contextOffset = span.node.start - cxStart; result.context = spanFile.text.slice(cxStart, cxStart + 50); } else if (span) { result.file = span.origin; storeSpan(srv, query, span, result); } return clean(result); } function findRefsToVariable(srv, query, file, expr, checkShadowing){ var name = expr.node.name; for (var scope = expr.state; scope && !(name in scope.props); scope = scope.prev){ } if (!scope) throw ternError("Could not find a definition for " + name + " " + !!srv.cx.topScope.props.x) var type, refs = [] ; function storeRef(file){ return function (node, scopeHere){ if (checkShadowing) for (var s = scopeHere; s != scope; s = s.prev){ var exists = s.hasProp(checkShadowing); if (exists) throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would make a variable at line " + (asLineChar(file, node.start).line + 1) + " point to the definition at line " + (asLineChar(file, exists.name.start).line + 1)) } refs.push({ file: file.name, start: outputPos(query, file, node.start), end: outputPos(query, file, node.end)} ); } ; } if (scope.node) { type = "local"; if (checkShadowing) { for (var prev = scope.prev; prev; prev = prev.prev)if (checkShadowing in prev.props) break ; if (prev) infer.findRefs(scope.node, scope, checkShadowing, prev, function (node){ throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would shadow the definition used at line " + (asLineChar(file, node.start).line + 1)) } ); } infer.findRefs(scope.node, scope, name, scope, storeRef(file)); } else { type = "global"; for (var i = 0; i < _AN_Read_length("length", srv.files); ++i){ var cur = srv.files[i]; infer.findRefs(cur.ast, cur.scope, name, scope, storeRef(cur)); } } return { refs: refs, type: type, name: name} ; } function findRefsToProperty(srv, query, expr, prop){ var objType = infer.expressionType(expr).getType(); if (!objType) throw ternError("Couldn't determine type of base object.") var refs = [] ; function storeRef(file){ return function (node){ refs.push({ file: file.name, start: outputPos(query, file, node.start), end: outputPos(query, file, node.end)} ); } ; } for (var i = 0; i < _AN_Read_length("length", srv.files); ++i){ var cur = srv.files[i]; infer.findPropRefs(cur.ast, cur.scope, objType, prop.name, storeRef(cur)); } return { refs: refs, name: prop.name} ; } function findRefs(srv, query, file){ var expr = findExpr(file, query, true ); if (expr && expr.node.type == "Identifier") { return findRefsToVariable(srv, query, file, expr); } else if (expr && expr.node.type == "MemberExpression" && !expr.node.computed) { var p = expr.node.property; expr.node = expr.node.object; return findRefsToProperty(srv, query, expr, p); } else if (expr && expr.node.type == "ObjectExpression") { var pos = resolvePos(file, query.end); for (var i = 0; i < _AN_Read_length("length", expr.node.properties); ++i){ var k = expr.node.properties[i].key; if (k.start <= pos && k.end >= pos) return findRefsToProperty(srv, query, expr, k); } } throw ternError("Not at a variable or property name.") } function buildRename(srv, query, file){ if (typeof query.newName != "string") throw ternError(".query.newName should be a string") var expr = findExpr(file, query); if (!expr || expr.node.type != "Identifier") throw ternError("Not at a variable.") var data = findRefsToVariable(srv, query, file, expr, query.newName), refs = data.refs; delete data.refs; data.files = srv.files.map(function (f){ return f.name; } ); var changes = data.changes = [] ; for (var i = 0; i < _AN_Read_length("length", refs); ++i){ var use = refs[i]; _AN_Write_text("text", use, false , query.newName); changes.push(use); } return data; } function listFiles(srv){ return { files: srv.files.map(function (f){ return f.name; } )} ; } exports.version = "0.5.1"; } ); (function (mod){ if (typeof exports == "object" && typeof module == "object") return mod(exports); if (typeof define == "function" && define.amd) return define(["exports"] , mod); mod((this.acorn || (this.acorn = { } )).walk = { } ); } )(function (exports){ "use strict"; exports.simple = function (node, visitors, base, state){ if (!base) base = exports.base; function c(node, st, override){ var type = override || node.type, found = visitors[type]; base[type](node, st, c); if (found) found(node, st); } c(node, state); } ; exports.recursive = function (node, state, funcs, base){ var visitor = funcs? exports.make(funcs, base): base; function c(node, st, override){ visitor[override || node.type](node, st, c); } c(node, state); } ; function makeTest(test){ if (typeof test == "string") return function (type){ return type == test; } ; else if (!test) return function (){ return true ; } ; else return test; } function Found(node, state){ this.node = node; this.state = state; } exports.findNodeAt = function (node, start, end, test, base, state){ test = makeTest(test); try { if (!base) base = exports.base; var c = function (node, st, override){ var type = override || node.type; if ((start == null || node.start <= start) && (end == null || node.end >= end)) base[type](node, st, c); if (test(type, node) && (start == null || node.start == start) && (end == null || node.end == end)) throw new Found(node, st) } ; c(node, state); } catch (e) { if (e instanceof Found) return e; throw e } } ; exports.findNodeAround = function (node, pos, test, base, state){ test = makeTest(test); try { if (!base) base = exports.base; var c = function (node, st, override){ var type = override || node.type; if (node.start > pos || node.end < pos) return ; base[type](node, st, c); if (test(type, node)) throw new Found(node, st) } ; c(node, state); } catch (e) { if (e instanceof Found) return e; throw e } } ; exports.findNodeAfter = function (node, pos, test, base, state){ test = makeTest(test); try { if (!base) base = exports.base; var c = function (node, st, override){ if (node.end < pos) return ; var type = override || node.type; if (node.start >= pos && test(type, node)) throw new Found(node, st) base[type](node, st, c); } ; c(node, state); } catch (e) { if (e instanceof Found) return e; throw e } } ; exports.findNodeBefore = function (node, pos, test, base, state){ test = makeTest(test); if (!base) base = exports.base; var max; var c = function (node, st, override){ if (node.start > pos) return ; var type = override || node.type; if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node)) max = new Found(node, st); base[type](node, st, c); } ; c(node, state); return max; } ; exports.make = function (funcs, base){ if (!base) base = exports.base; var visitor = { } ; for (var type in base)visitor[type] = base[type]; for (var type in funcs)visitor[type] = funcs[type]; return visitor; } ; function skipThrough(node, st, c){ c(node, st); } function ignore(_node, _st, _c){ } var base = exports.base = { } ; base.Program = base.BlockStatement = function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.body); ++i)c(node.body[i], st, "Statement"); } ; base.Statement = skipThrough; base.EmptyStatement = ignore; base.ExpressionStatement = function (node, st, c){ c(node.expression, st, "Expression"); } ; base.IfStatement = function (node, st, c){ c(node.test, st, "Expression"); c(node.consequent, st, "Statement"); if (node.alternate) c(node.alternate, st, "Statement"); } ; base.LabeledStatement = function (node, st, c){ c(node.body, st, "Statement"); } ; base.BreakStatement = base.ContinueStatement = ignore; base.WithStatement = function (node, st, c){ c(node.object, st, "Expression"); c(node.body, st, "Statement"); } ; base.SwitchStatement = function (node, st, c){ c(node.discriminant, st, "Expression"); for (var i = 0; i < _AN_Read_length("length", node.cases); ++i){ var cs = node.cases[i]; if (cs.test) c(cs.test, st, "Expression"); for (var j = 0; j < _AN_Read_length("length", cs.consequent); ++j)c(cs.consequent[j], st, "Statement"); } } ; base.ReturnStatement = function (node, st, c){ if (node.argument) c(node.argument, st, "Expression"); } ; base.ThrowStatement = function (node, st, c){ c(node.argument, st, "Expression"); } ; base.TryStatement = function (node, st, c){ c(node.block, st, "Statement"); if (node.handler) c(node.handler.body, st, "ScopeBody"); if (node.finalizer) c(node.finalizer, st, "Statement"); } ; base.WhileStatement = function (node, st, c){ c(node.test, st, "Expression"); c(node.body, st, "Statement"); } ; base.DoWhileStatement = base.WhileStatement; base.ForStatement = function (node, st, c){ if (node.init) c(node.init, st, "ForInit"); if (node.test) c(node.test, st, "Expression"); if (node.update) c(node.update, st, "Expression"); c(node.body, st, "Statement"); } ; base.ForInStatement = function (node, st, c){ c(node.left, st, "ForInit"); c(node.right, st, "Expression"); c(node.body, st, "Statement"); } ; base.ForInit = function (node, st, c){ if (node.type == "VariableDeclaration") c(node, st); else c(node, st, "Expression"); } ; base.DebuggerStatement = ignore; base.FunctionDeclaration = function (node, st, c){ c(node, st, "Function"); } ; base.VariableDeclaration = function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.declarations); ++i){ var decl = node.declarations[i]; if (decl.init) c(decl.init, st, "Expression"); } } ; base.Function = function (node, st, c){ c(node.body, st, "ScopeBody"); } ; base.ScopeBody = function (node, st, c){ c(node, st, "Statement"); } ; base.Expression = skipThrough; base.ThisExpression = ignore; base.ArrayExpression = function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.elements); ++i){ var elt = node.elements[i]; if (elt) c(elt, st, "Expression"); } } ; base.ObjectExpression = function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.properties); ++i)c(node.properties[i].value, st, "Expression"); } ; base.FunctionExpression = base.FunctionDeclaration; base.SequenceExpression = function (node, st, c){ for (var i = 0; i < _AN_Read_length("length", node.expressions); ++i)c(node.expressions[i], st, "Expression"); } ; base.UnaryExpression = base.UpdateExpression = function (node, st, c){ c(node.argument, st, "Expression"); } ; base.BinaryExpression = base.AssignmentExpression = base.LogicalExpression = function (node, st, c){ c(node.left, st, "Expression"); c(node.right, st, "Expression"); } ; base.ConditionalExpression = function (node, st, c){ c(node.test, st, "Expression"); c(node.consequent, st, "Expression"); c(node.alternate, st, "Expression"); } ; base.NewExpression = base.CallExpression = function (node, st, c){ c(node.callee, st, "Expression"); if (node.arguments) for (var i = 0; i < _AN_Read_length("length", node.arguments); ++i)c(node.arguments[i], st, "Expression"); } ; base.MemberExpression = function (node, st, c){ c(node.object, st, "Expression"); if (node.computed) c(node.property, st, "Expression"); } ; base.Identifier = base.Literal = ignore; function makeScope(prev, isCatch){ return { vars: Object.create(null ), prev: prev, isCatch: isCatch} ; } function normalScope(scope){ while (scope.isCatch)scope = scope.prev; return scope; } exports.scopeVisitor = exports.make({ Function: function (node, scope, c){ var inner = makeScope(scope); for (var i = 0; i < _AN_Read_length("length", node.params); ++i)inner.vars[node.params[i].name] = { type: "argument", node: node.params[i]} ; if (node.id) { var decl = node.type == "FunctionDeclaration"; (decl? normalScope(scope): inner).vars[node.id.name] = { type: decl? "function": "function name", node: node.id} ; } c(node.body, inner, "ScopeBody"); } , TryStatement: function (node, scope, c){ c(node.block, scope, "Statement"); if (node.handler) { var inner = makeScope(scope, true ); inner.vars[node.handler.param.name] = { type: "catch clause", node: node.handler.param} ; c(node.handler.body, inner, "ScopeBody"); } if (node.finalizer) c(node.finalizer, scope, "Statement"); } , VariableDeclaration: function (node, scope, c){ var target = normalScope(scope); for (var i = 0; i < _AN_Read_length("length", node.declarations); ++i){ var decl = node.declarations[i]; target.vars[decl.id.name] = { type: "var", node: decl.id} ; if (decl.init) c(decl.init, scope, "Expression"); } } } ); } );