diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index 18376fc4ae..663fd858ee 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -7,10 +7,8 @@ ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError; - exports.Lexer = Lexer = (function() { - function Lexer() {} - - Lexer.prototype.tokenize = function(code, opts = {}) { + exports.Lexer = Lexer = class Lexer { + tokenize(code, opts = {}) { var consumed, end, i, ref2; this.literate = opts.literate; this.indent = 0; @@ -48,9 +46,9 @@ return this.tokens; } return (new Rewriter).rewrite(this.tokens); - }; + } - Lexer.prototype.clean = function(code) { + clean(code) { if (code.charCodeAt(0) === BOM) { code = code.slice(1); } @@ -63,9 +61,9 @@ code = invertLiterate(code); } return code; - }; + } - Lexer.prototype.identifierToken = function() { + identifierToken() { var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, ref6, ref7, tag, tagToken; if (!(match = IDENTIFIER.exec(this.chunk))) { return 0; @@ -176,9 +174,9 @@ this.token(':', ':', colonOffset, colon.length); } return input.length; - }; + } - Lexer.prototype.numberToken = function() { + numberToken() { var base, lexedLength, match, number, numberValue, tag; if (!(match = NUMBER.exec(this.chunk))) { return 0; @@ -222,9 +220,9 @@ tag = numberValue === 2e308 ? 'INFINITY' : 'NUMBER'; this.token(tag, number, 0, lexedLength); return lexedLength; - }; + } - Lexer.prototype.stringToken = function() { + stringToken() { var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, quote, ref2, ref3, regex, token, tokens; quote = (STRING_START.exec(this.chunk) || [])[0]; if (!quote) { @@ -302,9 +300,9 @@ }); } return end; - }; + } - Lexer.prototype.commentToken = function() { + commentToken() { var comment, here, match; if (!(match = this.chunk.match(COMMENT))) { return 0; @@ -323,9 +321,9 @@ this.token('HERECOMMENT', here, 0, comment.length); } return comment.length; - }; + } - Lexer.prototype.jsToken = function() { + jsToken() { var match, script; if (!(this.chunk.charAt(0) === '`' && (match = HERE_JSTOKEN.exec(this.chunk) || JSTOKEN.exec(this.chunk)))) { return 0; @@ -335,9 +333,9 @@ }); this.token('JS', script, 0, match[0].length); return match[0].length; - }; + } - Lexer.prototype.regexToken = function() { + regexToken() { var body, closed, end, flags, index, match, origin, prev, ref2, ref3, ref4, regex, tokens; switch (false) { case !(match = REGEX_ILLEGAL.exec(this.chunk)): @@ -406,9 +404,9 @@ this.token('REGEX_END', ')', end, 0); } return end; - }; + } - Lexer.prototype.lineToken = function() { + lineToken() { var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size; if (!(match = MULTI_DENT.exec(this.chunk))) { return 0; @@ -468,9 +466,9 @@ this.outdentToken(this.indent - size, noNewlines, indent.length); } return indent.length; - }; + } - Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) { + outdentToken(moveOut, noNewlines, outdentLength) { var decreasedIndent, dent, lastIndent, ref2; decreasedIndent = this.indent - moveOut; while (moveOut > 0) { @@ -507,9 +505,9 @@ this.indent = decreasedIndent; this.indentLiteral = this.indentLiteral.slice(0, decreasedIndent); return this; - }; + } - Lexer.prototype.whitespaceToken = function() { + whitespaceToken() { var match, nline, prev, ref2; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { return 0; @@ -523,9 +521,9 @@ } else { return 0; } - }; + } - Lexer.prototype.newlineToken = function(offset) { + newlineToken(offset) { while (this.value() === ';') { this.tokens.pop(); } @@ -533,16 +531,16 @@ this.token('TERMINATOR', '\n', offset, 0); } return this; - }; + } - Lexer.prototype.suppressNewlines = function() { + suppressNewlines() { if (this.value() === '\\') { this.tokens.pop(); } return this; - }; + } - Lexer.prototype.literalToken = function() { + literalToken() { var match, message, origin, prev, ref2, ref3, ref4, ref5, ref6, skipToken, tag, token, value; if (match = OPERATOR.exec(this.chunk)) { value = match[0]; @@ -628,9 +626,9 @@ } this.tokens.push(token); return value.length; - }; + } - Lexer.prototype.tagParameters = function() { + tagParameters() { var i, stack, tok, tokens; if (this.tag() !== ')') { return this; @@ -657,13 +655,13 @@ } } return this; - }; + } - Lexer.prototype.closeIndentation = function() { + closeIndentation() { return this.outdentToken(this.indent); - }; + } - Lexer.prototype.matchWithInterpolations = function(regex, delimiter) { + matchWithInterpolations(regex, delimiter) { var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref2, ref3, ref4, str, strPart, tokens; tokens = []; offsetInChunk = delimiter.length; @@ -721,9 +719,9 @@ tokens: tokens, index: offsetInChunk + delimiter.length }; - }; + } - Lexer.prototype.mergeInterpolationTokens = function(tokens, options, fn) { + mergeInterpolationTokens(tokens, options, fn) { var converted, firstEmptyStringIndex, firstIndex, i, j, lastToken, len, locationToken, lparen, plusToken, rparen, tag, token, tokensToPush, value; if (tokens.length > 1) { lparen = this.token('STRING_START', '(', 0, 0); @@ -786,9 +784,9 @@ last_column: lastToken[2].last_column }; } - }; + } - Lexer.prototype.pair = function(tag) { + pair(tag) { var lastIndent, prev, ref2, ref3, wanted; ref2 = this.ends, prev = ref2[ref2.length - 1]; if (tag !== (wanted = prev != null ? prev.tag : void 0)) { @@ -800,9 +798,9 @@ return this.pair(tag); } return this.ends.pop(); - }; + } - Lexer.prototype.getLineAndColumnFromChunk = function(offset) { + getLineAndColumnFromChunk(offset) { var column, lastLine, lineCount, ref2, string; if (offset === 0) { return [this.chunkLine, this.chunkColumn]; @@ -821,9 +819,9 @@ column += string.length; } return [this.chunkLine + lineCount, column]; - }; + } - Lexer.prototype.makeToken = function(tag, value, offsetInChunk = 0, length = value.length) { + makeToken(tag, value, offsetInChunk = 0, length = value.length) { var lastCharacter, locationData, ref2, ref3, token; locationData = {}; ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = ref2[0], locationData.first_column = ref2[1]; @@ -831,9 +829,9 @@ ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = ref3[0], locationData.last_column = ref3[1]; token = [tag, value, locationData]; return token; - }; + } - Lexer.prototype.token = function(tag, value, offsetInChunk, length, origin) { + token(tag, value, offsetInChunk, length, origin) { var token; token = this.makeToken(tag, value, offsetInChunk, length); if (origin) { @@ -841,34 +839,34 @@ } this.tokens.push(token); return token; - }; + } - Lexer.prototype.tag = function() { + tag() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[0] : void 0; - }; + } - Lexer.prototype.value = function() { + value() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[1] : void 0; - }; + } - Lexer.prototype.unfinished = function() { + unfinished() { var ref2; return LINE_CONTINUER.test(this.chunk) || ((ref2 = this.tag()) === '\\' || ref2 === '.' || ref2 === '?.' || ref2 === '?::' || ref2 === 'UNARY' || ref2 === 'MATH' || ref2 === 'UNARY_MATH' || ref2 === '+' || ref2 === '-' || ref2 === '**' || ref2 === 'SHIFT' || ref2 === 'RELATION' || ref2 === 'COMPARE' || ref2 === '&' || ref2 === '^' || ref2 === '|' || ref2 === '&&' || ref2 === '||' || ref2 === 'BIN?' || ref2 === 'THROW' || ref2 === 'EXTENDS'); - }; + } - Lexer.prototype.formatString = function(str) { + formatString(str) { return str.replace(STRING_OMIT, '$1'); - }; + } - Lexer.prototype.formatHeregex = function(str) { + formatHeregex(str) { return str.replace(HEREGEX_OMIT, '$1$2'); - }; + } - Lexer.prototype.validateEscapes = function(str, options = {}) { + validateEscapes(str, options = {}) { var before, hex, invalidEscape, match, message, octal, ref2, unicode; match = INVALID_ESCAPE.exec(str); if (!match) { @@ -884,9 +882,9 @@ offset: ((ref2 = options.offsetInChunk) != null ? ref2 : 0) + match.index + before.length, length: invalidEscape.length }); - }; + } - Lexer.prototype.makeDelimitedLiteral = function(body, options = {}) { + makeDelimitedLiteral(body, options = {}) { var regex; if (body === '' && options.delimiter === '/') { body = '(?:)'; @@ -921,9 +919,9 @@ } }); return `${options.delimiter}${body}${options.delimiter}`; - }; + } - Lexer.prototype.error = function(message, options = {}) { + error(message, options = {}) { var first_column, first_line, location, ref2, ref3, ref4; location = 'first_line' in options ? options : ((ref3 = this.getLineAndColumnFromChunk((ref2 = options.offset) != null ? ref2 : 0), first_line = ref3[0], first_column = ref3[1], ref3), { first_line: first_line, @@ -931,11 +929,9 @@ last_column: first_column + ((ref4 = options.length) != null ? ref4 : 1) - 1 }); return throwSyntaxError(message, location); - }; - - return Lexer; + } - })(); + }; isUnassignable = function(name, displayName = name) { switch (false) { diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 5635202f05..60a3c8ab26 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1,8 +1,6 @@ // Generated by CoffeeScript 2.0.0-alpha (function() { - var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isComplexOrAssignable, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility, - extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty, + var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isComplexOrAssignable, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, slice = [].slice; @@ -35,21 +33,19 @@ return this; }; - exports.CodeFragment = CodeFragment = (function() { - function CodeFragment(parent, code) { + exports.CodeFragment = CodeFragment = class CodeFragment { + constructor(parent, code) { var ref3; this.code = `${code}`; this.locationData = parent != null ? parent.locationData : void 0; this.type = (parent != null ? (ref3 = parent.constructor) != null ? ref3.name : void 0 : void 0) || 'unknown'; } - CodeFragment.prototype.toString = function() { + toString() { return `${this.code}${(this.locationData ? ": " + locationDataToString(this.locationData) : '')}`; - }; - - return CodeFragment; + } - })(); + }; fragmentsToText = function(fragments) { var fragment; @@ -65,166 +61,250 @@ }; exports.Base = Base = (function() { - function Base() {} - - Base.prototype.compile = function(o, lvl) { - return fragmentsToText(this.compileToFragments(o, lvl)); - }; - - Base.prototype.compileToFragments = function(o, lvl) { - var node; - o = extend({}, o); - if (lvl) { - o.level = lvl; + class Base { + compile(o, lvl) { + return fragmentsToText(this.compileToFragments(o, lvl)); } - node = this.unfoldSoak(o) || this; - node.tab = o.indent; - if (o.level === LEVEL_TOP || !node.isStatement(o)) { - return node.compileNode(o); - } else { - return node.compileClosure(o); - } - }; - Base.prototype.compileClosure = function(o) { - var args, argumentsNode, func, jumpNode, meth, parts, ref3, ref4; - if (jumpNode = this.jumps()) { - jumpNode.error('cannot use a pure statement in an expression'); - } - o.sharedScope = true; - func = new Code([], Block.wrap([this])); - args = []; - if ((argumentsNode = this.contains(isLiteralArguments)) || this.contains(isLiteralThis)) { - args = [new ThisLiteral]; - if (argumentsNode) { - meth = 'apply'; - args.push(new IdentifierLiteral('arguments')); + compileToFragments(o, lvl) { + var node; + o = extend({}, o); + if (lvl) { + o.level = lvl; + } + node = this.unfoldSoak(o) || this; + node.tab = o.indent; + if (o.level === LEVEL_TOP || !node.isStatement(o)) { + return node.compileNode(o); } else { - meth = 'call'; + return node.compileClosure(o); } - func = new Value(func, [new Access(new PropertyName(meth))]); } - parts = (new Call(func, args)).compileNode(o); - switch (false) { - case !(func.isGenerator || ((ref3 = func.base) != null ? ref3.isGenerator : void 0)): - parts.unshift(this.makeCode("(yield* ")); - parts.push(this.makeCode(")")); - break; - case !(func.isAsync || ((ref4 = func.base) != null ? ref4.isAsync : void 0)): - parts.unshift(this.makeCode("(await ")); - parts.push(this.makeCode(")")); + + compileClosure(o) { + var args, argumentsNode, func, jumpNode, meth, parts, ref3, ref4; + if (jumpNode = this.jumps()) { + jumpNode.error('cannot use a pure statement in an expression'); + } + o.sharedScope = true; + func = new Code([], Block.wrap([this])); + args = []; + if ((argumentsNode = this.contains(isLiteralArguments)) || this.contains(isLiteralThis)) { + args = [new ThisLiteral]; + if (argumentsNode) { + meth = 'apply'; + args.push(new IdentifierLiteral('arguments')); + } else { + meth = 'call'; + } + func = new Value(func, [new Access(new PropertyName(meth))]); + } + parts = (new Call(func, args)).compileNode(o); + switch (false) { + case !(func.isGenerator || ((ref3 = func.base) != null ? ref3.isGenerator : void 0)): + parts.unshift(this.makeCode("(yield* ")); + parts.push(this.makeCode(")")); + break; + case !(func.isAsync || ((ref4 = func.base) != null ? ref4.isAsync : void 0)): + parts.unshift(this.makeCode("(await ")); + parts.push(this.makeCode(")")); + } + return parts; } - return parts; - }; - Base.prototype.cache = function(o, level, isComplex) { - var complex, ref, sub; - complex = isComplex != null ? isComplex(this) : this.isComplex(); - if (complex) { - ref = new IdentifierLiteral(o.scope.freeVariable('ref')); - sub = new Assign(ref, this); - if (level) { - return [sub.compileToFragments(o, level), [this.makeCode(ref.value)]]; + cache(o, level, isComplex) { + var complex, ref, sub; + complex = isComplex != null ? isComplex(this) : this.isComplex(); + if (complex) { + ref = new IdentifierLiteral(o.scope.freeVariable('ref')); + sub = new Assign(ref, this); + if (level) { + return [sub.compileToFragments(o, level), [this.makeCode(ref.value)]]; + } else { + return [sub, ref]; + } } else { - return [sub, ref]; + ref = level ? this.compileToFragments(o, level) : this; + return [ref, ref]; } - } else { - ref = level ? this.compileToFragments(o, level) : this; - return [ref, ref]; } - }; - Base.prototype.cacheToCodeFragments = function(cacheValues) { - return [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]; - }; + hoist() { + var compileNode, compileToFragments, target; + this.hoisted = true; + target = new HoistTarget(this); + compileNode = this.compileNode; + compileToFragments = this.compileToFragments; + this.compileNode = function(o) { + return target.update(compileNode, o); + }; + this.compileToFragments = function(o) { + return target.update(compileToFragments, o); + }; + return target; + } - Base.prototype.makeReturn = function(res) { - var me; - me = this.unwrapAll(); - if (res) { - return new Call(new Literal(`${res}.push`), [me]); - } else { - return new Return(me); + cacheToCodeFragments(cacheValues) { + return [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]; } - }; - Base.prototype.contains = function(pred) { - var node; - node = void 0; - this.traverseChildren(false, function(n) { - if (pred(n)) { - node = n; - return false; + makeReturn(res) { + var me; + me = this.unwrapAll(); + if (res) { + return new Call(new Literal(`${res}.push`), [me]); + } else { + return new Return(me); } - }); - return node; - }; + } + + contains(pred) { + var node; + node = void 0; + this.traverseChildren(false, function(n) { + if (pred(n)) { + node = n; + return false; + } + }); + return node; + } - Base.prototype.lastNonComment = function(list) { - var i; - i = list.length; - while (i--) { - if (!(list[i] instanceof Comment)) { - return list[i]; + lastNonComment(list) { + var i; + i = list.length; + while (i--) { + if (!(list[i] instanceof Comment)) { + return list[i]; + } } + return null; } - return null; - }; - Base.prototype.toString = function(idt = '', name = this.constructor.name) { - var tree; - tree = '\n' + idt + name; - if (this.soak) { - tree += '?'; + toString(idt = '', name = this.constructor.name) { + var tree; + tree = '\n' + idt + name; + if (this.soak) { + tree += '?'; + } + this.eachChild(function(node) { + return tree += node.toString(idt + TAB); + }); + return tree; } - this.eachChild(function(node) { - return tree += node.toString(idt + TAB); - }); - return tree; - }; - Base.prototype.eachChild = function(func) { - var attr, child, j, k, len1, len2, ref3, ref4; - if (!this.children) { + eachChild(func) { + var attr, child, j, k, len1, len2, ref3, ref4; + if (!this.children) { + return this; + } + ref3 = this.children; + for (j = 0, len1 = ref3.length; j < len1; j++) { + attr = ref3[j]; + if (this[attr]) { + ref4 = flatten([this[attr]]); + for (k = 0, len2 = ref4.length; k < len2; k++) { + child = ref4[k]; + if (func(child) === false) { + return this; + } + } + } + } return this; } - ref3 = this.children; - for (j = 0, len1 = ref3.length; j < len1; j++) { - attr = ref3[j]; - if (this[attr]) { - ref4 = flatten([this[attr]]); - for (k = 0, len2 = ref4.length; k < len2; k++) { - child = ref4[k]; - if (func(child) === false) { - return this; + + traverseChildren(crossScope, func) { + return this.eachChild(function(child) { + var recur; + recur = func(child); + if (recur !== false) { + return child.traverseChildren(crossScope, func); + } + }); + } + + replaceInContext(match, replacement) { + var attr, child, children, i, j, k, len1, len2, ref3, ref4; + if (!this.children) { + return false; + } + ref3 = this.children; + for (j = 0, len1 = ref3.length; j < len1; j++) { + attr = ref3[j]; + if (children = this[attr]) { + if (Array.isArray(children)) { + for (i = k = 0, len2 = children.length; k < len2; i = ++k) { + child = children[i]; + if (match(child)) { + [].splice.apply(children, [i, i - i + 1].concat(ref4 = replacement(child, this))), ref4; + return true; + } else { + if (child.replaceInContext(match, replacement)) { + return true; + } + } + } + } else if (match(children)) { + this[attr] = replacement(children, this); + return true; + } else { + if (children.replaceInContext(match, replacement)) { + return true; + } } } } } - return this; - }; - Base.prototype.traverseChildren = function(crossScope, func) { - return this.eachChild(function(child) { - var recur; - recur = func(child); - if (recur !== false) { - return child.traverseChildren(crossScope, func); + invert() { + return new Op('!', this); + } + + unwrapAll() { + var node; + node = this; + while (node !== (node = node.unwrap())) { + continue; } - }); - }; + return node; + } - Base.prototype.invert = function() { - return new Op('!', this); - }; + updateLocationDataIfMissing(locationData) { + if (this.locationData) { + return this; + } + this.locationData = locationData; + return this.eachChild(function(child) { + return child.updateLocationDataIfMissing(locationData); + }); + } + + error(message) { + return throwSyntaxError(message, this.locationData); + } + + makeCode(code) { + return new CodeFragment(this, code); + } - Base.prototype.unwrapAll = function() { - var node; - node = this; - while (node !== (node = node.unwrap())) { - continue; + wrapInBraces(fragments) { + return [].concat(this.makeCode('('), fragments, this.makeCode(')')); } - return node; + + joinFragmentArrays(fragmentsList, joinStr) { + var answer, fragments, i, j, len1; + answer = []; + for (i = j = 0, len1 = fragmentsList.length; j < len1; i = ++j) { + fragments = fragmentsList[i]; + if (i) { + answer.push(this.makeCode(joinStr)); + } + answer = answer.concat(fragments); + } + return answer; + } + }; Base.prototype.children = []; @@ -247,383 +327,403 @@ Base.prototype.assigns = NO; - Base.prototype.updateLocationDataIfMissing = function(locationData) { - if (this.locationData) { - return this; - } - this.locationData = locationData; - return this.eachChild(function(child) { - return child.updateLocationDataIfMissing(locationData); - }); - }; - - Base.prototype.error = function(message) { - return throwSyntaxError(message, this.locationData); - }; - - Base.prototype.makeCode = function(code) { - return new CodeFragment(this, code); - }; + return Base; - Base.prototype.wrapInBraces = function(fragments) { - return [].concat(this.makeCode('('), fragments, this.makeCode(')')); - }; + })(); - Base.prototype.joinFragmentArrays = function(fragmentsList, joinStr) { - var answer, fragments, i, j, len1; - answer = []; - for (i = j = 0, len1 = fragmentsList.length; j < len1; i = ++j) { - fragments = fragmentsList[i]; - if (i) { - answer.push(this.makeCode(joinStr)); + exports.HoistTarget = HoistTarget = (function(superClass) { + class HoistTarget extends superClass { + static expand(fragments) { + var fragment, i, j, ref3; + for (i = j = fragments.length - 1; j >= 0; i = j += -1) { + fragment = fragments[i]; + if (fragment.fragments) { + [].splice.apply(fragments, [i, i - i + 1].concat(ref3 = this.expand(fragment.fragments))), ref3; + } } - answer = answer.concat(fragments); + return fragments; } - return answer; - }; - return Base; + constructor(source1) { + super(); + this.source = source1; + this.options = {}; + this.targetFragments = { + fragments: [] + }; + } - })(); + isStatement(o) { + return this.source.isStatement(o); + } - exports.Block = Block = (function(superClass1) { - extend1(Block, superClass1); + update(compile, o) { + return this.targetFragments.fragments = compile.call(this.source, merge(o, this.options)); + } - function Block(nodes) { - this.expressions = compact(flatten(nodes || [])); - } + compileToFragments(o, level) { + this.options.indent = o.indent; + this.options.level = level != null ? level : o.level; + return [this.targetFragments]; + } - Block.prototype.children = ['expressions']; + compileNode(o) { + return this.compileToFragments(o); + } - Block.prototype.push = function(node) { - this.expressions.push(node); - return this; - }; + compileClosure(o) { + return this.compileToFragments(o); + } - Block.prototype.pop = function() { - return this.expressions.pop(); }; - Block.prototype.unshift = function(node) { - this.expressions.unshift(node); - return this; - }; + HoistTarget.__super__ = superClass.prototype; + + return HoistTarget; + + })(Base); - Block.prototype.unwrap = function() { - if (this.expressions.length === 1) { - return this.expressions[0]; - } else { + exports.Block = Block = (function(superClass) { + class Block extends superClass { + constructor(nodes) { + super(); + this.expressions = compact(flatten(nodes || [])); + } + + push(node) { + this.expressions.push(node); return this; } - }; - Block.prototype.isEmpty = function() { - return !this.expressions.length; - }; + pop() { + return this.expressions.pop(); + } - Block.prototype.isStatement = function(o) { - var exp, j, len1, ref3; - ref3 = this.expressions; - for (j = 0, len1 = ref3.length; j < len1; j++) { - exp = ref3[j]; - if (exp.isStatement(o)) { - return true; + unshift(node) { + this.expressions.unshift(node); + return this; + } + + unwrap() { + if (this.expressions.length === 1) { + return this.expressions[0]; + } else { + return this; } } - return false; - }; - Block.prototype.jumps = function(o) { - var exp, j, jumpNode, len1, ref3; - ref3 = this.expressions; - for (j = 0, len1 = ref3.length; j < len1; j++) { - exp = ref3[j]; - if (jumpNode = exp.jumps(o)) { - return jumpNode; + isEmpty() { + return !this.expressions.length; + } + + isStatement(o) { + var exp, j, len1, ref3; + ref3 = this.expressions; + for (j = 0, len1 = ref3.length; j < len1; j++) { + exp = ref3[j]; + if (exp.isStatement(o)) { + return true; + } } + return false; } - }; - Block.prototype.makeReturn = function(res) { - var expr, len; - len = this.expressions.length; - while (len--) { - expr = this.expressions[len]; - if (!(expr instanceof Comment)) { - this.expressions[len] = expr.makeReturn(res); - if (expr instanceof Return && !expr.expression) { - this.expressions.splice(len, 1); + jumps(o) { + var exp, j, jumpNode, len1, ref3; + ref3 = this.expressions; + for (j = 0, len1 = ref3.length; j < len1; j++) { + exp = ref3[j]; + if (jumpNode = exp.jumps(o)) { + return jumpNode; } - break; } } - return this; - }; - Block.prototype.compileToFragments = function(o = {}, level) { - if (o.scope) { - return Block.__super__.compileToFragments.call(this, o, level); - } else { - return this.compileRoot(o); + makeReturn(res) { + var expr, len; + len = this.expressions.length; + while (len--) { + expr = this.expressions[len]; + if (!(expr instanceof Comment)) { + this.expressions[len] = expr.makeReturn(res); + if (expr instanceof Return && !expr.expression) { + this.expressions.splice(len, 1); + } + break; + } + } + return this; } - }; - Block.prototype.compileNode = function(o) { - var answer, compiledNodes, fragments, index, j, len1, node, ref3, top; - this.tab = o.indent; - top = o.level === LEVEL_TOP; - compiledNodes = []; - ref3 = this.expressions; - for (index = j = 0, len1 = ref3.length; j < len1; index = ++j) { - node = ref3[index]; - node = node.unwrapAll(); - node = node.unfoldSoak(o) || node; - if (node instanceof Block) { - compiledNodes.push(node.compileNode(o)); - } else if (top) { - node.front = true; - fragments = node.compileToFragments(o); - if (!node.isStatement(o)) { - fragments.unshift(this.makeCode(`${this.tab}`)); - fragments.push(this.makeCode(";")); - } - compiledNodes.push(fragments); + compileToFragments(o = {}, level) { + if (o.scope) { + return Block.__super__.compileToFragments.call(this, o, level); } else { - compiledNodes.push(node.compileToFragments(o, LEVEL_LIST)); + return this.compileRoot(o); } } - if (top) { - if (this.spaced) { - return [].concat(this.joinFragmentArrays(compiledNodes, '\n\n'), this.makeCode("\n")); + + compileNode(o) { + var answer, compiledNodes, fragments, index, j, len1, node, ref3, top; + this.tab = o.indent; + top = o.level === LEVEL_TOP; + compiledNodes = []; + ref3 = this.expressions; + for (index = j = 0, len1 = ref3.length; j < len1; index = ++j) { + node = ref3[index]; + node = node.unwrapAll(); + node = node.unfoldSoak(o) || node; + if (node instanceof Block) { + compiledNodes.push(node.compileNode(o)); + } else if (node.hoisted) { + node.compileToFragments(o); + } else if (top) { + node.front = true; + fragments = node.compileToFragments(o); + if (!node.isStatement(o)) { + fragments.unshift(this.makeCode(`${this.tab}`)); + fragments.push(this.makeCode(";")); + } + compiledNodes.push(fragments); + } else { + compiledNodes.push(node.compileToFragments(o, LEVEL_LIST)); + } + } + if (top) { + if (this.spaced) { + return [].concat(this.joinFragmentArrays(compiledNodes, '\n\n'), this.makeCode("\n")); + } else { + return this.joinFragmentArrays(compiledNodes, '\n'); + } + } + if (compiledNodes.length) { + answer = this.joinFragmentArrays(compiledNodes, ', '); } else { - return this.joinFragmentArrays(compiledNodes, '\n'); + answer = [this.makeCode("void 0")]; + } + if (compiledNodes.length > 1 && o.level >= LEVEL_LIST) { + return this.wrapInBraces(answer); + } else { + return answer; } } - if (compiledNodes.length) { - answer = this.joinFragmentArrays(compiledNodes, ', '); - } else { - answer = [this.makeCode("void 0")]; - } - if (compiledNodes.length > 1 && o.level >= LEVEL_LIST) { - return this.wrapInBraces(answer); - } else { - return answer; - } - }; - Block.prototype.compileRoot = function(o) { - var exp, fragments, i, j, len1, name, prelude, preludeExps, ref3, ref4, rest; - o.indent = o.bare ? '' : TAB; - o.level = LEVEL_TOP; - this.spaced = true; - o.scope = new Scope(null, this, null, (ref3 = o.referencedVars) != null ? ref3 : []); - ref4 = o.locals || []; - for (j = 0, len1 = ref4.length; j < len1; j++) { - name = ref4[j]; - o.scope.parameter(name); - } - prelude = []; - if (!o.bare) { - preludeExps = (function() { - var k, len2, ref5, results; - ref5 = this.expressions; - results = []; - for (i = k = 0, len2 = ref5.length; k < len2; i = ++k) { - exp = ref5[i]; - if (!(exp.unwrap() instanceof Comment)) { - break; + compileRoot(o) { + var exp, fragments, i, j, len1, name, prelude, preludeExps, ref3, ref4, rest; + o.indent = o.bare ? '' : TAB; + o.level = LEVEL_TOP; + this.spaced = true; + o.scope = new Scope(null, this, null, (ref3 = o.referencedVars) != null ? ref3 : []); + ref4 = o.locals || []; + for (j = 0, len1 = ref4.length; j < len1; j++) { + name = ref4[j]; + o.scope.parameter(name); + } + prelude = []; + if (!o.bare) { + preludeExps = (function() { + var k, len2, ref5, results; + ref5 = this.expressions; + results = []; + for (i = k = 0, len2 = ref5.length; k < len2; i = ++k) { + exp = ref5[i]; + if (!(exp.unwrap() instanceof Comment)) { + break; + } + results.push(exp); } - results.push(exp); + return results; + }).call(this); + rest = this.expressions.slice(preludeExps.length); + this.expressions = preludeExps; + if (preludeExps.length) { + prelude = this.compileNode(merge(o, { + indent: '' + })); + prelude.push(this.makeCode("\n")); } - return results; - }).call(this); - rest = this.expressions.slice(preludeExps.length); - this.expressions = preludeExps; - if (preludeExps.length) { - prelude = this.compileNode(merge(o, { - indent: '' - })); - prelude.push(this.makeCode("\n")); + this.expressions = rest; } - this.expressions = rest; - } - fragments = this.compileWithDeclarations(o); - if (o.bare) { - return fragments; + fragments = this.compileWithDeclarations(o); + HoistTarget.expand(fragments); + if (o.bare) { + return fragments; + } + return [].concat(prelude, this.makeCode("(function() {\n"), fragments, this.makeCode("\n}).call(this);\n")); } - return [].concat(prelude, this.makeCode("(function() {\n"), fragments, this.makeCode("\n}).call(this);\n")); - }; - Block.prototype.compileWithDeclarations = function(o) { - var assigns, declars, exp, fragments, i, j, len1, post, ref3, ref4, ref5, rest, scope, spaced; - fragments = []; - post = []; - ref3 = this.expressions; - for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { - exp = ref3[i]; - exp = exp.unwrap(); - if (!(exp instanceof Comment || exp instanceof Literal)) { - break; - } - } - o = merge(o, { - level: LEVEL_TOP - }); - if (i) { - rest = this.expressions.splice(i, 9e9); - ref4 = [this.spaced, false], spaced = ref4[0], this.spaced = ref4[1]; - ref5 = [this.compileNode(o), spaced], fragments = ref5[0], this.spaced = ref5[1]; - this.expressions = rest; - } - post = this.compileNode(o); - scope = o.scope; - if (scope.expressions === this) { - declars = o.scope.hasDeclarations(); - assigns = scope.hasAssignments; - if (declars || assigns) { - if (i) { - fragments.push(this.makeCode('\n')); - } - fragments.push(this.makeCode(`${this.tab}var `)); - if (declars) { - fragments.push(this.makeCode(scope.declaredVariables().join(', '))); + compileWithDeclarations(o) { + var assigns, declars, exp, fragments, i, j, len1, post, ref3, ref4, ref5, rest, scope, spaced; + fragments = []; + post = []; + ref3 = this.expressions; + for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { + exp = ref3[i]; + exp = exp.unwrap(); + if (!(exp instanceof Comment || exp instanceof Literal)) { + break; } - if (assigns) { + } + o = merge(o, { + level: LEVEL_TOP + }); + if (i) { + rest = this.expressions.splice(i, 9e9); + ref4 = [this.spaced, false], spaced = ref4[0], this.spaced = ref4[1]; + ref5 = [this.compileNode(o), spaced], fragments = ref5[0], this.spaced = ref5[1]; + this.expressions = rest; + } + post = this.compileNode(o); + scope = o.scope; + if (scope.expressions === this) { + declars = o.scope.hasDeclarations(); + assigns = scope.hasAssignments; + if (declars || assigns) { + if (i) { + fragments.push(this.makeCode('\n')); + } + fragments.push(this.makeCode(`${this.tab}var `)); if (declars) { - fragments.push(this.makeCode(`,\n${this.tab + TAB}`)); + fragments.push(this.makeCode(scope.declaredVariables().join(', '))); + } + if (assigns) { + if (declars) { + fragments.push(this.makeCode(`,\n${this.tab + TAB}`)); + } + fragments.push(this.makeCode(scope.assignedVariables().join(`,\n${this.tab + TAB}`))); } - fragments.push(this.makeCode(scope.assignedVariables().join(`,\n${this.tab + TAB}`))); + fragments.push(this.makeCode(`;\n${(this.spaced ? '\n' : '')}`)); + } else if (fragments.length && post.length) { + fragments.push(this.makeCode("\n")); } - fragments.push(this.makeCode(`;\n${(this.spaced ? '\n' : '')}`)); - } else if (fragments.length && post.length) { - fragments.push(this.makeCode("\n")); } + return fragments.concat(post); } - return fragments.concat(post); - }; - Block.wrap = function(nodes) { - if (nodes.length === 1 && nodes[0] instanceof Block) { - return nodes[0]; + static wrap(nodes) { + if (nodes.length === 1 && nodes[0] instanceof Block) { + return nodes[0]; + } + return new Block(nodes); } - return new Block(nodes); + }; + Block.__super__ = superClass.prototype; + + Block.prototype.children = ['expressions']; + return Block; })(Base); - exports.Literal = Literal = (function(superClass1) { - extend1(Literal, superClass1); + exports.Literal = Literal = (function(superClass) { + class Literal extends superClass { + constructor(value1) { + super(); + this.value = value1; + } - function Literal(value1) { - this.value = value1; - } + assigns(name) { + return name === this.value; + } - Literal.prototype.isComplex = NO; + compileNode(o) { + return [this.makeCode(this.value)]; + } - Literal.prototype.assigns = function(name) { - return name === this.value; - }; + toString() { + return ` ${(this.isStatement() ? Literal.__super__.toString.call(this, ...arguments) : this.constructor.name)}: ${this.value}`; + } - Literal.prototype.compileNode = function(o) { - return [this.makeCode(this.value)]; }; - Literal.prototype.toString = function() { - return ` ${(this.isStatement() ? Literal.__super__.toString.call(this, ...arguments) : this.constructor.name)}: ${this.value}`; - }; + Literal.__super__ = superClass.prototype; + + Literal.prototype.isComplex = NO; return Literal; })(Base); - exports.NumberLiteral = NumberLiteral = (function(superClass1) { - extend1(NumberLiteral, superClass1); + exports.NumberLiteral = NumberLiteral = (function(superClass) { + class NumberLiteral extends superClass {}; - function NumberLiteral() { - return NumberLiteral.__super__.constructor.apply(this, arguments); - } + NumberLiteral.__super__ = superClass.prototype; return NumberLiteral; })(Literal); - exports.InfinityLiteral = InfinityLiteral = (function(superClass1) { - extend1(InfinityLiteral, superClass1); - - function InfinityLiteral() { - return InfinityLiteral.__super__.constructor.apply(this, arguments); - } + exports.InfinityLiteral = InfinityLiteral = (function(superClass) { + class InfinityLiteral extends superClass { + compileNode() { + return [this.makeCode('2e308')]; + } - InfinityLiteral.prototype.compileNode = function() { - return [this.makeCode('2e308')]; }; + InfinityLiteral.__super__ = superClass.prototype; + return InfinityLiteral; })(NumberLiteral); - exports.NaNLiteral = NaNLiteral = (function(superClass1) { - extend1(NaNLiteral, superClass1); - - function NaNLiteral() { - NaNLiteral.__super__.constructor.call(this, 'NaN'); - } + exports.NaNLiteral = NaNLiteral = (function(superClass) { + class NaNLiteral extends superClass { + constructor() { + super('NaN'); + } - NaNLiteral.prototype.compileNode = function(o) { - var code; - code = [this.makeCode('0/0')]; - if (o.level >= LEVEL_OP) { - return this.wrapInBraces(code); - } else { - return code; + compileNode(o) { + var code; + code = [this.makeCode('0/0')]; + if (o.level >= LEVEL_OP) { + return this.wrapInBraces(code); + } else { + return code; + } } + }; + NaNLiteral.__super__ = superClass.prototype; + return NaNLiteral; })(NumberLiteral); - exports.StringLiteral = StringLiteral = (function(superClass1) { - extend1(StringLiteral, superClass1); + exports.StringLiteral = StringLiteral = (function(superClass) { + class StringLiteral extends superClass {}; - function StringLiteral() { - return StringLiteral.__super__.constructor.apply(this, arguments); - } + StringLiteral.__super__ = superClass.prototype; return StringLiteral; })(Literal); - exports.RegexLiteral = RegexLiteral = (function(superClass1) { - extend1(RegexLiteral, superClass1); + exports.RegexLiteral = RegexLiteral = (function(superClass) { + class RegexLiteral extends superClass {}; - function RegexLiteral() { - return RegexLiteral.__super__.constructor.apply(this, arguments); - } + RegexLiteral.__super__ = superClass.prototype; return RegexLiteral; })(Literal); - exports.PassthroughLiteral = PassthroughLiteral = (function(superClass1) { - extend1(PassthroughLiteral, superClass1); + exports.PassthroughLiteral = PassthroughLiteral = (function(superClass) { + class PassthroughLiteral extends superClass {}; - function PassthroughLiteral() { - return PassthroughLiteral.__super__.constructor.apply(this, arguments); - } + PassthroughLiteral.__super__ = superClass.prototype; return PassthroughLiteral; })(Literal); - exports.IdentifierLiteral = IdentifierLiteral = (function(superClass1) { - extend1(IdentifierLiteral, superClass1); + exports.IdentifierLiteral = IdentifierLiteral = (function(superClass) { + class IdentifierLiteral extends superClass {}; - function IdentifierLiteral() { - return IdentifierLiteral.__super__.constructor.apply(this, arguments); - } + IdentifierLiteral.__super__ = superClass.prototype; IdentifierLiteral.prototype.isAssignable = YES; @@ -631,12 +731,10 @@ })(Literal); - exports.PropertyName = PropertyName = (function(superClass1) { - extend1(PropertyName, superClass1); + exports.PropertyName = PropertyName = (function(superClass) { + class PropertyName extends superClass {}; - function PropertyName() { - return PropertyName.__super__.constructor.apply(this, arguments); - } + PropertyName.__super__ = superClass.prototype; PropertyName.prototype.isAssignable = YES; @@ -644,94 +742,125 @@ })(Literal); - exports.StatementLiteral = StatementLiteral = (function(superClass1) { - extend1(StatementLiteral, superClass1); + exports.StatementLiteral = StatementLiteral = (function(superClass) { + class StatementLiteral extends superClass { + jumps(o) { + if (this.value === 'break' && !((o != null ? o.loop : void 0) || (o != null ? o.block : void 0))) { + return this; + } + if (this.value === 'continue' && !(o != null ? o.loop : void 0)) { + return this; + } + } - function StatementLiteral() { - return StatementLiteral.__super__.constructor.apply(this, arguments); - } + compileNode(o) { + return [this.makeCode(`${this.tab}${this.value};`)]; + } - StatementLiteral.prototype.isStatement = YES; + }; - StatementLiteral.prototype.makeReturn = THIS; + StatementLiteral.__super__ = superClass.prototype; - StatementLiteral.prototype.jumps = function(o) { - if (this.value === 'break' && !((o != null ? o.loop : void 0) || (o != null ? o.block : void 0))) { - return this; - } - if (this.value === 'continue' && !(o != null ? o.loop : void 0)) { - return this; - } - }; + StatementLiteral.prototype.isStatement = YES; - StatementLiteral.prototype.compileNode = function(o) { - return [this.makeCode(`${this.tab}${this.value};`)]; - }; + StatementLiteral.prototype.makeReturn = THIS; return StatementLiteral; })(Literal); - exports.ThisLiteral = ThisLiteral = (function(superClass1) { - extend1(ThisLiteral, superClass1); + exports.ThisLiteral = ThisLiteral = (function(superClass) { + class ThisLiteral extends superClass { + constructor() { + super('this'); + } - function ThisLiteral() { - ThisLiteral.__super__.constructor.call(this, 'this'); - } + compileNode(o) { + var code, ref3; + code = ((ref3 = o.scope.method) != null ? ref3.bound : void 0) ? o.scope.method.context : this.value; + return [this.makeCode(code)]; + } - ThisLiteral.prototype.compileNode = function(o) { - var code, ref3; - code = ((ref3 = o.scope.method) != null ? ref3.bound : void 0) ? o.scope.method.context : this.value; - return [this.makeCode(code)]; }; + ThisLiteral.__super__ = superClass.prototype; + return ThisLiteral; })(Literal); - exports.UndefinedLiteral = UndefinedLiteral = (function(superClass1) { - extend1(UndefinedLiteral, superClass1); + exports.UndefinedLiteral = UndefinedLiteral = (function(superClass) { + class UndefinedLiteral extends superClass { + constructor() { + super('undefined'); + } - function UndefinedLiteral() { - UndefinedLiteral.__super__.constructor.call(this, 'undefined'); - } + compileNode(o) { + return [this.makeCode(o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0')]; + } - UndefinedLiteral.prototype.compileNode = function(o) { - return [this.makeCode(o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0')]; }; + UndefinedLiteral.__super__ = superClass.prototype; + return UndefinedLiteral; })(Literal); - exports.NullLiteral = NullLiteral = (function(superClass1) { - extend1(NullLiteral, superClass1); + exports.NullLiteral = NullLiteral = (function(superClass) { + class NullLiteral extends superClass { + constructor() { + super('null'); + } - function NullLiteral() { - NullLiteral.__super__.constructor.call(this, 'null'); - } + }; + + NullLiteral.__super__ = superClass.prototype; return NullLiteral; })(Literal); - exports.BooleanLiteral = BooleanLiteral = (function(superClass1) { - extend1(BooleanLiteral, superClass1); + exports.BooleanLiteral = BooleanLiteral = (function(superClass) { + class BooleanLiteral extends superClass {}; - function BooleanLiteral() { - return BooleanLiteral.__super__.constructor.apply(this, arguments); - } + BooleanLiteral.__super__ = superClass.prototype; return BooleanLiteral; })(Literal); - exports.Return = Return = (function(superClass1) { - extend1(Return, superClass1); + exports.Return = Return = (function(superClass) { + class Return extends superClass { + constructor(expression1) { + super(); + this.expression = expression1; + } - function Return(expression) { - this.expression = expression; - } + compileToFragments(o, level) { + var expr, ref3; + expr = (ref3 = this.expression) != null ? ref3.makeReturn() : void 0; + if (expr && !(expr instanceof Return)) { + return expr.compileToFragments(o, level); + } else { + return Return.__super__.compileToFragments.call(this, o, level); + } + } + + compileNode(o) { + var answer; + answer = []; + answer.push(this.makeCode(this.tab + `return${(this.expression ? " " : "")}`)); + if (this.expression) { + answer = answer.concat(this.expression.compileToFragments(o, LEVEL_PAREN)); + } + answer.push(this.makeCode(";")); + return answer; + } + + }; + + Return.__super__ = superClass.prototype; Return.prototype.children = ['expression']; @@ -741,1030 +870,1293 @@ Return.prototype.jumps = THIS; - Return.prototype.compileToFragments = function(o, level) { - var expr, ref3; - expr = (ref3 = this.expression) != null ? ref3.makeReturn() : void 0; - if (expr && !(expr instanceof Return)) { - return expr.compileToFragments(o, level); - } else { - return Return.__super__.compileToFragments.call(this, o, level); - } - }; - - Return.prototype.compileNode = function(o) { - var answer; - answer = []; - answer.push(this.makeCode(this.tab + `return${(this.expression ? " " : "")}`)); - if (this.expression) { - answer = answer.concat(this.expression.compileToFragments(o, LEVEL_PAREN)); - } - answer.push(this.makeCode(";")); - return answer; - }; - return Return; })(Base); - exports.YieldReturn = YieldReturn = (function(superClass1) { - extend1(YieldReturn, superClass1); - - function YieldReturn() { - return YieldReturn.__super__.constructor.apply(this, arguments); - } - - YieldReturn.prototype.compileNode = function(o) { - if (o.scope.parent == null) { - this.error('yield can only occur inside functions'); + exports.YieldReturn = YieldReturn = (function(superClass) { + class YieldReturn extends superClass { + compileNode(o) { + if (o.scope.parent == null) { + this.error('yield can only occur inside functions'); + } + return YieldReturn.__super__.compileNode.call(this, ...arguments); } - return YieldReturn.__super__.compileNode.call(this, ...arguments); + }; + YieldReturn.__super__ = superClass.prototype; + return YieldReturn; })(Return); - exports.AwaitReturn = AwaitReturn = (function(superClass1) { - extend1(AwaitReturn, superClass1); - - function AwaitReturn() { - return AwaitReturn.__super__.constructor.apply(this, arguments); - } - - AwaitReturn.prototype.compileNode = function(o) { - if (o.scope.parent == null) { - this.error('await can only occur inside functions'); + exports.AwaitReturn = AwaitReturn = (function(superClass) { + class AwaitReturn extends superClass { + compileNode(o) { + if (o.scope.parent == null) { + this.error('await can only occur inside functions'); + } + return AwaitReturn.__super__.compileNode.call(this, ...arguments); } - return AwaitReturn.__super__.compileNode.call(this, ...arguments); + }; + AwaitReturn.__super__ = superClass.prototype; + return AwaitReturn; })(Return); - exports.Value = Value = (function(superClass1) { - extend1(Value, superClass1); - - function Value(base, props, tag) { - if (!props && base instanceof Value) { - return base; - } - this.base = base; - this.properties = props || []; - if (tag) { - this[tag] = true; + exports.Value = Value = (function(superClass) { + class Value extends superClass { + constructor(base, props, tag) { + if (!props && base instanceof Value) { + return base; + } + super(); + this.base = base; + this.properties = props || []; + if (tag) { + this[tag] = true; + } + return this; } - return this; - } - - Value.prototype.children = ['base', 'properties']; - Value.prototype.add = function(props) { - this.properties = this.properties.concat(props); - return this; - }; + add(props) { + this.properties = this.properties.concat(props); + return this; + } - Value.prototype.hasProperties = function() { - return !!this.properties.length; - }; + hasProperties() { + return !!this.properties.length; + } - Value.prototype.bareLiteral = function(type) { - return !this.properties.length && this.base instanceof type; - }; + bareLiteral(type) { + return !this.properties.length && this.base instanceof type; + } - Value.prototype.isArray = function() { - return this.bareLiteral(Arr); - }; + isArray() { + return this.bareLiteral(Arr); + } - Value.prototype.isRange = function() { - return this.bareLiteral(Range); - }; + isRange() { + return this.bareLiteral(Range); + } - Value.prototype.isComplex = function() { - return this.hasProperties() || this.base.isComplex(); - }; + isComplex() { + return this.hasProperties() || this.base.isComplex(); + } - Value.prototype.isAssignable = function() { - return this.hasProperties() || this.base.isAssignable(); - }; + isAssignable() { + return this.hasProperties() || this.base.isAssignable(); + } - Value.prototype.isNumber = function() { - return this.bareLiteral(NumberLiteral); - }; + isNumber() { + return this.bareLiteral(NumberLiteral); + } - Value.prototype.isString = function() { - return this.bareLiteral(StringLiteral); - }; + isString() { + return this.bareLiteral(StringLiteral); + } - Value.prototype.isRegex = function() { - return this.bareLiteral(RegexLiteral); - }; + isRegex() { + return this.bareLiteral(RegexLiteral); + } - Value.prototype.isUndefined = function() { - return this.bareLiteral(UndefinedLiteral); - }; + isUndefined() { + return this.bareLiteral(UndefinedLiteral); + } - Value.prototype.isNull = function() { - return this.bareLiteral(NullLiteral); - }; + isNull() { + return this.bareLiteral(NullLiteral); + } - Value.prototype.isBoolean = function() { - return this.bareLiteral(BooleanLiteral); - }; + isBoolean() { + return this.bareLiteral(BooleanLiteral); + } - Value.prototype.isAtomic = function() { - var j, len1, node, ref3; - ref3 = this.properties.concat(this.base); - for (j = 0, len1 = ref3.length; j < len1; j++) { - node = ref3[j]; - if (node.soak || node instanceof Call) { - return false; + isAtomic() { + var j, len1, node, ref3; + ref3 = this.properties.concat(this.base); + for (j = 0, len1 = ref3.length; j < len1; j++) { + node = ref3[j]; + if (node.soak || node instanceof Call) { + return false; + } } + return true; } - return true; - }; - - Value.prototype.isNotCallable = function() { - return this.isNumber() || this.isString() || this.isRegex() || this.isArray() || this.isRange() || this.isSplice() || this.isObject() || this.isUndefined() || this.isNull() || this.isBoolean(); - }; - - Value.prototype.isStatement = function(o) { - return !this.properties.length && this.base.isStatement(o); - }; - - Value.prototype.assigns = function(name) { - return !this.properties.length && this.base.assigns(name); - }; - - Value.prototype.jumps = function(o) { - return !this.properties.length && this.base.jumps(o); - }; - Value.prototype.isObject = function(onlyGenerated) { - if (this.properties.length) { - return false; + isNotCallable() { + return this.isNumber() || this.isString() || this.isRegex() || this.isArray() || this.isRange() || this.isSplice() || this.isObject() || this.isUndefined() || this.isNull() || this.isBoolean(); } - return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); - }; - - Value.prototype.isSplice = function() { - var lastProp, ref3; - ref3 = this.properties, lastProp = ref3[ref3.length - 1]; - return lastProp instanceof Slice; - }; - Value.prototype.looksStatic = function(className) { - var ref3; - return this.base.value === className && this.properties.length === 1 && ((ref3 = this.properties[0].name) != null ? ref3.value : void 0) !== 'prototype'; - }; + isStatement(o) { + return !this.properties.length && this.base.isStatement(o); + } - Value.prototype.unwrap = function() { - if (this.properties.length) { - return this; - } else { - return this.base; + assigns(name) { + return !this.properties.length && this.base.assigns(name); } - }; - Value.prototype.cacheReference = function(o) { - var base, bref, name, nref, ref3; - ref3 = this.properties, name = ref3[ref3.length - 1]; - if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { - return [this, this]; + jumps(o) { + return !this.properties.length && this.base.jumps(o); } - base = new Value(this.base, this.properties.slice(0, -1)); - if (base.isComplex()) { - bref = new IdentifierLiteral(o.scope.freeVariable('base')); - base = new Value(new Parens(new Assign(bref, base))); + + isObject(onlyGenerated) { + if (this.properties.length) { + return false; + } + return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); } - if (!name) { - return [base, bref]; + + isSplice() { + var lastProp, ref3; + ref3 = this.properties, lastProp = ref3[ref3.length - 1]; + return lastProp instanceof Slice; } - if (name.isComplex()) { - nref = new IdentifierLiteral(o.scope.freeVariable('name')); - name = new Index(new Assign(nref, name.index)); - nref = new Index(nref); + + looksStatic(className) { + var ref3; + return (this["this"] || this.base instanceof ThisLiteral || this.base.value === className) && this.properties.length === 1 && ((ref3 = this.properties[0].name) != null ? ref3.value : void 0) !== 'prototype'; } - return [base.add(name), new Value(bref || base.base, [nref || name])]; - }; - Value.prototype.compileNode = function(o) { - var fragments, j, len1, prop, props; - this.base.front = this.front; - props = this.properties; - fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null)); - if (props.length && SIMPLENUM.test(fragmentsToText(fragments))) { - fragments.push(this.makeCode('.')); + unwrap() { + if (this.properties.length) { + return this; + } else { + return this.base; + } } - for (j = 0, len1 = props.length; j < len1; j++) { - prop = props[j]; - fragments.push(...prop.compileToFragments(o)); + + cacheReference(o) { + var base, bref, name, nref, ref3; + ref3 = this.properties, name = ref3[ref3.length - 1]; + if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { + return [this, this]; + } + base = new Value(this.base, this.properties.slice(0, -1)); + if (base.isComplex()) { + bref = new IdentifierLiteral(o.scope.freeVariable('base')); + base = new Value(new Parens(new Assign(bref, base))); + } + if (!name) { + return [base, bref]; + } + if (name.isComplex()) { + nref = new IdentifierLiteral(o.scope.freeVariable('name')); + name = new Index(new Assign(nref, name.index)); + nref = new Index(nref); + } + return [base.add(name), new Value(bref || base.base, [nref || name])]; } - return fragments; - }; - Value.prototype.unfoldSoak = function(o) { - return this.unfoldedSoak != null ? this.unfoldedSoak : this.unfoldedSoak = (() => { - var fst, i, ifn, j, len1, prop, ref, ref3, snd; - if (ifn = this.base.unfoldSoak(o)) { - ifn.body.properties.push(...this.properties); - return ifn; + compileNode(o) { + var fragments, j, len1, prop, props; + this.base.front = this.front; + props = this.properties; + fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null)); + if (props.length && SIMPLENUM.test(fragmentsToText(fragments))) { + fragments.push(this.makeCode('.')); } - ref3 = this.properties; - for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { - prop = ref3[i]; - if (!prop.soak) { - continue; + for (j = 0, len1 = props.length; j < len1; j++) { + prop = props[j]; + fragments.push(...prop.compileToFragments(o)); + } + return fragments; + } + + unfoldSoak(o) { + return this.unfoldedSoak != null ? this.unfoldedSoak : this.unfoldedSoak = (() => { + var fst, i, ifn, j, len1, prop, ref, ref3, snd; + if (ifn = this.base.unfoldSoak(o)) { + ifn.body.properties.push(...this.properties); + return ifn; } - prop.soak = false; - fst = new Value(this.base, this.properties.slice(0, i)); - snd = new Value(this.base, this.properties.slice(i)); - if (fst.isComplex()) { - ref = new IdentifierLiteral(o.scope.freeVariable('ref')); - fst = new Parens(new Assign(ref, fst)); - snd.base = ref; + ref3 = this.properties; + for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { + prop = ref3[i]; + if (!prop.soak) { + continue; + } + prop.soak = false; + fst = new Value(this.base, this.properties.slice(0, i)); + snd = new Value(this.base, this.properties.slice(i)); + if (fst.isComplex()) { + ref = new IdentifierLiteral(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, fst)); + snd.base = ref; + } + return new If(new Existence(fst), snd, { + soak: true + }); } - return new If(new Existence(fst), snd, { - soak: true - }); - } - return false; - })(); + return false; + })(); + } + }; + Value.__super__ = superClass.prototype; + + Value.prototype.children = ['base', 'properties']; + return Value; })(Base); - exports.Comment = Comment = (function(superClass1) { - extend1(Comment, superClass1); + exports.Comment = Comment = (function(superClass) { + class Comment extends superClass { + constructor(comment1) { + super(); + this.comment = comment1; + } - function Comment(comment1) { - this.comment = comment1; - } + compileNode(o, level) { + var code, comment; + comment = this.comment.replace(/^(\s*)#(?=\s)/gm, "$1 *"); + code = `/*${multident(comment, this.tab)}${(indexOf.call(comment, '\n') >= 0 ? `\n${this.tab}` : '')} */`; + if ((level || o.level) === LEVEL_TOP) { + code = o.indent + code; + } + return [this.makeCode("\n"), this.makeCode(code)]; + } + + }; + + Comment.__super__ = superClass.prototype; Comment.prototype.isStatement = YES; Comment.prototype.makeReturn = THIS; - Comment.prototype.compileNode = function(o, level) { - var code, comment; - comment = this.comment.replace(/^(\s*)#(?=\s)/gm, "$1 *"); - code = `/*${multident(comment, this.tab)}${(indexOf.call(comment, '\n') >= 0 ? `\n${this.tab}` : '')} */`; - if ((level || o.level) === LEVEL_TOP) { - code = o.indent + code; - } - return [this.makeCode("\n"), this.makeCode(code)]; - }; - return Comment; })(Base); - exports.Call = Call = (function(superClass1) { - extend1(Call, superClass1); - - function Call(variable1, args1, soak1) { - var args1; - this.variable = variable1; - this.args = args1 != null ? args1 : []; - this.soak = soak1; - this.isNew = false; - if (this.variable instanceof Value && this.variable.isNotCallable()) { - this.variable.error("literal is not a function"); + exports.Call = Call = (function(superClass) { + class Call extends superClass { + constructor(variable1, args1 = [], soak1) { + super(); + this.variable = variable1; + this.args = args1; + this.soak = soak1; + this.isNew = false; + if (this.variable instanceof Value && this.variable.isNotCallable()) { + this.variable.error("literal is not a function"); + } } - } - - Call.prototype.children = ['variable', 'args']; - Call.prototype.newInstance = function() { - var base, ref3; - base = ((ref3 = this.variable) != null ? ref3.base : void 0) || this.variable; - if (base instanceof Call && !base.isNew) { - base.newInstance(); - } else { - this.isNew = true; + newInstance() { + var base, ref3; + base = ((ref3 = this.variable) != null ? ref3.base : void 0) || this.variable; + if (base instanceof Call && !base.isNew) { + base.newInstance(); + } else { + this.isNew = true; + } + return this; } - return this; - }; - Call.prototype.unfoldSoak = function(o) { - var call, ifn, j, left, len1, list, ref3, ref4, rite; - if (this.soak) { - if (this instanceof SuperCall) { - left = new Literal(this.superReference(o)); - rite = new Value(left); - } else { - if (ifn = unfoldSoak(o, this, 'variable')) { - return ifn; + unfoldSoak(o) { + var call, ifn, j, left, len1, list, ref3, ref4, rite; + if (this.soak) { + if (this instanceof SuperCall) { + left = new Literal(this.superReference(o)); + rite = new Value(left); + } else { + if (ifn = unfoldSoak(o, this, 'variable')) { + return ifn; + } + ref3 = new Value(this.variable).cacheReference(o), left = ref3[0], rite = ref3[1]; } - ref3 = new Value(this.variable).cacheReference(o), left = ref3[0], rite = ref3[1]; + rite = new Call(rite, this.args); + rite.isNew = this.isNew; + left = new Literal(`typeof ${left.compile(o)} === \"function\"`); + return new If(left, new Value(rite), { + soak: true + }); } - rite = new Call(rite, this.args); - rite.isNew = this.isNew; - left = new Literal(`typeof ${left.compile(o)} === \"function\"`); - return new If(left, new Value(rite), { - soak: true - }); - } - call = this; - list = []; - while (true) { - if (call.variable instanceof Call) { + call = this; + list = []; + while (true) { + if (call.variable instanceof Call) { + list.push(call); + call = call.variable; + continue; + } + if (!(call.variable instanceof Value)) { + break; + } list.push(call); - call = call.variable; - continue; - } - if (!(call.variable instanceof Value)) { - break; + if (!((call = call.variable.base) instanceof Call)) { + break; + } } - list.push(call); - if (!((call = call.variable.base) instanceof Call)) { - break; + ref4 = list.reverse(); + for (j = 0, len1 = ref4.length; j < len1; j++) { + call = ref4[j]; + if (ifn) { + if (call.variable instanceof Call) { + call.variable = ifn; + } else { + call.variable.base = ifn; + } + } + ifn = unfoldSoak(o, call, 'variable'); } + return ifn; } - ref4 = list.reverse(); - for (j = 0, len1 = ref4.length; j < len1; j++) { - call = ref4[j]; - if (ifn) { - if (call.variable instanceof Call) { - call.variable = ifn; + + compileNode(o) { + var arg, argIndex, compiledArgs, fragments, j, len1, preface, ref3, ref4; + if ((ref3 = this.variable) != null) { + ref3.front = this.front; + } + compiledArgs = []; + ref4 = this.args; + for (argIndex = j = 0, len1 = ref4.length; j < len1; argIndex = ++j) { + arg = ref4[argIndex]; + if (argIndex) { + compiledArgs.push(this.makeCode(", ")); + } + compiledArgs.push(...arg.compileToFragments(o, LEVEL_LIST)); + } + fragments = []; + if (this instanceof SuperCall) { + preface = this.superReference(o); + if (preface === 'super') { + preface += '('; } else { - call.variable.base = ifn; + preface += `.call(${this.superThis(o)}`; + if (compiledArgs.length) { + preface += ", "; + } + } + fragments.push(this.makeCode(preface)); + } else { + if (this.isNew) { + fragments.push(this.makeCode('new ')); } + fragments.push(...this.variable.compileToFragments(o, LEVEL_ACCESS)); + fragments.push(this.makeCode("(")); } - ifn = unfoldSoak(o, call, 'variable'); + fragments.push(...compiledArgs); + fragments.push(this.makeCode(")")); + return fragments; } - return ifn; - }; - Call.prototype.compileNode = function(o) { - var arg, argIndex, compiledArgs, fragments, j, len1, preface, ref3, ref4; - if ((ref3 = this.variable) != null) { - ref3.front = this.front; - } - compiledArgs = []; - ref4 = this.args; - for (argIndex = j = 0, len1 = ref4.length; j < len1; argIndex = ++j) { - arg = ref4[argIndex]; - if (argIndex) { - compiledArgs.push(this.makeCode(", ")); - } - compiledArgs.push(...arg.compileToFragments(o, LEVEL_LIST)); - } - fragments = []; - if (this instanceof SuperCall) { - preface = this.superReference(o) + `.call(${this.superThis(o)}`; - if (compiledArgs.length) { - preface += ", "; - } - fragments.push(this.makeCode(preface)); - } else { - if (this.isNew) { - fragments.push(this.makeCode('new ')); - } - fragments.push(...this.variable.compileToFragments(o, LEVEL_ACCESS)); - fragments.push(this.makeCode("(")); - } - fragments.push(...compiledArgs); - fragments.push(this.makeCode(")")); - return fragments; }; + Call.__super__ = superClass.prototype; + + Call.prototype.children = ['variable', 'args']; + return Call; })(Base); - exports.SuperCall = SuperCall = (function(superClass1) { - extend1(SuperCall, superClass1); + exports.SuperCall = SuperCall = (function(superClass) { + class SuperCall extends superClass { + constructor(args) { + super(null, args != null ? args : [new Splat(new IdentifierLiteral('arguments'))]); + this.isBare = args != null; + } - function SuperCall(args) { - SuperCall.__super__.constructor.call(this, null, args != null ? args : [new Splat(new IdentifierLiteral('arguments'))]); - this.isBare = args != null; - } + isStatement(o) { + var ref3; + return ((ref3 = this.expressions) != null ? ref3.length : void 0) && o.level === LEVEL_TOP; + } - SuperCall.prototype.superReference = function(o) { - var accesses, base, bref, klass, method, name, nref, variable; - method = o.scope.namedMethod(); - if (method != null ? method.klass : void 0) { - klass = method.klass, name = method.name, variable = method.variable; - if (klass.isComplex()) { - bref = new IdentifierLiteral(o.scope.parent.freeVariable('base')); - base = new Value(new Parens(new Assign(bref, klass))); - variable.base = base; - variable.properties.splice(0, klass.properties.length); - } - if (name.isComplex() || (name instanceof Index && name.index.isAssignable())) { - nref = new IdentifierLiteral(o.scope.parent.freeVariable('name')); - name = new Index(new Assign(nref, name.index)); - variable.properties.pop(); - variable.properties.push(name); + compileNode(o) { + var ref, ref3, ref4, replacement, superCall; + if (!((ref3 = this.expressions) != null ? ref3.length : void 0)) { + return SuperCall.__super__.compileNode.call(this, ...arguments); } - accesses = [new Access(new PropertyName('__super__'))]; - if (method["static"]) { - accesses.push(new Access(new PropertyName('constructor'))); + superCall = new Literal(fragmentsToText(SuperCall.__super__.compileNode.call(this, ...arguments))); + replacement = new Block(this.expressions.slice()); + if (o.level > LEVEL_TOP) { + ref4 = superCall.cache(o, null, YES), superCall = ref4[0], ref = ref4[1]; + replacement.push(ref); + } + replacement.unshift(superCall); + return replacement.compileToFragments(o, o.level === LEVEL_TOP ? o.level : LEVEL_LIST); + } + + superReference(o) { + var accesses, base, bref, klass, method, name, nref, variable; + method = o.scope.namedMethod(); + if (method != null ? method.ctor : void 0) { + return 'super'; + } else if (method != null ? method.klass : void 0) { + klass = method.klass, name = method.name, variable = method.variable; + if (klass.isComplex()) { + bref = new IdentifierLiteral(o.scope.parent.freeVariable('base')); + base = new Value(new Parens(new Assign(bref, klass))); + variable.base = base; + variable.properties.splice(0, klass.properties.length); + } + if (name.isComplex() || (name instanceof Index && name.index.isAssignable())) { + nref = new IdentifierLiteral(o.scope.parent.freeVariable('name')); + name.index = new Assign(nref, name.index); + } + accesses = [new Access(new PropertyName('__super__'))]; + if (method.isStatic) { + accesses.push(new Access(new PropertyName('constructor'))); + } + accesses.push(nref != null ? new Index(nref) : name); + return (new Value(bref != null ? bref : klass, accesses)).compile(o); + } else { + return this.error('cannot call super outside of an instance method.'); } - accesses.push(nref != null ? new Index(nref) : name); - return (new Value(bref != null ? bref : klass, accesses)).compile(o); - } else if (method != null ? method.ctor : void 0) { - return `${method.name}.__super__.constructor`; - } else { - return this.error('cannot call super outside of an instance method.'); } - }; - SuperCall.prototype.superThis = function(o) { - var method; - method = o.scope.method; - return (method && !method.klass && method.context) || "this"; + superThis(o) { + var method; + method = o.scope.method; + return (method && !method.klass && method.context) || "this"; + } + }; + SuperCall.__super__ = superClass.prototype; + + SuperCall.prototype.children = ['expressions']; + return SuperCall; })(Call); - exports.RegexWithInterpolations = RegexWithInterpolations = (function(superClass1) { - extend1(RegexWithInterpolations, superClass1); + exports.RegexWithInterpolations = RegexWithInterpolations = (function(superClass) { + class RegexWithInterpolations extends superClass { + constructor(args = []) { + super(new Value(new IdentifierLiteral('RegExp')), args, false); + } - function RegexWithInterpolations(args = []) { - RegexWithInterpolations.__super__.constructor.call(this, new Value(new IdentifierLiteral('RegExp')), args, false); - } + }; + + RegexWithInterpolations.__super__ = superClass.prototype; return RegexWithInterpolations; })(Call); - exports.TaggedTemplateCall = TaggedTemplateCall = (function(superClass1) { - extend1(TaggedTemplateCall, superClass1); + exports.TaggedTemplateCall = TaggedTemplateCall = (function(superClass) { + class TaggedTemplateCall extends superClass { + constructor(variable, arg, soak) { + if (arg instanceof StringLiteral) { + arg = new StringWithInterpolations(Block.wrap([new Value(arg)])); + } + super(variable, [arg], soak); + } - function TaggedTemplateCall(variable, arg, soak) { - if (arg instanceof StringLiteral) { - arg = new StringWithInterpolations(Block.wrap([new Value(arg)])); + compileNode(o) { + return this.variable.compileToFragments(o, LEVEL_ACCESS).concat(this.args[0].compileToFragments(o, LEVEL_LIST)); } - TaggedTemplateCall.__super__.constructor.call(this, variable, [arg], soak); - } - TaggedTemplateCall.prototype.compileNode = function(o) { - return this.variable.compileToFragments(o, LEVEL_ACCESS).concat(this.args[0].compileToFragments(o, LEVEL_LIST)); }; + TaggedTemplateCall.__super__ = superClass.prototype; + return TaggedTemplateCall; })(Call); - exports.Extends = Extends = (function(superClass1) { - extend1(Extends, superClass1); - - function Extends(child1, parent1) { - this.child = child1; - this.parent = parent1; - } + exports.Extends = Extends = (function(superClass) { + class Extends extends superClass { + constructor(child1, parent1) { + super(); + this.child = child1; + this.parent = parent1; + } - Extends.prototype.children = ['child', 'parent']; + compileToFragments(o) { + return new Call(new Value(new Literal(utility('extend', o))), [this.child, this.parent]).compileToFragments(o); + } - Extends.prototype.compileToFragments = function(o) { - return new Call(new Value(new Literal(utility('extend', o))), [this.child, this.parent]).compileToFragments(o); }; - return Extends; - - })(Base); + Extends.__super__ = superClass.prototype; - exports.Access = Access = (function(superClass1) { - extend1(Access, superClass1); + Extends.prototype.children = ['child', 'parent']; - function Access(name1, tag) { - this.name = name1; - this.soak = tag === 'soak'; - } + return Extends; - Access.prototype.children = ['name']; + })(Base); - Access.prototype.compileToFragments = function(o) { - var name, node, ref3; - name = this.name.compileToFragments(o); - node = this.name.unwrap(); - if (node instanceof PropertyName) { - if (ref3 = node.value, indexOf.call(JS_FORBIDDEN, ref3) >= 0) { - return [this.makeCode('["'), ...name, this.makeCode('"]')]; + exports.Access = Access = (function(superClass) { + class Access extends superClass { + constructor(name1, tag) { + super(); + this.name = name1; + this.soak = tag === 'soak'; + } + + compileToFragments(o) { + var name, node, ref3; + name = this.name.compileToFragments(o); + node = this.name.unwrap(); + if (node instanceof PropertyName) { + if (ref3 = node.value, indexOf.call(JS_FORBIDDEN, ref3) >= 0) { + return [this.makeCode('["'), ...name, this.makeCode('"]')]; + } else { + return [this.makeCode('.'), ...name]; + } } else { - return [this.makeCode('.'), ...name]; + return [this.makeCode('['), ...name, this.makeCode(']')]; } - } else { - return [this.makeCode('['), ...name, this.makeCode(']')]; } + }; + Access.__super__ = superClass.prototype; + + Access.prototype.children = ['name']; + Access.prototype.isComplex = NO; return Access; })(Base); - exports.Index = Index = (function(superClass1) { - extend1(Index, superClass1); + exports.Index = Index = (function(superClass) { + class Index extends superClass { + constructor(index1) { + super(); + this.index = index1; + } - function Index(index1) { - this.index = index1; - } + compileToFragments(o) { + return [].concat(this.makeCode("["), this.index.compileToFragments(o, LEVEL_PAREN), this.makeCode("]")); + } - Index.prototype.children = ['index']; + isComplex() { + return this.index.isComplex(); + } - Index.prototype.compileToFragments = function(o) { - return [].concat(this.makeCode("["), this.index.compileToFragments(o, LEVEL_PAREN), this.makeCode("]")); }; - Index.prototype.isComplex = function() { - return this.index.isComplex(); - }; + Index.__super__ = superClass.prototype; + + Index.prototype.children = ['index']; return Index; })(Base); - exports.Range = Range = (function(superClass1) { - extend1(Range, superClass1); - - Range.prototype.children = ['from', 'to']; - - function Range(from1, to1, tag) { - this.from = from1; - this.to = to1; - this.exclusive = tag === 'exclusive'; - this.equals = this.exclusive ? '' : '='; - } - - Range.prototype.compileVariables = function(o) { - var isComplex, ref3, ref4, ref5, step; - o = merge(o, { - top: true - }); - isComplex = del(o, 'isComplex'); - ref3 = this.cacheToCodeFragments(this.from.cache(o, LEVEL_LIST, isComplex)), this.fromC = ref3[0], this.fromVar = ref3[1]; - ref4 = this.cacheToCodeFragments(this.to.cache(o, LEVEL_LIST, isComplex)), this.toC = ref4[0], this.toVar = ref4[1]; - if (step = del(o, 'step')) { - ref5 = this.cacheToCodeFragments(step.cache(o, LEVEL_LIST, isComplex)), this.step = ref5[0], this.stepVar = ref5[1]; - } - this.fromNum = this.from.isNumber() ? Number(this.fromVar) : null; - this.toNum = this.to.isNumber() ? Number(this.toVar) : null; - return this.stepNum = (step != null ? step.isNumber() : void 0) ? Number(this.stepVar) : null; - }; - - Range.prototype.compileNode = function(o) { - var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, ref3, ref4, stepPart, to, varPart; - if (!this.fromVar) { - this.compileVariables(o); - } - if (!o.index) { - return this.compileArray(o); - } - known = (this.fromNum != null) && (this.toNum != null); - idx = del(o, 'index'); - idxName = del(o, 'name'); - namedIndex = idxName && idxName !== idx; - varPart = `${idx} = ${this.fromC}`; - if (this.toC !== this.toVar) { - varPart += `, ${this.toC}`; + exports.Range = Range = (function(superClass) { + class Range extends superClass { + constructor(from1, to1, tag) { + super(); + this.from = from1; + this.to = to1; + this.exclusive = tag === 'exclusive'; + this.equals = this.exclusive ? '' : '='; } - if (this.step !== this.stepVar) { - varPart += `, ${this.step}`; + + compileVariables(o) { + var isComplex, ref3, ref4, ref5, step; + o = merge(o, { + top: true + }); + isComplex = del(o, 'isComplex'); + ref3 = this.cacheToCodeFragments(this.from.cache(o, LEVEL_LIST, isComplex)), this.fromC = ref3[0], this.fromVar = ref3[1]; + ref4 = this.cacheToCodeFragments(this.to.cache(o, LEVEL_LIST, isComplex)), this.toC = ref4[0], this.toVar = ref4[1]; + if (step = del(o, 'step')) { + ref5 = this.cacheToCodeFragments(step.cache(o, LEVEL_LIST, isComplex)), this.step = ref5[0], this.stepVar = ref5[1]; + } + this.fromNum = this.from.isNumber() ? Number(this.fromVar) : null; + this.toNum = this.to.isNumber() ? Number(this.toVar) : null; + return this.stepNum = (step != null ? step.isNumber() : void 0) ? Number(this.stepVar) : null; } - ref3 = [`${idx} <${this.equals}`, `${idx} >${this.equals}`], lt = ref3[0], gt = ref3[1]; - condPart = this.stepNum != null ? this.stepNum > 0 ? `${lt} ${this.toVar}` : `${gt} ${this.toVar}` : known ? ((ref4 = [this.fromNum, this.toNum], from = ref4[0], to = ref4[1], ref4), from <= to ? `${lt} ${to}` : `${gt} ${to}`) : (cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`, `${cond} ? ${lt} ${this.toVar} : ${gt} ${this.toVar}`); - stepPart = this.stepVar ? `${idx} += ${this.stepVar}` : known ? namedIndex ? from <= to ? `++${idx}` : `--${idx}` : from <= to ? `${idx}++` : `${idx}--` : namedIndex ? `${cond} ? ++${idx} : --${idx}` : `${cond} ? ${idx}++ : ${idx}--`; - if (namedIndex) { - varPart = `${idxName} = ${varPart}`; + + compileNode(o) { + var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, ref3, ref4, stepPart, to, varPart; + if (!this.fromVar) { + this.compileVariables(o); + } + if (!o.index) { + return this.compileArray(o); + } + known = (this.fromNum != null) && (this.toNum != null); + idx = del(o, 'index'); + idxName = del(o, 'name'); + namedIndex = idxName && idxName !== idx; + varPart = `${idx} = ${this.fromC}`; + if (this.toC !== this.toVar) { + varPart += `, ${this.toC}`; + } + if (this.step !== this.stepVar) { + varPart += `, ${this.step}`; + } + ref3 = [`${idx} <${this.equals}`, `${idx} >${this.equals}`], lt = ref3[0], gt = ref3[1]; + condPart = this.stepNum != null ? this.stepNum > 0 ? `${lt} ${this.toVar}` : `${gt} ${this.toVar}` : known ? ((ref4 = [this.fromNum, this.toNum], from = ref4[0], to = ref4[1], ref4), from <= to ? `${lt} ${to}` : `${gt} ${to}`) : (cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`, `${cond} ? ${lt} ${this.toVar} : ${gt} ${this.toVar}`); + stepPart = this.stepVar ? `${idx} += ${this.stepVar}` : known ? namedIndex ? from <= to ? `++${idx}` : `--${idx}` : from <= to ? `${idx}++` : `${idx}--` : namedIndex ? `${cond} ? ++${idx} : --${idx}` : `${cond} ? ${idx}++ : ${idx}--`; + if (namedIndex) { + varPart = `${idxName} = ${varPart}`; + } + if (namedIndex) { + stepPart = `${idxName} = ${stepPart}`; + } + return [this.makeCode(`${varPart}; ${condPart}; ${stepPart}`)]; } - if (namedIndex) { - stepPart = `${idxName} = ${stepPart}`; + + compileArray(o) { + var args, body, cond, hasArgs, i, idt, j, known, post, pre, range, ref3, ref4, result, results, vars; + known = (this.fromNum != null) && (this.toNum != null); + if (known && Math.abs(this.fromNum - this.toNum) <= 20) { + range = (function() { + results = []; + for (var j = ref3 = this.fromNum, ref4 = this.toNum; ref3 <= ref4 ? j <= ref4 : j >= ref4; ref3 <= ref4 ? j++ : j--){ results.push(j); } + return results; + }).apply(this); + if (this.exclusive) { + range.pop(); + } + return [this.makeCode(`[${range.join(', ')}]`)]; + } + idt = this.tab + TAB; + i = o.scope.freeVariable('i', { + single: true + }); + result = o.scope.freeVariable('results'); + pre = `\n${idt}${result} = [];`; + if (known) { + o.index = i; + body = fragmentsToText(this.compileNode(o)); + } else { + vars = `${i} = ${this.fromC}` + (this.toC !== this.toVar ? `, ${this.toC}` : ''); + cond = `${this.fromVar} <= ${this.toVar}`; + body = `var ${vars}; ${cond} ? ${i} <${this.equals} ${this.toVar} : ${i} >${this.equals} ${this.toVar}; ${cond} ? ${i}++ : ${i}--`; + } + post = `{ ${result}.push(${i}); }\n${idt}return ${result};\n${o.indent}`; + hasArgs = function(node) { + return node != null ? node.contains(isLiteralArguments) : void 0; + }; + if (hasArgs(this.from) || hasArgs(this.to)) { + args = ', arguments'; + } + return [this.makeCode(`(function() {${pre}\n${idt}for (${body})${post}}).apply(this${args != null ? args : ''})`)]; } - return [this.makeCode(`${varPart}; ${condPart}; ${stepPart}`)]; - }; - Range.prototype.compileArray = function(o) { - var args, body, cond, hasArgs, i, idt, j, known, post, pre, range, ref3, ref4, result, results, vars; - known = (this.fromNum != null) && (this.toNum != null); - if (known && Math.abs(this.fromNum - this.toNum) <= 20) { - range = (function() { - results = []; - for (var j = ref3 = this.fromNum, ref4 = this.toNum; ref3 <= ref4 ? j <= ref4 : j >= ref4; ref3 <= ref4 ? j++ : j--){ results.push(j); } - return results; - }).apply(this); - if (this.exclusive) { - range.pop(); - } - return [this.makeCode(`[${range.join(', ')}]`)]; - } - idt = this.tab + TAB; - i = o.scope.freeVariable('i', { - single: true - }); - result = o.scope.freeVariable('results'); - pre = `\n${idt}${result} = [];`; - if (known) { - o.index = i; - body = fragmentsToText(this.compileNode(o)); - } else { - vars = `${i} = ${this.fromC}` + (this.toC !== this.toVar ? `, ${this.toC}` : ''); - cond = `${this.fromVar} <= ${this.toVar}`; - body = `var ${vars}; ${cond} ? ${i} <${this.equals} ${this.toVar} : ${i} >${this.equals} ${this.toVar}; ${cond} ? ${i}++ : ${i}--`; - } - post = `{ ${result}.push(${i}); }\n${idt}return ${result};\n${o.indent}`; - hasArgs = function(node) { - return node != null ? node.contains(isLiteralArguments) : void 0; - }; - if (hasArgs(this.from) || hasArgs(this.to)) { - args = ', arguments'; - } - return [this.makeCode(`(function() {${pre}\n${idt}for (${body})${post}}).apply(this${args != null ? args : ''})`)]; }; - return Range; - - })(Base); + Range.__super__ = superClass.prototype; - exports.Slice = Slice = (function(superClass1) { - extend1(Slice, superClass1); + Range.prototype.children = ['from', 'to']; - Slice.prototype.children = ['range']; + return Range; - function Slice(range1) { - this.range = range1; - Slice.__super__.constructor.call(this); - } + })(Base); - Slice.prototype.compileNode = function(o) { - var compiled, compiledText, from, fromCompiled, ref3, to, toStr; - ref3 = this.range, to = ref3.to, from = ref3.from; - fromCompiled = from && from.compileToFragments(o, LEVEL_PAREN) || [this.makeCode('0')]; - if (to) { - compiled = to.compileToFragments(o, LEVEL_PAREN); - compiledText = fragmentsToText(compiled); - if (!(!this.range.exclusive && +compiledText === -1)) { - toStr = ', ' + (this.range.exclusive ? compiledText : to.isNumber() ? `${+compiledText + 1}` : (compiled = to.compileToFragments(o, LEVEL_ACCESS), `+${fragmentsToText(compiled)} + 1 || 9e9`)); + exports.Slice = Slice = (function(superClass) { + class Slice extends superClass { + constructor(range1) { + super(); + this.range = range1; + } + + compileNode(o) { + var compiled, compiledText, from, fromCompiled, ref3, to, toStr; + ref3 = this.range, to = ref3.to, from = ref3.from; + fromCompiled = from && from.compileToFragments(o, LEVEL_PAREN) || [this.makeCode('0')]; + if (to) { + compiled = to.compileToFragments(o, LEVEL_PAREN); + compiledText = fragmentsToText(compiled); + if (!(!this.range.exclusive && +compiledText === -1)) { + toStr = ', ' + (this.range.exclusive ? compiledText : to.isNumber() ? `${+compiledText + 1}` : (compiled = to.compileToFragments(o, LEVEL_ACCESS), `+${fragmentsToText(compiled)} + 1 || 9e9`)); + } } + return [this.makeCode(`.slice(${fragmentsToText(fromCompiled)}${toStr || ''})`)]; } - return [this.makeCode(`.slice(${fragmentsToText(fromCompiled)}${toStr || ''})`)]; + }; - return Slice; + Slice.__super__ = superClass.prototype; - })(Base); + Slice.prototype.children = ['range']; - exports.Obj = Obj = (function(superClass1) { - extend1(Obj, superClass1); + return Slice; - function Obj(props, generated) { - var generated; - this.generated = generated != null ? generated : false; - this.objects = this.properties = props || []; - } + })(Base); - Obj.prototype.children = ['properties']; - - Obj.prototype.compileNode = function(o) { - var answer, i, idt, indent, j, join, k, key, lastNoncom, len1, len2, node, prop, props, ref3, value; - props = this.properties; - if (this.generated) { - for (j = 0, len1 = props.length; j < len1; j++) { - node = props[j]; - if (node instanceof Value) { - node.error('cannot have an implicit value in an implicit object'); + exports.Obj = Obj = (function(superClass) { + class Obj extends superClass { + constructor(props, generated = false) { + super(); + this.generated = generated; + this.objects = this.properties = props || []; + } + + compileNode(o) { + var answer, i, idt, indent, j, join, k, key, lastNoncom, len1, len2, node, prop, props, ref3, value; + props = this.properties; + if (this.generated) { + for (j = 0, len1 = props.length; j < len1; j++) { + node = props[j]; + if (node instanceof Value) { + node.error('cannot have an implicit value in an implicit object'); + } } } - } - idt = o.indent += TAB; - lastNoncom = this.lastNonComment(this.properties); - answer = []; - answer.push(this.makeCode(`{${(props.length === 0 ? '}' : '\n')}`)); - for (i = k = 0, len2 = props.length; k < len2; i = ++k) { - prop = props[i]; - join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; - indent = prop instanceof Comment ? '' : idt; - if (prop instanceof Assign) { - if (prop.context !== 'object') { - prop.operatorToken.error(`unexpected ${prop.operatorToken.value}`); + idt = o.indent += TAB; + lastNoncom = this.lastNonComment(this.properties); + answer = []; + answer.push(this.makeCode(`{${(props.length === 0 ? '}' : '\n')}`)); + for (i = k = 0, len2 = props.length; k < len2; i = ++k) { + prop = props[i]; + join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; + indent = prop instanceof Comment ? '' : idt; + if (prop instanceof Assign) { + if (prop.context !== 'object') { + prop.operatorToken.error(`unexpected ${prop.operatorToken.value}`); + } + if (prop.variable instanceof Value && prop.variable.hasProperties()) { + prop.variable.error('invalid object key'); + } } - if (prop.variable instanceof Value && prop.variable.hasProperties()) { - prop.variable.error('invalid object key'); + if (prop instanceof Value && prop["this"]) { + prop = new Assign(prop.properties[0].name, prop, 'object'); } - } - if (prop instanceof Value && prop["this"]) { - prop = new Assign(prop.properties[0].name, prop, 'object'); - } - if (!(prop instanceof Comment) && !(prop instanceof Assign)) { - if (prop.isComplex()) { - ref3 = prop.base.cache(o), key = ref3[0], value = ref3[1]; - if (key instanceof IdentifierLiteral) { - key = new PropertyName(key.value); + if (!(prop instanceof Comment) && !(prop instanceof Assign)) { + if (prop.isComplex()) { + ref3 = prop.base.cache(o), key = ref3[0], value = ref3[1]; + if (key instanceof IdentifierLiteral) { + key = new PropertyName(key.value); + } + prop = new Assign(key, value, 'object'); + } else { + prop = new Assign(prop, prop, 'object'); } - prop = new Assign(key, value, 'object'); - } else { - prop = new Assign(prop, prop, 'object'); + } + if (indent) { + answer.push(this.makeCode(indent)); + } + answer.push(...prop.compileToFragments(o, LEVEL_TOP)); + if (join) { + answer.push(this.makeCode(join)); } } - if (indent) { - answer.push(this.makeCode(indent)); + if (props.length !== 0) { + answer.push(this.makeCode(`\n${this.tab}}`)); } - answer.push(...prop.compileToFragments(o, LEVEL_TOP)); - if (join) { - answer.push(this.makeCode(join)); + if (this.front) { + return this.wrapInBraces(answer); + } else { + return answer; } } - if (props.length !== 0) { - answer.push(this.makeCode(`\n${this.tab}}`)); - } - if (this.front) { - return this.wrapInBraces(answer); - } else { - return answer; - } - }; - Obj.prototype.assigns = function(name) { - var j, len1, prop, ref3; - ref3 = this.properties; - for (j = 0, len1 = ref3.length; j < len1; j++) { - prop = ref3[j]; - if (prop.assigns(name)) { - return true; + assigns(name) { + var j, len1, prop, ref3; + ref3 = this.properties; + for (j = 0, len1 = ref3.length; j < len1; j++) { + prop = ref3[j]; + if (prop.assigns(name)) { + return true; + } } + return false; } - return false; + }; - return Obj; + Obj.__super__ = superClass.prototype; - })(Base); + Obj.prototype.children = ['properties']; - exports.Arr = Arr = (function(superClass1) { - extend1(Arr, superClass1); + return Obj; - function Arr(objs) { - this.objects = objs || []; - } + })(Base); - Arr.prototype.children = ['objects']; + exports.Arr = Arr = (function(superClass) { + class Arr extends superClass { + constructor(objs) { + super(); + this.objects = objs || []; + } - Arr.prototype.compileNode = function(o) { - var answer, compiledObjs, fragments, index, j, len1, obj; - if (!this.objects.length) { - return [this.makeCode('[]')]; + compileNode(o) { + var answer, compiledObjs, fragments, index, j, len1, obj; + if (!this.objects.length) { + return [this.makeCode('[]')]; + } + o.indent += TAB; + answer = []; + compiledObjs = (function() { + var j, len1, ref3, results; + ref3 = this.objects; + results = []; + for (j = 0, len1 = ref3.length; j < len1; j++) { + obj = ref3[j]; + results.push(obj.compileToFragments(o, LEVEL_LIST)); + } + return results; + }).call(this); + for (index = j = 0, len1 = compiledObjs.length; j < len1; index = ++j) { + fragments = compiledObjs[index]; + if (index) { + answer.push(this.makeCode(", ")); + } + answer.push(...fragments); + } + if (fragmentsToText(answer).indexOf('\n') >= 0) { + answer.unshift(this.makeCode(`[\n${o.indent}`)); + answer.push(this.makeCode(`\n${this.tab}]`)); + } else { + answer.unshift(this.makeCode("[")); + answer.push(this.makeCode("]")); + } + return answer; } - o.indent += TAB; - answer = []; - compiledObjs = (function() { - var j, len1, ref3, results; + + assigns(name) { + var j, len1, obj, ref3; ref3 = this.objects; - results = []; for (j = 0, len1 = ref3.length; j < len1; j++) { obj = ref3[j]; - results.push(obj.compileToFragments(o, LEVEL_LIST)); - } - return results; - }).call(this); - for (index = j = 0, len1 = compiledObjs.length; j < len1; index = ++j) { - fragments = compiledObjs[index]; - if (index) { - answer.push(this.makeCode(", ")); + if (obj.assigns(name)) { + return true; + } } - answer.push(...fragments); - } - if (fragmentsToText(answer).indexOf('\n') >= 0) { - answer.unshift(this.makeCode(`[\n${o.indent}`)); - answer.push(this.makeCode(`\n${this.tab}]`)); - } else { - answer.unshift(this.makeCode("[")); - answer.push(this.makeCode("]")); + return false; } - return answer; - }; - Arr.prototype.assigns = function(name) { - var j, len1, obj, ref3; - ref3 = this.objects; - for (j = 0, len1 = ref3.length; j < len1; j++) { - obj = ref3[j]; - if (obj.assigns(name)) { - return true; - } - } - return false; }; - return Arr; - - })(Base); - - exports.Class = Class = (function(superClass1) { - extend1(Class, superClass1); + Arr.__super__ = superClass.prototype; - function Class(variable1, parent1, body1) { - var body1; - this.variable = variable1; - this.parent = parent1; - this.body = body1 != null ? body1 : new Block; - this.boundFuncs = []; - this.body.classBody = true; - } + Arr.prototype.children = ['objects']; - Class.prototype.children = ['variable', 'parent', 'body']; + return Arr; - Class.prototype.defaultClassVariableName = '_Class'; + })(Base); - Class.prototype.determineName = function() { - var message, name, node, ref3, tail; - if (!this.variable) { - return this.defaultClassVariableName; - } - ref3 = this.variable.properties, tail = ref3[ref3.length - 1]; - node = tail ? tail instanceof Access && tail.name : this.variable.base; - if (!(node instanceof IdentifierLiteral || node instanceof PropertyName)) { - return this.defaultClassVariableName; - } - name = node.value; - if (!tail) { - message = isUnassignable(name); - if (message) { - this.variable.error(message); + exports.Class = Class = (function(superClass) { + class Class extends superClass { + constructor(variable1, parent1, body1 = new Block) { + super(); + this.variable = variable1; + this.parent = parent1; + this.body = body1; + } + + compileNode(o) { + var assign, executableBody, result; + this.name = this.determineName(); + executableBody = this.walkBody(); + if (executableBody) { + this.compileNode = this.compileClassDeclaration; + result = new ExecutableClassBody(this, executableBody).compileToFragments(o); + this.compileNode = this.constructor.prototype.compileNode; + } else { + result = this.compileClassDeclaration(o); + if ((this.name == null) && o.level === LEVEL_TOP) { + result = this.wrapInBraces(result); + } + } + if (this.variable) { + assign = new Assign(this.variable, new Literal(''), null, { + moduleDeclaration: this.moduleDeclaration + }); + return [...assign.compileToFragments(o), ...result]; + } else { + return result; } } - if (indexOf.call(JS_FORBIDDEN, name) >= 0) { - return `_${name}`; - } else { - return name; + + compileClassDeclaration(o) { + var ref3, result; + if (this.externalCtor || this.boundMethods.length) { + if (this.ctor == null) { + this.ctor = this.makeDefaultConstructor(); + } + } + if ((ref3 = this.ctor) != null) { + ref3.noReturn = true; + } + if (this.boundMethods.length) { + this.proxyBoundMethods(o); + } + o.indent += TAB; + result = []; + result.push(this.makeCode("class ")); + if (this.name) { + result.push(this.makeCode(`${this.name} `)); + } + if (this.parent) { + result.push(this.makeCode('extends '), ...this.parent.compileToFragments(o), this.makeCode(' ')); + } + result.push(this.makeCode('{')); + if (!this.body.isEmpty()) { + this.body.spaced = true; + result.push(this.makeCode('\n')); + result.push(...this.body.compileToFragments(o, LEVEL_TOP)); + result.push(this.makeCode(`\n${this.tab}`)); + } + result.push(this.makeCode('}')); + return result; } - }; - Class.prototype.setContext = function(name) { - return this.body.traverseChildren(false, function(node) { - if (node.classBody) { - return false; + determineName() { + var message, name, node, ref3, tail; + if (!this.variable) { + return null; } - if (node instanceof ThisLiteral) { - return node.value = name; - } else if (node instanceof Code) { - if (node.bound) { - return node.context = name; + ref3 = this.variable.properties, tail = ref3[ref3.length - 1]; + node = tail ? tail instanceof Access && tail.name : this.variable.base; + if (!(node instanceof IdentifierLiteral || node instanceof PropertyName)) { + return null; + } + name = node.value; + if (!tail) { + message = isUnassignable(name); + if (message) { + this.variable.error(message); } } - }); - }; - - Class.prototype.addBoundFunctions = function(o) { - var bvar, j, len1, lhs, ref3; - ref3 = this.boundFuncs; - for (j = 0, len1 = ref3.length; j < len1; j++) { - bvar = ref3[j]; - lhs = (new Value(new ThisLiteral, [new Access(bvar)])).compile(o); - this.ctor.body.unshift(new Literal(`${lhs} = ${utility('bind', o)}(${lhs}, this)`)); + if (indexOf.call(JS_FORBIDDEN, name) >= 0) { + return `_${name}`; + } else { + return name; + } } - }; - Class.prototype.addProperties = function(node, name, o) { - var acc, assign, base, exprs, func, props; - props = node.base.properties.slice(0); - exprs = (function() { - var results; - results = []; - while (assign = props.shift()) { - if (assign instanceof Assign) { - base = assign.variable.base; - delete assign.context; - func = assign.value; - if (base.value === 'constructor') { - if (this.ctor) { - assign.error('cannot define more than one constructor in a class'); - } - if (func.bound) { - assign.error('cannot define a constructor as a bound function'); + walkBody() { + var assign, end, executableBody, expression, expressions, exprs, i, initializer, initializerExpression, j, k, len1, len2, method, properties, pushSlice, ref3, start; + this.ctor = null; + this.boundMethods = []; + executableBody = null; + initializer = []; + expressions = this.body.expressions; + i = 0; + ref3 = expressions.slice(); + for (j = 0, len1 = ref3.length; j < len1; j++) { + expression = ref3[j]; + if (expression instanceof Value && expression.isObject(true)) { + properties = expression.base.properties; + exprs = []; + end = 0; + start = 0; + pushSlice = function() { + if (end > start) { + return exprs.push(new Value(new Obj(properties.slice(start, end), true))); } - if (func instanceof Code) { - assign = this.ctor = func; - } else { - this.externalCtor = o.classScope.freeVariable('ctor'); - assign = new Assign(new IdentifierLiteral(this.externalCtor), func); + }; + while (assign = properties[end]) { + if (initializerExpression = this.addInitializerExpression(assign)) { + pushSlice(); + exprs.push(initializerExpression); + initializer.push(initializerExpression); + start = end + 1; + } else if (initializer[initializer.length - 1] instanceof Comment) { + exprs.pop(); + initializer.pop(); + start--; } - } else { - if (assign.variable["this"]) { - func["static"] = true; - } else { - acc = base.isComplex() ? new Index(base) : new Access(base); - assign.variable = new Value(new IdentifierLiteral(name), [new Access(new PropertyName('prototype')), acc]); - if (func instanceof Code && func.bound) { - this.boundFuncs.push(base); - func.bound = false; - } + end++; + } + pushSlice(); + [].splice.apply(expressions, [i, i - i + 1].concat(exprs)), exprs; + i += exprs.length; + } else { + if (initializerExpression = this.addInitializerExpression(expression)) { + initializer.push(initializerExpression); + expressions[i] = initializerExpression; + } else if (initializer[initializer.length - 1] instanceof Comment) { + initializer.pop(); + } + i += 1; + } + } + for (k = 0, len2 = initializer.length; k < len2; k++) { + method = initializer[k]; + if (method instanceof Code) { + if (method.ctor) { + if (this.ctor) { + method.error('Cannot define more than one constructor in a class'); } + this.ctor = method; + } else if (method.bound && method.isStatic) { + method.context = this.name; + } else if (method.bound) { + this.boundMethods.push(method.name); + method.bound = false; } } - results.push(assign); } - return results; - }).call(this); - return compact(exprs); - }; + if (this.parent || initializer.length !== expressions.length) { + this.body.expressions = (function() { + var l, len3, results; + results = []; + for (l = 0, len3 = initializer.length; l < len3; l++) { + expression = initializer[l]; + results.push(expression.hoist()); + } + return results; + })(); + return new Block(expressions); + } + } + + addInitializerExpression(node) { + switch (false) { + case !(node instanceof Comment): + return node; + case !this.validInitializerMethod(node): + return this.addInitializerMethod(node); + default: + return null; + } + } - Class.prototype.walkBody = function(name, o) { - return this.traverseChildren(false, (child) => { - var cont, exps, i, j, len1, node, ref3; - cont = true; - if (child instanceof Class) { + validInitializerMethod(node) { + if (!(node instanceof Assign && node.value instanceof Code)) { return false; } - if (child instanceof Block) { - ref3 = exps = child.expressions; - for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { - node = ref3[i]; - if (node instanceof Assign && node.variable.looksStatic(name)) { - node.value["static"] = true; - } else if (node instanceof Value && node.isObject(true)) { - cont = false; - exps[i] = this.addProperties(node, name, o); - } + if (node.context === 'object' && !node.variable.hasProperties()) { + return true; + } + return node.variable.looksStatic(this.name) && (this.name || !node.value.bound); + } + + addInitializerMethod(assign) { + var method, methodName, variable; + variable = assign.variable; + method = assign.value; + method.isMethod = true; + method.isStatic = variable.looksStatic(this.name); + method.klass = new IdentifierLiteral(this.name); + method.variable = variable; + if (method.isStatic) { + method.name = variable.properties[0]; + } else { + methodName = variable.base; + method.name = new (methodName.isComplex() ? Index : Access)(methodName); + if (methodName.value === 'constructor') { + method.ctor = (this.parent ? 'derived' : 'base'); + } + if (method.bound && method.ctor) { + method.error('Cannot define a constructor as a bound function'); } - child.expressions = exps = flatten(exps); } - return cont && !(child instanceof Class); - }); - }; + return method; + } + + makeDefaultConstructor() { + var applyArgs, applyCtor, ctor; + ctor = this.addInitializerMethod(new Assign(new Value(new PropertyName('constructor')), new Code)); + this.body.unshift(ctor); + if (this.parent) { + ctor.body.push(new SuperCall); + } + if (this.externalCtor) { + applyCtor = new Value(this.externalCtor, [new Access(new PropertyName('apply'))]); + applyArgs = [new ThisLiteral, new IdentifierLiteral('arguments')]; + ctor.body.push(new Call(applyCtor, applyArgs)); + ctor.body.makeReturn(); + } + return ctor; + } - Class.prototype.hoistDirectivePrologue = function() { - var expressions, index, node; - index = 0; - expressions = this.body.expressions; - while ((node = expressions[index]) && node instanceof Comment || node instanceof Value && node.isString()) { - ++index; + proxyBoundMethods(o) { + var name; + this.ctor.thisAssignments = (function() { + var j, ref3, results; + ref3 = this.boundMethods; + results = []; + for (j = ref3.length - 1; j >= 0; j += -1) { + name = ref3[j]; + name = new Value(new ThisLiteral, [name]).compile(o); + results.push(new Literal(`${name} = ${utility('bind', o)}(${name}, this)`)); + } + return results; + }).call(this); + return null; } - return this.directives = expressions.splice(0, index); + }; - Class.prototype.ensureConstructor = function(name) { - if (!this.ctor) { - this.ctor = new Code; + Class.__super__ = superClass.prototype; + + Class.prototype.children = ['variable', 'parent', 'body']; + + return Class; + + })(Base); + + exports.ExecutableClassBody = ExecutableClassBody = (function(superClass) { + class ExecutableClassBody extends superClass { + constructor(_class, body1 = new Block) { + super(); + this["class"] = _class; + this.body = body1; + } + + compileNode(o) { + var args, argumentsNode, directives, externalCtor, ident, jumpNode, klass, params, parent, ref3, wrapper; + if (jumpNode = this.body.jumps()) { + jumpNode.error('Class bodies cannot contain pure statements'); + } + if (argumentsNode = this.body.contains(isLiteralArguments)) { + argumentsNode.error("Class bodies shouldn't reference arguments"); + } + this.name = (ref3 = this["class"].name) != null ? ref3 : this.defaultClassVariableName; + directives = this.walkBody(); + this.setContext(); + ident = new IdentifierLiteral(this.name); + params = []; + args = []; + wrapper = new Code(params, this.body); + klass = new Parens(new Call(wrapper, args)); + this.body.spaced = true; + o.classScope = wrapper.makeScope(o.scope); if (this.externalCtor) { - this.ctor.body.push(new Literal(`${this.externalCtor}.apply(this, arguments)`)); - } else if (this.parent) { - this.ctor.body.push(new Literal(`${name}.__super__.constructor.apply(this, arguments)`)); + externalCtor = new IdentifierLiteral(o.classScope.freeVariable('ctor', { + reserve: false + })); + this["class"].externalCtor = externalCtor; + this.externalCtor.variable.base = externalCtor; + } + if (this["class"].parent) { + parent = new IdentifierLiteral(o.classScope.freeVariable('superClass', { + reserve: false + })); + params.push(new Param(parent)); + args.push(this["class"].parent); + this["class"].parent = parent; + this.body.unshift(new Literal(`${this.name}.__super__ = ${parent.value}.prototype`)); + } + if (this.name !== this["class"].name) { + this.body.expressions.unshift(new Assign(new IdentifierLiteral(this.name), this["class"])); + } else { + this.body.expressions.unshift(this["class"]); + } + this.body.expressions.unshift(...directives); + this.body.push(ident); + return klass.compileToFragments(o); + } + + walkBody() { + var directives, expr, index; + directives = []; + index = 0; + while (expr = this.body.expressions[index]) { + if (!(expr instanceof Comment || expr instanceof Value && expr.isString())) { + break; + } + if (expr.hoisted) { + index++; + } else { + directives.push(...this.body.expressions.splice(index, 1)); + } } - this.ctor.body.makeReturn(); - this.body.expressions.unshift(this.ctor); + this.traverseChildren(false, (child) => { + var cont, i, j, len1, node, ref3; + if (child instanceof Class || child instanceof HoistTarget) { + return false; + } + cont = true; + if (child instanceof Block) { + ref3 = child.expressions; + for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { + node = ref3[i]; + if (node instanceof Value && node.isObject(true)) { + cont = false; + child.expressions[i] = this.addProperties(node.base.properties); + } else if (node instanceof Assign && node.variable.looksStatic(this.name)) { + node.value.isStatic = true; + } else if (node instanceof Code && node.isMethod) { + node.klass = new IdentifierLiteral(this.name); + } + } + child.expressions = flatten(child.expressions); + } + return cont; + }); + return directives; } - this.ctor.ctor = this.ctor.name = name; - this.ctor.klass = null; - return this.ctor.noReturn = true; - }; - Class.prototype.compileNode = function(o) { - var args, argumentsNode, func, jumpNode, klass, lname, name, superClass; - if (jumpNode = this.body.jumps()) { - jumpNode.error('Class bodies cannot contain pure statements'); - } - if (argumentsNode = this.body.contains(isLiteralArguments)) { - argumentsNode.error("Class bodies shouldn't reference arguments"); - } - name = this.determineName(); - lname = new IdentifierLiteral(name); - func = new Code([], Block.wrap([this.body])); - args = []; - o.classScope = func.makeScope(o.scope); - this.hoistDirectivePrologue(); - this.setContext(name); - this.walkBody(name, o); - this.ensureConstructor(name); - this.addBoundFunctions(o); - this.body.spaced = true; - this.body.expressions.push(lname); - if (this.parent) { - superClass = new IdentifierLiteral(o.classScope.freeVariable('superClass', { - reserve: false - })); - this.body.expressions.unshift(new Extends(lname, superClass)); - func.params.push(new Param(superClass)); - args.push(this.parent); - } - this.body.expressions.unshift(...this.directives); - klass = new Parens(new Call(func, args)); - if (this.variable) { - klass = new Assign(this.variable, klass, null, { - moduleDeclaration: this.moduleDeclaration + setContext() { + return this.body.traverseChildren(false, (node) => { + if (node instanceof ThisLiteral) { + return node.value = this.name; + } else if (node instanceof Code && node.bound) { + return node.context = this.name; + } }); } - return klass.compileToFragments(o); + + addProperties(assigns) { + var assign, base, name, prototype, result, value, variable; + result = (function() { + var j, len1, results; + results = []; + for (j = 0, len1 = assigns.length; j < len1; j++) { + assign = assigns[j]; + variable = assign.variable; + base = variable != null ? variable.base : void 0; + value = assign.value; + delete assign.context; + if (assign instanceof Comment) { + + } else if (base.value === 'constructor') { + if (value instanceof Code) { + base.error('constructors must be defined at the top level of a class body'); + } + assign = this.externalCtor = new Assign(new Value, value); + } else if (!assign.variable["this"]) { + name = new (base.isComplex() ? Index : Access)(base); + prototype = new Access(new PropertyName('prototype')); + variable = new Value(new ThisLiteral(), [prototype, name]); + assign.variable = variable; + } else if (assign.value instanceof Code) { + assign.value.isStatic = true; + } + results.push(assign); + } + return results; + }).call(this); + return compact(result); + } + }; - return Class; + ExecutableClassBody.__super__ = superClass.prototype; + + ExecutableClassBody.prototype.children = ['class', 'body']; + + ExecutableClassBody.prototype.defaultClassVariableName = '_Class'; + + return ExecutableClassBody; })(Base); - exports.ModuleDeclaration = ModuleDeclaration = (function(superClass1) { - extend1(ModuleDeclaration, superClass1); + exports.ModuleDeclaration = ModuleDeclaration = (function(superClass) { + class ModuleDeclaration extends superClass { + constructor(clause, source1) { + super(); + this.clause = clause; + this.source = source1; + this.checkSource(); + } - function ModuleDeclaration(clause, source1) { - this.clause = clause; - this.source = source1; - this.checkSource(); - } + checkSource() { + if ((this.source != null) && this.source instanceof StringWithInterpolations) { + return this.source.error('the name of the module to be imported from must be an uninterpolated string'); + } + } + + checkScope(o, moduleDeclarationType) { + if (o.indent.length !== 0) { + return this.error(`${moduleDeclarationType} statements must be at top-level scope`); + } + } + + }; + + ModuleDeclaration.__super__ = superClass.prototype; ModuleDeclaration.prototype.children = ['clause', 'source']; @@ -1774,492 +2166,408 @@ ModuleDeclaration.prototype.makeReturn = THIS; - ModuleDeclaration.prototype.checkSource = function() { - if ((this.source != null) && this.source instanceof StringWithInterpolations) { - return this.source.error('the name of the module to be imported from must be an uninterpolated string'); - } - }; - - ModuleDeclaration.prototype.checkScope = function(o, moduleDeclarationType) { - if (o.indent.length !== 0) { - return this.error(`${moduleDeclarationType} statements must be at top-level scope`); - } - }; - return ModuleDeclaration; })(Base); - exports.ImportDeclaration = ImportDeclaration = (function(superClass1) { - extend1(ImportDeclaration, superClass1); - - function ImportDeclaration() { - return ImportDeclaration.__super__.constructor.apply(this, arguments); - } - - ImportDeclaration.prototype.compileNode = function(o) { - var code, ref3; - this.checkScope(o, 'import'); - o.importedSymbols = []; - code = []; - code.push(this.makeCode(`${this.tab}import `)); - if (this.clause != null) { - code.push(...this.clause.compileNode(o)); - } - if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { - if (this.clause !== null) { - code.push(this.makeCode(' from ')); + exports.ImportDeclaration = ImportDeclaration = (function(superClass) { + class ImportDeclaration extends superClass { + compileNode(o) { + var code, ref3; + this.checkScope(o, 'import'); + o.importedSymbols = []; + code = []; + code.push(this.makeCode(`${this.tab}import `)); + if (this.clause != null) { + code.push(...this.clause.compileNode(o)); + } + if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { + if (this.clause !== null) { + code.push(this.makeCode(' from ')); + } + code.push(this.makeCode(this.source.value)); } - code.push(this.makeCode(this.source.value)); + code.push(this.makeCode(';')); + return code; } - code.push(this.makeCode(';')); - return code; + }; + ImportDeclaration.__super__ = superClass.prototype; + return ImportDeclaration; })(ModuleDeclaration); - exports.ImportClause = ImportClause = (function(superClass1) { - extend1(ImportClause, superClass1); - - function ImportClause(defaultBinding, namedImports) { - this.defaultBinding = defaultBinding; - this.namedImports = namedImports; - } - - ImportClause.prototype.children = ['defaultBinding', 'namedImports']; - - ImportClause.prototype.compileNode = function(o) { - var code; - code = []; - if (this.defaultBinding != null) { - code.push(...this.defaultBinding.compileNode(o)); + exports.ImportClause = ImportClause = (function(superClass) { + class ImportClause extends superClass { + constructor(defaultBinding, namedImports) { + super(); + this.defaultBinding = defaultBinding; + this.namedImports = namedImports; + } + + compileNode(o) { + var code; + code = []; + if (this.defaultBinding != null) { + code.push(...this.defaultBinding.compileNode(o)); + if (this.namedImports != null) { + code.push(this.makeCode(', ')); + } + } if (this.namedImports != null) { - code.push(this.makeCode(', ')); + code.push(...this.namedImports.compileNode(o)); } + return code; } - if (this.namedImports != null) { - code.push(...this.namedImports.compileNode(o)); - } - return code; + }; - return ImportClause; + ImportClause.__super__ = superClass.prototype; - })(Base); + ImportClause.prototype.children = ['defaultBinding', 'namedImports']; - exports.ExportDeclaration = ExportDeclaration = (function(superClass1) { - extend1(ExportDeclaration, superClass1); + return ImportClause; - function ExportDeclaration() { - return ExportDeclaration.__super__.constructor.apply(this, arguments); - } + })(Base); - ExportDeclaration.prototype.compileNode = function(o) { - var code, ref3; - this.checkScope(o, 'export'); - code = []; - code.push(this.makeCode(`${this.tab}export `)); - if (this instanceof ExportDefaultDeclaration) { - code.push(this.makeCode('default ')); - } - if (!(this instanceof ExportDefaultDeclaration) && (this.clause instanceof Assign || this.clause instanceof Class)) { - if (this.clause instanceof Class && !this.clause.variable) { - this.clause.error('anonymous classes cannot be exported'); + exports.ExportDeclaration = ExportDeclaration = (function(superClass) { + class ExportDeclaration extends superClass { + compileNode(o) { + var code, ref3; + this.checkScope(o, 'export'); + code = []; + code.push(this.makeCode(`${this.tab}export `)); + if (this instanceof ExportDefaultDeclaration) { + code.push(this.makeCode('default ')); } - code.push(this.makeCode('var ')); - this.clause.moduleDeclaration = 'export'; - } - if ((this.clause.body != null) && this.clause.body instanceof Block) { - code = code.concat(this.clause.compileToFragments(o, LEVEL_TOP)); - } else { - code = code.concat(this.clause.compileNode(o)); - } - if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { - code.push(this.makeCode(` from ${this.source.value}`)); + if (!(this instanceof ExportDefaultDeclaration) && (this.clause instanceof Assign || this.clause instanceof Class)) { + if (this.clause instanceof Class && !this.clause.variable) { + this.clause.error('anonymous classes cannot be exported'); + } + code.push(this.makeCode('var ')); + this.clause.moduleDeclaration = 'export'; + } + if ((this.clause.body != null) && this.clause.body instanceof Block) { + code = code.concat(this.clause.compileToFragments(o, LEVEL_TOP)); + } else { + code = code.concat(this.clause.compileNode(o)); + } + if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { + code.push(this.makeCode(` from ${this.source.value}`)); + } + code.push(this.makeCode(';')); + return code; } - code.push(this.makeCode(';')); - return code; + }; + ExportDeclaration.__super__ = superClass.prototype; + return ExportDeclaration; })(ModuleDeclaration); - exports.ExportNamedDeclaration = ExportNamedDeclaration = (function(superClass1) { - extend1(ExportNamedDeclaration, superClass1); + exports.ExportNamedDeclaration = ExportNamedDeclaration = (function(superClass) { + class ExportNamedDeclaration extends superClass {}; - function ExportNamedDeclaration() { - return ExportNamedDeclaration.__super__.constructor.apply(this, arguments); - } + ExportNamedDeclaration.__super__ = superClass.prototype; return ExportNamedDeclaration; })(ExportDeclaration); - exports.ExportDefaultDeclaration = ExportDefaultDeclaration = (function(superClass1) { - extend1(ExportDefaultDeclaration, superClass1); + exports.ExportDefaultDeclaration = ExportDefaultDeclaration = (function(superClass) { + class ExportDefaultDeclaration extends superClass {}; - function ExportDefaultDeclaration() { - return ExportDefaultDeclaration.__super__.constructor.apply(this, arguments); - } + ExportDefaultDeclaration.__super__ = superClass.prototype; return ExportDefaultDeclaration; })(ExportDeclaration); - exports.ExportAllDeclaration = ExportAllDeclaration = (function(superClass1) { - extend1(ExportAllDeclaration, superClass1); + exports.ExportAllDeclaration = ExportAllDeclaration = (function(superClass) { + class ExportAllDeclaration extends superClass {}; - function ExportAllDeclaration() { - return ExportAllDeclaration.__super__.constructor.apply(this, arguments); - } + ExportAllDeclaration.__super__ = superClass.prototype; return ExportAllDeclaration; })(ExportDeclaration); - exports.ModuleSpecifierList = ModuleSpecifierList = (function(superClass1) { - extend1(ModuleSpecifierList, superClass1); - - function ModuleSpecifierList(specifiers) { - this.specifiers = specifiers; - } - - ModuleSpecifierList.prototype.children = ['specifiers']; + exports.ModuleSpecifierList = ModuleSpecifierList = (function(superClass) { + class ModuleSpecifierList extends superClass { + constructor(specifiers) { + super(); + this.specifiers = specifiers; + } - ModuleSpecifierList.prototype.compileNode = function(o) { - var code, compiledList, fragments, index, j, len1, specifier; - code = []; - o.indent += TAB; - compiledList = (function() { - var j, len1, ref3, results; - ref3 = this.specifiers; - results = []; - for (j = 0, len1 = ref3.length; j < len1; j++) { - specifier = ref3[j]; - results.push(specifier.compileToFragments(o, LEVEL_LIST)); - } - return results; - }).call(this); - if (this.specifiers.length !== 0) { - code.push(this.makeCode(`{\n${o.indent}`)); - for (index = j = 0, len1 = compiledList.length; j < len1; index = ++j) { - fragments = compiledList[index]; - if (index) { - code.push(this.makeCode(`,\n${o.indent}`)); + compileNode(o) { + var code, compiledList, fragments, index, j, len1, specifier; + code = []; + o.indent += TAB; + compiledList = (function() { + var j, len1, ref3, results; + ref3 = this.specifiers; + results = []; + for (j = 0, len1 = ref3.length; j < len1; j++) { + specifier = ref3[j]; + results.push(specifier.compileToFragments(o, LEVEL_LIST)); + } + return results; + }).call(this); + if (this.specifiers.length !== 0) { + code.push(this.makeCode(`{\n${o.indent}`)); + for (index = j = 0, len1 = compiledList.length; j < len1; index = ++j) { + fragments = compiledList[index]; + if (index) { + code.push(this.makeCode(`,\n${o.indent}`)); + } + code.push(...fragments); } - code.push(...fragments); + code.push(this.makeCode("\n}")); + } else { + code.push(this.makeCode('{}')); } - code.push(this.makeCode("\n}")); - } else { - code.push(this.makeCode('{}')); + return code; } - return code; + }; + ModuleSpecifierList.__super__ = superClass.prototype; + + ModuleSpecifierList.prototype.children = ['specifiers']; + return ModuleSpecifierList; })(Base); - exports.ImportSpecifierList = ImportSpecifierList = (function(superClass1) { - extend1(ImportSpecifierList, superClass1); + exports.ImportSpecifierList = ImportSpecifierList = (function(superClass) { + class ImportSpecifierList extends superClass {}; - function ImportSpecifierList() { - return ImportSpecifierList.__super__.constructor.apply(this, arguments); - } + ImportSpecifierList.__super__ = superClass.prototype; return ImportSpecifierList; })(ModuleSpecifierList); - exports.ExportSpecifierList = ExportSpecifierList = (function(superClass1) { - extend1(ExportSpecifierList, superClass1); + exports.ExportSpecifierList = ExportSpecifierList = (function(superClass) { + class ExportSpecifierList extends superClass {}; - function ExportSpecifierList() { - return ExportSpecifierList.__super__.constructor.apply(this, arguments); - } + ExportSpecifierList.__super__ = superClass.prototype; return ExportSpecifierList; })(ModuleSpecifierList); - exports.ModuleSpecifier = ModuleSpecifier = (function(superClass1) { - extend1(ModuleSpecifier, superClass1); + exports.ModuleSpecifier = ModuleSpecifier = (function(superClass) { + class ModuleSpecifier extends superClass { + constructor(original, alias, moduleDeclarationType1) { + super(); + this.original = original; + this.alias = alias; + this.moduleDeclarationType = moduleDeclarationType1; + this.identifier = this.alias != null ? this.alias.value : this.original.value; + } + + compileNode(o) { + var code; + o.scope.add(this.identifier, this.moduleDeclarationType); + code = []; + code.push(this.makeCode(this.original.value)); + if (this.alias != null) { + code.push(this.makeCode(` as ${this.alias.value}`)); + } + return code; + } - function ModuleSpecifier(original, alias, moduleDeclarationType1) { - this.original = original; - this.alias = alias; - this.moduleDeclarationType = moduleDeclarationType1; - this.identifier = this.alias != null ? this.alias.value : this.original.value; - } + }; - ModuleSpecifier.prototype.children = ['original', 'alias']; + ModuleSpecifier.__super__ = superClass.prototype; - ModuleSpecifier.prototype.compileNode = function(o) { - var code; - o.scope.add(this.identifier, this.moduleDeclarationType); - code = []; - code.push(this.makeCode(this.original.value)); - if (this.alias != null) { - code.push(this.makeCode(` as ${this.alias.value}`)); - } - return code; - }; + ModuleSpecifier.prototype.children = ['original', 'alias']; return ModuleSpecifier; })(Base); - exports.ImportSpecifier = ImportSpecifier = (function(superClass1) { - extend1(ImportSpecifier, superClass1); - - function ImportSpecifier(imported, local) { - ImportSpecifier.__super__.constructor.call(this, imported, local, 'import'); - } + exports.ImportSpecifier = ImportSpecifier = (function(superClass) { + class ImportSpecifier extends superClass { + constructor(imported, local) { + super(imported, local, 'import'); + } - ImportSpecifier.prototype.compileNode = function(o) { - var ref3; - if ((ref3 = this.identifier, indexOf.call(o.importedSymbols, ref3) >= 0) || o.scope.check(this.identifier)) { - this.error(`'${this.identifier}' has already been declared`); - } else { - o.importedSymbols.push(this.identifier); + compileNode(o) { + var ref3; + if ((ref3 = this.identifier, indexOf.call(o.importedSymbols, ref3) >= 0) || o.scope.check(this.identifier)) { + this.error(`'${this.identifier}' has already been declared`); + } else { + o.importedSymbols.push(this.identifier); + } + return ImportSpecifier.__super__.compileNode.call(this, o); } - return ImportSpecifier.__super__.compileNode.call(this, o); + }; + ImportSpecifier.__super__ = superClass.prototype; + return ImportSpecifier; })(ModuleSpecifier); - exports.ImportDefaultSpecifier = ImportDefaultSpecifier = (function(superClass1) { - extend1(ImportDefaultSpecifier, superClass1); + exports.ImportDefaultSpecifier = ImportDefaultSpecifier = (function(superClass) { + class ImportDefaultSpecifier extends superClass {}; - function ImportDefaultSpecifier() { - return ImportDefaultSpecifier.__super__.constructor.apply(this, arguments); - } + ImportDefaultSpecifier.__super__ = superClass.prototype; return ImportDefaultSpecifier; })(ImportSpecifier); - exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier = (function(superClass1) { - extend1(ImportNamespaceSpecifier, superClass1); + exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier = (function(superClass) { + class ImportNamespaceSpecifier extends superClass {}; - function ImportNamespaceSpecifier() { - return ImportNamespaceSpecifier.__super__.constructor.apply(this, arguments); - } + ImportNamespaceSpecifier.__super__ = superClass.prototype; return ImportNamespaceSpecifier; })(ImportSpecifier); - exports.ExportSpecifier = ExportSpecifier = (function(superClass1) { - extend1(ExportSpecifier, superClass1); + exports.ExportSpecifier = ExportSpecifier = (function(superClass) { + class ExportSpecifier extends superClass { + constructor(local, exported) { + super(local, exported, 'export'); + } + + }; - function ExportSpecifier(local, exported) { - ExportSpecifier.__super__.constructor.call(this, local, exported, 'export'); - } + ExportSpecifier.__super__ = superClass.prototype; return ExportSpecifier; })(ModuleSpecifier); - exports.Assign = Assign = (function(superClass1) { - extend1(Assign, superClass1); - - function Assign(variable1, value1, context, options = {}) { - this.variable = variable1; - this.value = value1; - this.context = context; - this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken, this.moduleDeclaration = options.moduleDeclaration; - } - - Assign.prototype.children = ['variable', 'value']; + exports.Assign = Assign = (function(superClass) { + class Assign extends superClass { + constructor(variable1, value1, context1, options = {}) { + super(); + this.variable = variable1; + this.value = value1; + this.context = context1; + this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken, this.moduleDeclaration = options.moduleDeclaration; + } - Assign.prototype.isStatement = function(o) { - return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && (this.moduleDeclaration || indexOf.call(this.context, "?") >= 0); - }; + isStatement(o) { + return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && (this.moduleDeclaration || indexOf.call(this.context, "?") >= 0); + } - Assign.prototype.checkAssignability = function(o, varBase) { - if (Object.prototype.hasOwnProperty.call(o.scope.positions, varBase.value) && o.scope.variables[o.scope.positions[varBase.value]].type === 'import') { - return varBase.error(`'${varBase.value}' is read-only`); + checkAssignability(o, varBase) { + if (Object.prototype.hasOwnProperty.call(o.scope.positions, varBase.value) && o.scope.variables[o.scope.positions[varBase.value]].type === 'import') { + return varBase.error(`'${varBase.value}' is read-only`); + } } - }; - Assign.prototype.assigns = function(name) { - return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); - }; + assigns(name) { + return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); + } - Assign.prototype.unfoldSoak = function(o) { - return unfoldSoak(o, this, 'variable'); - }; + unfoldSoak(o) { + return unfoldSoak(o, this, 'variable'); + } - Assign.prototype.compileNode = function(o) { - var answer, compiledName, isValue, j, name, properties, prototype, ref3, ref4, ref5, ref6, ref7, ref8, val, varBase; - if (isValue = this.variable instanceof Value) { - if (this.variable.isArray() || this.variable.isObject()) { - return this.compilePatternMatch(o); - } - if (this.variable.isSplice()) { - return this.compileSplice(o); - } - if ((ref3 = this.context) === '||=' || ref3 === '&&=' || ref3 === '?=') { - return this.compileConditional(o); - } - if ((ref4 = this.context) === '**=' || ref4 === '//=' || ref4 === '%%=') { - return this.compileSpecialMath(o); + compileNode(o) { + var answer, compiledName, isValue, j, name, properties, prototype, ref3, ref4, ref5, ref6, ref7, ref8, val, varBase; + if (isValue = this.variable instanceof Value) { + if (this.variable.isArray() || this.variable.isObject()) { + return this.compilePatternMatch(o); + } + if (this.variable.isSplice()) { + return this.compileSplice(o); + } + if ((ref3 = this.context) === '||=' || ref3 === '&&=' || ref3 === '?=') { + return this.compileConditional(o); + } + if ((ref4 = this.context) === '**=' || ref4 === '//=' || ref4 === '%%=') { + return this.compileSpecialMath(o); + } } - } - if (this.value instanceof Code) { - if (this.value["static"]) { - this.value.klass = this.variable.base; - this.value.name = this.variable.properties[0]; - this.value.variable = this.variable; - } else if (((ref5 = this.variable.properties) != null ? ref5.length : void 0) >= 2) { - ref6 = this.variable.properties, properties = 3 <= ref6.length ? slice.call(ref6, 0, j = ref6.length - 2) : (j = 0, []), prototype = ref6[j++], name = ref6[j++]; - if (((ref7 = prototype.name) != null ? ref7.value : void 0) === 'prototype') { - this.value.klass = new Value(this.variable.base, properties); - this.value.name = name; + if (this.value instanceof Code) { + if (this.value.isStatic) { + this.value.klass = this.variable.base; + this.value.name = this.variable.properties[0]; this.value.variable = this.variable; + } else if (((ref5 = this.variable.properties) != null ? ref5.length : void 0) >= 2) { + ref6 = this.variable.properties, properties = 3 <= ref6.length ? slice.call(ref6, 0, j = ref6.length - 2) : (j = 0, []), prototype = ref6[j++], name = ref6[j++]; + if (((ref7 = prototype.name) != null ? ref7.value : void 0) === 'prototype') { + this.value.klass = new Value(this.variable.base, properties); + this.value.name = name; + this.value.variable = this.variable; + } } } - } - if (!this.context) { - varBase = this.variable.unwrapAll(); - if (!varBase.isAssignable()) { - this.variable.error(`'${this.variable.compile(o)}' can't be assigned`); - } - if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { - if (this.moduleDeclaration) { - this.checkAssignability(o, varBase); - o.scope.add(varBase.value, this.moduleDeclaration); - } else if (this.param) { - o.scope.add(varBase.value, 'var'); - } else { - this.checkAssignability(o, varBase); - o.scope.find(varBase.value); + if (!this.context) { + varBase = this.variable.unwrapAll(); + if (!varBase.isAssignable()) { + this.variable.error(`'${this.variable.compile(o)}' can't be assigned`); + } + if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { + if (this.moduleDeclaration) { + this.checkAssignability(o, varBase); + o.scope.add(varBase.value, this.moduleDeclaration); + } else if (this.param) { + o.scope.add(varBase.value, 'var'); + } else { + this.checkAssignability(o, varBase); + o.scope.find(varBase.value); + } } } - } - val = this.value.compileToFragments(o, LEVEL_LIST); - if (isValue && this.variable.base instanceof Obj) { - this.variable.front = true; - } - compiledName = this.variable.compileToFragments(o, LEVEL_LIST); - if (this.context === 'object') { - if (this.variable.isComplex()) { - compiledName.unshift(this.makeCode('[')); - compiledName.push(this.makeCode(']')); - } else if (ref8 = fragmentsToText(compiledName), indexOf.call(JS_FORBIDDEN, ref8) >= 0) { - compiledName.unshift(this.makeCode('"')); - compiledName.push(this.makeCode('"')); - } - return compiledName.concat(this.makeCode(": "), val); - } - answer = compiledName.concat(this.makeCode(` ${this.context || '='} `), val); - if (o.level <= LEVEL_LIST) { - return answer; - } else { - return this.wrapInBraces(answer); - } - }; - - Assign.prototype.compilePatternMatch = function(o) { - var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, rest, top, val, value, vvar, vvarText; - top = o.level === LEVEL_TOP; - value = this.value; - objects = this.variable.base.objects; - if (!(olen = objects.length)) { - code = value.compileToFragments(o); - if (o.level >= LEVEL_OP) { - return this.wrapInBraces(code); - } else { - return code; + val = this.value.compileToFragments(o, LEVEL_LIST); + if (isValue && this.variable.base instanceof Obj) { + this.variable.front = true; } - } - obj = objects[0]; - if (olen === 1 && obj instanceof Expansion) { - obj.error('Destructuring assignment has no target'); - } - isObject = this.variable.isObject(); - if (top && olen === 1 && !(obj instanceof Splat)) { - defaultValue = null; - if (obj instanceof Assign && obj.context === 'object') { - ref3 = obj, (ref4 = ref3.variable, idx = ref4.base), obj = ref3.value; - if (obj instanceof Assign) { - defaultValue = obj.value; - obj = obj.variable; + compiledName = this.variable.compileToFragments(o, LEVEL_LIST); + if (this.context === 'object') { + if (this.variable.isComplex()) { + compiledName.unshift(this.makeCode('[')); + compiledName.push(this.makeCode(']')); + } else if (ref8 = fragmentsToText(compiledName), indexOf.call(JS_FORBIDDEN, ref8) >= 0) { + compiledName.unshift(this.makeCode('"')); + compiledName.push(this.makeCode('"')); } + return compiledName.concat(this.makeCode(": "), val); + } + answer = compiledName.concat(this.makeCode(` ${this.context || '='} `), val); + if (o.level <= LEVEL_LIST) { + return answer; } else { - if (obj instanceof Assign) { - defaultValue = obj.value; - obj = obj.variable; - } - idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new NumberLiteral(0); + return this.wrapInBraces(answer); } - acc = idx.unwrap() instanceof PropertyName; - value = new Value(value); - value.properties.push(new (acc ? Access : Index)(idx)); - message = isUnassignable(obj.unwrap().value); - if (message) { - obj.error(message); - } - if (defaultValue) { - value = new Op('?', value, defaultValue); - } - return new Assign(obj, value, null, { - param: this.param - }).compileToFragments(o, LEVEL_TOP); - } - vvar = value.compileToFragments(o, LEVEL_LIST); - vvarText = fragmentsToText(vvar); - assigns = []; - expandedIdx = false; - if (!(value.unwrap() instanceof IdentifierLiteral) || this.variable.assigns(vvarText)) { - assigns.push([this.makeCode(`${(ref = o.scope.freeVariable('ref'))} = `), ...vvar]); - vvar = [this.makeCode(ref)]; - vvarText = ref; - } - for (i = j = 0, len1 = objects.length; j < len1; i = ++j) { - obj = objects[i]; - idx = i; - if (!expandedIdx && obj instanceof Splat) { - name = obj.name.unwrap().value; - obj = obj.unwrap(); - val = `${olen} <= ${vvarText}.length ? ${utility('slice', o)}.call(${vvarText}, ${i}`; - if (rest = olen - i - 1) { - ivar = o.scope.freeVariable('i', { - single: true - }); - val += `, ${ivar} = ${vvarText}.length - ${rest}) : (${ivar} = ${i}, [])`; + } + + compilePatternMatch(o) { + var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, rest, top, val, value, vvar, vvarText; + top = o.level === LEVEL_TOP; + value = this.value; + objects = this.variable.base.objects; + if (!(olen = objects.length)) { + code = value.compileToFragments(o); + if (o.level >= LEVEL_OP) { + return this.wrapInBraces(code); } else { - val += ") : []"; - } - val = new Literal(val); - expandedIdx = `${ivar}++`; - } else if (!expandedIdx && obj instanceof Expansion) { - if (rest = olen - i - 1) { - if (rest === 1) { - expandedIdx = `${vvarText}.length - 1`; - } else { - ivar = o.scope.freeVariable('i', { - single: true - }); - val = new Literal(`${ivar} = ${vvarText}.length - ${rest}`); - expandedIdx = `${ivar}++`; - assigns.push(val.compileToFragments(o, LEVEL_LIST)); - } - } - continue; - } else { - if (obj instanceof Splat || obj instanceof Expansion) { - obj.error("multiple splats/expansions are disallowed in an assignment"); + return code; } + } + obj = objects[0]; + if (olen === 1 && obj instanceof Expansion) { + obj.error('Destructuring assignment has no target'); + } + isObject = this.variable.isObject(); + if (top && olen === 1 && !(obj instanceof Splat)) { defaultValue = null; if (obj instanceof Assign && obj.context === 'object') { - ref5 = obj, (ref6 = ref5.variable, idx = ref6.base), obj = ref5.value; + ref3 = obj, (ref4 = ref3.variable, idx = ref4.base), obj = ref3.value; if (obj instanceof Assign) { defaultValue = obj.value; obj = obj.variable; @@ -2269,917 +2577,1144 @@ defaultValue = obj.value; obj = obj.variable; } - idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new Literal(expandedIdx || idx); + idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new NumberLiteral(0); } - name = obj.unwrap().value; acc = idx.unwrap() instanceof PropertyName; - val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]); + value = new Value(value); + value.properties.push(new (acc ? Access : Index)(idx)); + message = isUnassignable(obj.unwrap().value); + if (message) { + obj.error(message); + } if (defaultValue) { - val = new Op('?', val, defaultValue); + value = new Op('?', value, defaultValue); } + return new Assign(obj, value, null, { + param: this.param + }).compileToFragments(o, LEVEL_TOP); } - if (name != null) { - message = isUnassignable(name); - if (message) { - obj.error(message); + vvar = value.compileToFragments(o, LEVEL_LIST); + vvarText = fragmentsToText(vvar); + assigns = []; + expandedIdx = false; + if (!(value.unwrap() instanceof IdentifierLiteral) || this.variable.assigns(vvarText)) { + assigns.push([this.makeCode(`${(ref = o.scope.freeVariable('ref'))} = `), ...vvar]); + vvar = [this.makeCode(ref)]; + vvarText = ref; + } + for (i = j = 0, len1 = objects.length; j < len1; i = ++j) { + obj = objects[i]; + idx = i; + if (!expandedIdx && obj instanceof Splat) { + name = obj.name.unwrap().value; + obj = obj.unwrap(); + val = `${olen} <= ${vvarText}.length ? ${utility('slice', o)}.call(${vvarText}, ${i}`; + if (rest = olen - i - 1) { + ivar = o.scope.freeVariable('i', { + single: true + }); + val += `, ${ivar} = ${vvarText}.length - ${rest}) : (${ivar} = ${i}, [])`; + } else { + val += ") : []"; + } + val = new Literal(val); + expandedIdx = `${ivar}++`; + } else if (!expandedIdx && obj instanceof Expansion) { + if (rest = olen - i - 1) { + if (rest === 1) { + expandedIdx = `${vvarText}.length - 1`; + } else { + ivar = o.scope.freeVariable('i', { + single: true + }); + val = new Literal(`${ivar} = ${vvarText}.length - ${rest}`); + expandedIdx = `${ivar}++`; + assigns.push(val.compileToFragments(o, LEVEL_LIST)); + } + } + continue; + } else { + if (obj instanceof Splat || obj instanceof Expansion) { + obj.error("multiple splats/expansions are disallowed in an assignment"); + } + defaultValue = null; + if (obj instanceof Assign && obj.context === 'object') { + ref5 = obj, (ref6 = ref5.variable, idx = ref6.base), obj = ref5.value; + if (obj instanceof Assign) { + defaultValue = obj.value; + obj = obj.variable; + } + } else { + if (obj instanceof Assign) { + defaultValue = obj.value; + obj = obj.variable; + } + idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new Literal(expandedIdx || idx); + } + name = obj.unwrap().value; + acc = idx.unwrap() instanceof PropertyName; + val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]); + if (defaultValue) { + val = new Op('?', val, defaultValue); + } + } + if (name != null) { + message = isUnassignable(name); + if (message) { + obj.error(message); + } } + assigns.push(new Assign(obj, val, null, { + param: this.param, + subpattern: true + }).compileToFragments(o, LEVEL_LIST)); } - assigns.push(new Assign(obj, val, null, { - param: this.param, - subpattern: true - }).compileToFragments(o, LEVEL_LIST)); - } - if (!(top || this.subpattern)) { - assigns.push(vvar); - } - fragments = this.joinFragmentArrays(assigns, ', '); - if (o.level < LEVEL_LIST) { - return fragments; - } else { - return this.wrapInBraces(fragments); - } - }; - - Assign.prototype.compileConditional = function(o) { - var fragments, left, ref3, right; - ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; - if (!left.properties.length && left.base instanceof Literal && !(left.base instanceof ThisLiteral) && !o.scope.check(left.base.value)) { - this.variable.error(`the variable \"${left.base.value}\" can't be assigned with ${this.context} because it has not been declared before`); - } - if (indexOf.call(this.context, "?") >= 0) { - o.isExistentialEquals = true; - return new If(new Existence(left), right, { - type: 'if' - }).addElse(new Assign(right, this.value, '=')).compileToFragments(o); - } else { - fragments = new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o); - if (o.level <= LEVEL_LIST) { + if (!(top || this.subpattern)) { + assigns.push(vvar); + } + fragments = this.joinFragmentArrays(assigns, ', '); + if (o.level < LEVEL_LIST) { return fragments; } else { return this.wrapInBraces(fragments); } } - }; - - Assign.prototype.compileSpecialMath = function(o) { - var left, ref3, right; - ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; - return new Assign(left, new Op(this.context.slice(0, -1), right, this.value)).compileToFragments(o); - }; - Assign.prototype.compileSplice = function(o) { - var answer, exclusive, from, fromDecl, fromRef, name, ref3, ref4, ref5, to, valDef, valRef; - ref3 = this.variable.properties.pop().range, from = ref3.from, to = ref3.to, exclusive = ref3.exclusive; - name = this.variable.compile(o); - if (from) { - ref4 = this.cacheToCodeFragments(from.cache(o, LEVEL_OP)), fromDecl = ref4[0], fromRef = ref4[1]; - } else { - fromDecl = fromRef = '0'; - } - if (to) { - if ((from != null ? from.isNumber() : void 0) && to.isNumber()) { - to = to.compile(o) - fromRef; - if (!exclusive) { - to += 1; - } + compileConditional(o) { + var fragments, left, ref3, right; + ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; + if (!left.properties.length && left.base instanceof Literal && !(left.base instanceof ThisLiteral) && !o.scope.check(left.base.value)) { + this.variable.error(`the variable \"${left.base.value}\" can't be assigned with ${this.context} because it has not been declared before`); + } + if (indexOf.call(this.context, "?") >= 0) { + o.isExistentialEquals = true; + return new If(new Existence(left), right, { + type: 'if' + }).addElse(new Assign(right, this.value, '=')).compileToFragments(o); } else { - to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; - if (!exclusive) { - to += ' + 1'; + fragments = new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o); + if (o.level <= LEVEL_LIST) { + return fragments; + } else { + return this.wrapInBraces(fragments); } } - } else { - to = "9e9"; - } - ref5 = this.value.cache(o, LEVEL_LIST), valDef = ref5[0], valRef = ref5[1]; - answer = [].concat(this.makeCode(`[].splice.apply(${name}, [${fromDecl}, ${to}].concat(`), valDef, this.makeCode(")), "), valRef); - if (o.level > LEVEL_TOP) { - return this.wrapInBraces(answer); - } else { - return answer; } - }; - - return Assign; - - })(Base); - exports.Code = Code = (function(superClass1) { - extend1(Code, superClass1); + compileSpecialMath(o) { + var left, ref3, right; + ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; + return new Assign(left, new Op(this.context.slice(0, -1), right, this.value)).compileToFragments(o); + } - function Code(params, body, tag) { - this.params = params || []; - this.body = body || new Block; - this.bound = tag === 'boundfunc'; - this.isGenerator = false; - this.isAsync = false; - this.body.traverseChildren(false, (node) => { - if ((node instanceof Op && node.isYield()) || node instanceof YieldReturn) { - this.isGenerator = true; + compileSplice(o) { + var answer, exclusive, from, fromDecl, fromRef, name, ref3, ref4, ref5, to, valDef, valRef; + ref3 = this.variable.properties.pop().range, from = ref3.from, to = ref3.to, exclusive = ref3.exclusive; + name = this.variable.compile(o); + if (from) { + ref4 = this.cacheToCodeFragments(from.cache(o, LEVEL_OP)), fromDecl = ref4[0], fromRef = ref4[1]; + } else { + fromDecl = fromRef = '0'; } - if ((node instanceof Op && node.isAwait()) || node instanceof AwaitReturn) { - this.isAsync = true; + if (to) { + if ((from != null ? from.isNumber() : void 0) && to.isNumber()) { + to = to.compile(o) - fromRef; + if (!exclusive) { + to += 1; + } + } else { + to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; + if (!exclusive) { + to += ' + 1'; + } + } + } else { + to = "9e9"; } - if (this.isGenerator && this.isAsync) { - return node.error("function can't contain both yield and await"); + ref5 = this.value.cache(o, LEVEL_LIST), valDef = ref5[0], valRef = ref5[1]; + answer = [].concat(this.makeCode(`[].splice.apply(${name}, [${fromDecl}, ${to}].concat(`), valDef, this.makeCode(")), "), valRef); + if (o.level > LEVEL_TOP) { + return this.wrapInBraces(answer); + } else { + return answer; } - }); - } - - Code.prototype.children = ['params', 'body']; + } - Code.prototype.isStatement = function() { - return !!this.ctor; }; - Code.prototype.jumps = NO; + Assign.__super__ = superClass.prototype; - Code.prototype.makeScope = function(parentScope) { - return new Scope(parentScope, this.body, this); - }; + Assign.prototype.children = ['variable', 'value']; + + return Assign; + + })(Base); + + exports.Code = Code = (function(superClass) { + class Code extends superClass { + constructor(params, body, tag) { + super(); + this.params = params || []; + this.body = body || new Block; + this.bound = tag === 'boundfunc'; + this.isGenerator = false; + this.isAsync = false; + this.isMethod = false; + this.body.traverseChildren(false, (node) => { + if ((node instanceof Op && node.isYield()) || node instanceof YieldReturn) { + this.isGenerator = true; + } + if ((node instanceof Op && node.isAwait()) || node instanceof AwaitReturn) { + this.isAsync = true; + } + if (this.isGenerator && this.isAsync) { + return node.error("function can't contain both yield and await"); + } + }); + } + + isStatement() { + return this.isMethod; + } - Code.prototype.compileNode = function(o) { - var answer, code, condition, exprs, haveSplatParam, i, ifTrue, j, k, len1, len2, param, paramNames, params, paramsAfterSplat, ref, ref3, ref4, ref5, splatParamName, val, wasEmpty; - if (this.bound) { - if ((ref3 = o.scope.method) != null ? ref3.bound : void 0) { - this.context = o.scope.method.context; + makeScope(parentScope) { + return new Scope(parentScope, this.body, this); + } + + compileNode(o) { + var answer, body, condition, exprs, haveSplatParam, i, ifTrue, j, k, len1, len2, m, modifiers, name, param, paramNames, params, paramsAfterSplat, ref, ref3, ref4, ref5, ref6, ref7, signature, splatParamName, thisAssignments, val, wasEmpty; + if (this.ctor) { + if (this.isAsync) { + this.variable.error('Class constructor may not be async'); + } + if (this.isGenerator) { + this.variable.error('Class constructor may not be a generator'); + } } - if (!this.context) { - this.context = 'this'; - } - } - o.scope = del(o, 'classScope') || this.makeScope(o.scope); - o.scope.shared = del(o, 'sharedScope'); - o.indent += TAB; - delete o.bare; - delete o.isExistentialEquals; - params = []; - exprs = []; - paramsAfterSplat = []; - haveSplatParam = false; - paramNames = []; - this.eachParamName((name, node) => { - if (indexOf.call(paramNames, name) >= 0) { - node.error(`multiple parameters named '${name}'`); - } - return paramNames.push(name); - }); - ref4 = this.params; - for (i = j = 0, len1 = ref4.length; j < len1; i = ++j) { - param = ref4[i]; - if (param.splat || param instanceof Expansion) { - if (haveSplatParam) { - param.error('only one splat or expansion parameter is allowed per function definition'); - } else if (param instanceof Expansion && this.params.length === 1) { - param.error('an expansion parameter cannot be the only parameter in a function definition'); - } - haveSplatParam = true; - if (param.splat) { - params.push(ref = param.asReference(o)); - splatParamName = fragmentsToText(ref.compileNode(o)); - if (param.isComplex()) { - exprs.push(new Assign(new Value(param.name), ref, '=', { - param: true - })); - } - } else { - splatParamName = o.scope.freeVariable('args'); - params.push(new Value(new IdentifierLiteral(splatParamName))); + if (this.bound) { + if ((ref3 = o.scope.method) != null ? ref3.bound : void 0) { + this.context = o.scope.method.context; } - o.scope.parameter(splatParamName); - } else { - if (param.isComplex()) { - val = ref = param.asReference(o); - if (param.value) { - val = new Op('?', ref, param.value); + if (!this.context) { + this.context = 'this'; + } + } + o.scope = del(o, 'classScope') || this.makeScope(o.scope); + o.scope.shared = del(o, 'sharedScope'); + o.indent += TAB; + delete o.bare; + delete o.isExistentialEquals; + params = []; + exprs = []; + thisAssignments = (ref4 = (ref5 = this.thisAssignments) != null ? ref5.slice() : void 0) != null ? ref4 : []; + paramsAfterSplat = []; + haveSplatParam = false; + paramNames = []; + this.eachParamName(function(name, node, param) { + var target; + if (indexOf.call(paramNames, name) >= 0) { + node.error(`multiple parameters named '${name}'`); + } + paramNames.push(name); + if (node["this"]) { + name = node.properties[0].name.value; + if (indexOf.call(JS_FORBIDDEN, name) >= 0) { + name = `_${name}`; } - exprs.push(new Assign(new Value(param.name), val, '=', { - param: true - })); + target = new IdentifierLiteral(o.scope.freeVariable(name)); + param.renameParam(node, target); + return thisAssignments.push(new Assign(node, target)); } - if (!haveSplatParam) { - if (!param.isComplex()) { - ref = param.value != null ? new Assign(new Value(param.name), param.value, '=') : param; + }); + ref6 = this.params; + for (i = j = 0, len1 = ref6.length; j < len1; i = ++j) { + param = ref6[i]; + if (param.splat || param instanceof Expansion) { + if (haveSplatParam) { + param.error('only one splat or expansion parameter is allowed per function definition'); + } else if (param instanceof Expansion && this.params.length === 1) { + param.error('an expansion parameter cannot be the only parameter in a function definition'); + } + haveSplatParam = true; + if (param.splat) { + params.push(ref = param.asReference(o)); + splatParamName = fragmentsToText(ref.compileNode(o)); + if (param.isComplex()) { + exprs.push(new Assign(new Value(param.name), ref, '=', { + param: true + })); + } + } else { + splatParamName = o.scope.freeVariable('args'); + params.push(new Value(new IdentifierLiteral(splatParamName))); } - o.scope.parameter(fragmentsToText((param.value != null ? param : ref).compileToFragments(o))); - params.push(ref); + o.scope.parameter(splatParamName); } else { - paramsAfterSplat.push(param); - if ((param.value != null) && !param.isComplex()) { - condition = new Literal(param.name.value + ' === undefined'); - ifTrue = new Assign(new Value(param.name), param.value, '='); - exprs.push(new If(condition, ifTrue)); + if (param.isComplex()) { + val = ref = param.asReference(o); + if (param.value) { + val = new Op('?', ref, param.value); + } + exprs.push(new Assign(new Value(param.name), val, '=', { + param: true + })); } - if (((ref5 = param.name) != null ? ref5.value : void 0) != null) { - o.scope.add(param.name.value, 'var', true); + if (!haveSplatParam) { + if (!param.isComplex()) { + ref = param.value != null ? new Assign(new Value(param.name), param.value, '=') : param; + } + o.scope.parameter(fragmentsToText((param.value != null ? param : ref).compileToFragments(o))); + params.push(ref); + } else { + paramsAfterSplat.push(param); + if ((param.value != null) && !param.isComplex()) { + condition = new Literal(param.name.value + ' === undefined'); + ifTrue = new Assign(new Value(param.name), param.value, '='); + exprs.push(new If(condition, ifTrue)); + } + if (((ref7 = param.name) != null ? ref7.value : void 0) != null) { + o.scope.add(param.name.value, 'var', true); + } } } } - } - if (paramsAfterSplat.length !== 0) { - exprs.unshift(new Assign(new Value(new Arr([ - new Splat(new IdentifierLiteral(splatParamName)), ...(function() { - var k, len2, results; - results = []; - for (k = 0, len2 = paramsAfterSplat.length; k < len2; k++) { - param = paramsAfterSplat[k]; - results.push(param.asReference(o)); - } - return results; - })() - ])), new Value(new IdentifierLiteral(splatParamName)))); - } - wasEmpty = this.body.isEmpty(); - if (exprs.length) { + if (paramsAfterSplat.length !== 0) { + exprs.unshift(new Assign(new Value(new Arr([ + new Splat(new IdentifierLiteral(splatParamName)), ...(function() { + var k, len2, results; + results = []; + for (k = 0, len2 = paramsAfterSplat.length; k < len2; k++) { + param = paramsAfterSplat[k]; + results.push(param.asReference(o)); + } + return results; + })() + ])), new Value(new IdentifierLiteral(splatParamName)))); + } + wasEmpty = this.body.isEmpty(); + if (!this.expandCtorSuper(thisAssignments)) { + this.body.expressions.unshift(...thisAssignments); + } this.body.expressions.unshift(...exprs); - } - if (!(wasEmpty || this.noReturn)) { - this.body.makeReturn(); - } - code = ''; - if (this.isAsync) { - code += 'async '; - } - if (!this.bound) { - code += 'function'; + if (!(wasEmpty || this.noReturn)) { + this.body.makeReturn(); + } + modifiers = []; + if (this.isMethod && this.isStatic) { + modifiers.push('static'); + } + if (this.isAsync) { + modifiers.push('async'); + } + if (!this.isMethod && !this.bound) { + modifiers.push('function'); + } if (this.isGenerator) { - code += '*'; + modifiers.push('*'); } - if (this.ctor) { - code += ' ' + this.name; + signature = [this.makeCode('(')]; + for (i = k = 0, len2 = params.length; k < len2; i = ++k) { + param = params[i]; + if (i) { + signature.push(this.makeCode(', ')); + } + if (haveSplatParam && i === params.length - 1) { + signature.push(this.makeCode('...')); + } + signature.push(...param.compileToFragments(o)); } - } - code += '('; - answer = [this.makeCode(code)]; - for (i = k = 0, len2 = params.length; k < len2; i = ++k) { - param = params[i]; - if (i) { - answer.push(this.makeCode(', ')); + signature.push(this.makeCode(')')); + if (!this.body.isEmpty()) { + body = this.body.compileWithDeclarations(o); } - if (haveSplatParam && i === params.length - 1) { - answer.push(this.makeCode('...')); + if (this.isMethod) { + name = this.name.compileToFragments(o); + if (name[0].code === '.') { + name.shift(); + } + } + answer = this.joinFragmentArrays((function() { + var l, len3, results; + results = []; + for (l = 0, len3 = modifiers.length; l < len3; l++) { + m = modifiers[l]; + results.push(this.makeCode(m)); + } + return results; + }).call(this), ' '); + if (modifiers.length && name) { + answer.push(this.makeCode(' ')); + } + if (name) { + answer.push(...name); + } + answer.push(...signature); + if (this.bound && !this.isMethod) { + answer.push(this.makeCode(' =>')); + } + answer.push(this.makeCode(' {')); + if (body != null ? body.length : void 0) { + answer.push(this.makeCode('\n'), ...body, this.makeCode(`\n${this.tab}`)); + } + answer.push(this.makeCode('}')); + if (this.isMethod) { + return [this.makeCode(this.tab), ...answer]; + } + if (this.front || (o.level >= LEVEL_ACCESS)) { + return this.wrapInBraces(answer); + } else { + return answer; } - answer.push(...param.compileToFragments(o)); - } - answer.push(this.makeCode(!this.bound ? ') {' : ') => {')); - if (!this.body.isEmpty()) { - answer = answer.concat(this.makeCode("\n"), this.body.compileWithDeclarations(o), this.makeCode(`\n${this.tab}`)); } - answer.push(this.makeCode('}')); - if (this.ctor) { - return [this.makeCode(this.tab), ...answer]; + + eachParamName(iterator) { + var j, len1, param, ref3, results; + ref3 = this.params; + results = []; + for (j = 0, len1 = ref3.length; j < len1; j++) { + param = ref3[j]; + results.push(param.eachName(iterator)); + } + return results; } - if (this.front || (o.level >= LEVEL_ACCESS)) { - return this.wrapInBraces(answer); - } else { - return answer; + + traverseChildren(crossScope, func) { + if (crossScope) { + return Code.__super__.traverseChildren.call(this, crossScope, func); + } } - }; - Code.prototype.eachParamName = function(iterator) { - var j, len1, param, ref3, results; - ref3 = this.params; - results = []; - for (j = 0, len1 = ref3.length; j < len1; j++) { - param = ref3[j]; - results.push(param.eachName(iterator)); + replaceInContext(child, replacement) { + if (this.bound) { + return Code.__super__.replaceInContext.call(this, child, replacement); + } else { + return false; + } } - return results; - }; - Code.prototype.traverseChildren = function(crossScope, func) { - if (crossScope) { - return Code.__super__.traverseChildren.call(this, crossScope, func); + expandCtorSuper(thisAssignments) { + var haveThisParam, param, ref3, seenSuper; + if (!this.ctor) { + return false; + } + this.eachSuperCall(Block.wrap(this.params), function(superCall) { + return superCall.error("'super' is not allowed in constructor parameter defaults"); + }); + seenSuper = this.eachSuperCall(this.body, (superCall) => { + if (this.ctor === 'base') { + superCall.error("'super' is only allowed in derived class constructors"); + } + return superCall.expressions = thisAssignments; + }); + haveThisParam = thisAssignments.length && thisAssignments.length !== ((ref3 = this.thisAssignments) != null ? ref3.length : void 0); + if (this.ctor === 'derived' && !seenSuper && haveThisParam) { + param = thisAssignments[0].variable; + param.error("Can't use @params in derived class constructors without calling super"); + } + return seenSuper; + } + + eachSuperCall(context, iterator) { + var seenSuper; + seenSuper = false; + context.traverseChildren(true, (child) => { + if (child instanceof SuperCall) { + seenSuper = true; + iterator(child); + } else if (child instanceof ThisLiteral && this.ctor === 'derived' && !seenSuper) { + child.error("Can't reference 'this' before calling super in derived class constructors"); + } + return !(child instanceof SuperCall) && (!(child instanceof Code) || child.bound); + }); + return seenSuper; } + }; + Code.__super__ = superClass.prototype; + + Code.prototype.children = ['params', 'body']; + + Code.prototype.jumps = NO; + return Code; })(Base); - exports.Param = Param = (function(superClass1) { - extend1(Param, superClass1); - - function Param(name1, value1, splat) { - var message, token; - this.name = name1; - this.value = value1; - this.splat = splat; - message = isUnassignable(this.name.unwrapAll().value); - if (message) { - this.name.error(message); - } - if (this.name instanceof Obj && this.name.generated) { - token = this.name.objects[0].operatorToken; - token.error(`unexpected ${token.value}`); + exports.Param = Param = (function(superClass) { + class Param extends superClass { + constructor(name1, value1, splat) { + var message, token; + super(); + this.name = name1; + this.value = value1; + this.splat = splat; + message = isUnassignable(this.name.unwrapAll().value); + if (message) { + this.name.error(message); + } + if (this.name instanceof Obj && this.name.generated) { + token = this.name.objects[0].operatorToken; + token.error(`unexpected ${token.value}`); + } } - } - Param.prototype.children = ['name', 'value']; + compileToFragments(o) { + return this.name.compileToFragments(o, LEVEL_LIST); + } - Param.prototype.compileToFragments = function(o) { - return this.name.compileToFragments(o, LEVEL_LIST); - }; + asReference(o) { + var name, node; + if (this.reference) { + return this.reference; + } + node = this.name; + if (node["this"]) { + name = node.properties[0].name.value; + if (indexOf.call(JS_FORBIDDEN, name) >= 0) { + name = `_${name}`; + } + node = new IdentifierLiteral(o.scope.freeVariable(name)); + } else if (node.isComplex()) { + node = new IdentifierLiteral(o.scope.freeVariable('arg')); + } + node = new Value(node); + node.updateLocationDataIfMissing(this.locationData); + return this.reference = node; + } - Param.prototype.asReference = function(o) { - var name, node; - if (this.reference) { - return this.reference; + isComplex() { + return this.name.isComplex(); } - node = this.name; - if (node["this"]) { - name = node.properties[0].name.value; - if (indexOf.call(JS_FORBIDDEN, name) >= 0) { - name = `_${name}`; + + eachName(iterator, name = this.name) { + var atParam, j, len1, node, obj, ref3, ref4; + atParam = (obj) => { + return iterator(`@${obj.properties[0].name.value}`, obj, this); + }; + if (name instanceof Literal) { + return iterator(name.value, name, this); + } + if (name instanceof Value) { + return atParam(name); + } + ref4 = (ref3 = name.objects) != null ? ref3 : []; + for (j = 0, len1 = ref4.length; j < len1; j++) { + obj = ref4[j]; + if (obj instanceof Assign && (obj.context == null)) { + obj = obj.variable; + } + if (obj instanceof Assign) { + if (obj.value instanceof Assign) { + obj = obj.value; + } + this.eachName(iterator, obj.value.unwrap()); + } else if (obj instanceof Splat) { + node = obj.name.unwrap(); + iterator(node.value, node, this); + } else if (obj instanceof Value) { + if (obj.isArray() || obj.isObject()) { + this.eachName(iterator, obj.base); + } else if (obj["this"]) { + atParam(obj); + } else { + iterator(obj.base.value, obj.base, this); + } + } else if (!(obj instanceof Expansion)) { + obj.error(`illegal parameter ${obj.compile()}`); + } } - node = new IdentifierLiteral(o.scope.freeVariable(name)); - } else if (node.isComplex()) { - node = new IdentifierLiteral(o.scope.freeVariable('arg')); } - node = new Value(node); - node.updateLocationDataIfMissing(this.locationData); - return this.reference = node; - }; - - Param.prototype.isComplex = function() { - return this.name.isComplex(); - }; - Param.prototype.eachName = function(iterator, name = this.name) { - var atParam, j, len1, node, obj, ref3, ref4; - atParam = function(obj) { - return iterator(`@${obj.properties[0].name.value}`, obj); - }; - if (name instanceof Literal) { - return iterator(name.value, name); - } - if (name instanceof Value) { - return atParam(name); - } - ref4 = (ref3 = name.objects) != null ? ref3 : []; - for (j = 0, len1 = ref4.length; j < len1; j++) { - obj = ref4[j]; - if (obj instanceof Assign && (obj.context == null)) { - obj = obj.variable; - } - if (obj instanceof Assign) { - if (obj.value instanceof Assign) { - obj = obj.value; - } - this.eachName(iterator, obj.value.unwrap()); - } else if (obj instanceof Splat) { - node = obj.name.unwrap(); - iterator(node.value, node); - } else if (obj instanceof Value) { - if (obj.isArray() || obj.isObject()) { - this.eachName(iterator, obj.base); - } else if (obj["this"]) { - atParam(obj); + renameParam(node, newNode) { + var isNode, replacement; + isNode = function(candidate) { + return candidate === node; + }; + replacement = (node, parent) => { + var key; + if (parent instanceof Obj) { + key = node; + if (node["this"]) { + key = node.properties[0].name; + } + return new Assign(new Value(key), newNode, 'object'); } else { - iterator(obj.base.value, obj.base); + return newNode; } - } else if (!(obj instanceof Expansion)) { - obj.error(`illegal parameter ${obj.compile()}`); - } + }; + return this.replaceInContext(isNode, replacement); } + }; + Param.__super__ = superClass.prototype; + + Param.prototype.children = ['name', 'value']; + return Param; })(Base); - exports.Splat = Splat = (function(superClass1) { - extend1(Splat, superClass1); + exports.Splat = Splat = (function(superClass) { + class Splat extends superClass { + constructor(name) { + super(); + this.name = name.compile ? name : new Literal(name); + } - Splat.prototype.children = ['name']; + assigns(name) { + return this.name.assigns(name); + } - Splat.prototype.isAssignable = YES; + compileToFragments(o) { + return [this.makeCode('...'), ...this.name.compileToFragments(o)]; + } - function Splat(name) { - this.name = name.compile ? name : new Literal(name); - } + unwrap() { + return this.name; + } - Splat.prototype.assigns = function(name) { - return this.name.assigns(name); }; - Splat.prototype.compileToFragments = function(o) { - return [this.makeCode('...'), ...this.name.compileToFragments(o)]; - }; + Splat.__super__ = superClass.prototype; - Splat.prototype.unwrap = function() { - return this.name; - }; + Splat.prototype.children = ['name']; + + Splat.prototype.isAssignable = YES; return Splat; })(Base); - exports.Expansion = Expansion = (function(superClass1) { - extend1(Expansion, superClass1); + exports.Expansion = Expansion = (function(superClass) { + class Expansion extends superClass { + compileNode(o) { + return this.error('Expansion must be used inside a destructuring assignment or parameter list'); + } - function Expansion() { - return Expansion.__super__.constructor.apply(this, arguments); - } + asReference(o) { + return this; + } - Expansion.prototype.isComplex = NO; + eachName(iterator) {} - Expansion.prototype.compileNode = function(o) { - return this.error('Expansion must be used inside a destructuring assignment or parameter list'); }; - Expansion.prototype.asReference = function(o) { - return this; - }; + Expansion.__super__ = superClass.prototype; - Expansion.prototype.eachName = function(iterator) {}; + Expansion.prototype.isComplex = NO; return Expansion; })(Base); - exports.While = While = (function(superClass1) { - extend1(While, superClass1); - - function While(condition, options) { - this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; - this.guard = options != null ? options.guard : void 0; - } - - While.prototype.children = ['condition', 'guard', 'body']; + exports.While = While = (function(superClass) { + class While extends superClass { + constructor(condition, options) { + super(); + this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; + this.guard = options != null ? options.guard : void 0; + } - While.prototype.isStatement = YES; + makeReturn(res) { + if (res) { + return While.__super__.makeReturn.call(this, ...arguments); + } else { + this.returns = !this.jumps({ + loop: true + }); + return this; + } + } - While.prototype.makeReturn = function(res) { - if (res) { - return While.__super__.makeReturn.call(this, ...arguments); - } else { - this.returns = !this.jumps({ - loop: true - }); + addBody(body1) { + this.body = body1; return this; } - }; - - While.prototype.addBody = function(body1) { - this.body = body1; - return this; - }; - While.prototype.jumps = function() { - var expressions, j, jumpNode, len1, node; - expressions = this.body.expressions; - if (!expressions.length) { - return false; - } - for (j = 0, len1 = expressions.length; j < len1; j++) { - node = expressions[j]; - if (jumpNode = node.jumps({ - loop: true - })) { - return jumpNode; + jumps() { + var expressions, j, jumpNode, len1, node; + expressions = this.body.expressions; + if (!expressions.length) { + return false; } + for (j = 0, len1 = expressions.length; j < len1; j++) { + node = expressions[j]; + if (jumpNode = node.jumps({ + loop: true + })) { + return jumpNode; + } + } + return false; } - return false; - }; - While.prototype.compileNode = function(o) { - var answer, body, rvar, set; - o.indent += TAB; - set = ''; - body = this.body; - if (body.isEmpty()) { - body = this.makeCode(''); - } else { - if (this.returns) { - body.makeReturn(rvar = o.scope.freeVariable('results')); - set = `${this.tab}${rvar} = [];\n`; - } - if (this.guard) { - if (body.expressions.length > 1) { - body.expressions.unshift(new If((new Parens(this.guard)).invert(), new StatementLiteral("continue"))); - } else { - if (this.guard) { - body = Block.wrap([new If(this.guard, body)]); + compileNode(o) { + var answer, body, rvar, set; + o.indent += TAB; + set = ''; + body = this.body; + if (body.isEmpty()) { + body = this.makeCode(''); + } else { + if (this.returns) { + body.makeReturn(rvar = o.scope.freeVariable('results')); + set = `${this.tab}${rvar} = [];\n`; + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new StatementLiteral("continue"))); + } else { + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } } } + body = [].concat(this.makeCode("\n"), body.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}`)); } - body = [].concat(this.makeCode("\n"), body.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}`)); - } - answer = [].concat(this.makeCode(set + this.tab + "while ("), this.condition.compileToFragments(o, LEVEL_PAREN), this.makeCode(") {"), body, this.makeCode("}")); - if (this.returns) { - answer.push(this.makeCode(`\n${this.tab}return ${rvar};`)); + answer = [].concat(this.makeCode(set + this.tab + "while ("), this.condition.compileToFragments(o, LEVEL_PAREN), this.makeCode(") {"), body, this.makeCode("}")); + if (this.returns) { + answer.push(this.makeCode(`\n${this.tab}return ${rvar};`)); + } + return answer; } - return answer; + }; + While.__super__ = superClass.prototype; + + While.prototype.children = ['condition', 'guard', 'body']; + + While.prototype.isStatement = YES; + return While; })(Base); - exports.Op = Op = (function(superClass1) { + exports.Op = Op = (function(superClass) { var CONVERSIONS, INVERSIONS; - extend1(Op, superClass1); - - function Op(op, first, second, flip) { - if (op === 'in') { - return new In(first, second); - } - if (op === 'do') { - return this.generateDo(first); - } - if (op === 'new') { - if (first instanceof Call && !first["do"] && !first.isNew) { - return first.newInstance(); + class Op extends superClass { + constructor(op, first, second, flip) { + if (op === 'in') { + return new In(first, second); } - if (first instanceof Code && first.bound || first["do"]) { - first = new Parens(first); + if (op === 'do') { + return Op.prototype.generateDo(first); + } + if (op === 'new') { + if (first instanceof Call && !first["do"] && !first.isNew) { + return first.newInstance(); + } + if (first instanceof Code && first.bound || first["do"]) { + first = new Parens(first); + } } + super(); + this.operator = CONVERSIONS[op] || op; + this.first = first; + this.second = second; + this.flip = !!flip; + return this; } - this.operator = CONVERSIONS[op] || op; - this.first = first; - this.second = second; - this.flip = !!flip; - return this; - } - CONVERSIONS = { - '==': '===', - '!=': '!==', - 'of': 'in', - 'yieldfrom': 'yield*' - }; + isNumber() { + var ref3; + return this.isUnary() && ((ref3 = this.operator) === '+' || ref3 === '-') && this.first instanceof Value && this.first.isNumber(); + } - INVERSIONS = { - '!==': '===', - '===': '!==' - }; + isAwait() { + return this.operator === 'await'; + } - Op.prototype.children = ['first', 'second']; + isYield() { + var ref3; + return (ref3 = this.operator) === 'yield' || ref3 === 'yield*'; + } - Op.prototype.isNumber = function() { - var ref3; - return this.isUnary() && ((ref3 = this.operator) === '+' || ref3 === '-') && this.first instanceof Value && this.first.isNumber(); - }; + isUnary() { + return !this.second; + } - Op.prototype.isAwait = function() { - return this.operator === 'await'; - }; + isComplex() { + return !this.isNumber(); + } - Op.prototype.isYield = function() { - var ref3; - return (ref3 = this.operator) === 'yield' || ref3 === 'yield*'; - }; + isChainable() { + var ref3; + return (ref3 = this.operator) === '<' || ref3 === '>' || ref3 === '>=' || ref3 === '<=' || ref3 === '===' || ref3 === '!=='; + } - Op.prototype.isUnary = function() { - return !this.second; - }; + invert() { + var allInvertable, curr, fst, op, ref3; + if (this.isChainable() && this.first.isChainable()) { + allInvertable = true; + curr = this; + while (curr && curr.operator) { + allInvertable && (allInvertable = curr.operator in INVERSIONS); + curr = curr.first; + } + if (!allInvertable) { + return new Parens(this).invert(); + } + curr = this; + while (curr && curr.operator) { + curr.invert = !curr.invert; + curr.operator = INVERSIONS[curr.operator]; + curr = curr.first; + } + return this; + } else if (op = INVERSIONS[this.operator]) { + this.operator = op; + if (this.first.unwrap() instanceof Op) { + this.first.invert(); + } + return this; + } else if (this.second) { + return new Parens(this).invert(); + } else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((ref3 = fst.operator) === '!' || ref3 === 'in' || ref3 === 'instanceof')) { + return fst; + } else { + return new Op('!', this); + } + } - Op.prototype.isComplex = function() { - return !this.isNumber(); - }; + unfoldSoak(o) { + var ref3; + return ((ref3 = this.operator) === '++' || ref3 === '--' || ref3 === 'delete') && unfoldSoak(o, this, 'first'); + } - Op.prototype.isChainable = function() { - var ref3; - return (ref3 = this.operator) === '<' || ref3 === '>' || ref3 === '>=' || ref3 === '<=' || ref3 === '===' || ref3 === '!=='; - }; + generateDo(exp) { + var call, func, j, len1, param, passedParams, ref, ref3; + passedParams = []; + func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; + ref3 = func.params || []; + for (j = 0, len1 = ref3.length; j < len1; j++) { + param = ref3[j]; + if (param.value) { + passedParams.push(param.value); + delete param.value; + } else { + passedParams.push(param); + } + } + call = new Call(exp, passedParams); + call["do"] = true; + return call; + } - Op.prototype.invert = function() { - var allInvertable, curr, fst, op, ref3; - if (this.isChainable() && this.first.isChainable()) { - allInvertable = true; - curr = this; - while (curr && curr.operator) { - allInvertable && (allInvertable = curr.operator in INVERSIONS); - curr = curr.first; + compileNode(o) { + var answer, isChain, lhs, message, ref3, rhs; + isChain = this.isChainable() && this.first.isChainable(); + if (!isChain) { + this.first.front = this.front; } - if (!allInvertable) { - return new Parens(this).invert(); + if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { + this.error('delete operand may not be argument or var'); } - curr = this; - while (curr && curr.operator) { - curr.invert = !curr.invert; - curr.operator = INVERSIONS[curr.operator]; - curr = curr.first; + if ((ref3 = this.operator) === '--' || ref3 === '++') { + message = isUnassignable(this.first.unwrapAll().value); + if (message) { + this.first.error(message); + } } - return this; - } else if (op = INVERSIONS[this.operator]) { - this.operator = op; - if (this.first.unwrap() instanceof Op) { - this.first.invert(); + if (this.isYield() || this.isAwait()) { + return this.compileContinuation(o); + } + if (this.isUnary()) { + return this.compileUnary(o); + } + if (isChain) { + return this.compileChain(o); + } + switch (this.operator) { + case '?': + return this.compileExistence(o); + case '**': + return this.compilePower(o); + case '//': + return this.compileFloorDivision(o); + case '%%': + return this.compileModulo(o); + default: + lhs = this.first.compileToFragments(o, LEVEL_OP); + rhs = this.second.compileToFragments(o, LEVEL_OP); + answer = [].concat(lhs, this.makeCode(` ${this.operator} `), rhs); + if (o.level <= LEVEL_OP) { + return answer; + } else { + return this.wrapInBraces(answer); + } } - return this; - } else if (this.second) { - return new Parens(this).invert(); - } else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((ref3 = fst.operator) === '!' || ref3 === 'in' || ref3 === 'instanceof')) { - return fst; - } else { - return new Op('!', this); } - }; - Op.prototype.unfoldSoak = function(o) { - var ref3; - return ((ref3 = this.operator) === '++' || ref3 === '--' || ref3 === 'delete') && unfoldSoak(o, this, 'first'); - }; + compileChain(o) { + var fragments, fst, ref3, shared; + ref3 = this.first.second.cache(o), this.first.second = ref3[0], shared = ref3[1]; + fst = this.first.compileToFragments(o, LEVEL_OP); + fragments = fst.concat(this.makeCode(` ${(this.invert ? '&&' : '||')} `), shared.compileToFragments(o), this.makeCode(` ${this.operator} `), this.second.compileToFragments(o, LEVEL_OP)); + return this.wrapInBraces(fragments); + } - Op.prototype.generateDo = function(exp) { - var call, func, j, len1, param, passedParams, ref, ref3; - passedParams = []; - func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; - ref3 = func.params || []; - for (j = 0, len1 = ref3.length; j < len1; j++) { - param = ref3[j]; - if (param.value) { - passedParams.push(param.value); - delete param.value; + compileExistence(o) { + var fst, ref; + if (this.first.isComplex()) { + ref = new IdentifierLiteral(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, this.first)); } else { - passedParams.push(param); + fst = this.first; + ref = fst; } + return new If(new Existence(fst), ref, { + type: 'if' + }).addElse(this.second).compileToFragments(o); } - call = new Call(exp, passedParams); - call["do"] = true; - return call; - }; - Op.prototype.compileNode = function(o) { - var answer, isChain, lhs, message, ref3, rhs; - isChain = this.isChainable() && this.first.isChainable(); - if (!isChain) { - this.first.front = this.front; - } - if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { - this.error('delete operand may not be argument or var'); + compileUnary(o) { + var op, parts, plusMinus; + parts = []; + op = this.operator; + parts.push([this.makeCode(op)]); + if (op === '!' && this.first instanceof Existence) { + this.first.negated = !this.first.negated; + return this.first.compileToFragments(o); + } + if (o.level >= LEVEL_ACCESS) { + return (new Parens(this)).compileToFragments(o); + } + plusMinus = op === '+' || op === '-'; + if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { + parts.push([this.makeCode(' ')]); + } + if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { + this.first = new Parens(this.first); + } + parts.push(this.first.compileToFragments(o, LEVEL_OP)); + if (this.flip) { + parts.reverse(); + } + return this.joinFragmentArrays(parts, ''); } - if ((ref3 = this.operator) === '--' || ref3 === '++') { - message = isUnassignable(this.first.unwrapAll().value); - if (message) { - this.first.error(message); - } - } - if (this.isYield() || this.isAwait()) { - return this.compileContinuation(o); - } - if (this.isUnary()) { - return this.compileUnary(o); - } - if (isChain) { - return this.compileChain(o); - } - switch (this.operator) { - case '?': - return this.compileExistence(o); - case '**': - return this.compilePower(o); - case '//': - return this.compileFloorDivision(o); - case '%%': - return this.compileModulo(o); - default: - lhs = this.first.compileToFragments(o, LEVEL_OP); - rhs = this.second.compileToFragments(o, LEVEL_OP); - answer = [].concat(lhs, this.makeCode(` ${this.operator} `), rhs); - if (o.level <= LEVEL_OP) { - return answer; - } else { - return this.wrapInBraces(answer); + + compileContinuation(o) { + var op, parts, ref3, ref4; + parts = []; + op = this.operator; + if (o.scope.parent == null) { + this.error(`${this.operator} can only occur inside functions`); + } + if (((ref3 = o.scope.method) != null ? ref3.bound : void 0) && o.scope.method.isGenerator) { + this.error('yield cannot occur inside bound (fat arrow) functions'); + } + if (indexOf.call(Object.keys(this.first), 'expression') >= 0 && !(this.first instanceof Throw)) { + if (this.first.expression != null) { + parts.push(this.first.expression.compileToFragments(o, LEVEL_OP)); } + } else { + if (o.level >= LEVEL_PAREN) { + parts.push([this.makeCode("(")]); + } + parts.push([this.makeCode(op)]); + if (((ref4 = this.first.base) != null ? ref4.value : void 0) !== '') { + parts.push([this.makeCode(" ")]); + } + parts.push(this.first.compileToFragments(o, LEVEL_OP)); + if (o.level >= LEVEL_PAREN) { + parts.push([this.makeCode(")")]); + } + } + return this.joinFragmentArrays(parts, ''); } - }; - - Op.prototype.compileChain = function(o) { - var fragments, fst, ref3, shared; - ref3 = this.first.second.cache(o), this.first.second = ref3[0], shared = ref3[1]; - fst = this.first.compileToFragments(o, LEVEL_OP); - fragments = fst.concat(this.makeCode(` ${(this.invert ? '&&' : '||')} `), shared.compileToFragments(o), this.makeCode(` ${this.operator} `), this.second.compileToFragments(o, LEVEL_OP)); - return this.wrapInBraces(fragments); - }; - Op.prototype.compileExistence = function(o) { - var fst, ref; - if (this.first.isComplex()) { - ref = new IdentifierLiteral(o.scope.freeVariable('ref')); - fst = new Parens(new Assign(ref, this.first)); - } else { - fst = this.first; - ref = fst; - } - return new If(new Existence(fst), ref, { - type: 'if' - }).addElse(this.second).compileToFragments(o); - }; - - Op.prototype.compileUnary = function(o) { - var op, parts, plusMinus; - parts = []; - op = this.operator; - parts.push([this.makeCode(op)]); - if (op === '!' && this.first instanceof Existence) { - this.first.negated = !this.first.negated; - return this.first.compileToFragments(o); - } - if (o.level >= LEVEL_ACCESS) { - return (new Parens(this)).compileToFragments(o); - } - plusMinus = op === '+' || op === '-'; - if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { - parts.push([this.makeCode(' ')]); - } - if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { - this.first = new Parens(this.first); + compilePower(o) { + var pow; + pow = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('pow'))]); + return new Call(pow, [this.first, this.second]).compileToFragments(o); } - parts.push(this.first.compileToFragments(o, LEVEL_OP)); - if (this.flip) { - parts.reverse(); - } - return this.joinFragmentArrays(parts, ''); - }; - Op.prototype.compileContinuation = function(o) { - var op, parts, ref3, ref4; - parts = []; - op = this.operator; - if (o.scope.parent == null) { - this.error(`${this.operator} can only occur inside functions`); + compileFloorDivision(o) { + var div, floor, second; + floor = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('floor'))]); + second = this.second.isComplex() ? new Parens(this.second) : this.second; + div = new Op('/', this.first, second); + return new Call(floor, [div]).compileToFragments(o); } - if (((ref3 = o.scope.method) != null ? ref3.bound : void 0) && o.scope.method.isGenerator) { - this.error('yield cannot occur inside bound (fat arrow) functions'); + + compileModulo(o) { + var mod; + mod = new Value(new Literal(utility('modulo', o))); + return new Call(mod, [this.first, this.second]).compileToFragments(o); } - if (indexOf.call(Object.keys(this.first), 'expression') >= 0 && !(this.first instanceof Throw)) { - if (this.first.expression != null) { - parts.push(this.first.expression.compileToFragments(o, LEVEL_OP)); - } - } else { - if (o.level >= LEVEL_PAREN) { - parts.push([this.makeCode("(")]); - } - parts.push([this.makeCode(op)]); - if (((ref4 = this.first.base) != null ? ref4.value : void 0) !== '') { - parts.push([this.makeCode(" ")]); - } - parts.push(this.first.compileToFragments(o, LEVEL_OP)); - if (o.level >= LEVEL_PAREN) { - parts.push([this.makeCode(")")]); - } + + toString(idt) { + return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); } - return this.joinFragmentArrays(parts, ''); - }; - Op.prototype.compilePower = function(o) { - var pow; - pow = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('pow'))]); - return new Call(pow, [this.first, this.second]).compileToFragments(o); }; - Op.prototype.compileFloorDivision = function(o) { - var div, floor, second; - floor = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('floor'))]); - second = this.second.isComplex() ? new Parens(this.second) : this.second; - div = new Op('/', this.first, second); - return new Call(floor, [div]).compileToFragments(o); - }; + Op.__super__ = superClass.prototype; - Op.prototype.compileModulo = function(o) { - var mod; - mod = new Value(new Literal(utility('modulo', o))); - return new Call(mod, [this.first, this.second]).compileToFragments(o); + CONVERSIONS = { + '==': '===', + '!=': '!==', + 'of': 'in', + 'yieldfrom': 'yield*' }; - Op.prototype.toString = function(idt) { - return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); + INVERSIONS = { + '!==': '===', + '===': '!==' }; + Op.prototype.children = ['first', 'second']; + return Op; })(Base); - exports.In = In = (function(superClass1) { - extend1(In, superClass1); - - function In(object, array) { - this.object = object; - this.array = array; - } - - In.prototype.children = ['object', 'array']; - - In.prototype.invert = NEGATE; + exports.In = In = (function(superClass) { + class In extends superClass { + constructor(object, array) { + super(); + this.object = object; + this.array = array; + } + + compileNode(o) { + var hasSplat, j, len1, obj, ref3; + if (this.array instanceof Value && this.array.isArray() && this.array.base.objects.length) { + ref3 = this.array.base.objects; + for (j = 0, len1 = ref3.length; j < len1; j++) { + obj = ref3[j]; + if (!(obj instanceof Splat)) { + continue; + } + hasSplat = true; + break; + } + if (!hasSplat) { + return this.compileOrTest(o); + } + } + return this.compileLoopTest(o); + } - In.prototype.compileNode = function(o) { - var hasSplat, j, len1, obj, ref3; - if (this.array instanceof Value && this.array.isArray() && this.array.base.objects.length) { - ref3 = this.array.base.objects; - for (j = 0, len1 = ref3.length; j < len1; j++) { - obj = ref3[j]; - if (!(obj instanceof Splat)) { - continue; + compileOrTest(o) { + var cmp, cnj, i, item, j, len1, ref, ref3, ref4, ref5, sub, tests; + ref3 = this.object.cache(o, LEVEL_OP), sub = ref3[0], ref = ref3[1]; + ref4 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = ref4[0], cnj = ref4[1]; + tests = []; + ref5 = this.array.base.objects; + for (i = j = 0, len1 = ref5.length; j < len1; i = ++j) { + item = ref5[i]; + if (i) { + tests.push(this.makeCode(cnj)); } - hasSplat = true; - break; + tests = tests.concat((i ? ref : sub), this.makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)); } - if (!hasSplat) { - return this.compileOrTest(o); + if (o.level < LEVEL_OP) { + return tests; + } else { + return this.wrapInBraces(tests); } } - return this.compileLoopTest(o); - }; - In.prototype.compileOrTest = function(o) { - var cmp, cnj, i, item, j, len1, ref, ref3, ref4, ref5, sub, tests; - ref3 = this.object.cache(o, LEVEL_OP), sub = ref3[0], ref = ref3[1]; - ref4 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = ref4[0], cnj = ref4[1]; - tests = []; - ref5 = this.array.base.objects; - for (i = j = 0, len1 = ref5.length; j < len1; i = ++j) { - item = ref5[i]; - if (i) { - tests.push(this.makeCode(cnj)); + compileLoopTest(o) { + var fragments, ref, ref3, sub; + ref3 = this.object.cache(o, LEVEL_LIST), sub = ref3[0], ref = ref3[1]; + fragments = [].concat(this.makeCode(utility('indexOf', o) + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0'))); + if (fragmentsToText(sub) === fragmentsToText(ref)) { + return fragments; + } + fragments = sub.concat(this.makeCode(', '), fragments); + if (o.level < LEVEL_LIST) { + return fragments; + } else { + return this.wrapInBraces(fragments); } - tests = tests.concat((i ? ref : sub), this.makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)); - } - if (o.level < LEVEL_OP) { - return tests; - } else { - return this.wrapInBraces(tests); } - }; - In.prototype.compileLoopTest = function(o) { - var fragments, ref, ref3, sub; - ref3 = this.object.cache(o, LEVEL_LIST), sub = ref3[0], ref = ref3[1]; - fragments = [].concat(this.makeCode(utility('indexOf', o) + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0'))); - if (fragmentsToText(sub) === fragmentsToText(ref)) { - return fragments; - } - fragments = sub.concat(this.makeCode(', '), fragments); - if (o.level < LEVEL_LIST) { - return fragments; - } else { - return this.wrapInBraces(fragments); + toString(idt) { + return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); } - }; - In.prototype.toString = function(idt) { - return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); }; - return In; + In.__super__ = superClass.prototype; - })(Base); + In.prototype.children = ['object', 'array']; - exports.Try = Try = (function(superClass1) { - extend1(Try, superClass1); + In.prototype.invert = NEGATE; - function Try(attempt, errorVariable, recovery, ensure) { - this.attempt = attempt; - this.errorVariable = errorVariable; - this.recovery = recovery; - this.ensure = ensure; - } + return In; - Try.prototype.children = ['attempt', 'recovery', 'ensure']; + })(Base); - Try.prototype.isStatement = YES; + exports.Try = Try = (function(superClass) { + class Try extends superClass { + constructor(attempt, errorVariable, recovery, ensure) { + super(); + this.attempt = attempt; + this.errorVariable = errorVariable; + this.recovery = recovery; + this.ensure = ensure; + } - Try.prototype.jumps = function(o) { - var ref3; - return this.attempt.jumps(o) || ((ref3 = this.recovery) != null ? ref3.jumps(o) : void 0); - }; + jumps(o) { + var ref3; + return this.attempt.jumps(o) || ((ref3 = this.recovery) != null ? ref3.jumps(o) : void 0); + } - Try.prototype.makeReturn = function(res) { - if (this.attempt) { - this.attempt = this.attempt.makeReturn(res); + makeReturn(res) { + if (this.attempt) { + this.attempt = this.attempt.makeReturn(res); + } + if (this.recovery) { + this.recovery = this.recovery.makeReturn(res); + } + return this; } - if (this.recovery) { - this.recovery = this.recovery.makeReturn(res); + + compileNode(o) { + var catchPart, ensurePart, generatedErrorVariableName, message, placeholder, tryPart; + o.indent += TAB; + tryPart = this.attempt.compileToFragments(o, LEVEL_TOP); + catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', { + reserve: false + }), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? (message = isUnassignable(this.errorVariable.unwrapAll().value), message ? this.errorVariable.error(message) : void 0, this.recovery.unshift(new Assign(this.errorVariable, placeholder))) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', { + reserve: false + }), [this.makeCode(` catch (${generatedErrorVariableName}) {}`)]) : []; + ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`)) : []; + return [].concat(this.makeCode(`${this.tab}try {\n`), tryPart, this.makeCode(`\n${this.tab}}`), catchPart, ensurePart); } - return this; - }; - Try.prototype.compileNode = function(o) { - var catchPart, ensurePart, generatedErrorVariableName, message, placeholder, tryPart; - o.indent += TAB; - tryPart = this.attempt.compileToFragments(o, LEVEL_TOP); - catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', { - reserve: false - }), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? (message = isUnassignable(this.errorVariable.unwrapAll().value), message ? this.errorVariable.error(message) : void 0, this.recovery.unshift(new Assign(this.errorVariable, placeholder))) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', { - reserve: false - }), [this.makeCode(` catch (${generatedErrorVariableName}) {}`)]) : []; - ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`)) : []; - return [].concat(this.makeCode(`${this.tab}try {\n`), tryPart, this.makeCode(`\n${this.tab}}`), catchPart, ensurePart); }; + Try.__super__ = superClass.prototype; + + Try.prototype.children = ['attempt', 'recovery', 'ensure']; + + Try.prototype.isStatement = YES; + return Try; })(Base); - exports.Throw = Throw = (function(superClass1) { - extend1(Throw, superClass1); + exports.Throw = Throw = (function(superClass) { + class Throw extends superClass { + constructor(expression1) { + super(); + this.expression = expression1; + } + + compileNode(o) { + return [].concat(this.makeCode(this.tab + "throw "), this.expression.compileToFragments(o), this.makeCode(";")); + } - function Throw(expression) { - this.expression = expression; - } + }; + + Throw.__super__ = superClass.prototype; Throw.prototype.children = ['expression']; @@ -3189,535 +3724,555 @@ Throw.prototype.makeReturn = THIS; - Throw.prototype.compileNode = function(o) { - return [].concat(this.makeCode(this.tab + "throw "), this.expression.compileToFragments(o), this.makeCode(";")); - }; - return Throw; })(Base); - exports.Existence = Existence = (function(superClass1) { - extend1(Existence, superClass1); + exports.Existence = Existence = (function(superClass) { + class Existence extends superClass { + constructor(expression1) { + super(); + this.expression = expression1; + } - function Existence(expression) { - this.expression = expression; - } + compileNode(o) { + var cmp, cnj, code, ref3; + this.expression.front = this.front; + code = this.expression.compile(o, LEVEL_OP); + if (this.expression.unwrap() instanceof IdentifierLiteral && !o.scope.check(code)) { + ref3 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = ref3[0], cnj = ref3[1]; + code = `typeof ${code} ${cmp} \"undefined\" ${cnj} ${code} ${cmp} null`; + } else { + code = `${code} ${(this.negated ? '==' : '!=')} null`; + } + return [this.makeCode(o.level <= LEVEL_COND ? code : `(${code})`)]; + } + + }; + + Existence.__super__ = superClass.prototype; Existence.prototype.children = ['expression']; Existence.prototype.invert = NEGATE; - Existence.prototype.compileNode = function(o) { - var cmp, cnj, code, ref3; - this.expression.front = this.front; - code = this.expression.compile(o, LEVEL_OP); - if (this.expression.unwrap() instanceof IdentifierLiteral && !o.scope.check(code)) { - ref3 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = ref3[0], cnj = ref3[1]; - code = `typeof ${code} ${cmp} \"undefined\" ${cnj} ${code} ${cmp} null`; - } else { - code = `${code} ${(this.negated ? '==' : '!=')} null`; - } - return [this.makeCode(o.level <= LEVEL_COND ? code : `(${code})`)]; - }; - return Existence; })(Base); - exports.Parens = Parens = (function(superClass1) { - extend1(Parens, superClass1); + exports.Parens = Parens = (function(superClass) { + class Parens extends superClass { + constructor(body1) { + super(); + this.body = body1; + } - function Parens(body1) { - this.body = body1; - } + unwrap() { + return this.body; + } - Parens.prototype.children = ['body']; + isComplex() { + return this.body.isComplex(); + } - Parens.prototype.unwrap = function() { - return this.body; - }; + compileNode(o) { + var bare, expr, fragments; + expr = this.body.unwrap(); + if (expr instanceof Value && expr.isAtomic()) { + expr.front = this.front; + return expr.compileToFragments(o); + } + fragments = expr.compileToFragments(o, LEVEL_PAREN); + bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)); + if (bare) { + return fragments; + } else { + return this.wrapInBraces(fragments); + } + } - Parens.prototype.isComplex = function() { - return this.body.isComplex(); }; - Parens.prototype.compileNode = function(o) { - var bare, expr, fragments; - expr = this.body.unwrap(); - if (expr instanceof Value && expr.isAtomic()) { - expr.front = this.front; - return expr.compileToFragments(o); - } - fragments = expr.compileToFragments(o, LEVEL_PAREN); - bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)); - if (bare) { - return fragments; - } else { - return this.wrapInBraces(fragments); - } - }; + Parens.__super__ = superClass.prototype; + + Parens.prototype.children = ['body']; return Parens; })(Base); - exports.StringWithInterpolations = StringWithInterpolations = (function(superClass1) { - extend1(StringWithInterpolations, superClass1); - - function StringWithInterpolations(body1) { - this.body = body1; - } - - StringWithInterpolations.prototype.children = ['body']; + exports.StringWithInterpolations = StringWithInterpolations = (function(superClass) { + class StringWithInterpolations extends superClass { + constructor(body1) { + super(); + this.body = body1; + } - StringWithInterpolations.prototype.unwrap = function() { - return this; - }; + unwrap() { + return this; + } - StringWithInterpolations.prototype.isComplex = function() { - return this.body.isComplex(); - }; + isComplex() { + return this.body.isComplex(); + } - StringWithInterpolations.prototype.compileNode = function(o) { - var element, elements, expr, fragments, j, len1, value; - expr = this.body.unwrap(); - elements = []; - expr.traverseChildren(false, function(node) { - if (node instanceof StringLiteral) { - elements.push(node); + compileNode(o) { + var element, elements, expr, fragments, j, len1, value; + expr = this.body.unwrap(); + elements = []; + expr.traverseChildren(false, function(node) { + if (node instanceof StringLiteral) { + elements.push(node); + return true; + } else if (node instanceof Parens) { + elements.push(node); + return false; + } return true; - } else if (node instanceof Parens) { - elements.push(node); - return false; - } - return true; - }); - fragments = []; - fragments.push(this.makeCode('`')); - for (j = 0, len1 = elements.length; j < len1; j++) { - element = elements[j]; - if (element instanceof StringLiteral) { - value = element.value.slice(1, -1); - value = value.replace(/(\\*)(`|\$\{)/g, function(match, backslashes, toBeEscaped) { - if (backslashes.length % 2 === 0) { - return `${backslashes}\\${toBeEscaped}`; - } else { - return match; - } - }); - fragments.push(this.makeCode(value)); - } else { - fragments.push(this.makeCode('${')); - fragments.push(...element.compileToFragments(o, LEVEL_PAREN)); - fragments.push(this.makeCode('}')); + }); + fragments = []; + fragments.push(this.makeCode('`')); + for (j = 0, len1 = elements.length; j < len1; j++) { + element = elements[j]; + if (element instanceof StringLiteral) { + value = element.value.slice(1, -1); + value = value.replace(/(\\*)(`|\$\{)/g, function(match, backslashes, toBeEscaped) { + if (backslashes.length % 2 === 0) { + return `${backslashes}\\${toBeEscaped}`; + } else { + return match; + } + }); + fragments.push(this.makeCode(value)); + } else { + fragments.push(this.makeCode('${')); + fragments.push(...element.compileToFragments(o, LEVEL_PAREN)); + fragments.push(this.makeCode('}')); + } } + fragments.push(this.makeCode('`')); + return fragments; } - fragments.push(this.makeCode('`')); - return fragments; - }; - return StringWithInterpolations; + }; - })(Base); + StringWithInterpolations.__super__ = superClass.prototype; - exports.For = For = (function(superClass1) { - extend1(For, superClass1); + StringWithInterpolations.prototype.children = ['body']; - function For(body, source) { - var ref3; - this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; - this.body = Block.wrap([body]); - this.own = !!source.own; - this.object = !!source.object; - this.from = !!source.from; - if (this.from && this.index) { - this.index.error('cannot use index with for-from'); - } - if (this.own && !this.object) { - source.ownTag.error(`cannot use own with for-${(this.from ? 'from' : 'in')}`); - } - if (this.object) { - ref3 = [this.index, this.name], this.name = ref3[0], this.index = ref3[1]; - } - if (this.index instanceof Value) { - this.index.error('index cannot be a pattern matching expression'); - } - this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length && !this.from; - this.pattern = this.name instanceof Value; - if (this.range && this.index) { - this.index.error('indexes do not apply to range loops'); - } - if (this.range && this.pattern) { - this.name.error('cannot pattern match over range loops'); - } - this.returns = false; - } + return StringWithInterpolations; - For.prototype.children = ['body', 'source', 'guard', 'step']; + })(Base); - For.prototype.compileNode = function(o) { - var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref3, ref4, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart; - body = Block.wrap([this.body]); - ref3 = body.expressions, last = ref3[ref3.length - 1]; - if ((last != null ? last.jumps() : void 0) instanceof Return) { + exports.For = For = (function(superClass) { + class For extends superClass { + constructor(body, source) { + var ref3; + super(); + this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; + this.body = Block.wrap([body]); + this.own = !!source.own; + this.object = !!source.object; + this.from = !!source.from; + if (this.from && this.index) { + this.index.error('cannot use index with for-from'); + } + if (this.own && !this.object) { + source.ownTag.error(`cannot use own with for-${(this.from ? 'from' : 'in')}`); + } + if (this.object) { + ref3 = [this.index, this.name], this.name = ref3[0], this.index = ref3[1]; + } + if (this.index instanceof Value) { + this.index.error('index cannot be a pattern matching expression'); + } + this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length && !this.from; + this.pattern = this.name instanceof Value; + if (this.range && this.index) { + this.index.error('indexes do not apply to range loops'); + } + if (this.range && this.pattern) { + this.name.error('cannot pattern match over range loops'); + } this.returns = false; } - source = this.range ? this.source.base : this.source; - scope = o.scope; - if (!this.pattern) { - name = this.name && (this.name.compile(o, LEVEL_LIST)); - } - index = this.index && (this.index.compile(o, LEVEL_LIST)); - if (name && !this.pattern) { - scope.find(name); - } - if (index) { - scope.find(index); - } - if (this.returns) { - rvar = scope.freeVariable('results'); - } - if (this.from) { - if (this.pattern) { - ivar = scope.freeVariable('x', { + + compileNode(o) { + var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref3, ref4, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart; + body = Block.wrap([this.body]); + ref3 = body.expressions, last = ref3[ref3.length - 1]; + if ((last != null ? last.jumps() : void 0) instanceof Return) { + this.returns = false; + } + source = this.range ? this.source.base : this.source; + scope = o.scope; + if (!this.pattern) { + name = this.name && (this.name.compile(o, LEVEL_LIST)); + } + index = this.index && (this.index.compile(o, LEVEL_LIST)); + if (name && !this.pattern) { + scope.find(name); + } + if (index) { + scope.find(index); + } + if (this.returns) { + rvar = scope.freeVariable('results'); + } + if (this.from) { + if (this.pattern) { + ivar = scope.freeVariable('x', { + single: true + }); + } + } else { + ivar = (this.object && index) || scope.freeVariable('i', { single: true }); } - } else { - ivar = (this.object && index) || scope.freeVariable('i', { - single: true - }); - } - kvar = ((this.range || this.from) && name) || index || ivar; - kvarAssign = kvar !== ivar ? `${kvar} = ` : ""; - if (this.step && !this.range) { - ref4 = this.cacheToCodeFragments(this.step.cache(o, LEVEL_LIST, isComplexOrAssignable)), step = ref4[0], stepVar = ref4[1]; - if (this.step.isNumber()) { - stepNum = Number(stepVar); - } - } - if (this.pattern) { - name = ivar; - } - varPart = ''; - guardPart = ''; - defPart = ''; - idt1 = this.tab + TAB; - if (this.range) { - forPartFragments = source.compileToFragments(merge(o, { - index: ivar, - name: name, - step: this.step, - isComplex: isComplexOrAssignable - })); - } else { - svar = this.source.compile(o, LEVEL_LIST); - if ((name || this.own) && !(this.source.unwrap() instanceof IdentifierLiteral)) { - defPart += `${this.tab}${(ref = scope.freeVariable('ref'))} = ${svar};\n`; - svar = ref; - } - if (name && !this.pattern && !this.from) { - namePart = `${name} = ${svar}[${kvar}]`; - } - if (!this.object && !this.from) { - if (step !== stepVar) { - defPart += `${this.tab}${step};\n`; - } - down = stepNum < 0; - if (!(this.step && (stepNum != null) && down)) { - lvar = scope.freeVariable('len'); - } - declare = `${kvarAssign}${ivar} = 0, ${lvar} = ${svar}.length`; - declareDown = `${kvarAssign}${ivar} = ${svar}.length - 1`; - compare = `${ivar} < ${lvar}`; - compareDown = `${ivar} >= 0`; - if (this.step) { - if (stepNum != null) { - if (down) { - compare = compareDown; - declare = declareDown; + kvar = ((this.range || this.from) && name) || index || ivar; + kvarAssign = kvar !== ivar ? `${kvar} = ` : ""; + if (this.step && !this.range) { + ref4 = this.cacheToCodeFragments(this.step.cache(o, LEVEL_LIST, isComplexOrAssignable)), step = ref4[0], stepVar = ref4[1]; + if (this.step.isNumber()) { + stepNum = Number(stepVar); + } + } + if (this.pattern) { + name = ivar; + } + varPart = ''; + guardPart = ''; + defPart = ''; + idt1 = this.tab + TAB; + if (this.range) { + forPartFragments = source.compileToFragments(merge(o, { + index: ivar, + name: name, + step: this.step, + isComplex: isComplexOrAssignable + })); + } else { + svar = this.source.compile(o, LEVEL_LIST); + if ((name || this.own) && !(this.source.unwrap() instanceof IdentifierLiteral)) { + defPart += `${this.tab}${(ref = scope.freeVariable('ref'))} = ${svar};\n`; + svar = ref; + } + if (name && !this.pattern && !this.from) { + namePart = `${name} = ${svar}[${kvar}]`; + } + if (!this.object && !this.from) { + if (step !== stepVar) { + defPart += `${this.tab}${step};\n`; + } + down = stepNum < 0; + if (!(this.step && (stepNum != null) && down)) { + lvar = scope.freeVariable('len'); + } + declare = `${kvarAssign}${ivar} = 0, ${lvar} = ${svar}.length`; + declareDown = `${kvarAssign}${ivar} = ${svar}.length - 1`; + compare = `${ivar} < ${lvar}`; + compareDown = `${ivar} >= 0`; + if (this.step) { + if (stepNum != null) { + if (down) { + compare = compareDown; + declare = declareDown; + } + } else { + compare = `${stepVar} > 0 ? ${compare} : ${compareDown}`; + declare = `(${stepVar} > 0 ? (${declare}) : ${declareDown})`; } + increment = `${ivar} += ${stepVar}`; } else { - compare = `${stepVar} > 0 ? ${compare} : ${compareDown}`; - declare = `(${stepVar} > 0 ? (${declare}) : ${declareDown})`; + increment = `${(kvar !== ivar ? `++${ivar}` : `${ivar}++`)}`; } - increment = `${ivar} += ${stepVar}`; + forPartFragments = [this.makeCode(`${declare}; ${compare}; ${kvarAssign}${increment}`)]; + } + } + if (this.returns) { + resultPart = `${this.tab}${rvar} = [];\n`; + returnResult = `\n${this.tab}return ${rvar};`; + body.makeReturn(rvar); + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new StatementLiteral("continue"))); } else { - increment = `${(kvar !== ivar ? `++${ivar}` : `${ivar}++`)}`; + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } } - forPartFragments = [this.makeCode(`${declare}; ${compare}; ${kvarAssign}${increment}`)]; } - } - if (this.returns) { - resultPart = `${this.tab}${rvar} = [];\n`; - returnResult = `\n${this.tab}return ${rvar};`; - body.makeReturn(rvar); - } - if (this.guard) { - if (body.expressions.length > 1) { - body.expressions.unshift(new If((new Parens(this.guard)).invert(), new StatementLiteral("continue"))); - } else { - if (this.guard) { - body = Block.wrap([new If(this.guard, body)]); + if (this.pattern) { + body.expressions.unshift(new Assign(this.name, this.from ? new IdentifierLiteral(kvar) : new Literal(`${svar}[${kvar}]`))); + } + defPartFragments = [].concat(this.makeCode(defPart), this.pluckDirectCall(o, body)); + if (namePart) { + varPart = `\n${idt1}${namePart};`; + } + if (this.object) { + forPartFragments = [this.makeCode(`${kvar} in ${svar}`)]; + if (this.own) { + guardPart = `\n${idt1}if (!${utility('hasProp', o)}.call(${svar}, ${kvar})) continue;`; } + } else if (this.from) { + forPartFragments = [this.makeCode(`${kvar} of ${svar}`)]; } - } - if (this.pattern) { - body.expressions.unshift(new Assign(this.name, this.from ? new IdentifierLiteral(kvar) : new Literal(`${svar}[${kvar}]`))); - } - defPartFragments = [].concat(this.makeCode(defPart), this.pluckDirectCall(o, body)); - if (namePart) { - varPart = `\n${idt1}${namePart};`; - } - if (this.object) { - forPartFragments = [this.makeCode(`${kvar} in ${svar}`)]; - if (this.own) { - guardPart = `\n${idt1}if (!${utility('hasProp', o)}.call(${svar}, ${kvar})) continue;`; + bodyFragments = body.compileToFragments(merge(o, { + indent: idt1 + }), LEVEL_TOP); + if (bodyFragments && bodyFragments.length > 0) { + bodyFragments = [].concat(this.makeCode("\n"), bodyFragments, this.makeCode("\n")); } - } else if (this.from) { - forPartFragments = [this.makeCode(`${kvar} of ${svar}`)]; + return [].concat(defPartFragments, this.makeCode(`${resultPart || ''}${this.tab}for (`), forPartFragments, this.makeCode(`) {${guardPart}${varPart}`), bodyFragments, this.makeCode(`${this.tab}}${returnResult || ''}`)); } - bodyFragments = body.compileToFragments(merge(o, { - indent: idt1 - }), LEVEL_TOP); - if (bodyFragments && bodyFragments.length > 0) { - bodyFragments = [].concat(this.makeCode("\n"), bodyFragments, this.makeCode("\n")); - } - return [].concat(defPartFragments, this.makeCode(`${resultPart || ''}${this.tab}for (`), forPartFragments, this.makeCode(`) {${guardPart}${varPart}`), bodyFragments, this.makeCode(`${this.tab}}${returnResult || ''}`)); - }; - For.prototype.pluckDirectCall = function(o, body) { - var base, defs, expr, fn, idx, j, len1, ref, ref3, ref4, ref5, ref6, ref7, ref8, ref9, val; - defs = []; - ref3 = body.expressions; - for (idx = j = 0, len1 = ref3.length; j < len1; idx = ++j) { - expr = ref3[idx]; - expr = expr.unwrapAll(); - if (!(expr instanceof Call)) { - continue; - } - val = (ref4 = expr.variable) != null ? ref4.unwrapAll() : void 0; - if (!((val instanceof Code) || (val instanceof Value && ((ref5 = val.base) != null ? ref5.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((ref6 = (ref7 = val.properties[0].name) != null ? ref7.value : void 0) === 'call' || ref6 === 'apply')))) { - continue; - } - fn = ((ref8 = val.base) != null ? ref8.unwrapAll() : void 0) || val; - ref = new IdentifierLiteral(o.scope.freeVariable('fn')); - base = new Value(ref); - if (val.base) { - ref9 = [base, val], val.base = ref9[0], base = ref9[1]; + pluckDirectCall(o, body) { + var base, defs, expr, fn, idx, j, len1, ref, ref3, ref4, ref5, ref6, ref7, ref8, ref9, val; + defs = []; + ref3 = body.expressions; + for (idx = j = 0, len1 = ref3.length; j < len1; idx = ++j) { + expr = ref3[idx]; + expr = expr.unwrapAll(); + if (!(expr instanceof Call)) { + continue; + } + val = (ref4 = expr.variable) != null ? ref4.unwrapAll() : void 0; + if (!((val instanceof Code) || (val instanceof Value && ((ref5 = val.base) != null ? ref5.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((ref6 = (ref7 = val.properties[0].name) != null ? ref7.value : void 0) === 'call' || ref6 === 'apply')))) { + continue; + } + fn = ((ref8 = val.base) != null ? ref8.unwrapAll() : void 0) || val; + ref = new IdentifierLiteral(o.scope.freeVariable('fn')); + base = new Value(ref); + if (val.base) { + ref9 = [base, val], val.base = ref9[0], base = ref9[1]; + } + body.expressions[idx] = new Call(base, expr.args); + defs = defs.concat(this.makeCode(this.tab), new Assign(ref, fn).compileToFragments(o, LEVEL_TOP), this.makeCode(';\n')); } - body.expressions[idx] = new Call(base, expr.args); - defs = defs.concat(this.makeCode(this.tab), new Assign(ref, fn).compileToFragments(o, LEVEL_TOP), this.makeCode(';\n')); + return defs; } - return defs; - }; - return For; + }; - })(While); + For.__super__ = superClass.prototype; - exports.Switch = Switch = (function(superClass1) { - extend1(Switch, superClass1); + For.prototype.children = ['body', 'source', 'guard', 'step']; - function Switch(subject, cases, otherwise) { - this.subject = subject; - this.cases = cases; - this.otherwise = otherwise; - } + return For; - Switch.prototype.children = ['subject', 'cases', 'otherwise']; + })(While); - Switch.prototype.isStatement = YES; + exports.Switch = Switch = (function(superClass) { + class Switch extends superClass { + constructor(subject, cases, otherwise) { + super(); + this.subject = subject; + this.cases = cases; + this.otherwise = otherwise; + } - Switch.prototype.jumps = function(o = { - block: true - }) { - var block, conds, j, jumpNode, len1, ref3, ref4, ref5; - ref3 = this.cases; - for (j = 0, len1 = ref3.length; j < len1; j++) { - ref4 = ref3[j], conds = ref4[0], block = ref4[1]; - if (jumpNode = block.jumps(o)) { - return jumpNode; + jumps(o = { + block: true + }) { + var block, conds, j, jumpNode, len1, ref3, ref4, ref5; + ref3 = this.cases; + for (j = 0, len1 = ref3.length; j < len1; j++) { + ref4 = ref3[j], conds = ref4[0], block = ref4[1]; + if (jumpNode = block.jumps(o)) { + return jumpNode; + } } + return (ref5 = this.otherwise) != null ? ref5.jumps(o) : void 0; } - return (ref5 = this.otherwise) != null ? ref5.jumps(o) : void 0; - }; - Switch.prototype.makeReturn = function(res) { - var j, len1, pair, ref3, ref4; - ref3 = this.cases; - for (j = 0, len1 = ref3.length; j < len1; j++) { - pair = ref3[j]; - pair[1].makeReturn(res); - } - if (res) { - this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); - } - if ((ref4 = this.otherwise) != null) { - ref4.makeReturn(res); + makeReturn(res) { + var j, len1, pair, ref3, ref4; + ref3 = this.cases; + for (j = 0, len1 = ref3.length; j < len1; j++) { + pair = ref3[j]; + pair[1].makeReturn(res); + } + if (res) { + this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); + } + if ((ref4 = this.otherwise) != null) { + ref4.makeReturn(res); + } + return this; } - return this; - }; - Switch.prototype.compileNode = function(o) { - var block, body, cond, conditions, expr, fragments, i, idt1, idt2, j, k, len1, len2, ref3, ref4, ref5; - idt1 = o.indent + TAB; - idt2 = o.indent = idt1 + TAB; - fragments = [].concat(this.makeCode(this.tab + "switch ("), (this.subject ? this.subject.compileToFragments(o, LEVEL_PAREN) : this.makeCode("false")), this.makeCode(") {\n")); - ref3 = this.cases; - for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { - ref4 = ref3[i], conditions = ref4[0], block = ref4[1]; - ref5 = flatten([conditions]); - for (k = 0, len2 = ref5.length; k < len2; k++) { - cond = ref5[k]; - if (!this.subject) { - cond = cond.invert(); - } - fragments = fragments.concat(this.makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), this.makeCode(":\n")); - } - if ((body = block.compileToFragments(o, LEVEL_TOP)).length > 0) { - fragments = fragments.concat(body, this.makeCode('\n')); - } - if (i === this.cases.length - 1 && !this.otherwise) { - break; - } - expr = this.lastNonComment(block.expressions); - if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) { - continue; + compileNode(o) { + var block, body, cond, conditions, expr, fragments, i, idt1, idt2, j, k, len1, len2, ref3, ref4, ref5; + idt1 = o.indent + TAB; + idt2 = o.indent = idt1 + TAB; + fragments = [].concat(this.makeCode(this.tab + "switch ("), (this.subject ? this.subject.compileToFragments(o, LEVEL_PAREN) : this.makeCode("false")), this.makeCode(") {\n")); + ref3 = this.cases; + for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { + ref4 = ref3[i], conditions = ref4[0], block = ref4[1]; + ref5 = flatten([conditions]); + for (k = 0, len2 = ref5.length; k < len2; k++) { + cond = ref5[k]; + if (!this.subject) { + cond = cond.invert(); + } + fragments = fragments.concat(this.makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), this.makeCode(":\n")); + } + if ((body = block.compileToFragments(o, LEVEL_TOP)).length > 0) { + fragments = fragments.concat(body, this.makeCode('\n')); + } + if (i === this.cases.length - 1 && !this.otherwise) { + break; + } + expr = this.lastNonComment(block.expressions); + if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) { + continue; + } + fragments.push(cond.makeCode(idt2 + 'break;\n')); } - fragments.push(cond.makeCode(idt2 + 'break;\n')); - } - if (this.otherwise && this.otherwise.expressions.length) { - fragments.push(this.makeCode(idt1 + "default:\n"), ...this.otherwise.compileToFragments(o, LEVEL_TOP), this.makeCode("\n")); + if (this.otherwise && this.otherwise.expressions.length) { + fragments.push(this.makeCode(idt1 + "default:\n"), ...this.otherwise.compileToFragments(o, LEVEL_TOP), this.makeCode("\n")); + } + fragments.push(this.makeCode(this.tab + '}')); + return fragments; } - fragments.push(this.makeCode(this.tab + '}')); - return fragments; + }; - return Switch; + Switch.__super__ = superClass.prototype; - })(Base); + Switch.prototype.children = ['subject', 'cases', 'otherwise']; - exports.If = If = (function(superClass1) { - extend1(If, superClass1); + Switch.prototype.isStatement = YES; - function If(condition, body1, options = {}) { - this.body = body1; - this.condition = options.type === 'unless' ? condition.invert() : condition; - this.elseBody = null; - this.isChain = false; - this.soak = options.soak; - } + return Switch; - If.prototype.children = ['condition', 'body', 'elseBody']; + })(Base); - If.prototype.bodyNode = function() { - var ref3; - return (ref3 = this.body) != null ? ref3.unwrap() : void 0; - }; + exports.If = If = (function(superClass) { + class If extends superClass { + constructor(condition, body1, options = {}) { + super(); + this.body = body1; + this.condition = options.type === 'unless' ? condition.invert() : condition; + this.elseBody = null; + this.isChain = false; + this.soak = options.soak; + } - If.prototype.elseBodyNode = function() { - var ref3; - return (ref3 = this.elseBody) != null ? ref3.unwrap() : void 0; - }; + bodyNode() { + var ref3; + return (ref3 = this.body) != null ? ref3.unwrap() : void 0; + } - If.prototype.addElse = function(elseBody) { - if (this.isChain) { - this.elseBodyNode().addElse(elseBody); - } else { - this.isChain = elseBody instanceof If; - this.elseBody = this.ensureBlock(elseBody); - this.elseBody.updateLocationDataIfMissing(elseBody.locationData); + elseBodyNode() { + var ref3; + return (ref3 = this.elseBody) != null ? ref3.unwrap() : void 0; } - return this; - }; - If.prototype.isStatement = function(o) { - var ref3; - return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((ref3 = this.elseBodyNode()) != null ? ref3.isStatement(o) : void 0); - }; + addElse(elseBody) { + if (this.isChain) { + this.elseBodyNode().addElse(elseBody); + } else { + this.isChain = elseBody instanceof If; + this.elseBody = this.ensureBlock(elseBody); + this.elseBody.updateLocationDataIfMissing(elseBody.locationData); + } + return this; + } - If.prototype.jumps = function(o) { - var ref3; - return this.body.jumps(o) || ((ref3 = this.elseBody) != null ? ref3.jumps(o) : void 0); - }; + isStatement(o) { + var ref3; + return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((ref3 = this.elseBodyNode()) != null ? ref3.isStatement(o) : void 0); + } - If.prototype.compileNode = function(o) { - if (this.isStatement(o)) { - return this.compileStatement(o); - } else { - return this.compileExpression(o); + jumps(o) { + var ref3; + return this.body.jumps(o) || ((ref3 = this.elseBody) != null ? ref3.jumps(o) : void 0); + } + + compileNode(o) { + if (this.isStatement(o)) { + return this.compileStatement(o); + } else { + return this.compileExpression(o); + } } - }; - If.prototype.makeReturn = function(res) { - if (res) { - this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); + makeReturn(res) { + if (res) { + this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); + } + this.body && (this.body = new Block([this.body.makeReturn(res)])); + this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); + return this; } - this.body && (this.body = new Block([this.body.makeReturn(res)])); - this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); - return this; - }; - If.prototype.ensureBlock = function(node) { - if (node instanceof Block) { - return node; - } else { - return new Block([node]); + ensureBlock(node) { + if (node instanceof Block) { + return node; + } else { + return new Block([node]); + } } - }; - If.prototype.compileStatement = function(o) { - var answer, body, child, cond, exeq, ifPart, indent; - child = del(o, 'chainChild'); - exeq = del(o, 'isExistentialEquals'); - if (exeq) { - return new If(this.condition.invert(), this.elseBodyNode(), { - type: 'if' - }).compileToFragments(o); - } - indent = o.indent + TAB; - cond = this.condition.compileToFragments(o, LEVEL_PAREN); - body = this.ensureBlock(this.body).compileToFragments(merge(o, { - indent: indent - })); - ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body, this.makeCode(`\n${this.tab}}`)); - if (!child) { - ifPart.unshift(this.makeCode(this.tab)); - } - if (!this.elseBody) { - return ifPart; - } - answer = ifPart.concat(this.makeCode(' else ')); - if (this.isChain) { - o.chainChild = true; - answer = answer.concat(this.elseBody.unwrap().compileToFragments(o, LEVEL_TOP)); - } else { - answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(merge(o, { + compileStatement(o) { + var answer, body, child, cond, exeq, ifPart, indent; + child = del(o, 'chainChild'); + exeq = del(o, 'isExistentialEquals'); + if (exeq) { + return new If(this.condition.invert(), this.elseBodyNode(), { + type: 'if' + }).compileToFragments(o); + } + indent = o.indent + TAB; + cond = this.condition.compileToFragments(o, LEVEL_PAREN); + body = this.ensureBlock(this.body).compileToFragments(merge(o, { indent: indent - }), LEVEL_TOP), this.makeCode(`\n${this.tab}}`)); + })); + ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body, this.makeCode(`\n${this.tab}}`)); + if (!child) { + ifPart.unshift(this.makeCode(this.tab)); + } + if (!this.elseBody) { + return ifPart; + } + answer = ifPart.concat(this.makeCode(' else ')); + if (this.isChain) { + o.chainChild = true; + answer = answer.concat(this.elseBody.unwrap().compileToFragments(o, LEVEL_TOP)); + } else { + answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(merge(o, { + indent: indent + }), LEVEL_TOP), this.makeCode(`\n${this.tab}}`)); + } + return answer; } - return answer; - }; - If.prototype.compileExpression = function(o) { - var alt, body, cond, fragments; - cond = this.condition.compileToFragments(o, LEVEL_COND); - body = this.bodyNode().compileToFragments(o, LEVEL_LIST); - alt = this.elseBodyNode() ? this.elseBodyNode().compileToFragments(o, LEVEL_LIST) : [this.makeCode('void 0')]; - fragments = cond.concat(this.makeCode(" ? "), body, this.makeCode(" : "), alt); - if (o.level >= LEVEL_COND) { - return this.wrapInBraces(fragments); - } else { - return fragments; + compileExpression(o) { + var alt, body, cond, fragments; + cond = this.condition.compileToFragments(o, LEVEL_COND); + body = this.bodyNode().compileToFragments(o, LEVEL_LIST); + alt = this.elseBodyNode() ? this.elseBodyNode().compileToFragments(o, LEVEL_LIST) : [this.makeCode('void 0')]; + fragments = cond.concat(this.makeCode(" ? "), body, this.makeCode(" : "), alt); + if (o.level >= LEVEL_COND) { + return this.wrapInBraces(fragments); + } else { + return fragments; + } + } + + unfoldSoak() { + return this.soak && this; } - }; - If.prototype.unfoldSoak = function() { - return this.soak && this; }; + If.__super__ = superClass.prototype; + + If.prototype.children = ['condition', 'body', 'elseBody']; + return If; })(Base); diff --git a/lib/coffee-script/optparse.js b/lib/coffee-script/optparse.js index 5e1abad3bc..cefe05c8af 100644 --- a/lib/coffee-script/optparse.js +++ b/lib/coffee-script/optparse.js @@ -4,13 +4,13 @@ repeat = require('./helpers').repeat; - exports.OptionParser = OptionParser = (function() { - function OptionParser(rules, banner) { + exports.OptionParser = OptionParser = class OptionParser { + constructor(rules, banner) { this.banner = banner; this.rules = buildRules(rules); } - OptionParser.prototype.parse = function(args) { + parse(args) { var arg, i, isOption, j, k, len, len1, matchedRule, options, originalArgs, pos, ref, rule, seenNonOptionArg, skippingArgument, value; options = { "arguments": [] @@ -56,9 +56,9 @@ } } return options; - }; + } - OptionParser.prototype.help = function() { + help() { var j, len, letPart, lines, ref, rule, spaces; lines = []; if (this.banner) { @@ -73,11 +73,9 @@ lines.push(' ' + letPart + rule.longFlag + spaces + rule.description); } return `\n${lines.join('\n')}\n`; - }; - - return OptionParser; + } - })(); + }; LONG_FLAG = /^(--\w[\w\-]*)/; diff --git a/lib/coffee-script/rewriter.js b/lib/coffee-script/rewriter.js index 02f5de8882..b903991d84 100644 --- a/lib/coffee-script/rewriter.js +++ b/lib/coffee-script/rewriter.js @@ -14,470 +14,471 @@ }; exports.Rewriter = (function() { - function Rewriter() {} - - Rewriter.prototype.rewrite = function(tokens1) { - this.tokens = tokens1; - this.removeLeadingNewlines(); - this.closeOpenCalls(); - this.closeOpenIndexes(); - this.normalizeLines(); - this.tagPostfixConditionals(); - this.addImplicitBracesAndParens(); - this.addLocationDataToGeneratedTokens(); - this.fixOutdentLocationData(); - return this.tokens; - }; - - Rewriter.prototype.scanTokens = function(block) { - var i, token, tokens; - tokens = this.tokens; - i = 0; - while (token = tokens[i]) { - i += block.call(this, token, i, tokens); + class Rewriter { + rewrite(tokens1) { + this.tokens = tokens1; + this.removeLeadingNewlines(); + this.closeOpenCalls(); + this.closeOpenIndexes(); + this.normalizeLines(); + this.tagPostfixConditionals(); + this.addImplicitBracesAndParens(); + this.addLocationDataToGeneratedTokens(); + this.fixOutdentLocationData(); + return this.tokens; } - return true; - }; - Rewriter.prototype.detectEnd = function(i, condition, action) { - var levels, ref, ref1, token, tokens; - tokens = this.tokens; - levels = 0; - while (token = tokens[i]) { - if (levels === 0 && condition.call(this, token, i)) { - return action.call(this, token, i); - } - if (!token || levels < 0) { - return action.call(this, token, i - 1); - } - if (ref = token[0], indexOf.call(EXPRESSION_START, ref) >= 0) { - levels += 1; - } else if (ref1 = token[0], indexOf.call(EXPRESSION_END, ref1) >= 0) { - levels -= 1; + scanTokens(block) { + var i, token, tokens; + tokens = this.tokens; + i = 0; + while (token = tokens[i]) { + i += block.call(this, token, i, tokens); } - i += 1; + return true; } - return i - 1; - }; - Rewriter.prototype.removeLeadingNewlines = function() { - var i, k, len, ref, tag; - ref = this.tokens; - for (i = k = 0, len = ref.length; k < len; i = ++k) { - tag = ref[i][0]; - if (tag !== 'TERMINATOR') { - break; + detectEnd(i, condition, action) { + var levels, ref, ref1, token, tokens; + tokens = this.tokens; + levels = 0; + while (token = tokens[i]) { + if (levels === 0 && condition.call(this, token, i)) { + return action.call(this, token, i); + } + if (!token || levels < 0) { + return action.call(this, token, i - 1); + } + if (ref = token[0], indexOf.call(EXPRESSION_START, ref) >= 0) { + levels += 1; + } else if (ref1 = token[0], indexOf.call(EXPRESSION_END, ref1) >= 0) { + levels -= 1; + } + i += 1; } + return i - 1; } - if (i) { - return this.tokens.splice(0, i); - } - }; - - Rewriter.prototype.closeOpenCalls = function() { - var action, condition; - condition = function(token, i) { - var ref; - return ((ref = token[0]) === ')' || ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; - }; - action = function(token, i) { - return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; - }; - return this.scanTokens(function(token, i) { - if (token[0] === 'CALL_START') { - this.detectEnd(i + 1, condition, action); - } - return 1; - }); - }; - - Rewriter.prototype.closeOpenIndexes = function() { - var action, condition; - condition = function(token, i) { - var ref; - return (ref = token[0]) === ']' || ref === 'INDEX_END'; - }; - action = function(token, i) { - return token[0] = 'INDEX_END'; - }; - return this.scanTokens(function(token, i) { - if (token[0] === 'INDEX_START') { - this.detectEnd(i + 1, condition, action); - } - return 1; - }); - }; - Rewriter.prototype.indexOfTag = function(i, ...pattern) { - var fuzz, j, k, ref, ref1; - fuzz = 0; - for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) { - while (this.tag(i + j + fuzz) === 'HERECOMMENT') { - fuzz += 2; - } - if (pattern[j] == null) { - continue; - } - if (typeof pattern[j] === 'string') { - pattern[j] = [pattern[j]]; + removeLeadingNewlines() { + var i, k, len, ref, tag; + ref = this.tokens; + for (i = k = 0, len = ref.length; k < len; i = ++k) { + tag = ref[i][0]; + if (tag !== 'TERMINATOR') { + break; + } } - if (ref1 = this.tag(i + j + fuzz), indexOf.call(pattern[j], ref1) < 0) { - return -1; + if (i) { + return this.tokens.splice(0, i); } } - return i + j + fuzz - 1; - }; - Rewriter.prototype.looksObjectish = function(j) { - var end, index; - if (this.indexOfTag(j, '@', null, ':') > -1 || this.indexOfTag(j, null, ':') > -1) { - return true; + closeOpenCalls() { + var action, condition; + condition = function(token, i) { + var ref; + return ((ref = token[0]) === ')' || ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; + }; + action = function(token, i) { + return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'CALL_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); } - index = this.indexOfTag(j, EXPRESSION_START); - if (index > -1) { - end = null; - this.detectEnd(index + 1, (function(token) { + + closeOpenIndexes() { + var action, condition; + condition = function(token, i) { var ref; - return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0; - }), (function(token, i) { - return end = i; - })); - if (this.tag(end + 1) === ':') { - return true; + return (ref = token[0]) === ']' || ref === 'INDEX_END'; + }; + action = function(token, i) { + return token[0] = 'INDEX_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'INDEX_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); + } + + indexOfTag(i, ...pattern) { + var fuzz, j, k, ref, ref1; + fuzz = 0; + for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) { + while (this.tag(i + j + fuzz) === 'HERECOMMENT') { + fuzz += 2; + } + if (pattern[j] == null) { + continue; + } + if (typeof pattern[j] === 'string') { + pattern[j] = [pattern[j]]; + } + if (ref1 = this.tag(i + j + fuzz), indexOf.call(pattern[j], ref1) < 0) { + return -1; + } } + return i + j + fuzz - 1; } - return false; - }; - Rewriter.prototype.findTagsBackwards = function(i, tags) { - var backStack, ref, ref1, ref2, ref3, ref4, ref5; - backStack = []; - while (i >= 0 && (backStack.length || (ref2 = this.tag(i), indexOf.call(tags, ref2) < 0) && ((ref3 = this.tag(i), indexOf.call(EXPRESSION_START, ref3) < 0) || this.tokens[i].generated) && (ref4 = this.tag(i), indexOf.call(LINEBREAKS, ref4) < 0))) { - if (ref = this.tag(i), indexOf.call(EXPRESSION_END, ref) >= 0) { - backStack.push(this.tag(i)); + looksObjectish(j) { + var end, index; + if (this.indexOfTag(j, '@', null, ':') > -1 || this.indexOfTag(j, null, ':') > -1) { + return true; } - if ((ref1 = this.tag(i), indexOf.call(EXPRESSION_START, ref1) >= 0) && backStack.length) { - backStack.pop(); + index = this.indexOfTag(j, EXPRESSION_START); + if (index > -1) { + end = null; + this.detectEnd(index + 1, (function(token) { + var ref; + return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0; + }), (function(token, i) { + return end = i; + })); + if (this.tag(end + 1) === ':') { + return true; + } } - i -= 1; + return false; } - return ref5 = this.tag(i), indexOf.call(tags, ref5) >= 0; - }; - Rewriter.prototype.addImplicitBracesAndParens = function() { - var stack, start; - stack = []; - start = null; - return this.scanTokens(function(token, i, tokens) { - var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag; - tag = token[0]; - prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0]; - nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0]; - stackTop = function() { - return stack[stack.length - 1]; - }; - startIdx = i; - forward = function(n) { - return i - startIdx + n; - }; - inImplicit = function() { - var ref, ref1; - return (ref = stackTop()) != null ? (ref1 = ref[2]) != null ? ref1.ours : void 0 : void 0; - }; - inImplicitCall = function() { - var ref; - return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '('; - }; - inImplicitObject = function() { - var ref; - return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '{'; - }; - inImplicitControl = function() { - var ref; - return inImplicit && ((ref = stackTop()) != null ? ref[0] : void 0) === 'CONTROL'; - }; - startImplicitCall = function(j) { - var idx; - idx = j != null ? j : i; - stack.push([ - '(', idx, { - ours: true + findTagsBackwards(i, tags) { + var backStack, ref, ref1, ref2, ref3, ref4, ref5; + backStack = []; + while (i >= 0 && (backStack.length || (ref2 = this.tag(i), indexOf.call(tags, ref2) < 0) && ((ref3 = this.tag(i), indexOf.call(EXPRESSION_START, ref3) < 0) || this.tokens[i].generated) && (ref4 = this.tag(i), indexOf.call(LINEBREAKS, ref4) < 0))) { + if (ref = this.tag(i), indexOf.call(EXPRESSION_END, ref) >= 0) { + backStack.push(this.tag(i)); + } + if ((ref1 = this.tag(i), indexOf.call(EXPRESSION_START, ref1) >= 0) && backStack.length) { + backStack.pop(); + } + i -= 1; + } + return ref5 = this.tag(i), indexOf.call(tags, ref5) >= 0; + } + + addImplicitBracesAndParens() { + var stack, start; + stack = []; + start = null; + return this.scanTokens(function(token, i, tokens) { + var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag; + tag = token[0]; + prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0]; + nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0]; + stackTop = function() { + return stack[stack.length - 1]; + }; + startIdx = i; + forward = function(n) { + return i - startIdx + n; + }; + inImplicit = function() { + var ref, ref1; + return (ref = stackTop()) != null ? (ref1 = ref[2]) != null ? ref1.ours : void 0 : void 0; + }; + inImplicitCall = function() { + var ref; + return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '('; + }; + inImplicitObject = function() { + var ref; + return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '{'; + }; + inImplicitControl = function() { + var ref; + return inImplicit && ((ref = stackTop()) != null ? ref[0] : void 0) === 'CONTROL'; + }; + startImplicitCall = function(j) { + var idx; + idx = j != null ? j : i; + stack.push([ + '(', idx, { + ours: true + } + ]); + tokens.splice(idx, 0, generate('CALL_START', '(')); + if (j == null) { + return i += 1; } - ]); - tokens.splice(idx, 0, generate('CALL_START', '(')); - if (j == null) { + }; + endImplicitCall = function() { + stack.pop(); + tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]])); return i += 1; - } - }; - endImplicitCall = function() { - stack.pop(); - tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]])); - return i += 1; - }; - startImplicitObject = function(j, startsLine = true) { - var idx, val; - idx = j != null ? j : i; - stack.push([ - '{', idx, { - sameLine: true, - startsLine: startsLine, - ours: true + }; + startImplicitObject = function(j, startsLine = true) { + var idx, val; + idx = j != null ? j : i; + stack.push([ + '{', idx, { + sameLine: true, + startsLine: startsLine, + ours: true + } + ]); + val = new String('{'); + val.generated = true; + tokens.splice(idx, 0, generate('{', val, token)); + if (j == null) { + return i += 1; } - ]); - val = new String('{'); - val.generated = true; - tokens.splice(idx, 0, generate('{', val, token)); - if (j == null) { + }; + endImplicitObject = function(j) { + j = j != null ? j : i; + stack.pop(); + tokens.splice(j, 0, generate('}', '}', token)); return i += 1; + }; + if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) { + stack.push([ + 'CONTROL', i, { + ours: true + } + ]); + return forward(1); } - }; - endImplicitObject = function(j) { - j = j != null ? j : i; - stack.pop(); - tokens.splice(j, 0, generate('}', '}', token)); - return i += 1; - }; - if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) { - stack.push([ - 'CONTROL', i, { - ours: true + if (tag === 'INDENT' && inImplicit()) { + if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') { + while (inImplicitCall()) { + endImplicitCall(); + } } - ]); - return forward(1); - } - if (tag === 'INDENT' && inImplicit()) { - if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') { - while (inImplicitCall()) { - endImplicitCall(); + if (inImplicitControl()) { + stack.pop(); } + stack.push([tag, i]); + return forward(1); } - if (inImplicitControl()) { - stack.pop(); + if (indexOf.call(EXPRESSION_START, tag) >= 0) { + stack.push([tag, i]); + return forward(1); } - stack.push([tag, i]); - return forward(1); - } - if (indexOf.call(EXPRESSION_START, tag) >= 0) { - stack.push([tag, i]); - return forward(1); - } - if (indexOf.call(EXPRESSION_END, tag) >= 0) { - while (inImplicit()) { - if (inImplicitCall()) { - endImplicitCall(); - } else if (inImplicitObject()) { - endImplicitObject(); - } else { - stack.pop(); + if (indexOf.call(EXPRESSION_END, tag) >= 0) { + while (inImplicit()) { + if (inImplicitCall()) { + endImplicitCall(); + } else if (inImplicitObject()) { + endImplicitObject(); + } else { + stack.pop(); + } } + start = stack.pop(); } - start = stack.pop(); - } - if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((ref = tokens[i + 1]) != null ? ref.spaced : void 0) && !((ref1 = tokens[i + 1]) != null ? ref1.newLine : void 0))) { - if (tag === '?') { - tag = token[0] = 'FUNC_EXIST'; + if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((ref = tokens[i + 1]) != null ? ref.spaced : void 0) && !((ref1 = tokens[i + 1]) != null ? ref1.newLine : void 0))) { + if (tag === '?') { + tag = token[0] = 'FUNC_EXIST'; + } + startImplicitCall(i + 1); + return forward(2); } - startImplicitCall(i + 1); - return forward(2); - } - if (indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.indexOfTag(i + 1, 'INDENT') > -1 && this.looksObjectish(i + 2) && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) { - startImplicitCall(i + 1); - stack.push(['INDENT', i + 2]); - return forward(3); - } - if (tag === ':') { - s = (function() { - var ref2; - switch (false) { - case ref2 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref2) < 0: - return start[1]; - case this.tag(i - 2) !== '@': - return i - 2; - default: - return i - 1; + if (indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.indexOfTag(i + 1, 'INDENT') > -1 && this.looksObjectish(i + 2) && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) { + startImplicitCall(i + 1); + stack.push(['INDENT', i + 2]); + return forward(3); + } + if (tag === ':') { + s = (function() { + var ref2; + switch (false) { + case ref2 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref2) < 0: + return start[1]; + case this.tag(i - 2) !== '@': + return i - 2; + default: + return i - 1; + } + }).call(this); + while (this.tag(s - 2) === 'HERECOMMENT') { + s -= 2; } - }).call(this); - while (this.tag(s - 2) === 'HERECOMMENT') { - s -= 2; - } - this.insideForDeclaration = nextTag === 'FOR'; - startsLine = s === 0 || (ref2 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref2) >= 0) || tokens[s - 1].newLine; - if (stackTop()) { - ref3 = stackTop(), stackTag = ref3[0], stackIdx = ref3[1]; - if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) { - return forward(1); + this.insideForDeclaration = nextTag === 'FOR'; + startsLine = s === 0 || (ref2 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref2) >= 0) || tokens[s - 1].newLine; + if (stackTop()) { + ref3 = stackTop(), stackTag = ref3[0], stackIdx = ref3[1]; + if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) { + return forward(1); + } } + startImplicitObject(s, !!startsLine); + return forward(2); } - startImplicitObject(s, !!startsLine); - return forward(2); - } - if (inImplicitObject() && indexOf.call(LINEBREAKS, tag) >= 0) { - stackTop()[2].sameLine = false; - } - newLine = prevTag === 'OUTDENT' || prevToken.newLine; - if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) { - while (inImplicit()) { - ref4 = stackTop(), stackTag = ref4[0], stackIdx = ref4[1], (ref5 = ref4[2], sameLine = ref5.sameLine, startsLine = ref5.startsLine); - if (inImplicitCall() && prevTag !== ',') { - endImplicitCall(); - } else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') { - endImplicitObject(); - } else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) { - if (nextTag === 'HERECOMMENT') { - return forward(1); + if (inImplicitObject() && indexOf.call(LINEBREAKS, tag) >= 0) { + stackTop()[2].sameLine = false; + } + newLine = prevTag === 'OUTDENT' || prevToken.newLine; + if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) { + while (inImplicit()) { + ref4 = stackTop(), stackTag = ref4[0], stackIdx = ref4[1], (ref5 = ref4[2], sameLine = ref5.sameLine, startsLine = ref5.startsLine); + if (inImplicitCall() && prevTag !== ',') { + endImplicitCall(); + } else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') { + endImplicitObject(); + } else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) { + if (nextTag === 'HERECOMMENT') { + return forward(1); + } + endImplicitObject(); + } else { + break; } - endImplicitObject(); - } else { - break; } } - } - if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) { - offset = nextTag === 'OUTDENT' ? 1 : 0; - while (inImplicitObject()) { - endImplicitObject(i + offset); + if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) { + offset = nextTag === 'OUTDENT' ? 1 : 0; + while (inImplicitObject()) { + endImplicitObject(i + offset); + } } - } - return forward(1); - }); - }; + return forward(1); + }); + } - Rewriter.prototype.addLocationDataToGeneratedTokens = function() { - return this.scanTokens(function(token, i, tokens) { - var column, line, nextLocation, prevLocation, ref, ref1; - if (token[2]) { - return 1; - } - if (!(token.generated || token.explicit)) { + addLocationDataToGeneratedTokens() { + return this.scanTokens(function(token, i, tokens) { + var column, line, nextLocation, prevLocation, ref, ref1; + if (token[2]) { + return 1; + } + if (!(token.generated || token.explicit)) { + return 1; + } + if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) { + line = nextLocation.first_line, column = nextLocation.first_column; + } else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) { + line = prevLocation.last_line, column = prevLocation.last_column; + } else { + line = column = 0; + } + token[2] = { + first_line: line, + first_column: column, + last_line: line, + last_column: column + }; return 1; - } - if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) { - line = nextLocation.first_line, column = nextLocation.first_column; - } else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) { - line = prevLocation.last_line, column = prevLocation.last_column; - } else { - line = column = 0; - } - token[2] = { - first_line: line, - first_column: column, - last_line: line, - last_column: column - }; - return 1; - }); - }; + }); + } - Rewriter.prototype.fixOutdentLocationData = function() { - return this.scanTokens(function(token, i, tokens) { - var prevLocationData; - if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) { + fixOutdentLocationData() { + return this.scanTokens(function(token, i, tokens) { + var prevLocationData; + if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) { + return 1; + } + prevLocationData = tokens[i - 1][2]; + token[2] = { + first_line: prevLocationData.last_line, + first_column: prevLocationData.last_column, + last_line: prevLocationData.last_line, + last_column: prevLocationData.last_column + }; return 1; - } - prevLocationData = tokens[i - 1][2]; - token[2] = { - first_line: prevLocationData.last_line, - first_column: prevLocationData.last_column, - last_line: prevLocationData.last_line, - last_column: prevLocationData.last_column - }; - return 1; - }); - }; + }); + } - Rewriter.prototype.normalizeLines = function() { - var action, condition, indent, outdent, starter; - starter = indent = outdent = null; - condition = function(token, i) { - var ref, ref1, ref2, ref3; - return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && this.tokens[i - 1].newLine; - }; - action = function(token, i) { - return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent); - }; - return this.scanTokens(function(token, i, tokens) { - var j, k, ref, ref1, ref2, tag; - tag = token[0]; - if (tag === 'TERMINATOR') { - if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { - tokens.splice(i, 1, ...this.indentation()); - return 1; + normalizeLines() { + var action, condition, indent, outdent, starter; + starter = indent = outdent = null; + condition = function(token, i) { + var ref, ref1, ref2, ref3; + return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && this.tokens[i - 1].newLine; + }; + action = function(token, i) { + return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent); + }; + return this.scanTokens(function(token, i, tokens) { + var j, k, ref, ref1, ref2, tag; + tag = token[0]; + if (tag === 'TERMINATOR') { + if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { + tokens.splice(i, 1, ...this.indentation()); + return 1; + } + if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) { + tokens.splice(i, 1); + return 0; + } } - if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) { - tokens.splice(i, 1); - return 0; + if (tag === 'CATCH') { + for (j = k = 1; k <= 2; j = ++k) { + if (!((ref1 = this.tag(i + j)) === 'OUTDENT' || ref1 === 'TERMINATOR' || ref1 === 'FINALLY')) { + continue; + } + tokens.splice(i + j, 0, ...this.indentation()); + return 2 + j; + } } - } - if (tag === 'CATCH') { - for (j = k = 1; k <= 2; j = ++k) { - if (!((ref1 = this.tag(i + j)) === 'OUTDENT' || ref1 === 'TERMINATOR' || ref1 === 'FINALLY')) { - continue; + if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { + starter = tag; + ref2 = this.indentation(tokens[i]), indent = ref2[0], outdent = ref2[1]; + if (starter === 'THEN') { + indent.fromThen = true; } - tokens.splice(i + j, 0, ...this.indentation()); - return 2 + j; + tokens.splice(i + 1, 0, indent); + this.detectEnd(i + 2, condition, action); + if (tag === 'THEN') { + tokens.splice(i, 1); + } + return 1; } - } - if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { - starter = tag; - ref2 = this.indentation(tokens[i]), indent = ref2[0], outdent = ref2[1]; - if (starter === 'THEN') { - indent.fromThen = true; + return 1; + }); + } + + tagPostfixConditionals() { + var action, condition, original; + original = null; + condition = function(token, i) { + var prevTag, tag; + tag = token[0]; + prevTag = this.tokens[i - 1][0]; + return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0); + }; + action = function(token, i) { + if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) { + return original[0] = 'POST_' + original[0]; } - tokens.splice(i + 1, 0, indent); - this.detectEnd(i + 2, condition, action); - if (tag === 'THEN') { - tokens.splice(i, 1); + }; + return this.scanTokens(function(token, i) { + if (token[0] !== 'IF') { + return 1; } + original = token; + this.detectEnd(i + 1, condition, action); return 1; - } - return 1; - }); - }; + }); + } - Rewriter.prototype.tagPostfixConditionals = function() { - var action, condition, original; - original = null; - condition = function(token, i) { - var prevTag, tag; - tag = token[0]; - prevTag = this.tokens[i - 1][0]; - return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0); - }; - action = function(token, i) { - if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) { - return original[0] = 'POST_' + original[0]; - } - }; - return this.scanTokens(function(token, i) { - if (token[0] !== 'IF') { - return 1; + indentation(origin) { + var indent, outdent; + indent = ['INDENT', 2]; + outdent = ['OUTDENT', 2]; + if (origin) { + indent.generated = outdent.generated = true; + indent.origin = outdent.origin = origin; + } else { + indent.explicit = outdent.explicit = true; } - original = token; - this.detectEnd(i + 1, condition, action); - return 1; - }); - }; + return [indent, outdent]; + } - Rewriter.prototype.indentation = function(origin) { - var indent, outdent; - indent = ['INDENT', 2]; - outdent = ['OUTDENT', 2]; - if (origin) { - indent.generated = outdent.generated = true; - indent.origin = outdent.origin = origin; - } else { - indent.explicit = outdent.explicit = true; + tag(i) { + var ref; + return (ref = this.tokens[i]) != null ? ref[0] : void 0; } - return [indent, outdent]; + }; Rewriter.prototype.generate = generate; - Rewriter.prototype.tag = function(i) { - var ref; - return (ref = this.tokens[i]) != null ? ref[0] : void 0; - }; - return Rewriter; })(); diff --git a/lib/coffee-script/scope.js b/lib/coffee-script/scope.js index 99e1d4a239..2d2030b899 100644 --- a/lib/coffee-script/scope.js +++ b/lib/coffee-script/scope.js @@ -3,8 +3,8 @@ var Scope, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - exports.Scope = Scope = (function() { - function Scope(parent, expressions, method, referencedVars) { + exports.Scope = Scope = class Scope { + constructor(parent, expressions, method, referencedVars) { var ref, ref1; this.parent = parent; this.expressions = expressions; @@ -23,7 +23,7 @@ this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : this; } - Scope.prototype.add = function(name, type, immediate) { + add(name, type, immediate) { if (this.shared && !immediate) { return this.parent.add(name, type, immediate); } @@ -35,37 +35,37 @@ type: type }) - 1; } - }; + } - Scope.prototype.namedMethod = function() { + namedMethod() { var ref; if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) { return this.method; } return this.parent.namedMethod(); - }; + } - Scope.prototype.find = function(name) { + find(name) { if (this.check(name)) { return true; } this.add(name, 'var'); return false; - }; + } - Scope.prototype.parameter = function(name) { + parameter(name) { if (this.shared && this.parent.check(name, true)) { return; } return this.add(name, 'param'); - }; + } - Scope.prototype.check = function(name) { + check(name) { var ref; return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0)); - }; + } - Scope.prototype.temporary = function(name, index, single = false) { + temporary(name, index, single = false) { var diff, endCode, letter, newCode, num, startCode; if (single) { startCode = name.charCodeAt(0); @@ -78,9 +78,9 @@ } else { return `${name}${index || ''}`; } - }; + } - Scope.prototype.type = function(name) { + type(name) { var i, len, ref, v; ref = this.variables; for (i = 0, len = ref.length; i < len; i++) { @@ -90,9 +90,9 @@ } } return null; - }; + } - Scope.prototype.freeVariable = function(name, options = {}) { + freeVariable(name, options = {}) { var index, ref, temp; index = 0; while (true) { @@ -106,21 +106,21 @@ this.add(temp, 'var', true); } return temp; - }; + } - Scope.prototype.assign = function(name, value) { + assign(name, value) { this.add(name, { value: value, assigned: true }, true); return this.hasAssignments = true; - }; + } - Scope.prototype.hasDeclarations = function() { + hasDeclarations() { return !!this.declaredVariables().length; - }; + } - Scope.prototype.declaredVariables = function() { + declaredVariables() { var v; return ((function() { var i, len, ref, results; @@ -134,9 +134,9 @@ } return results; }).call(this)).sort(); - }; + } - Scope.prototype.assignedVariables = function() { + assignedVariables() { var i, len, ref, results, v; ref = this.variables; results = []; @@ -147,10 +147,8 @@ } } return results; - }; - - return Scope; + } - })(); + }; }).call(this); diff --git a/lib/coffee-script/sourcemap.js b/lib/coffee-script/sourcemap.js index 2bbbf82c78..9bce3aae36 100644 --- a/lib/coffee-script/sourcemap.js +++ b/lib/coffee-script/sourcemap.js @@ -2,13 +2,13 @@ (function() { var LineMap, SourceMap; - LineMap = (function() { - function LineMap(line1) { + LineMap = class LineMap { + constructor(line1) { this.line = line1; this.columns = []; } - LineMap.prototype.add = function(column, arg, options = {}) { + add(column, arg, options = {}) { var sourceColumn, sourceLine; sourceLine = arg[0], sourceColumn = arg[1]; if (this.columns[column] && options.noReplace) { @@ -20,94 +20,117 @@ sourceLine: sourceLine, sourceColumn: sourceColumn }; - }; + } - LineMap.prototype.sourceLocation = function(column) { + sourceLocation(column) { var mapping; while (!((mapping = this.columns[column]) || (column <= 0))) { column--; } return mapping && [mapping.sourceLine, mapping.sourceColumn]; - }; - - return LineMap; + } - })(); + }; SourceMap = (function() { var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK; - function SourceMap() { - this.lines = []; - } + class SourceMap { + constructor() { + this.lines = []; + } - SourceMap.prototype.add = function(sourceLocation, generatedLocation, options = {}) { - var base, column, line, lineMap; - line = generatedLocation[0], column = generatedLocation[1]; - lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line))); - return lineMap.add(column, sourceLocation, options); - }; + add(sourceLocation, generatedLocation, options = {}) { + var base, column, line, lineMap; + line = generatedLocation[0], column = generatedLocation[1]; + lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line))); + return lineMap.add(column, sourceLocation, options); + } - SourceMap.prototype.sourceLocation = function(arg) { - var column, line, lineMap; - line = arg[0], column = arg[1]; - while (!((lineMap = this.lines[line]) || (line <= 0))) { - line--; + sourceLocation(arg) { + var column, line, lineMap; + line = arg[0], column = arg[1]; + while (!((lineMap = this.lines[line]) || (line <= 0))) { + line--; + } + return lineMap && lineMap.sourceLocation(column); } - return lineMap && lineMap.sourceLocation(column); - }; - SourceMap.prototype.generate = function(options = {}, code = null) { - var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline; - writingline = 0; - lastColumn = 0; - lastSourceLine = 0; - lastSourceColumn = 0; - needComma = false; - buffer = ""; - ref = this.lines; - for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) { - lineMap = ref[lineNumber]; - if (lineMap) { - ref1 = lineMap.columns; - for (j = 0, len1 = ref1.length; j < len1; j++) { - mapping = ref1[j]; - if (!(mapping)) { - continue; - } - while (writingline < mapping.line) { - lastColumn = 0; - needComma = false; - buffer += ";"; - writingline++; - } - if (needComma) { - buffer += ","; - needComma = false; + generate(options = {}, code = null) { + var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline; + writingline = 0; + lastColumn = 0; + lastSourceLine = 0; + lastSourceColumn = 0; + needComma = false; + buffer = ""; + ref = this.lines; + for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) { + lineMap = ref[lineNumber]; + if (lineMap) { + ref1 = lineMap.columns; + for (j = 0, len1 = ref1.length; j < len1; j++) { + mapping = ref1[j]; + if (!(mapping)) { + continue; + } + while (writingline < mapping.line) { + lastColumn = 0; + needComma = false; + buffer += ";"; + writingline++; + } + if (needComma) { + buffer += ","; + needComma = false; + } + buffer += this.encodeVlq(mapping.column - lastColumn); + lastColumn = mapping.column; + buffer += this.encodeVlq(0); + buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine); + lastSourceLine = mapping.sourceLine; + buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn); + lastSourceColumn = mapping.sourceColumn; + needComma = true; } - buffer += this.encodeVlq(mapping.column - lastColumn); - lastColumn = mapping.column; - buffer += this.encodeVlq(0); - buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine); - lastSourceLine = mapping.sourceLine; - buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn); - lastSourceColumn = mapping.sourceColumn; - needComma = true; } } + v3 = { + version: 3, + file: options.generatedFile || '', + sourceRoot: options.sourceRoot || '', + sources: options.sourceFiles || [''], + names: [], + mappings: buffer + }; + if (options.inlineMap) { + v3.sourcesContent = [code]; + } + return v3; } - v3 = { - version: 3, - file: options.generatedFile || '', - sourceRoot: options.sourceRoot || '', - sources: options.sourceFiles || [''], - names: [], - mappings: buffer - }; - if (options.inlineMap) { - v3.sourcesContent = [code]; + + encodeVlq(value) { + var answer, nextChunk, signBit, valueToEncode; + answer = ''; + signBit = value < 0 ? 1 : 0; + valueToEncode = (Math.abs(value) << 1) + signBit; + while (valueToEncode || !answer) { + nextChunk = valueToEncode & VLQ_VALUE_MASK; + valueToEncode = valueToEncode >> VLQ_SHIFT; + if (valueToEncode) { + nextChunk |= VLQ_CONTINUATION_BIT; + } + answer += this.encodeBase64(nextChunk); + } + return answer; + } + + encodeBase64(value) { + return BASE64_CHARS[value] || (function() { + throw new Error(`Cannot Base64 encode value: ${value}`); + })(); } - return v3; + }; VLQ_SHIFT = 5; @@ -116,30 +139,8 @@ VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1; - SourceMap.prototype.encodeVlq = function(value) { - var answer, nextChunk, signBit, valueToEncode; - answer = ''; - signBit = value < 0 ? 1 : 0; - valueToEncode = (Math.abs(value) << 1) + signBit; - while (valueToEncode || !answer) { - nextChunk = valueToEncode & VLQ_VALUE_MASK; - valueToEncode = valueToEncode >> VLQ_SHIFT; - if (valueToEncode) { - nextChunk |= VLQ_CONTINUATION_BIT; - } - answer += this.encodeBase64(nextChunk); - } - return answer; - }; - BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - SourceMap.prototype.encodeBase64 = function(value) { - return BASE64_CHARS[value] || (function() { - throw new Error(`Cannot Base64 encode value: ${value}`); - })(); - }; - return SourceMap; })(); diff --git a/src/nodes.coffee b/src/nodes.coffee index 73fadbce4d..9e722b0f6b 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -117,6 +117,29 @@ exports.Base = class Base ref = if level then @compileToFragments o, level else this [ref, ref] + # Occasionally it may be useful to make an expression behave as if it was 'hoisted', whereby the + # result of the expression is available before its location in the source, but the expression's + # variable scope corresponds the source position. This is used extensively to deal with executable + # class bodies in classes. + # + # Calling this method mutates the node, proxying the `compileNode` and `compileToFragments` + # methods to store their result for later replacing the `target` node, which is returned by the + # call. + hoist: -> + @hoisted = yes + target = new HoistTarget @ + + compileNode = @compileNode + compileToFragments = @compileToFragments + + @compileNode = (o) -> + target.update compileNode, o + + @compileToFragments = (o) -> + target.update compileToFragments, o + + target + cacheToCodeFragments: (cacheValues) -> [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])] @@ -169,6 +192,24 @@ exports.Base = class Base recur = func(child) child.traverseChildren(crossScope, func) unless recur is no + # `replaceInContext` will traverse children looking for a node for which `match` returns + # true. Once found, the matching node will be replaced by the result of calling `replacement`. + replaceInContext: (match, replacement) -> + return false unless @children + for attr in @children when children = @[attr] + if Array.isArray children + for child, i in children + if match child + children[i..i] = replacement child, @ + return true + else + return true if child.replaceInContext match, replacement + else if match children + @[attr] = replacement children, @ + return true + else + return true if children.replaceInContext match, replacement + invert: -> new Op '!', this @@ -223,6 +264,47 @@ exports.Base = class Base answer = answer.concat fragments answer +#### HoistTarget + +# A **HoistTargetNode** represents the output location in the node tree for a hoisted node. +# See Base#hoist. +exports.HoistTarget = class HoistTarget extends Base + # Expands hoisted fragments in the given array + @expand = (fragments) -> + for fragment, i in fragments by -1 when fragment.fragments + fragments[i..i] = @expand fragment.fragments + fragments + + constructor: (@source) -> + super() + + # Holds presentational options to apply when the source node is compiled + @options = {} + + # Placeholder fragments to be replaced by the source node's compilation + @targetFragments = { fragments: [] } + + isStatement: (o) -> + @source.isStatement o + + # Update the target fragments with the result of compiling the source. + # Calls the given compile function with the node and options (overriden with the target + # presentational options). + update: (compile, o) -> + @targetFragments.fragments = compile.call @source, merge o, @options + + # Copies the target indent and level, and returns the placeholder fragments + compileToFragments: (o, level) -> + @options.indent = o.indent + @options.level = level ? o.level + [ @targetFragments ] + + compileNode: (o) -> + @compileToFragments o + + compileClosure: (o) -> + @compileToFragments o + #### Block # The block is the list of expressions that forms the body of an @@ -230,6 +312,8 @@ exports.Base = class Base # `if`, `switch`, or `try`, and so on... exports.Block = class Block extends Base constructor: (nodes) -> + super() + @expressions = compact flatten nodes or [] children: ['expressions'] @@ -299,6 +383,9 @@ exports.Block = class Block extends Base # it in a new scope; we just compile the statements in this block along with # our own compiledNodes.push node.compileNode o + else if node.hoisted + # This is a hoisted expression. We want to compile this and ignore the result. + node.compileToFragments o else if top node.front = true fragments = node.compileToFragments o @@ -343,6 +430,7 @@ exports.Block = class Block extends Base prelude.push @makeCode "\n" @expressions = rest fragments = @compileWithDeclarations o + HoistTarget.expand fragments return fragments if o.bare [].concat prelude, @makeCode("(function() {\n"), fragments, @makeCode("\n}).call(this);\n") @@ -391,6 +479,7 @@ exports.Block = class Block extends Base # `true`, `false`, `null`... exports.Literal = class Literal extends Base constructor: (@value) -> + super() isComplex: NO @@ -468,6 +557,7 @@ exports.BooleanLiteral = class BooleanLiteral extends Literal # make sense. exports.Return = class Return extends Base constructor: (@expression) -> + super() children: ['expression'] @@ -511,6 +601,9 @@ exports.AwaitReturn = class AwaitReturn extends Return exports.Value = class Value extends Base constructor: (base, props, tag) -> return base if not props and base instanceof Value + + super() + @base = base @properties = props or [] @[tag] = true if tag @@ -562,8 +655,8 @@ exports.Value = class Value extends Base lastProp instanceof Slice looksStatic: (className) -> - @base.value is className and @properties.length is 1 and - @properties[0].name?.value isnt 'prototype' + (@this or @base instanceof ThisLiteral or @base.value is className) and + @properties.length is 1 and @properties[0].name?.value isnt 'prototype' # The value can be unwrapped as its inner node, if there are no attached # properties. @@ -625,6 +718,7 @@ exports.Value = class Value extends Base # at the same position. exports.Comment = class Comment extends Base constructor: (@comment) -> + super() isStatement: YES makeReturn: THIS @@ -640,6 +734,8 @@ exports.Comment = class Comment extends Base # Node for a function invocation. exports.Call = class Call extends Base constructor: (@variable, @args = [], @soak) -> + super() + @isNew = false if @variable instanceof Value and @variable.isNotCallable() @variable.error "literal is not a function" @@ -697,8 +793,12 @@ exports.Call = class Call extends Base fragments = [] if this instanceof SuperCall - preface = @superReference(o) + ".call(#{@superThis(o)}" - if compiledArgs.length then preface += ", " + preface = @superReference o + if preface is 'super' + preface += '(' + else + preface += ".call(#{@superThis(o)}" + if compiledArgs.length then preface += ", " fragments.push @makeCode preface else if @isNew then fragments.push @makeCode 'new ' @@ -712,17 +812,41 @@ exports.Call = class Call extends Base # Takes care of converting `super()` calls into calls against the prototype's # function of the same name. +# When `expressions` are set the call will be compiled in such a way that the +# expressions are evaluated without altering the return value of the `SuperCall` +# expression. exports.SuperCall = class SuperCall extends Call + children: ['expressions'] + constructor: (args) -> super null, args ? [new Splat new IdentifierLiteral 'arguments'] # Allow to recognize a bare `super` call without parentheses and arguments. @isBare = args? + isStatement: (o) -> + @expressions?.length and o.level is LEVEL_TOP + + compileNode: (o) -> + return super unless @expressions?.length + + superCall = new Literal fragmentsToText super + replacement = new Block @expressions.slice() + + if o.level > LEVEL_TOP + # If we might be in an expression we need to cache and return the result + [superCall, ref] = superCall.cache o, null, YES + replacement.push ref + + replacement.unshift superCall + replacement.compileToFragments o, if o.level is LEVEL_TOP then o.level else LEVEL_LIST + # Grab the reference to the superclass's implementation of the current # method. superReference: (o) -> method = o.scope.namedMethod() - if method?.klass + if method?.ctor + 'super' + else if method?.klass {klass, name, variable} = method if klass.isComplex() bref = new IdentifierLiteral o.scope.parent.freeVariable 'base' @@ -731,15 +855,11 @@ exports.SuperCall = class SuperCall extends Call variable.properties.splice 0, klass.properties.length if name.isComplex() or (name instanceof Index and name.index.isAssignable()) nref = new IdentifierLiteral o.scope.parent.freeVariable 'name' - name = new Index new Assign nref, name.index - variable.properties.pop() - variable.properties.push name + name.index = new Assign nref, name.index accesses = [new Access new PropertyName '__super__'] - accesses.push new Access new PropertyName 'constructor' if method.static + accesses.push new Access new PropertyName 'constructor' if method.isStatic accesses.push if nref? then new Index nref else name (new Value bref ? klass, accesses).compile o - else if method?.ctor - "#{method.name}.__super__.constructor" else @error 'cannot call super outside of an instance method.' @@ -773,6 +893,7 @@ exports.TaggedTemplateCall = class TaggedTemplateCall extends Call # [Closure Library](https://github.com/google/closure-library/blob/master/closure/goog/base.js). exports.Extends = class Extends extends Base constructor: (@child, @parent) -> + super() children: ['child', 'parent'] @@ -786,6 +907,7 @@ exports.Extends = class Extends extends Base # an access into the object's prototype. exports.Access = class Access extends Base constructor: (@name, tag) -> + super() @soak = tag is 'soak' children: ['name'] @@ -808,6 +930,7 @@ exports.Access = class Access extends Base # A `[ ... ]` indexed access into an array or object. exports.Index = class Index extends Base constructor: (@index) -> + super() children: ['index'] @@ -827,6 +950,8 @@ exports.Range = class Range extends Base children: ['from', 'to'] constructor: (@from, @to, tag) -> + super() + @exclusive = tag is 'exclusive' @equals = if @exclusive then '' else '=' @@ -951,6 +1076,8 @@ exports.Slice = class Slice extends Base # An object literal, nothing fancy. exports.Obj = class Obj extends Base constructor: (props, @generated = false) -> + super() + @objects = @properties = props or [] children: ['properties'] @@ -1001,6 +1128,8 @@ exports.Obj = class Obj extends Base # An array literal. exports.Arr = class Arr extends Base constructor: (objs) -> + super() + @objects = objs or [] children: ['objects'] @@ -1030,162 +1159,312 @@ exports.Arr = class Arr extends Base #### Class # The CoffeeScript class definition. -# Initialize a **Class** with its name, an optional superclass, and a -# list of prototype property assignments. +# Initialize a **Class** with its name, an optional superclass, and a body. + exports.Class = class Class extends Base + children: ['variable', 'parent', 'body'] + constructor: (@variable, @parent, @body = new Block) -> - @boundFuncs = [] - @body.classBody = yes + super() - children: ['variable', 'parent', 'body'] + compileNode: (o) -> + @name = @determineName() + executableBody = @walkBody() - defaultClassVariableName: '_Class' + if executableBody + @compileNode = @compileClassDeclaration + result = new ExecutableClassBody(@, executableBody).compileToFragments o + @compileNode = @constructor::compileNode + else + result = @compileClassDeclaration o + + # Anonymous classes are only valid in expressions + result = @wrapInBraces result if not @name? and o.level is LEVEL_TOP - # Figure out the appropriate name for the constructor function of this class. + if @variable + assign = new Assign @variable, new Literal(''), null, { @moduleDeclaration } + [ assign.compileToFragments(o)..., result... ] + else + result + + compileClassDeclaration: (o) -> + @ctor ?= @makeDefaultConstructor() if @externalCtor or @boundMethods.length + @ctor?.noReturn = true + + @proxyBoundMethods o if @boundMethods.length + + o.indent += TAB + + result = [] + result.push @makeCode "class " + result.push @makeCode "#{@name} " if @name + result.push @makeCode('extends '), @parent.compileToFragments(o)..., @makeCode ' ' if @parent + + result.push @makeCode '{' + unless @body.isEmpty() + @body.spaced = true + result.push @makeCode '\n' + result.push @body.compileToFragments(o, LEVEL_TOP)... + result.push @makeCode "\n#{@tab}" + result.push @makeCode '}' + + result + + # Figure out the appropriate name for this class determineName: -> - return @defaultClassVariableName unless @variable + return null unless @variable [..., tail] = @variable.properties node = if tail tail instanceof Access and tail.name else @variable.base unless node instanceof IdentifierLiteral or node instanceof PropertyName - return @defaultClassVariableName + return null name = node.value unless tail message = isUnassignable name @variable.error message if message if name in JS_FORBIDDEN then "_#{name}" else name - # For all `this`-references and bound functions in the class definition, - # `this` is the Class being constructed. - setContext: (name) -> - @body.traverseChildren false, (node) -> - return false if node.classBody - if node instanceof ThisLiteral - node.value = name - else if node instanceof Code - node.context = name if node.bound - - # Ensure that all functions bound to the instance are proxied in the - # constructor. - addBoundFunctions: (o) -> - for bvar in @boundFuncs - lhs = (new Value (new ThisLiteral), [new Access bvar]).compile o - @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind', o}(#{lhs}, this)" - return + walkBody: -> + @ctor = null + @boundMethods = [] + executableBody = null + + initializer = [] + { expressions } = @body + + i = 0 + for expression in expressions.slice() + if expression instanceof Value and expression.isObject true + { properties } = expression.base + exprs = [] + end = 0 + start = 0 + pushSlice = -> exprs.push new Value new Obj properties[start...end], true if end > start + + while assign = properties[end] + if initializerExpression = @addInitializerExpression assign + pushSlice() + exprs.push initializerExpression + initializer.push initializerExpression + start = end + 1 + else if initializer[initializer.length - 1] instanceof Comment + # Try to keep comments with their subsequent assign + exprs.pop() + initializer.pop() + start-- + end++ + pushSlice() + + expressions[i..i] = exprs + i += exprs.length + else + if initializerExpression = @addInitializerExpression expression + initializer.push initializerExpression + expressions[i] = initializerExpression + else if initializer[initializer.length - 1] instanceof Comment + # Try to keep comments with their subsequent assign + initializer.pop() + i += 1 + + for method in initializer when method instanceof Code + if method.ctor + method.error 'Cannot define more than one constructor in a class' if @ctor + @ctor = method + else if method.bound and method.isStatic + method.context = @name + else if method.bound + @boundMethods.push method.name + method.bound = false + + # TODO Once `super` has been changed over to ES, the check for @parent can be removed + if @parent or initializer.length != expressions.length + @body.expressions = (expression.hoist() for expression in initializer) + new Block expressions + + # Add an expression to the class initializer + # + # NOTE Currently, only comments, methods and static methods are valid in ES class initializers. + # When additional expressions become valid, this method should be updated to handle them. + addInitializerExpression: (node) -> + switch + when node instanceof Comment + node + when @validInitializerMethod node + @addInitializerMethod node + else + null + + # Checks if the given node is a valid ES class initializer method. + validInitializerMethod: (node) -> + return false unless node instanceof Assign and node.value instanceof Code + return true if node.context is 'object' and not node.variable.hasProperties() + return node.variable.looksStatic(@name) and (@name or not node.value.bound) + + # Returns a configured class initializer method + addInitializerMethod: (assign) -> + variable = assign.variable + method = assign.value + method.isMethod = yes + method.isStatic = variable.looksStatic @name + method.klass = new IdentifierLiteral @name + method.variable = variable + + if method.isStatic + method.name = variable.properties[0] + else + methodName = variable.base + method.name = new (if methodName.isComplex() then Index else Access) methodName + method.ctor = (if @parent then 'derived' else 'base') if methodName.value is 'constructor' + method.error 'Cannot define a constructor as a bound function' if method.bound and method.ctor - # Merge the properties from a top-level object as prototypal properties - # on the class. - addProperties: (node, name, o) -> - props = node.base.properties[..] - exprs = while assign = props.shift() - if assign instanceof Assign - base = assign.variable.base - delete assign.context - func = assign.value - if base.value is 'constructor' - if @ctor - assign.error 'cannot define more than one constructor in a class' - if func.bound - assign.error 'cannot define a constructor as a bound function' - if func instanceof Code - assign = @ctor = func - else - @externalCtor = o.classScope.freeVariable 'ctor' - assign = new Assign new IdentifierLiteral(@externalCtor), func - else - if assign.variable.this - func.static = yes - else - acc = if base.isComplex() then new Index base else new Access base - assign.variable = new Value(new IdentifierLiteral(name), [(new Access new PropertyName 'prototype'), acc]) - if func instanceof Code and func.bound - @boundFuncs.push base - func.bound = no - assign - compact exprs + method + + makeDefaultConstructor: -> + ctor = @addInitializerMethod new Assign (new Value new PropertyName 'constructor'), new Code + @body.unshift ctor + + ctor.body.push new SuperCall if @parent + + if @externalCtor + applyCtor = new Value @externalCtor, [ new Access new PropertyName 'apply' ] + applyArgs = [ new ThisLiteral, new IdentifierLiteral 'arguments' ] + ctor.body.push new Call applyCtor, applyArgs + ctor.body.makeReturn() + + ctor + + proxyBoundMethods: (o) -> + @ctor.thisAssignments = for name in @boundMethods by -1 + name = new Value(new ThisLiteral, [ name ]).compile o + new Literal "#{name} = #{utility 'bind', o}(#{name}, this)" + + null + +exports.ExecutableClassBody = class ExecutableClassBody extends Base + children: [ 'class', 'body' ] + + defaultClassVariableName: '_Class' + + constructor: (@class, @body = new Block) -> + super() - # Walk the body of the class, looking for prototype properties to be converted - # and tagging static assignments. - walkBody: (name, o) -> - @traverseChildren false, (child) => - cont = true - return false if child instanceof Class - if child instanceof Block - for node, i in exps = child.expressions - if node instanceof Assign and node.variable.looksStatic name - node.value.static = yes - else if node instanceof Value and node.isObject(true) - cont = false - exps[i] = @addProperties node, name, o - child.expressions = exps = flatten exps - cont and child not instanceof Class - - # `use strict` (and other directives) must be the first expression statement(s) - # of a function body. This method ensures the prologue is correctly positioned - # above the `constructor`. - hoistDirectivePrologue: -> - index = 0 - {expressions} = @body - ++index while (node = expressions[index]) and node instanceof Comment or - node instanceof Value and node.isString() - @directives = expressions.splice 0, index - - # Make sure that a constructor is defined for the class, and properly - # configured. - ensureConstructor: (name) -> - if not @ctor - @ctor = new Code - if @externalCtor - @ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" - else if @parent - @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" - @ctor.body.makeReturn() - @body.expressions.unshift @ctor - @ctor.ctor = @ctor.name = name - @ctor.klass = null - @ctor.noReturn = yes - - # Instead of generating the JavaScript string directly, we build up the - # equivalent syntax tree and compile that, in pieces. You can see the - # constructor, property assignments, and inheritance getting built out below. compileNode: (o) -> if jumpNode = @body.jumps() jumpNode.error 'Class bodies cannot contain pure statements' if argumentsNode = @body.contains isLiteralArguments argumentsNode.error "Class bodies shouldn't reference arguments" - name = @determineName() - lname = new IdentifierLiteral name - func = new Code [], Block.wrap [@body] - args = [] - o.classScope = func.makeScope o.scope - - @hoistDirectivePrologue() - @setContext name - @walkBody name, o - @ensureConstructor name - @addBoundFunctions o - @body.spaced = yes - @body.expressions.push lname - - if @parent - superClass = new IdentifierLiteral o.classScope.freeVariable 'superClass', reserve: no - @body.expressions.unshift new Extends lname, superClass - func.params.push new Param superClass - args.push @parent - - @body.expressions.unshift @directives... - - klass = new Parens new Call func, args - klass = new Assign @variable, klass, null, { @moduleDeclaration } if @variable + @name = @class.name ? @defaultClassVariableName + directives = @walkBody() + @setContext() + + ident = new IdentifierLiteral @name + params = [] + args = [] + wrapper = new Code params, @body + klass = new Parens new Call wrapper, args + + @body.spaced = true + + o.classScope = wrapper.makeScope o.scope + + if @externalCtor + externalCtor = new IdentifierLiteral o.classScope.freeVariable 'ctor', reserve: no + @class.externalCtor = externalCtor + @externalCtor.variable.base = externalCtor + + if @class.parent + parent = new IdentifierLiteral o.classScope.freeVariable 'superClass', reserve: no + params.push new Param parent + args.push @class.parent + + @class.parent = parent + @body.unshift new Literal "#{@name}.__super__ = #{parent.value}.prototype" + + if @name != @class.name + @body.expressions.unshift new Assign (new IdentifierLiteral @name), @class + else + @body.expressions.unshift @class + @body.expressions.unshift directives... + @body.push ident + klass.compileToFragments o + # Traverse the class's children and: + # - Hoist valid ES properties into `@properties` + # - Hoist static assignments into `@properties` + # - Convert invalid ES properties into class or prototype assignments + walkBody: -> + directives = [] + + index = 0 + while expr = @body.expressions[index] + break unless expr instanceof Comment or expr instanceof Value and expr.isString() + if expr.hoisted + index++ + else + directives.push @body.expressions.splice(index, 1)... + + @traverseChildren false, (child) => + return false if child instanceof Class or child instanceof HoistTarget + + cont = true + if child instanceof Block + for node, i in child.expressions + if node instanceof Value and node.isObject(true) + cont = false + child.expressions[i] = @addProperties node.base.properties + else if node instanceof Assign and node.variable.looksStatic @name + node.value.isStatic = yes + else if node instanceof Code and node.isMethod + node.klass = new IdentifierLiteral @name + child.expressions = flatten child.expressions + cont + + directives + + setContext: -> + @body.traverseChildren false, (node) => + if node instanceof ThisLiteral + node.value = @name + else if node instanceof Code and node.bound + node.context = @name + + # Make class/prototype assignments for invalid ES properties + addProperties: (assigns) -> + result = for assign in assigns + variable = assign.variable + base = variable?.base + value = assign.value + delete assign.context + + if assign instanceof Comment + # Passthrough + else if base.value is 'constructor' + if value instanceof Code + base.error 'constructors must be defined at the top level of a class body' + + # The class scope is not available yet, so return the assignment to update later + assign = @externalCtor = new Assign new Value, value + else if not assign.variable.this + name = new (if base.isComplex() then Index else Access) base + prototype = new Access new PropertyName 'prototype' + variable = new Value new ThisLiteral(), [ prototype, name ] + + assign.variable = variable + else if assign.value instanceof Code + assign.value.isStatic = true + + assign + compact result + #### Import and Export exports.ModuleDeclaration = class ModuleDeclaration extends Base constructor: (@clause, @source) -> + super() @checkSource() children: ['clause', 'source'] @@ -1220,6 +1499,7 @@ exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration exports.ImportClause = class ImportClause extends Base constructor: (@defaultBinding, @namedImports) -> + super() children: ['defaultBinding', 'namedImports'] @@ -1249,7 +1529,6 @@ exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration if @clause instanceof Class and not @clause.variable @clause.error 'anonymous classes cannot be exported' - # When the ES2015 `class` keyword is supported, don’t add a `var` here code.push @makeCode 'var ' @clause.moduleDeclaration = 'export' @@ -1270,6 +1549,7 @@ exports.ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclarat exports.ModuleSpecifierList = class ModuleSpecifierList extends Base constructor: (@specifiers) -> + super() children: ['specifiers'] @@ -1294,6 +1574,8 @@ exports.ExportSpecifierList = class ExportSpecifierList extends ModuleSpecifierL exports.ModuleSpecifier = class ModuleSpecifier extends Base constructor: (@original, @alias, @moduleDeclarationType) -> + super() + # The name of the variable entering the local scope @identifier = if @alias? then @alias.value else @original.value @@ -1333,6 +1615,7 @@ exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier # property of an object -- including within object literals. exports.Assign = class Assign extends Base constructor: (@variable, @value, @context, options = {}) -> + super() {@param, @subpattern, @operatorToken, @moduleDeclaration} = options children: ['variable', 'value'] @@ -1362,7 +1645,7 @@ exports.Assign = class Assign extends Base return @compileConditional o if @context in ['||=', '&&=', '?='] return @compileSpecialMath o if @context in ['**=', '//=', '%%='] if @value instanceof Code - if @value.static + if @value.isStatic @value.klass = @variable.base @value.name = @variable.properties[0] @value.variable = @variable @@ -1564,11 +1847,14 @@ exports.Assign = class Assign extends Base # has no *children* -- they're within the inner scope. exports.Code = class Code extends Base constructor: (params, body, tag) -> + super() + @params = params or [] @body = body or new Block @bound = tag is 'boundfunc' @isGenerator = no @isAsync = no + @isMethod = no @body.traverseChildren no, (node) => if (node instanceof Op and node.isYield()) or node instanceof YieldReturn @@ -1580,7 +1866,7 @@ exports.Code = class Code extends Base children: ['params', 'body'] - isStatement: -> !!@ctor + isStatement: -> @isMethod jumps: NO @@ -1593,6 +1879,10 @@ exports.Code = class Code extends Base # parameters after the splat, they are declared via expressions in the # function body. compileNode: (o) -> + if @ctor + @variable.error 'Class constructor may not be async' if @isAsync + @variable.error 'Class constructor may not be a generator' if @isGenerator + if @bound @context = o.scope.method.context if o.scope.method?.bound @context = 'this' unless @context @@ -1604,15 +1894,23 @@ exports.Code = class Code extends Base delete o.isExistentialEquals params = [] exprs = [] + thisAssignments = @thisAssignments?.slice() ? [] paramsAfterSplat = [] haveSplatParam = no - # Check for duplicate parameters. + # Check for duplicate parameters and separate `this` assignments paramNames = [] - @eachParamName (name, node) => + @eachParamName (name, node, param) -> node.error "multiple parameters named '#{name}'" if name in paramNames paramNames.push name + if node.this + name = node.properties[0].name.value + name = "_#{name}" if name in JS_FORBIDDEN + target = new IdentifierLiteral o.scope.freeVariable name + param.renameParam node, target + thisAssignments.push new Assign node, target + # Parse the parameters, adding them to the list of parameters to put in the # function definition; and dealing with splats or expansions, including # adding expressions to the function body to declare all parameter @@ -1631,12 +1929,11 @@ exports.Code = class Code extends Base if param.splat params.push ref = param.asReference o splatParamName = fragmentsToText ref.compileNode o - if param.isComplex() # Parameter is destructured or attached to `this` + if param.isComplex() # Parameter is destructured exprs.push new Assign new Value(param.name), ref, '=', param: yes - # TODO: output destrucutred parameters as is, *unless* they contain - # `this` parameters; and fix destructuring of objects with default - # values to work in this context (see Obj.compileNode - # `if prop.context isnt 'object'`) + # TODO: output destructured parameters as is, and fix destructuring + # of objects with default values to work in this context (see + # Obj.compileNode `if prop.context isnt 'object'`) else # `param` is an Expansion splatParamName = o.scope.freeVariable 'args' @@ -1649,10 +1946,9 @@ exports.Code = class Code extends Base # the function definition. else if param.isComplex() - # This parameter is attached to `this`, which ES doesn’t allow; - # or it’s destructured. So add a statement to the function body - # assigning it, e.g. `(a) => { this.a = a; }` or with a default - # value if it has one. + # This parameter is destructured. So add a statement to the function + # body assigning it, e.g. `(arg) => { var a = arg.a; }` or with a + # default value if it has one. val = ref = param.asReference o val = new Op '?', ref, param.value if param.value exprs.push new Assign new Value(param.name), val, '=', param: yes @@ -1691,27 +1987,41 @@ exports.Code = class Code extends Base # Add new expressions to the function body wasEmpty = @body.isEmpty() - @body.expressions.unshift exprs... if exprs.length + @body.expressions.unshift thisAssignments... unless @expandCtorSuper thisAssignments + @body.expressions.unshift exprs... @body.makeReturn() unless wasEmpty or @noReturn # Assemble the output - code = '' - code += 'async ' if @isAsync - unless @bound - code += 'function' - code += '*' if @isGenerator # Arrow functions can’t be generators - code += ' ' + @name if @ctor - code += '(' - answer = [@makeCode(code)] + modifiers = [] + modifiers.push 'static' if @isMethod and @isStatic + modifiers.push 'async' if @isAsync + modifiers.push 'function' if not @isMethod and not @bound + modifiers.push '*' if @isGenerator + + signature = [@makeCode '('] for param, i in params - answer.push @makeCode ', ' if i - answer.push @makeCode '...' if haveSplatParam and i is params.length - 1 # Rest syntax is always on the last parameter - answer.push param.compileToFragments(o)... - answer.push @makeCode unless @bound then ') {' else ') => {' - answer = answer.concat(@makeCode("\n"), @body.compileWithDeclarations(o), @makeCode("\n#{@tab}")) unless @body.isEmpty() + signature.push @makeCode ', ' if i + signature.push @makeCode '...' if haveSplatParam and i is params.length - 1 + signature.push param.compileToFragments(o)... + signature.push @makeCode ')' + + body = @body.compileWithDeclarations o unless @body.isEmpty() + + # We need to compile the body before method names to ensure super references are handled + if @isMethod + name = @name.compileToFragments o + name.shift() if name[0].code is '.' + + answer = @joinFragmentArrays (@makeCode m for m in modifiers), ' ' + answer.push @makeCode ' ' if modifiers.length and name + answer.push name... if name + answer.push signature... + answer.push @makeCode ' =>' if @bound and not @isMethod + answer.push @makeCode ' {' + answer.push @makeCode('\n'), body..., @makeCode("\n#{@tab}") if body?.length answer.push @makeCode '}' - return [@makeCode(@tab), answer...] if @ctor + return [@makeCode(@tab), answer...] if @isMethod if @front or (o.level >= LEVEL_ACCESS) then @wrapInBraces answer else answer eachParamName: (iterator) -> @@ -1722,6 +2032,48 @@ exports.Code = class Code extends Base traverseChildren: (crossScope, func) -> super(crossScope, func) if crossScope + # Short-circuit `replaceInContext` method to prevent it from crossing context boundaries. Bound + # functions have the same context. + replaceInContext: (child, replacement) -> + if @bound + super child, replacement + else + false + + expandCtorSuper: (thisAssignments) -> + return false unless @ctor + + @eachSuperCall Block.wrap(@params), (superCall) -> + superCall.error "'super' is not allowed in constructor parameter defaults" + + seenSuper = @eachSuperCall @body, (superCall) => + superCall.error "'super' is only allowed in derived class constructors" if @ctor is 'base' + superCall.expressions = thisAssignments + + haveThisParam = thisAssignments.length and thisAssignments.length != @thisAssignments?.length + if @ctor is 'derived' and not seenSuper and haveThisParam + param = thisAssignments[0].variable + param.error "Can't use @params in derived class constructors without calling super" + + seenSuper + + # Find all super calls in the given context node + # Returns `true` if `iterator` is called + eachSuperCall: (context, iterator) -> + seenSuper = no + + context.traverseChildren true, (child) => + if child instanceof SuperCall + seenSuper = yes + iterator child + else if child instanceof ThisLiteral and @ctor is 'derived' and not seenSuper + child.error "Can't reference 'this' before calling super in derived class constructors" + + # `super` has the same target in bound (arrow) functions, so check them too + child not instanceof SuperCall and (child not instanceof Code or child.bound) + + seenSuper + #### Param # A parameter in a function definition. Beyond a typical JavaScript parameter, @@ -1729,6 +2081,8 @@ exports.Code = class Code extends Base # as well as be a splat, gathering up a group of parameters into an array. exports.Param = class Param extends Base constructor: (@name, @value, @splat) -> + super() + message = isUnassignable @name.unwrapAll().value @name.error message if message if @name instanceof Obj and @name.generated @@ -1763,9 +2117,9 @@ exports.Param = class Param extends Base # `name` is the name of the parameter and `node` is the AST node corresponding # to that name. eachName: (iterator, name = @name) -> - atParam = (obj) -> iterator "@#{obj.properties[0].name.value}", obj + atParam = (obj) => iterator "@#{obj.properties[0].name.value}", obj, @ # * simple literals `foo` - return iterator name.value, name if name instanceof Literal + return iterator name.value, name, @ if name instanceof Literal # * at-params `@foo` return atParam name if name instanceof Value for obj in name.objects ? [] @@ -1781,7 +2135,7 @@ exports.Param = class Param extends Base # * splats within destructured parameters `[xs...]` else if obj instanceof Splat node = obj.name.unwrap() - iterator node.value, node + iterator node.value, node, @ else if obj instanceof Value # * destructured parameters within destructured parameters `[{a}]` if obj.isArray() or obj.isObject() @@ -1790,11 +2144,25 @@ exports.Param = class Param extends Base else if obj.this atParam obj # * simple destructured parameters {foo} - else iterator obj.base.value, obj.base + else iterator obj.base.value, obj.base, @ else if obj not instanceof Expansion obj.error "illegal parameter #{obj.compile()}" return + # Rename a param by replacing the given AST node for a name with a new node. + # This needs to ensure that the the source for object destructuring does not change. + renameParam: (node, newNode) -> + isNode = (candidate) -> candidate is node + replacement = (node, parent) => + if parent instanceof Obj + key = node + key = node.properties[0].name if node.this + new Assign new Value(key), newNode, 'object' + else + newNode + + @replaceInContext isNode, replacement + #### Splat # A splat, either as a parameter to a function, an argument to a call, @@ -1806,6 +2174,7 @@ exports.Splat = class Splat extends Base isAssignable: YES constructor: (name) -> + super() @name = if name.compile then name else new Literal name assigns: (name) -> @@ -1840,6 +2209,8 @@ exports.Expansion = class Expansion extends Base # flexibility or more speed than a comprehension can provide. exports.While = class While extends Base constructor: (condition, options) -> + super() + @condition = if options?.invert then condition.invert() else condition @guard = options?.guard @@ -1897,10 +2268,13 @@ exports.Op = class Op extends Base constructor: (op, first, second, flip ) -> return new In first, second if op is 'in' if op is 'do' - return @generateDo first + return Op::generateDo first if op is 'new' return first.newInstance() if first instanceof Call and not first.do and not first.isNew first = new Parens first if first instanceof Code and first.bound or first.do + + super() + @operator = CONVERSIONS[op] or op @first = first @second = second @@ -2091,6 +2465,7 @@ exports.Op = class Op extends Base #### In exports.In = class In extends Base constructor: (@object, @array) -> + super() children: ['object', 'array'] @@ -2130,6 +2505,7 @@ exports.In = class In extends Base # A classic *try/catch/finally* block. exports.Try = class Try extends Base constructor: (@attempt, @errorVariable, @recovery, @ensure) -> + super() children: ['attempt', 'recovery', 'ensure'] @@ -2175,6 +2551,7 @@ exports.Try = class Try extends Base # Simple node to throw an exception. exports.Throw = class Throw extends Base constructor: (@expression) -> + super() children: ['expression'] @@ -2194,6 +2571,7 @@ exports.Throw = class Throw extends Base # table. exports.Existence = class Existence extends Base constructor: (@expression) -> + super() children: ['expression'] @@ -2219,6 +2597,7 @@ exports.Existence = class Existence extends Base # Parentheses are a good way to force any statement to become an expression. exports.Parens = class Parens extends Base constructor: (@body) -> + super() children: ['body'] @@ -2239,6 +2618,7 @@ exports.Parens = class Parens extends Base exports.StringWithInterpolations = class StringWithInterpolations extends Base constructor: (@body) -> + super() children: ['body'] @@ -2294,6 +2674,8 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base # you can map and filter in a single pass. exports.For = class For extends While constructor: (body, source) -> + super() + {@source, @guard, @step, @name, @index} = source @body = Block.wrap [body] @own = !!source.own @@ -2420,6 +2802,7 @@ exports.For = class For extends While # A JavaScript *switch* statement. Converts into a returnable expression on-demand. exports.Switch = class Switch extends Base constructor: (@subject, @cases, @otherwise) -> + super() children: ['subject', 'cases', 'otherwise'] @@ -2465,6 +2848,8 @@ exports.Switch = class Switch extends Base # because ternaries are already proper expressions, and don't need conversion. exports.If = class If extends Base constructor: (condition, @body, options = {}) -> + super() + @condition = if options.type is 'unless' then condition.invert() else condition @elseBody = null @isChain = false diff --git a/test/assignment.coffee b/test/assignment.coffee index a5add30852..aff5371a1d 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -449,7 +449,7 @@ test "#1591, #1101: splatted expressions in destructuring assignment must be ass test "#1643: splatted accesses in destructuring assignments should not be declared as variables", -> nonce = {} - accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a'] + accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'f().a', 'o?.a', 'o?.a.b', 'f?().a'] for access in accesses for i,j in [1,2,3] #position can matter code = diff --git a/test/async.coffee b/test/async.coffee index 7f39d2aa4c..ebc028674e 100644 --- a/test/async.coffee +++ b/test/async.coffee @@ -191,3 +191,20 @@ test "implicit call with `await`", -> a = addOne await 3 eq a, 4 + +test "async methods in classes", -> + class Base + @static: -> + await 1 + method: -> + await 2 + + eq await Base.static(), 1 + eq await new Base().method(), 2 + + class Child extends Base + @static: -> super + method: -> super + + eq await Child.static(), 1 + eq await new Child().method(), 2 diff --git a/test/classes.coffee b/test/classes.coffee index 1a92f5186d..beb3a45420 100644 --- a/test/classes.coffee +++ b/test/classes.coffee @@ -4,6 +4,7 @@ # * Class Definition # * Class Instantiation # * Inheritance and Super +# * ES2015+ Class Interoperability test "classes with a four-level inheritance chain", -> @@ -26,7 +27,9 @@ test "classes with a four-level inheritance chain", -> @array = [1, 2, 3] class ThirdChild extends SecondChild - constructor: -> thirdCtor.call this + constructor: -> + super() + thirdCtor.call this # Gratuitous comment for testing. func: (string) -> @@ -66,25 +69,6 @@ test "constructors with inheritance and super", -> ok (new SubClass).prop is 'top-super-sub' -test "Overriding the static property new doesn't clobber Function::new", -> - - class OneClass - @new: 'new' - function: 'function' - constructor: (name) -> @name = name - - class TwoClass extends OneClass - delete TwoClass.new - - Function.prototype.new = -> new this arguments... - - ok (TwoClass.new('three')).name is 'three' - ok (new OneClass).function is 'function' - ok OneClass.new is 'new' - - delete Function.prototype.new - - test "basic classes, again, but in the manual prototype style", -> Base = -> @@ -464,7 +448,7 @@ test "ensure that constructors invoked with splats return a new object", -> # Ensure that constructors invoked with splats cache the function. called = 0 get = -> if called++ then false else class Type - new get() args... + new (get()) args... test "`new` shouldn't add extra parens", -> @@ -480,6 +464,7 @@ test "`new` works against bare function", -> test "#1182: a subclass should be able to set its constructor to an external function", -> ctor = -> @val = 1 + return class A class B extends A constructor: ctor @@ -498,7 +483,7 @@ test "#1313: misplaced __extends", -> class A class B extends A prop: nonce - constructor: -> + constructor: -> super eq nonce, B::prop test "#1182: execution order needs to be considered as well", -> @@ -738,21 +723,21 @@ test "#2599: other typed constructors should be inherited", -> ok (new Derived) not instanceof Base ok (new Base) not instanceof Base -test "#2359: extending native objects that use other typed constructors requires defining a constructor", -> - class BrokenArray extends Array - method: -> 'no one will call me' +test "extending native objects works with and without defining a constructor", -> + class MyArray extends Array + method: -> 'yes!' - brokenArray = new BrokenArray - ok brokenArray not instanceof BrokenArray - ok typeof brokenArray.method is 'undefined' + myArray = new MyArray + ok myArray instanceof MyArray + ok 'yes!', myArray.method() - class WorkingArray extends Array + class OverrideArray extends Array constructor: -> super method: -> 'yes!' - workingArray = new WorkingArray - ok workingArray instanceof WorkingArray - eq 'yes!', workingArray.method() + overrideArray = new OverrideArray + ok overrideArray instanceof OverrideArray + eq 'yes!', overrideArray.method() test "#2782: non-alphanumeric-named bound functions", -> @@ -855,7 +840,7 @@ test "#1392 calling `super` in methods defined on namespaced classes", -> eq 1, count class C - @a: -> + @a: (->) @a extends Base @a::m = -> super eq 5, (new C.a).m() @@ -898,3 +883,811 @@ test "dynamic method names and super", -> class C extends B m: -> super eq 5, (new C).m() + +# ES2015+ class interoperability +# Based on https://github.com/balupton/es6-javascript-class-interop +# Helper functions to generate true ES classes to extend: +getBasicClass = -> + ``` + class BasicClass { + constructor (greeting) { + this.greeting = greeting || 'hi' + } + } + ``` + BasicClass + +getExtendedClass = (BaseClass) -> + ``` + class ExtendedClass extends BaseClass { + constructor (greeting, name) { + super(greeting || 'hello') + this.name = name + } + } + ``` + ExtendedClass + +test "can instantiate a basic ES class", -> + BasicClass = getBasicClass() + i = new BasicClass 'howdy!' + eq i.greeting, 'howdy!' + +test "can instantiate an extended ES class", -> + BasicClass = getBasicClass() + ExtendedClass = getExtendedClass BasicClass + i = new ExtendedClass 'yo', 'buddy' + eq i.greeting, 'yo' + eq i.name, 'buddy' + +test "can extend a basic ES class", -> + BasicClass = getBasicClass() + class ExtendedClass extends BasicClass + constructor: (@name) -> + super() + i = new ExtendedClass 'dude' + eq i.name, 'dude' + +test "can extend an extended ES class", -> + BasicClass = getBasicClass() + ExtendedClass = getExtendedClass BasicClass + + class ExtendedExtendedClass extends ExtendedClass + constructor: (@value) -> + super() + getDoubledValue: -> + @value * 2 + + i = new ExtendedExtendedClass 7 + eq i.getDoubledValue(), 14 + +test "CoffeeScript class can be extended in ES", -> + class CoffeeClass + constructor: (@favoriteDrink = 'latte', @size = 'grande') -> + getDrinkOrder: -> + "#{@size} #{@favoriteDrink}" + + ``` + class ECMAScriptClass extends CoffeeClass { + constructor (favoriteDrink) { + super(favoriteDrink); + this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons'; + } + } + ``` + + e = new ECMAScriptClass 'coffee' + eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons' + +test "extended CoffeeScript class can be extended in ES", -> + class CoffeeClass + constructor: (@favoriteDrink = 'latte') -> + + class CoffeeClassWithDrinkOrder extends CoffeeClass + constructor: (@favoriteDrink, @size = 'grande') -> + super() + getDrinkOrder: -> + "#{@size} #{@favoriteDrink}" + + ``` + class ECMAScriptClass extends CoffeeClassWithDrinkOrder { + constructor (favoriteDrink) { + super(favoriteDrink); + this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons'; + } + } + ``` + + e = new ECMAScriptClass 'coffee' + eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons' + +test "`this` access after `super` in extended classes", -> + class Base + + class Test extends Base + constructor: (param, @param) -> + eq param, nonce + + result = { super: super(), @param, @method } + eq result.super, this + eq result.param, @param + eq result.method, @method + ok result.method isnt Test::method + + method: => + + nonce = {} + new Test nonce, {} + +test "`@`-params and bound methods with multiple `super` paths (blocks)", -> + nonce = {} + + class Base + constructor: (@name) -> + + class Test extends Base + constructor: (param, @param) -> + if param + super 'param' + eq @name, 'param' + else + super 'not param' + eq @name, 'not param' + eq @param, nonce + ok @method isnt Test::method + method: => + new Test true, nonce + new Test false, nonce + + +test "`@`-params and bound methods with multiple `super` paths (expressions)", -> + nonce = {} + + class Base + constructor: (@name) -> + + class Test extends Base + constructor: (param, @param) -> + # Contrived example: force each path into an expression with inline assertions + if param + result = ( + eq (super 'param'), @; + eq @name, 'param'; + eq @param, nonce; + ok @method isnt Test::method + ) + else + result = ( + eq (super 'not param'), @; + eq @name, 'not param'; + eq @param, nonce; + ok @method isnt Test::method + ) + method: => + new Test true, nonce + new Test false, nonce + +test "constructor super in arrow functions", -> + class Test extends (class) + constructor: (@param) -> + do => super + eq @param, nonce + + new Test nonce = {} + +# Ensure that we always throw if we experience more than one super() +# call in a constructor. This ends up being a runtime error. +# Should be caught at compile time. +test "multiple super calls", -> + throwsA = """ + class A + constructor: (@drink) -> + make: -> "Making a #{@drink}" + + class MultiSuper extends A + constructor: (drink) -> + super(drink) + super(drink) + @newDrink = drink + new MultiSuper('Late').make() + """ + throws -> CoffeeScript.run throwsA, bare: yes + +# Basic test to ensure we can pass @params in a constuctor and +# inheritance works correctly +test "@ params", -> + class A + constructor: (@drink, @shots, @flavor) -> + make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)" + + a = new A('Machiato', 2, 'chocolate') + eq a.make(), "Making a chocolate Machiato with 2 shot(s)" + + class B extends A + b = new B('Machiato', 2, 'chocolate') + eq b.make(), "Making a chocolate Machiato with 2 shot(s)" + +# Ensure we can accept @params with default parameters in a constructor +test "@ params with defaults in a constructor", -> + class A + # Multiple @ params with defaults + constructor: (@drink = 'Americano', @shots = '1', @flavor = 'caramel') -> + make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)" + + a = new A() + eq a.make(), "Making a caramel Americano with 1 shot(s)" + +# Ensure we can handle default constructors with class params +test "@ params with class params", -> + class Beverage + drink: 'Americano' + shots: '1' + flavor: 'caramel' + + class A + # Class creation as a default param with `this` + constructor: (@drink = new Beverage()) -> + a = new A() + eq a.drink.drink, 'Americano' + + beverage = new Beverage + class B + # class costruction with a default external param + constructor: (@drink = beverage) -> + + b = new B() + eq b.drink.drink, 'Americano' + + class C + # Default constructor with anonymous empty class + constructor: (@meta = class) -> + c = new C() + ok c.meta instanceof Function + +test "@ params without super, including errors", -> + classA = """ + class A + constructor: (@drink) -> + make: -> "Making a #{@drink}" + a = new A('Machiato') + """ + + throwsB = """ + class B extends A + #implied super + constructor: (@drink) -> + b = new B('Machiato') + """ + throws -> CoffeeScript.compile classA + throwsB, bare: yes + +test "@ params super race condition", -> + classA = """ + class A + constructor: (@drink) -> + make: -> "Making a #{@drink}" + """ + + throwsB = """ + class B extends A + constructor: (@params) -> + + b = new B('Machiato') + """ + throws -> CoffeeScript.compile classA + throwsB, bare: yes + + # Race condition with @ and super + throwsC = """ + class C extends A + constructor: (@params) -> + super(@params) + + c = new C('Machiato') + """ + throws -> CoffeeScript.compile classA + throwsC, bare: yes + + +test "@ with super call", -> + class D + make: -> "Making a #{@drink}" + + class E extends D + constructor: (@drink) -> + super() + + e = new E('Machiato') + eq e.make(), "Making a Machiato" + +test "@ with splats and super call", -> + class A + make: -> "Making a #{@drink}" + + class B extends A + constructor: (@drink...) -> + super() + + B = new B('Machiato') + eq B.make(), "Making a Machiato" + + +test "super and external constructors", -> + # external constructor with @ param is allowed + ctorA = (@drink) -> + class A + constructor: ctorA + make: -> "Making a #{@drink}" + a = new A('Machiato') + eq a.make(), "Making a Machiato" + + # External constructor with super + throwsC = """ + class B + constructor: (@drink) -> + make: -> "Making a #{@drink}" + + ctorC = (drink) -> + super(drink) + + class C extends B + constructor: ctorC + c = new C('Machiato') + """ + throws -> CoffeeScript.compile throwsC, bare: yes + + +test "super in external prototype", -> + class A + constructor: (@drink) -> + make: -> "Making a #{@drink}" + + class B extends A + B::make = (@flavor) -> super() + " with #{@flavor}" + b = new B('Machiato') + eq b.make('caramel'), "Making a Machiato with caramel" + + # Fails, bound + # TODO: Could this throw a compile error? + class C extends A + C::make = (@flavor) => super() + " with #{@flavor}" + c = new C('Machiato') + ok c.make('caramel') isnt "Making a Machiato with caramel" + + +test "bound functions without super", -> + # Bound function with @ + # Throw on compile, since bound + # constructors are illegal + throwsA = """ + class A + constructor: (drink) => + @drink = drink + + """ + throws -> CoffeeScript.compile throwsA, bare: yes + +test "super in a bound function in a constructor", -> + throwsB = """ + class A + class B extends A + constructor: do => super + """ + throws -> CoffeeScript.compile throwsB, bare: yes + +test "super in a bound function", -> + class A + constructor: (@drink) -> + make: -> "Making a #{@drink}" + + class B extends A + make: (@flavor) => + super + " with #{@flavor}" + + b = new B('Machiato') + eq b.make('vanilla'), "Making a Machiato with vanilla" + + # super in a bound function in a bound function + class C extends A + make: (@flavor) => + func = () => + super + " with #{@flavor}" + func() + + c = new C('Machiato') + eq c.make('vanilla'), "Making a Machiato with vanilla" + + # bound function in a constructor + class D extends A + constructor: (drink) -> + super(drink) + x = => + eq @drink, "Machiato" + x() + d = new D('Machiato') + eq d.make(), "Making a Machiato" + +# duplicate +test "super in a try/catch", -> + classA = """ + class A + constructor: (param) -> + throw "" unless param + """ + + throwsB = """ + class B extends A + constructor: -> + try + super + """ + + throwsC = """ + ctor = -> + try + super + + class C extends A + constructor: ctor + """ + throws -> CoffeeScript.run classA + throwsB, bare: yes + throws -> CoffeeScript.run classA + throwsC, bare: yes + +test "mixed ES6 and CS6 classes with a four-level inheritance chain", -> + # Extended test + # ES2015+ class interoperability + + ``` + class Base { + constructor (greeting) { + this.greeting = greeting || 'hi'; + } + func (string) { + return 'zero/' + string; + } + static staticFunc (string) { + return 'static/' + string; + } + } + ``` + + class FirstChild extends Base + func: (string) -> + super('one/') + string + + + ``` + class SecondChild extends FirstChild { + func (string) { + return super.func('two/' + string); + } + } + ``` + + thirdCtor = -> + @array = [1, 2, 3] + + class ThirdChild extends SecondChild + constructor: -> + super() + thirdCtor.call this + func: (string) -> + super('three/') + string + + result = (new ThirdChild).func 'four' + ok result is 'zero/one/two/three/four' + ok Base.staticFunc('word') is 'static/word' + +# exercise extends in a nested class +test "nested classes with super", -> + class Outer + constructor: -> + @label = 'outer' + + class @Inner + constructor: -> + @label = 'inner' + + class @ExtendedInner extends @Inner + constructor: -> + tmp = super() + @label = tmp.label + ' extended' + + @extender: () => + class ExtendedSelf extends @ + constructor: -> + tmp = super() + @label = tmp.label + ' from this' + new ExtendedSelf + + eq (new Outer).label, 'outer' + eq (new Outer.Inner).label, 'inner' + eq (new Outer.ExtendedInner).label, 'inner extended' + eq (Outer.extender()).label, 'outer from this' + +test "Static methods generate 'static' keywords", -> + compile = """ + class CheckStatic + constructor: (@drink) -> + @className: -> 'CheckStatic' + + c = new CheckStatic('Machiato') + """ + result = CoffeeScript.compile compile, bare: yes + ok result.match(' static ') + +test "Static methods in nested classes", -> + class Outer + @name: -> 'Outer' + + class @Inner + @name: -> 'Inner' + + eq Outer.name(), 'Outer' + eq Outer.Inner.name(), 'Inner' + + +test "mixed constructors with inheritance and ES6 super", -> + identity = (f) -> f + + class TopClass + constructor: (arg) -> + @prop = 'top-' + arg + + ``` + class SuperClass extends TopClass { + constructor (arg) { + identity(super('super-' + arg)); + } + } + ``` + class SubClass extends SuperClass + constructor: -> + identity super 'sub' + + ok (new SubClass).prop is 'top-super-sub' + +test "ES6 static class methods can be overriden", -> + class A + @name: -> 'A' + + class B extends A + @name: -> 'B' + + eq A.name(), 'A' + eq B.name(), 'B' + +# If creating static by direct assignment rather than ES6 static keyword +test "ES6 Static methods should set `this` to undefined // ES6 ", -> + class A + @test: -> + eq this, undefined + +# Ensure that our object prototypes work with ES6 +test "ES6 prototypes can be overriden", -> + class A + className: 'classA' + + ``` + class B { + test () {return "B";}; + } + ``` + b = new B + a = new A + eq a.className, 'classA' + eq b.test(), 'B' + Object.setPrototypeOf(b, a) + eq b.className, 'classA' + # This shouldn't throw, + # as we only change inheritance not object construction + # This may be an issue with ES, rather than CS construction? + #eq b.test(), 'B' + + class D extends B + B::test = () -> 'D' + eq (new D).test(), 'D' + +# TODO: implement this error check +# test "ES6 conformance to extending non-classes", -> +# A = (@title) -> +# 'Title: ' + @ + +# class B extends A +# b = new B('caffeinated') +# eq b.title, 'caffeinated' + +# # Check inheritance chain +# A::getTitle = () -> @title +# eq b.getTitle(), 'caffeinated' + +# throwsC = """ +# C = {title: 'invalid'} +# class D extends {} +# """ +# # This should catch on compile and message should be "class can only extend classes and functions." +# throws -> CoffeeScript.run throwsC, bare: yes + +# TODO: Evaluate future compliance with "strict mode"; +# test "Class function environment should be in `strict mode`, ie as if 'use strict' was in use", -> +# class A +# # this might be a meaningless test, since these are likely to be runtime errors and different +# # for every browser. Thoughts? +# constructor: () -> +# # Ivalid: prop reassignment +# @state = {prop: [1], prop: {a: 'a'}} +# # eval reassignment +# @badEval = eval; + +# # Should throw, but doesn't +# a = new A + +# TODO: new.target needs support Separate issue +# test "ES6 support for new.target (functions and constructors)", -> +# throwsA = """ +# class A +# constructor: () -> +# a = new.target.name +# """ +# throws -> CoffeeScript.compile throwsA, bare: yes + +test "only one method named constructor allowed", -> + throwsA = """ + class A + constructor: (@first) -> + constructor: (@last) -> + """ + throws -> CoffeeScript.compile throwsA, bare: yes + +test "If the constructor of a child class does not call super,it should return an object.", -> + nonce = {} + + class A + class B extends A + constructor: -> + return nonce + + eq nonce, new B + + +test "super can only exist in extended classes", -> + throwsA = """ + class A + constructor: (@name) -> + super() + """ + throws -> CoffeeScript.compile throwsA, bare: yes + +# --- CS1 classes compatability breaks --- +test "CS6 Class extends a CS1 compiled class", -> + ``` + // Generated by CoffeeScript 1.11.1 + var BaseCS1, ExtendedCS1, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + BaseCS1 = (function() { + function BaseCS1(drink) { + this.drink = drink; + } + + BaseCS1.prototype.make = function() { + return "making a " + this.drink; + }; + + BaseCS1.className = function() { + return 'BaseCS1'; + }; + + return BaseCS1; + + })(); + + ExtendedCS1 = (function(superClass) { + extend(ExtendedCS1, superClass); + + function ExtendedCS1(flavor) { + this.flavor = flavor; + ExtendedCS1.__super__.constructor.call(this, 'cafe ole'); + } + + ExtendedCS1.prototype.make = function() { + return "making a " + this.drink + " with " + this.flavor; + }; + + ExtendedCS1.className = function() { + return 'ExtendedCS1'; + }; + + return ExtendedCS1; + + })(BaseCS1); + + ``` + class B extends BaseCS1 + eq B.className(), 'BaseCS1' + b = new B('machiato') + eq b.make(), "making a machiato" + + +test "CS6 Class extends an extended CS1 compiled class", -> + ``` + // Generated by CoffeeScript 1.11.1 + var BaseCS1, ExtendedCS1, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + BaseCS1 = (function() { + function BaseCS1(drink) { + this.drink = drink; + } + + BaseCS1.prototype.make = function() { + return "making a " + this.drink; + }; + + BaseCS1.className = function() { + return 'BaseCS1'; + }; + + return BaseCS1; + + })(); + + ExtendedCS1 = (function(superClass) { + extend(ExtendedCS1, superClass); + + function ExtendedCS1(flavor) { + this.flavor = flavor; + ExtendedCS1.__super__.constructor.call(this, 'cafe ole'); + } + + ExtendedCS1.prototype.make = function() { + return "making a " + this.drink + " with " + this.flavor; + }; + + ExtendedCS1.className = function() { + return 'ExtendedCS1'; + }; + + return ExtendedCS1; + + })(BaseCS1); + + ``` + class B extends ExtendedCS1 + eq B.className(), 'ExtendedCS1' + b = new B('vanilla') + eq b.make(), "making a cafe ole with vanilla" + +test "CS6 Class extends a CS1 compiled class with super()", -> + ``` + // Generated by CoffeeScript 1.11.1 + var BaseCS1, ExtendedCS1, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + BaseCS1 = (function() { + function BaseCS1(drink) { + this.drink = drink; + } + + BaseCS1.prototype.make = function() { + return "making a " + this.drink; + }; + + BaseCS1.className = function() { + return 'BaseCS1'; + }; + + return BaseCS1; + + })(); + + ExtendedCS1 = (function(superClass) { + extend(ExtendedCS1, superClass); + + function ExtendedCS1(flavor) { + this.flavor = flavor; + ExtendedCS1.__super__.constructor.call(this, 'cafe ole'); + } + + ExtendedCS1.prototype.make = function() { + return "making a " + this.drink + " with " + this.flavor; + }; + + ExtendedCS1.className = function() { + return 'ExtendedCS1'; + }; + + return ExtendedCS1; + + })(BaseCS1); + + ``` + class B extends ExtendedCS1 + constructor: (@shots) -> + super('caramel') + make: () -> + super + " and #{@shots} shots of espresso" + + eq B.className(), 'ExtendedCS1' + b = new B('three') + eq b.make(), "making a cafe ole with caramel and three shots of espresso" diff --git a/test/comments.coffee b/test/comments.coffee index 563cd47524..e6489b2467 100644 --- a/test/comments.coffee +++ b/test/comments.coffee @@ -378,11 +378,15 @@ test "#3132: Place block-comments nicely", -> var DummyClass; DummyClass = (function() { + class DummyClass { - /** - * @constructor - */ - function DummyClass() {} + /** + * @constructor + */ + + constructor() {} + + }; /** diff --git a/test/error_messages.coffee b/test/error_messages.coffee index 8034e4efeb..c98c4263a1 100644 --- a/test/error_messages.coffee +++ b/test/error_messages.coffee @@ -1205,3 +1205,45 @@ test "tagged template literals must be called by an identifier", -> 1"""#{b}""" ^ ''' + +test "constructor functions can't be async", -> + assertErrorFormat 'class then constructor: -> await x', ''' + [stdin]:1:12: error: Class constructor may not be async + class then constructor: -> await x + ^^^^^^^^^^^ + ''' + +test "constructor functions can't be generators", -> + assertErrorFormat 'class then constructor: -> yield', ''' + [stdin]:1:12: error: Class constructor may not be a generator + class then constructor: -> yield + ^^^^^^^^^^^ + ''' + +test "non-derived constructors can't call super", -> + assertErrorFormat 'class then constructor: -> super', ''' + [stdin]:1:28: error: 'super' is only allowed in derived class constructors + class then constructor: -> super + ^^^^^ + ''' + +test "derived constructors can't reference `this` before calling super", -> + assertErrorFormat 'class extends A then constructor: -> @', ''' + [stdin]:1:38: error: Can't reference 'this' before calling super in derived class constructors + class extends A then constructor: -> @ + ^ + ''' + +test "derived constructors can't use @params without calling super", -> + assertErrorFormat 'class extends A then constructor: (@a) ->', ''' + [stdin]:1:36: error: Can't use @params in derived class constructors without calling super + class extends A then constructor: (@a) -> + ^^ + ''' + +test "'super' is not allowed in constructor parameter defaults", -> + assertErrorFormat 'class extends A then constructor: (a = super) ->', ''' + [stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults + class extends A then constructor: (a = super) -> + ^^^^^ + ''' diff --git a/test/generators.coffee b/test/generators.coffee index c00d685003..3d02c4db8f 100644 --- a/test/generators.coffee +++ b/test/generators.coffee @@ -325,3 +325,20 @@ test "from as a destructured array variable name in a for loop declaration", -> for [from, to] from a b.push from arrayEq b, [1, 3] + +test "generator methods in classes", -> + class Base + @static: -> + yield 1 + method: -> + yield 2 + + arrayEq [1], Array.from Base.static() + arrayEq [2], Array.from new Base().method() + + class Child extends Base + @static: -> super + method: -> super + + arrayEq [1], Array.from Child.static() + arrayEq [2], Array.from new Child().method() diff --git a/test/modules.coffee b/test/modules.coffee index a7753bbad3..81994ac232 100644 --- a/test/modules.coffee +++ b/test/modules.coffee @@ -457,7 +457,7 @@ test "export class", -> baz: -> console.log 'hello, world!'""" output = toJS input - ok /^export (class foo|var foo = \(function)/.test toJS input + ok /^export (var foo = class foo|var foo = \(function)/.test toJS input test "export class that extends", -> input = """ diff --git a/test/operators.coffee b/test/operators.coffee index 9c683aaefb..0b94e30ee9 100644 --- a/test/operators.coffee +++ b/test/operators.coffee @@ -436,3 +436,27 @@ test "#3598: Unary + and - coerce the operand once when it is an identifier", -> ok ~a in [0, -2] assertOneCoercion (a) -> ok a / 2 in [0, 0.5] + +test "'new' target", -> + nonce = {} + ctor = -> nonce + + eq (new ctor), nonce + eq (new ctor()), nonce + + ok new class + + ctor = class + ok (new ctor) instanceof ctor + ok (new ctor()) instanceof ctor + + # Force an executable class body + ctor = class then a = 1 + ok (new ctor) instanceof ctor + + get = -> ctor + ok (new get()) not instanceof ctor + ok (new (get())()) instanceof ctor + + # classes must be called with `new`. In this case `new` applies to `get` only + throws -> new get()() diff --git a/test/repl.coffee b/test/repl.coffee index d9926ef495..4bf2c60d0d 100644 --- a/test/repl.coffee +++ b/test/repl.coffee @@ -8,6 +8,7 @@ Stream = require 'stream' class MockInputStream extends Stream constructor: -> + super() @readable = true resume: -> @@ -17,6 +18,7 @@ class MockInputStream extends Stream class MockOutputStream extends Stream constructor: -> + super() @writable = true @written = []