livescript
Version:
LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate. While LiveScript adds many features to assist in functional style programming,
1,739 lines • 55.5 kB
JavaScript
// Generated by LiveScript 1.6.0
var string, TABS, unlines, enlines, enslash, reslash, camelize, deheregex, character, KEYWORDS_SHARED, KEYWORDS_UNUSED, JS_KEYWORDS, LS_KEYWORDS, ID, SYMBOL, SPACE, MULTIDENT, SIMPLESTR, JSTOKEN, BSTOKEN, NUMBER, NUMBER_OMIT, REGEX, HEREGEX_OMIT, LASTDENT, INLINEDENT, NONASCII, OPENERS, CLOSERS, INVERSES, i, o, c, CHAIN, ARG, BLOCK_USERS, slice$ = [].slice, arrayFrom$ = Array.from || function(x){return slice$.call(x);};
exports.lex = function(code, options){
return clone$(exports).tokenize(code || '', options || {});
};
exports.rewrite = function(it){
var ref$;
it || (it = this.tokens);
firstPass(it);
addImplicitIndentation(it);
rewriteBlockless(it);
addImplicitParentheses(it);
addImplicitBraces(it);
expandLiterals(it);
if (((ref$ = it[0]) != null ? ref$[0] : void 8) === 'NEWLINE') {
it.shift();
}
return it;
};
exports.tokenize = function(code, o){
var i, prevIndex, c, charsConsumed, that;
this.inter || (code = code.replace(/[\r\u2028\u2029\uFEFF]/g, ''));
code = '\n' + code;
this.tokens = [this.last = ['NEWLINE', '\n', 0, 0]];
this.line = ~-o.line;
this.column = o.column || 0;
this.dents = [];
this.closes = [];
this.parens = [];
this.flags = [];
i = 0;
prevIndex = i;
this.charsCounted = 0;
this.isAtPrefix = true;
while (c = code.charAt(i)) {
charsConsumed = i - prevIndex;
prevIndex = i;
if (this.charsCounted > charsConsumed) {
throw new Error('Location information out-of-sync in lexer');
}
this.column += charsConsumed - this.charsCounted;
this.charsCounted = 0;
switch (c) {
case ' ':
i += this.doSpace(code, i);
break;
case '\n':
i += this.doLine(code, i);
break;
case '\\':
i += this.doBackslash(code, i);
break;
case '\'':
case '"':
i += this.doString(code, i, c);
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
i += this.doNumber(code, i);
break;
case '/':
switch (code.charAt(i + 1)) {
case '*':
i += this.doComment(code, i);
break;
case '/':
i += this.doHeregex(code, i);
break;
default:
i += this.doRegex(code, i) || this.doLiteral(code, i);
}
break;
case '`':
if ('`' === code.charAt(i + 1)) {
i += this.doJS(code, i);
} else {
i += this.doLiteral(code, i);
}
break;
default:
i += this.doID(code, i) || this.doLiteral(code, i) || this.doSpace(code, i);
}
}
this.dedent(this.dent);
if (that = this.closes.pop()) {
this.carp("missing `" + that + "`");
}
if (this.inter) {
this.rest == null && this.carp('unterminated interpolation');
} else {
this.last.spaced = true;
this.newline();
}
o.raw || this.rewrite();
return this.tokens;
};
exports.dent = 0;
exports.identifiers = {};
exports.reset = function(){
this.dent = 0;
this.identifiers = {};
};
exports.hasOwn = Object.prototype.hasOwnProperty;
exports.checkConsistency = function(camel, id){
if (this.hasOwn.call(this.identifiers, camel) && this.identifiers[camel] !== id) {
throw new ReferenceError("Inconsistent use of " + camel + " as " + id + " on line " + (-~this.line));
} else {
return this.identifiers[camel] = id;
}
};
exports.doID = function(code, index){
var regexMatch, input, id, e, last, ref$, tag, ref1$, that;
input = (regexMatch = (ID.lastIndex = index, ID).exec(code))[0];
if (!input) {
return 0;
}
id = camelize(regexMatch[1]);
if (/-/.test(regexMatch[1])) {
this.checkConsistency(id, regexMatch[1]);
}
if (NONASCII.test(id)) {
try {
Function("var " + id);
} catch (e$) {
e = e$;
this.carp("invalid identifier '" + id + "'");
}
}
last = this.last;
if (regexMatch[2] || last[0] === 'DOT' || this.adi()) {
this.token('ID', in$(id, JS_KEYWORDS) ? (ref$ = Object(id), ref$.reserved = true, ref$) : id);
if (regexMatch[2]) {
this.token(':', ':');
}
return input.length;
}
switch (id) {
case 'true':
case 'false':
case 'on':
case 'off':
case 'yes':
case 'no':
case 'null':
case 'void':
case 'arguments':
case 'debugger':
tag = 'LITERAL';
break;
case 'new':
case 'do':
case 'typeof':
case 'delete':
tag = 'UNARY';
break;
case 'yield':
case 'await':
tag = 'YIELD';
break;
case 'return':
case 'throw':
tag = 'HURL';
break;
case 'break':
case 'continue':
tag = 'JUMP';
break;
case 'this':
case 'eval':
case 'super':
return this.token('LITERAL', id, true).length;
case 'for':
id = [];
this.fset('for', true);
this.fset('to', false);
this.fset('by', true);
break;
case 'then':
this.fset('for', false);
this.fset('to', false);
break;
case 'catch':
case 'function':
id = '';
break;
case 'in':
case 'of':
if (this.fget('for')) {
this.fset('for', false);
if (id === 'in') {
this.fset('by', true);
id = '';
if (last[0] === 'ID' && ((ref$ = (ref1$ = this.tokens)[ref1$.length - 2][0]) === ',' || ref$ === ']' || ref$ === '}')) {
id = this.tokens.pop()[1];
if ((ref$ = this.tokens)[ref$.length - 1][0] === ',') {
this.tokens.pop();
}
}
}
break;
}
// fallthrough
case 'instanceof':
if (last[1] === '!') {
id = this.tokens.pop()[1] + id;
}
tag = (ref$ = this.tokens)[ref$.length - 1][0] === '(' ? 'BIOPR' : 'RELATION';
break;
case 'not':
if (last.alias && last[1] === '===') {
return last[1] = '!==', 3;
}
tag = 'UNARY';
id = '!';
break;
case 'and':
case 'or':
case 'xor':
case 'is':
case 'isnt':
this.unline();
tag = id === 'is' || id === 'isnt' ? 'COMPARE' : 'LOGIC';
if (last[0] === '(') {
tag = 'BIOP';
}
this.token(tag, (function(){
switch (id) {
case 'is':
return '===';
case 'isnt':
return '!==';
case 'or':
return '||';
case 'and':
return '&&';
case 'xor':
return 'xor';
}
}()));
this.last.alias = true;
return id.length;
case 'unless':
tag = 'IF';
break;
case 'until':
tag = 'WHILE';
break;
case 'import':
if (last[0] === '(') {
id = '<<<';
tag = 'BIOP';
} else {
if (able(this.tokens)) {
id = '<<<';
} else {
tag = 'DECL';
}
}
break;
case 'export':
case 'const':
case 'var':
tag = 'DECL';
break;
case 'with':
tag = (function(){
switch (false) {
case !able(this.tokens):
return 'CLONEPORT';
case last[0] !== '(':
return 'BIOP';
default:
return 'WITH';
}
}.call(this));
break;
case 'when':
tag = 'CASE';
// fallthrough
case 'case':
if (this.doCase()) {
return input.length;
}
break;
case 'match':
tag = 'SWITCH';
break;
case 'loop':
this.token('WHILE', id);
this.token('LITERAL', 'true');
return input.length;
case 'let':
case 'own':
if (last[0] === 'FOR' && !in$(id, last[1])) {
last[1].push(id);
return 3;
}
// fallthrough
default:
if (in$(id, KEYWORDS_SHARED)) {
break;
}
if (in$(id, KEYWORDS_UNUSED)) {
this.carp("reserved word '" + id + "'");
}
if (!last[1] && ((ref$ = last[0]) === 'FUNCTION' || ref$ === 'GENERATOR' || ref$ === 'LABEL')) {
last[1] = id;
last.spaced = false;
return input.length;
}
tag = 'ID';
switch (id) {
case 'otherwise':
if ((ref$ = last[0]) === 'CASE' || ref$ === '|') {
last[0] = 'DEFAULT';
return id.length;
}
break;
case 'all':
if (that = last[1] === '<<<' && '<' || last[1] === 'import' && 'All') {
last[1] += that;
return 3;
}
break;
case 'from':
if (last[1] === 'yield') {
last[1] += 'from';
return 4;
}
this.forange() && (tag = 'FROM');
break;
case 'to':
case 'til':
this.forange() && this.tokens.push(['FROM', '', this.line, this.column], ['STRNUM', '0', this.line, this.column]);
if (this.fget('from')) {
this.fset('from', false);
this.fset('by', true);
tag = 'TO';
} else if (!last.callable && last[0] === 'STRNUM' && (ref$ = this.tokens)[ref$.length - 2][0] === '[') {
last[0] = 'RANGE';
last.op = id;
return id.length;
} else if (in$(']', this.closes)) {
this.token('TO', id);
return id.length;
}
break;
case 'by':
if (last[0] === 'STRNUM' && (ref$ = this.tokens)[ref$.length - 2][0] === 'RANGE' && (ref$ = this.tokens)[ref$.length - 3][0] === '[') {
tag = 'RANGE_BY';
} else if (in$(']', this.closes)) {
tag = 'BY';
} else if (this.fget('by') && last[0] !== 'FOR') {
tag = 'BY';
this.fset('by', false);
}
break;
case 'ever':
if (last[0] === 'FOR') {
this.fset('for', false);
last[0] = 'WHILE';
tag = 'LITERAL';
id = 'true';
}
}
}
tag || (tag = regexMatch[1].toUpperCase());
if ((tag === 'COMPARE' || tag === 'LOGIC' || tag === 'RELATION') && last[0] === '(') {
tag = tag === 'RELATION' ? 'BIOPR' : 'BIOP';
}
if (tag === 'THEN' || tag === 'IF' || tag === 'WHILE') {
this.fset('for', false);
this.fset('by', false);
}
if (tag === 'RELATION' || tag === 'THEN' || tag === 'ELSE' || tag === 'CASE' || tag === 'DEFAULT' || tag === 'CATCH' || tag === 'FINALLY' || tag === 'IN' || tag === 'OF' || tag === 'FROM' || tag === 'TO' || tag === 'BY' || tag === 'EXTENDS' || tag === 'IMPLEMENTS' || tag === 'WHERE') {
this.unline();
}
this.token(tag, id);
return input.length;
};
exports.doNumber = function(code, lastIndex){
var input, regexMatch, last, radix, num, rnum, bound, ref$;
NUMBER.lastIndex = lastIndex;
if (!(input = (regexMatch = NUMBER.exec(code))[0])) {
return 0;
}
last = this.last;
if (regexMatch[5] && (last[0] === 'DOT' || this.adi())) {
this.token('STRNUM', regexMatch[4].replace(NUMBER_OMIT, ''));
return regexMatch[4].length;
}
if (radix = regexMatch[1]) {
num = parseInt(rnum = regexMatch[2].replace(NUMBER_OMIT, ''), radix);
bound = false;
if (radix > 36 || radix < 2) {
if (/[0-9]/.exec(rnum)) {
this.carp("invalid number base " + radix + " (with number " + rnum + "),base must be from 2 to 36");
} else {
bound = true;
}
}
if (isNaN(num) || num === parseInt(rnum.slice(0, -1), radix)) {
this.strnum(regexMatch[1]);
this.token('DOT', '.~');
this.token('ID', regexMatch[2]);
return input.length;
}
num += '';
} else {
num = (regexMatch[3] || input).replace(NUMBER_OMIT, '');
if (regexMatch[3] && num.charAt() === '0' && ((ref$ = num.charAt(1)) !== '' && ref$ !== '.')) {
this.carp("deprecated octal literal " + regexMatch[4]);
}
}
if (!last.spaced && last[0] === '+-') {
last[0] = 'STRNUM';
last[1] += num;
return input.length;
}
this.strnum(num);
return input.length;
};
exports.doString = function(code, index, q){
var parts, str;
if (q === code.charAt(index + 1)) {
return q === code.charAt(index + 2)
? this.doHeredoc(code, index, q)
: (this.strnum(q + q), 2);
}
if (q === '"') {
parts = this.interpolate(code, index, q);
this.addInterpolated(parts, unlines);
return parts.size;
}
str = (SIMPLESTR.lastIndex = index, SIMPLESTR).exec(code)[0] || this.carp('unterminated string');
this.strnum(unlines(this.string(q, str.slice(1, -1))));
return this.countLines(str).length;
};
exports.doHeredoc = function(code, index, q){
var end, raw, doc, parts, tabs, i$, len$, i, t;
if (q === '\'') {
~(end = code.indexOf(q + q + q, index + 3)) || this.carp('unterminated heredoc');
raw = code.slice(index + 3, end);
doc = raw.replace(LASTDENT, '');
this.strnum(enlines(this.string(q, lchomp(detab(doc, heretabs(doc))))));
return this.countLines(raw).length + 6;
}
parts = this.interpolate(code, index, q + q + q);
tabs = heretabs(code.slice(index + 3, index + parts.size - 3).replace(LASTDENT, ''));
for (i$ = 0, len$ = parts.length; i$ < len$; ++i$) {
i = i$;
t = parts[i$];
if (t[0] === 'S') {
if (i + 1 === parts.length) {
t[1] = t[1].replace(LASTDENT, '');
}
t[1] = detab(t[1], tabs);
if (i === 0) {
t[1] = lchomp(t[1]);
}
}
}
this.addInterpolated(parts, enlines);
return parts.size;
};
exports.doComment = function(code, index){
var comment, end, ref$;
comment = ~(end = code.indexOf('*/', index + 2))
? code.slice(index, end + 2)
: code.slice(index) + '*/';
if ((ref$ = this.last[0]) === 'NEWLINE' || ref$ === 'INDENT' || ref$ === 'THEN') {
this.token('COMMENT', detab(comment, this.dent));
this.token('NEWLINE', '\n');
}
return this.countLines(comment).length;
};
exports.doJS = function(code, lastIndex){
var js, ref$;
JSTOKEN.lastIndex = lastIndex;
js = JSTOKEN.exec(code)[0] || this.carp('unterminated JS literal');
this.token('LITERAL', (ref$ = Object(detab(js.slice(2, -2), this.dent)), ref$.js = true, ref$), true);
return this.countLines(js).length;
};
exports.doRegex = function(code, index){
var divisible, ref$, input, body, flag;
if (divisible = able(this.tokens) || this.last[0] === 'CREMENT') {
if (!this.last.spaced || ((ref$ = code.charAt(index + 1)) === ' ' || ref$ === '=')) {
return 0;
}
}
ref$ = (REGEX.lastIndex = index, REGEX).exec(code), input = ref$[0], body = ref$[1], flag = ref$[2];
if (input) {
this.regex(body, flag);
} else if (!divisible && this.last[0] !== '(') {
this.carp('unterminated regex');
}
return input.length;
};
exports.doHeregex = function(code, index){
var tokens, last, parts, rest, flag, i$, i, t, dynaflag, len$, val, one;
tokens = this.tokens, last = this.last;
parts = this.interpolate(code, index, '//');
rest = code.slice(index + parts.size);
flag = this.validate(/^(?:[gimy]{1,4}|[?$]?)/.exec(rest)[0]);
if (parts[1]) {
if (flag === '$') {
this.adi();
this.token('(', '"');
} else {
tokens.push(['ID', 'RegExp', last[2], last[3]], ['CALL(', '', last[2], last[3]]);
if (flag === '?') {
for (i$ = parts.length - 1; i$ >= 0; --i$) {
i = i$;
t = parts[i$];
if (t[0] === 'TOKENS') {
dynaflag = parts.splice(i, 1)[0][1];
break;
}
}
}
}
for (i$ = 0, len$ = parts.length; i$ < len$; ++i$) {
i = i$;
t = parts[i$];
if (t[0] === 'TOKENS') {
tokens.push.apply(tokens, t[1]);
} else {
val = deheregex(t[1]);
if (one && !val) {
continue;
}
one = tokens.push((t[0] = 'STRNUM', t[1] = this.string('\'', enslash(val)), t));
}
tokens.push(['+-', '+', tokens[tokens.length - 1][2], tokens[tokens.length - 1][3]]);
}
--tokens.length;
if (dynaflag || flag >= 'g') {
this.token(',', ',');
if (dynaflag) {
tokens.push.apply(tokens, dynaflag);
} else {
this.token('STRNUM', "'" + flag + "'");
}
}
this.token(flag === '$' ? ')' : ')CALL', '');
} else {
this.regex(reslash(deheregex(parts[0][1])), flag);
}
return parts.size + flag.length;
};
exports.doBackslash = function(code, lastIndex){
var ref$, input, word;
BSTOKEN.lastIndex = lastIndex;
ref$ = BSTOKEN.exec(code), input = ref$[0], word = ref$[1];
if (word) {
this.strnum(this.string('\'', word));
} else {
this.countLines(input);
}
return input.length;
};
exports.doLine = function(code, index){
var ref$, input, tabs, length, last, that, delta, tag, val;
ref$ = (MULTIDENT.lastIndex = index, MULTIDENT).exec(code), input = ref$[0], tabs = ref$[1];
length = this.countLines(input).length;
last = this.last;
last.eol = true;
last.spaced = true;
if (index + length >= code.length) {
return length;
}
if (that = tabs && (this.emender || (this.emender = RegExp('[^' + tabs.charAt() + ']'))).exec(tabs)) {
this.carp("contaminated indent " + escape(that));
}
if (0 > (delta = tabs.length - this.dent)) {
this.dedent(-delta);
this.newline();
} else {
tag = last[0], val = last[1];
if (tag === 'ASSIGN' && ((ref$ = val + '') !== '=' && ref$ !== ':=' && ref$ !== '+=') || tag === 'CREMENT' && val === '++' && (ref$ = this.tokens)[ref$.length - 2].spaced || (tag === '+-' || tag === 'PIPE' || tag === 'BACKPIPE' || tag === 'COMPOSE' || tag === 'DOT' || tag === 'LOGIC' || tag === 'MATH' || tag === 'COMPARE' || tag === 'RELATION' || tag === 'SHIFT' || tag === 'IN' || tag === 'OF' || tag === 'TO' || tag === 'BY' || tag === 'FROM' || tag === 'EXTENDS' || tag === 'IMPLEMENTS')) {
return length;
}
if (delta) {
this.indent(delta);
} else {
this.newline();
}
}
this.fset('for', false);
this.fset('by', false);
return length;
};
exports.doSpace = function(code, lastIndex){
var input;
SPACE.lastIndex = lastIndex;
if (input = SPACE.exec(code)[0]) {
this.last.spaced = true;
}
return input.length;
};
exports.doCase = function(){
var ref$, ref1$;
this.fset('for', false);
if (((ref$ = this.last[0]) === 'ASSIGN' || ref$ === '->' || ref$ === ':') || (this.last[0] === 'INDENT' && ((ref$ = (ref1$ = this.tokens)[ref1$.length - 2][0]) === 'ASSIGN' || ref$ === '->' || ref$ === ':'))) {
this.token('SWITCH', 'switch');
return this.token('CASE', 'case');
}
};
exports.doLiteral = function(code, index){
var sym, tag, val, ref$, that;
if (!(sym = (SYMBOL.lastIndex = index, SYMBOL).exec(code)[0])) {
return 0;
}
switch (tag = val = sym) {
case '|':
tag = 'CASE';
if (this.doCase()) {
return sym.length;
}
break;
case '|>':
tag = 'PIPE';
break;
case '`':
tag = 'BACKTICK';
break;
case '<<':
case '>>':
tag = 'COMPOSE';
break;
case '<|':
tag = 'BACKPIPE';
break;
case '+':
case '-':
tag = '+-';
break;
case '&&':
case '||':
tag = 'LOGIC';
break;
case '.&.':
case '.|.':
case '.^.':
tag = 'BITWISE';
break;
case '^^':
tag = 'CLONE';
break;
case '**':
case '^':
tag = 'POWER';
break;
case '?':
if (this.last[0] === '(') {
this.token('PARAM(', '(');
this.token(')PARAM', ')');
this.token('->', '->');
this.token('ID', 'it');
} else {
if (this.last.spaced) {
tag = 'LOGIC';
}
}
break;
case '/':
case '%':
case '%%':
tag = 'MATH';
break;
case '++':
case '--':
tag = 'CREMENT';
break;
case '<<<':
case '<<<<':
tag = 'IMPORT';
break;
case ';':
tag = 'NEWLINE';
this.fset('by', false);
break;
case '..':
this.token('LITERAL', '..', true);
return 2;
case '.':
if (this.last[1] === '?') {
this.last[0] = '?';
}
tag = 'DOT';
break;
case ',':
switch (this.last[0]) {
case ',':
case '[':
case '(':
case 'CALL(':
this.token('LITERAL', 'void');
break;
case 'FOR':
case 'OWN':
this.token('ID', '');
}
break;
case '!=':
case '~=':
if (!(able(this.tokens) || ((ref$ = this.last[0]) === '(' || ref$ === 'CREMENT'))) {
this.tokens.push(val === '!='
? ['UNARY', '!', this.line, this.column]
: ['UNARY', '~', this.line, this.column], ['ASSIGN', '=', this.line, this.column]);
return 2;
}
// fallthrough
case '!~=':
case '==':
val = (function(){
switch (val) {
case '~=':
return '==';
case '!~=':
return '!=';
case '==':
return '===';
case '!=':
return '!==';
}
}());
tag = 'COMPARE';
break;
case '===':
case '!==':
val += '=';
// fallthrough
case '<':
case '>':
case '<=':
case '>=':
case '<==':
case '>==':
case '>>=':
case '<<=':
tag = 'COMPARE';
break;
case '.<<.':
case '.>>.':
case '.>>>.':
case '<?':
case '>?':
tag = 'SHIFT';
break;
case '(':
if (!(((ref$ = this.last[0]) === 'FUNCTION' || ref$ === 'GENERATOR' || ref$ === 'LET') || this.able(true) || this.last[1] === '.@')) {
this.token('(', '(');
this.closes.push(')');
this.parens.push(this.last);
return 1;
}
tag = 'CALL(';
this.closes.push(')CALL');
break;
case '[':
case '{':
this.adi();
this.closes.push(']}'.charAt(val === '{'));
break;
case '}':
if (this.inter && val !== (ref$ = this.closes)[ref$.length - 1]) {
this.rest = code.slice(index + 1);
return 9e9;
}
// fallthrough
case ']':
case ')':
if (tag === ')' && ((ref$ = this.last[0]) === '+-' || ref$ === 'COMPARE' || ref$ === 'LOGIC' || ref$ === 'MATH' || ref$ === 'POWER' || ref$ === 'SHIFT' || ref$ === 'BITWISE' || ref$ === 'CONCAT' || ref$ === 'COMPOSE' || ref$ === 'RELATION' || ref$ === 'PIPE' || ref$ === 'BACKPIPE' || ref$ === 'IMPORT' || ref$ === 'CLONEPORT' || ref$ === 'ASSIGN')) {
(ref$ = this.tokens)[ref$.length - 1][0] = (function(){
switch (this.last[0]) {
case 'RELATION':
return 'BIOPR';
case 'PIPE':
this.parameters(false, -1);
return 'BIOPP';
default:
return 'BIOP';
}
}.call(this));
}
if (')' === (tag = val = this.pair(val))) {
this.lpar = this.parens.pop();
}
break;
case '=':
case ':':
if (val === ':') {
switch (this.last[0]) {
case 'ID':
case 'STRNUM':
case ')':
break;
case '...':
this.last[0] = 'STRNUM';
break;
default:
tag = 'LABEL';
val = '';
}
this.token(tag, val);
return sym.length;
}
// fallthrough
case ':=':
case '+=':
case '-=':
case '*=':
case '/=':
case '%=':
case '%%=':
case '<?=':
case '>?=':
case '**=':
case '^=':
case '.&.=':
case '.|.=':
case '.^.=':
case '.<<.=':
case '.>>.=':
case '.>>>.=':
case '++=':
case '|>=':
if (this.last[1] === '.' || this.last[0] === '?' && this.adi()) {
this.last[1] += val;
return val.length;
}
if (this.last[0] === 'LOGIC') {
(val = Object(val)).logic = this.tokens.pop()[1];
} else if ((val === '+=' || val === '-=') && !able(this.tokens) && ((ref$ = this.last[0]) !== '+-' && ref$ !== 'UNARY' && ref$ !== 'LABEL')) {
this.token('UNARY', val.charAt());
val = '=';
}
tag = 'ASSIGN';
break;
case '::=':
this.token('DOT', '.');
this.token('ID', 'prototype');
this.token('IMPORT', '<<');
return sym.length;
case '*':
if (this.last[0] === 'FUNCTION') {
this.last[0] = 'GENERATOR';
return sym.length;
}
if (that = ((ref$ = this.last[0]) === 'NEWLINE' || ref$ === 'INDENT' || ref$ === 'THEN' || ref$ === '=>') && (INLINEDENT.lastIndex = index + 1, INLINEDENT).exec(code)[0].length) {
this.tokens.push(['LITERAL', 'void', this.line, this.column], ['ASSIGN', '=', this.line, this.column]);
this.indent(index + that - 1 - this.dent - code.lastIndexOf('\n', index - 1));
return that;
}
tag = able(this.tokens) || this.last[0] === 'CREMENT' && able(this.tokens, this.tokens.length - 1) || this.last[0] === '(' ? 'MATH' : 'STRNUM';
break;
case '@':
this.adi();
if (this.last[0] === 'DOT' && this.last[1] === '.' && (ref$ = this.tokens)[ref$.length - 2][0] === 'ID' && (ref$ = this.tokens)[ref$.length - 2][1] === 'constructor') {
this.tokens.pop();
this.tokens.pop();
this.token('LITERAL', 'this', true);
this.adi();
this.token('ID', 'constructor', true);
} else {
this.token('LITERAL', 'this', true);
}
return 1;
case '@@':
this.adi();
this.token('ID', 'constructor', true);
return 2;
case '&':
this.token('LITERAL', 'arguments');
return 1;
case '!':
switch (false) {
default:
if (!this.last.spaced) {
if (this.last[1] === 'require') {
this.last[0] = 'REQUIRE';
this.last[1] = 'require!';
} else if (able(this.tokens, null, true)) {
this.token('CALL(', '!');
this.token(')CALL', ')');
} else if (this.last[1] === 'typeof') {
this.last[1] = 'classof';
} else if (this.last[1] === 'delete') {
this.last[1] = 'jsdelete';
} else {
break;
}
return 1;
}
}
tag = 'UNARY';
break;
case '|':
tag = 'BITWISE';
break;
case '~':
if (this.dotcat(val)) {
return 1;
}
tag = 'UNARY';
break;
case '::':
this.adi();
val = 'prototype';
tag = 'ID';
break;
case '=>':
this.unline();
this.fset('for', false);
tag = 'THEN';
break;
default:
if (/^!?(?:--?|~~?)>>?\*?$/.test(val)) {
this.parameters(tag = '->');
} else if (/^\*?<(?:--?|~~?)!?$/.test(val)) {
this.parameters(tag = '<-');
} else {
switch (val.charAt(0)) {
case '(':
this.token('CALL(', '(');
tag = ')CALL';
val = ')';
break;
case '<':
if (val.length < 4) {
this.carp('unterminated words');
}
this.token('WORDS', val.slice(2, -2), this.adi());
return this.countLines(val).length;
}
}
}
if ((tag === '+-' || tag === 'COMPARE' || tag === 'LOGIC' || tag === 'MATH' || tag === 'POWER' || tag === 'SHIFT' || tag === 'BITWISE' || tag === 'CONCAT' || tag === 'RELATION' || tag === 'PIPE' || tag === 'BACKPIPE' || tag === 'COMPOSE' || tag === 'IMPORT') && this.last[0] === '(') {
tag = tag === 'BACKPIPE' ? 'BIOPBP' : 'BIOP';
}
if (tag === ',' || tag === 'CASE' || tag === 'PIPE' || tag === 'BACKPIPE' || tag === 'COMPOSE' || tag === 'DOT' || tag === 'LOGIC' || tag === 'COMPARE' || tag === 'MATH' || tag === 'POWER' || tag === 'IMPORT' || tag === 'SHIFT' || tag === 'BITWISE') {
this.unline();
}
this.token(tag, val);
return sym.length;
};
exports.token = function(tag, value, callable){
this.tokens.push(this.last = [tag, value, this.line, this.column]);
if (callable) {
this.last.callable = true;
}
return value;
};
exports.indent = function(delta){
this.dent += delta;
this.dents.push(this.token('INDENT', delta));
this.closes.push('DEDENT');
};
exports.dedent = function(debt){
var dent;
this.dent -= debt;
while (debt > 0 && (dent = this.dents.pop())) {
if (debt < dent && !this.inter) {
this.carp("unmatched dedent (" + debt + " for " + dent + ")");
}
this.pair('DEDENT');
debt -= typeof dent === 'number' ? this.token('DEDENT', dent) : dent;
}
};
exports.newline = function(){
var ref$;
if (!(this.last[0] === 'NEWLINE' && this.last[1] === '\n')) {
this.tokens.push(this.last = (ref$ = ['NEWLINE', '\n', this.line, this.column], ref$.spaced = true, ref$));
}
};
exports.unline = function(){
var ref$;
if (!this.tokens[1]) {
return;
}
switch (this.last[0]) {
case 'INDENT':
(ref$ = this.dents)[ref$.length - 1] += '';
// fallthrough
case 'NEWLINE':
this.tokens.length--;
}
};
exports.parameters = function(arrow, offset){
var i$, ref$, i, t, ref1$;
if (this.last[0] === ')' && ')' === this.last[1]) {
this.lpar[0] = 'PARAM(';
this.last[0] = ')PARAM';
return;
}
if (arrow === '->') {
this.token('PARAM(', '');
} else {
for (i$ = (ref$ = this.tokens).length - 1; i$ >= 0; --i$) {
i = i$;
t = ref$[i$];
if ((ref1$ = t[0]) === 'NEWLINE' || ref1$ === 'INDENT' || ref1$ === 'THEN' || ref1$ === '=>' || ref1$ === '(') {
break;
}
}
this.tokens.splice(i + 1, 0, ['PARAM(', '', t[2], t[3]]);
}
if (offset) {
this.tokens.splice(this.tokens.length + offset, 0, [')PARAM', '', t[2], t[3]]);
} else {
this.token(')PARAM', '');
}
};
exports.interpolate = function(str, idx, end){
var parts, end0, pos, i, ref$, oldLine, oldColumn, ch, c1, id, stringified, length, tag, e, delta, nested, clone, ref1$;
parts = [];
end0 = end.charAt(0);
pos = 0;
i = -1;
str = str.slice(idx + end.length);
ref$ = [this.line, this.column], oldLine = ref$[0], oldColumn = ref$[1];
this.countLines(end);
while (ch = str.charAt(++i)) {
switch (ch) {
case end0:
if (end !== str.slice(i, i + end.length)) {
continue;
}
parts.push(['S', this.countLines(str.slice(0, i)), oldLine, oldColumn]);
this.countLines(end);
return parts.size = pos + i + end.length * 2, parts;
case '#':
c1 = str.charAt(i + 1);
id = c1 === '@' && c1 || (ID.lastIndex = i + 1, ID).exec(str)[1];
if (!(id || c1 === '{')) {
continue;
}
break;
case '\\':
++i;
// fallthrough
default:
continue;
}
if (i || nested && !stringified) {
stringified = parts.push(['S', this.countLines(str.slice(0, i)), oldLine, oldColumn]);
ref$ = [this.line, this.column], oldLine = ref$[0], oldColumn = ref$[1];
}
if (id) {
length = id.length;
if (id === '@') {
id = 'this';
}
if (id === 'this') {
tag = 'LITERAL';
} else {
id = camelize(id);
try {
Function("'use strict'; var " + id);
} catch (e$) {
e = e$;
this.carp("invalid variable interpolation '" + id + "'");
}
tag = 'ID';
}
str = str.slice(delta = i + 1 + length);
parts.push(['TOKENS', nested = [[tag, id, this.line, this.column]]]);
} else {
clone = (ref$ = clone$(exports), ref$.inter = true, ref$.emender = this.emender, ref$);
nested = clone.tokenize(str.slice(i + 2), {
line: this.line,
column: this.column + 2,
raw: true
});
delta = str.length - clone.rest.length;
this.countLines(str.slice(i, delta));
str = clone.rest;
while (((ref$ = nested[0]) != null ? ref$[0] : void 8) === 'NEWLINE') {
nested.shift();
}
if (nested.length) {
nested.unshift(['(', '(', oldLine, oldColumn]);
nested.push([')', ')', this.line, this.column - 1]);
parts.push(['TOKENS', nested]);
}
ref1$ = [this.line, this.column], oldLine = ref1$[0], oldColumn = ref1$[1];
}
pos += delta;
i = -1;
}
this.carp("missing `" + end + "`");
};
exports.addInterpolated = function(parts, nlines){
var tokens, last, ref$, left, right, joint, callable, i$, len$, i, t;
if (!parts[1]) {
return this.strnum(nlines(this.string('"', parts[0][1])));
}
tokens = this.tokens, last = this.last;
ref$ = !last.spaced && last[1] === '%'
? (--tokens.length, this.last = last = tokens[tokens.length - 1], ['[', ']', [',', ',']])
: ['(', ')', ['+-', '+']], left = ref$[0], right = ref$[1], joint = ref$[2];
callable = this.adi();
tokens.push([left, '"', last[2], last[3]]);
for (i$ = 0, len$ = parts.length; i$ < len$; ++i$) {
i = i$;
t = parts[i$];
if (t[0] === 'TOKENS') {
tokens.push.apply(tokens, t[1]);
} else {
if (i > 1 && !t[1]) {
continue;
}
tokens.push(['STRNUM', nlines(this.string('"', t[1])), t[2], t[3]]);
}
tokens.push(joint.concat(tokens[tokens.length - 1][2], tokens[tokens.length - 1][3]));
}
--tokens.length;
this.token(right, '', callable);
};
exports.strnum = function(it){
this.token('STRNUM', it, this.adi() || this.last[0] === 'DOT');
};
exports.regex = function(body, flag){
var e;
try {
RegExp(body);
} catch (e$) {
e = e$;
this.carp(e.message);
}
if (flag === '$') {
return this.strnum(this.string('\'', enslash(body)));
}
return this.token('LITERAL', "/" + (body || '(?:)') + "/" + this.validate(flag));
};
exports.adi = function(){
if (this.last.spaced) {
return;
}
if (!able(this.tokens)) {
return;
}
return this.token('DOT', '.');
};
exports.dotcat = function(it){
if (this.last[1] === '.' || this.adi()) {
return this.last[1] += it;
}
};
exports.pair = function(it){
var wanted, ref$;
if (!(it === (wanted = (ref$ = this.closes)[ref$.length - 1]) || ')CALL' === wanted && it === ')')) {
if ('DEDENT' !== wanted) {
this.carp("unmatched `" + it + "`");
}
this.dedent((ref$ = this.dents)[ref$.length - 1]);
return this.pair(it);
}
this.unline();
this.fclear();
return this.closes.pop();
};
exports.able = function(call){
return !this.last.spaced && able(this.tokens, null, call);
};
exports.countLines = function(it){
var pos;
if (!this.isAtPrefix) {
this.column += it.length;
}
while (pos = 1 + it.indexOf('\n', pos)) {
if (!this.isAtPrefix) {
this.column = 0;
}
this.column += it.length - pos;
++this.line;
this.isAtPrefix = false;
}
this.charsCounted += it.length;
return it;
};
exports.forange = function(){
var ref$, ref1$, ref2$;
if (((ref$ = (ref1$ = this.tokens)[ref1$.length - 2 - ((ref2$ = this.last[0]) === 'NEWLINE' || ref2$ === 'INDENT')]) != null ? ref$[0] : void 8) === 'FOR' || this.last[0] === 'FOR') {
this.fset('for', false);
this.fset('from', true);
return true;
} else {
return false;
}
};
exports.validate = function(flag){
var that;
if (that = flag && /(.).*\1/.exec(flag)) {
this.carp("duplicate regex flag `" + that[1] + "`");
}
return flag;
};
exports.fget = function(key){
var ref$;
return (ref$ = this.flags[this.closes.length]) != null ? ref$[key] : void 8;
};
exports.fset = function(key, val){
var ref$, key$;
((ref$ = this.flags)[key$ = this.closes.length] || (ref$[key$] = {}))[key] = val;
};
exports.fclear = function(){
this.flags.splice(this.closes.length);
};
exports.carp = function(it){
carp(it, this.line);
};
exports.string = function(q, body){
return string(q, body, this.line);
};
function carp(msg, lno){
throw SyntaxError(msg + " on line " + (-~lno));
}
function able(tokens, i, call){
var token, tag;
i == null && (i = tokens.length);
tag = (token = tokens[i - 1])[0];
return (tag === 'ID' || tag === ']' || tag === '?') || (call
? token.callable || (tag === ')' || tag === ')CALL' || tag === 'BIOPBP') && token[1]
: tag === '}' || tag === ')' || tag === ')CALL' || tag === 'STRNUM' || tag === 'LITERAL' || tag === 'WORDS');
}
string = (function(re){
return function(q, body, lno){
body = body.replace(re, function(it, oct, xu, rest){
if (it === q || it === '\\') {
return '\\' + it;
}
if (oct) {
return '\\x' + (0x100 + parseInt(oct, 8)).toString(16).slice(1);
}
if (xu) {
carp('malformed character escape sequence', lno);
}
if (!rest || q === rest) {
return it;
} else {
return rest;
}
});
return q + body + q;
};
}.call(this, /['"]|\\(?:([0-3]?[0-7]{2}|[1-7]|0(?=[89]))|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|([xu])|[\\0bfnrtv]|[^\n\S]|([\w\W]))?/g));
function heretabs(doc){
var dent, that, ref$;
dent = 0 / 0;
while (that = TABS.exec(doc)) {
dent <= (ref$ = that[0].length - 1) || (dent = ref$);
}
return dent;
}
TABS = /\n(?!$)[^\n\S]*/mg;
function detab(str, len){
if (len) {
return str.replace(detab[len] || (detab[len] = RegExp('\\n[^\\n\\S]{1,' + len + '}', 'g')), '\n');
} else {
return str;
}
}
unlines = function(it){
return it.replace(/\n[^\n\S]*/g, '');
};
enlines = function(it){
return it.replace(/\n/g, '\\n');
};
enslash = function(it){
return it.replace(/\\/g, '\\\\');
};
reslash = function(it){
return it.replace(/(\\.)|\//g, function(){
return arguments[1] || '\\/';
});
};
camelize = function(it){
return it.replace(/-[a-z]/ig, function(it){
return it.charAt(1).toUpperCase();
});
};
deheregex = function(it){
return it.replace(/\s+(?:#.*)?|(\\[\s\S])/g, function(arg$, bs){
bs || (bs = '');
if ('\n' === bs.charAt(1)) {
return '\\n';
} else {
return bs;
}
});
};
function lchomp(it){
return it.slice(1 + it.lastIndexOf('\n', 0));
}
function decode(val, lno){
if (!isNaN(val)) {
return [+val];
}
val = val.length > 8
? 'ng'
: Function('return ' + val)();
val.length === 1 || carp('bad string in range', lno);
return [val.charCodeAt(), true];
}
function uxxxx(it){
return '"\\u' + ('000' + it.toString(16)).slice(-4) + '"';
}
character = typeof JSON == 'undefined' || JSON === null
? uxxxx
: function(it){
switch (it) {
case 0x2028:
case 0x2029:
return uxxxx(it);
default:
return JSON.stringify(String.fromCharCode(it));
}
};
function firstPass(tokens){
var prev, i, token, tag, val, line, column, next, parens, i$, j, ts, ref$;
prev = ['NEWLINE', '\n', 0];
i = 0;
while (token = tokens[++i]) {
tag = token[0], val = token[1], line = token[2], column = token[3];
switch (tag) {
case 'ASSIGN':
if (in$(prev[1], LS_KEYWORDS) && tokens[i - 2][0] !== 'DOT') {
carp("cannot assign to reserved word '" + prev[1] + "'", line);
}
break;
case 'DOT':
switch (false) {
case !(prev[0] === ']' && tokens[i - 2][0] === '[' && tokens[i - 3][0] === 'DOT'):
tokens.splice(i - 2, 3);
tokens[i - 3][1] = '[]';
i -= 3;
break;
case !(prev[0] === '}' && tokens[i - 2][0] === '{' && tokens[i - 3][0] === 'DOT'):
tokens.splice(i - 2, 3);
tokens[i - 3][1] = '{}';
i -= 3;
break;
case !(val === '.' && token.spaced && prev.spaced):
tokens[i] = ['COMPOSE', '<<', line, column];
break;
default:
next = tokens[i + 1];
if (prev[0] === '(' && next[0] === ')') {
tokens[i][0] = 'BIOP';
} else if (prev[0] === '(') {
tokens.splice(i, 0, ['PARAM(', '(', line, column], [')PARAM', ')', line, column], ['->', '~>', line, column], ['ID', 'it', line, column]);
} else if (next[0] === ')') {
tokens.splice(i + 1, 0, ['[', '[', line, column], ['ID', 'it', line, column], [']', ']', line, column]);
parens = 1;
LOOP: for (i$ = i + 1; i$ >= 0; --i$) {
j = i$;
switch (tokens[j][0]) {
case ')':
++parens;
break;
case '(':
if (--parens === 0) {
tokens.splice(j + 1, 0, ['PARAM(', '(', line, column], ['ID', 'it', line, column], [')PARAM', ')', line, column], ['->', '~>', line, column]);
break LOOP;
}
}
}
}
}
break;
case 'CREMENT':
if (!(val === '++' && (next = tokens[i + 1]))) {
break;
}
ts = ['ID', 'LITERAL', 'STRNUM'];
if (prev.spaced && token.spaced || !(prev.spaced || token.spaced) && in$(prev[0], ts) && in$(next[0], ts)) {
tokens[i][0] = 'CONCAT';
}
if (prev[0] === '(' && next[0] === ')' || prev[0] === '(' && token.spaced || next[0] === ')' && prev.spaced) {
tokens[i][0] = 'BIOP';
}
break;
case 'ID':
if (val !== 'async') {
break;
}
next = tokens[i + 1];
if ((ref$ = next[0]) === 'FUNCTION' || ref$ === 'GENERATOR') {
token[0] = 'ASYNC';
}
}
prev = token;
continue;
}
}
function rewriteBlockless(tokens){
var i, token, tag;
i = -1;
while (token = tokens[++i]) {
tag = token[0];
if (tag === 'IF' || tag === 'CLASS' || tag === 'CATCH') {
detectEnd(tokens, i + 1, ok, go);
}
}
function ok(it){
var ref$;
return (ref$ = it[0]) === 'NEWLINE' || ref$ === 'INDENT';
}
function go(it, i){
var lno, cno;
if (tag === 'IF') {
if (it[0] !== 'INDENT' || !it[1] && !it.then || in$(tokens[i - 1][0], BLOCK_USERS)) {
token[0] = 'POST_IF';
}
} else if (it[0] !== 'INDENT') {
tokens.splice(i, 0, ['INDENT', 0, lno = tokens[i - 1][2], cno = tokens[i - 1][3]], ['DEDENT', 0, lno, cno]);
}
}
}
function addImplicitIndentation(tokens){
var i, token, tag, next, indent, dedent, ref$, ref1$, idx;
i = 0;
while (token = tokens[++i]) {
tag = token[0];
if (tag !== '->' && tag !== 'THEN' && tag !== 'ELSE' && tag !== 'DEFAULT' && tag !== 'TRY' && tag !== 'FINALLY' && tag !== 'DECL') {
continue;
}
switch (next = tokens[i + 1][0]) {
case 'IF':
if (tag === 'ELSE') {
continue;
}
break;
case 'INDENT':
case 'THEN':
if (tag === 'THEN') {
tokens.splice(i--, 1);
}
continue;
}
indent = ['INDENT', 0, token[2], token[3]];
dedent = ['DEDENT', 0];
if (tag === 'THEN') {
(tokens[i] = indent).then = true;
} else {
tokens.splice(++i, 0, indent);
}
switch (false) {
case tag !== 'DECL':
break;
case next !== 'DOT' && next !== '?' && next !== ',' && next !== 'PIPE' && next !== 'BACKPIPE':
--i;
// fallthrough
case !((next === 'ID' || next === 'STRNUM' || next === 'LITERAL') && ',' === ((ref$ = tokens[i + 2]) != null ? ref$[0] : void 8)):
go(0, i += 2);
++i;
continue;
case !((next === '(' || next === '[' || next === '{') && ',' === ((ref1$ = tokens[idx = 1 + indexOfPair(tokens, i + 1)]) != null ? ref1$[0] : void 8)):
go(0, idx);
++i;
continue;
}
detectEnd(tokens, i + 1, ok, go);
}
function ok(token, i){
var t0, t;
t0 = token[0];
t = tag;
if (tag === t0 || tag === 'THEN' && t0 === 'SWITCH') {
tag = '';
}
switch (t0) {
case 'NEWLINE':
return token[1] !== ';';
case 'DOT':
case '?':
case ',':
case 'PIPE':
case 'BACKPIPE':
return tokens[i - 1].eol;
case 'ELSE':
return t === 'THEN';
case 'CATCH':
return t === 'TRY';
case 'FINALLY':
return t === 'TRY' || t === 'CATCH' || t === 'THEN';
case 'CASE':
case 'DEFAULT':
return t === 'CASE' || t === 'THEN';
}
}
function go(arg$, i){
var prev;
prev = tokens[i - 1];
tokens.splice(prev[0] === ',' ? i - 1 : i, 0, (dedent[2] = prev[2], dedent[3] = prev[3], dedent));
}
}
function addImplicitParentheses(tokens){
var i, brackets, token, endi, ref$, tpair, tag, prev, ref1$, skipBlock, seenSwitch;
i = 0;
brackets = [];
while (token = tokens[++i]) {
if (token[1] === 'do' && tokens[i + 1][0] === 'INDENT') {
endi = indexOfPair(tokens, i + 1);
if (tokens[endi + 1][0] === 'NEWLINE' && ((ref$ = tokens[endi + 2]) != null ? ref$[0] : void 8) === 'WHILE') {
token[0] = 'DO';
tokens[endi + 2].done = true;
tokens.splice(endi + 1, 1);
} else {
(token = tokens[1 + i])[0] = '(';
(tpair = tokens[endi])[0] = ')';
token.doblock = true;
tokens.splice(i, 1);
}
}
tag = token[0];
prev = tokens[i - 1];
tag === '[' && brackets.push(prev[0] === 'DOT');
if (prev[0] === ']') {
if (brackets.pop()) {
prev.index = true;
} else {
continue;
}
}
if (!(((ref1$ = prev[0]) === 'FUNCTION' || ref1$ === 'GENERATOR' || ref1$ === 'LET' || ref1$ === 'WHERE') || prev.spaced && able(tokens, i, true))) {
continue;
}
if (token.doblock) {
token[0] = 'CALL(';
tpair[0] = ')CALL';
continue;
}
if (!exp(token)) {
continue;
}
if (tag === 'CREMENT') {
if (token.spaced || !in$((ref1$ = tokens[i + 1]) != null ? ref1$[0] : void 8, CHAIN)) {
continue;
}
}
skipBlock = seenSwitch = false;
tokens.splice(i++, 0, ['CALL(', '', token[2], token[3]]);
detectEnd(tokens, i, ok, go);
}
function exp(token){
var tag;
tag = token[0];
return in$(tag, ARG) || !token.spaced && (tag === '+-' || tag === 'CLONE');
}
function ok(token, i){
var tag, ref$, pre;
tag = token[0];
if (tag === 'POST_IF' || tag === 'PIPE' || tag === 'BACKPIPE') {
return true;
}
if (!skipBlock) {
if (token.alias && ((ref$ = token[1]) === '&&' || ref$ === '||' || ref$ === 'xor') || (tag === 'TO' || tag === 'BY' || tag === 'IMPLEMENTS')) {
return true;
}
}
pre = tokens[i - 1];
switch (tag) {
case 'NEWLINE':
return pre[0] !== ',';
case 'DOT':
case '?':
return !skipBlock && (pre.spaced || pre[0] === 'DEDENT');
case 'SWITCH':
seenSwitch = true;
// fallthrough
case 'IF':
case 'CLASS':
case 'FUNCTION':
case 'GENERATOR':
case 'LET':
case 'WITH':
case 'CATCH':
skipBlock = true;
break;
case 'CASE':
if (seenSwitch) {
skipBlock = true;
} else {
return true;
}
break;
case 'INDENT':
if (skipBlock) {
return skipBlock = false;
}
return !in$(pre[0], BLOCK_USERS);
case 'WHILE':
if (token.done) {
return false;
}
// fallthrough
case 'FOR':
skipBlock = true;
return able(tokens, i) || pre[0] === 'CREMENT' || pre[0] === '...' && pre.spaced;
}
return false;
}
function go(token, i){
tokens.splice(i, 0, [')CALL', '', tokens[i - 1][2], tokens[i - 1][3]]);
}
}
function addImplicitBraces(tokens){
var stack, i, token, tag, start, paren, index, pre, ref$, inline, ref1$;
stack = [];
i = 0;
while (token = tokens[++i]) {
if (':' !== (tag = token[0])) {
switch (false) {
case !in$(tag, CLOSERS):
start = stack.pop();
break;
case !in$(tag, OPENERS):
if (tag === 'INDENT' && tokens[i - 1][0] === '{') {
tag = '{';
}
stack.push([tag, i]);
}
continue;
}
paren = tokens[i - 1][0] === ')';
index = paren
? start[1]
: i - 1;
pre = tokens[index - 1];
if (!(((ref$ = pre[0]) === ':' || ref$ === 'ASSIGN' || ref$ === 'IMPORT') || ((ref$ = stack[stack.length - 1]) != null ? ref$[0] : void 8) !== '{')) {
continue;
}
stack.push(['{']);
inline = !pre.doblock && ((ref1$ = pre[0]) !== 'NEWLINE' && ref1$ !== 'INDENT');
while (((ref1$ = tokens[index - 2]) != null ? ref1$[0] : void 8) === 'COMMENT') {
index -= 2;
}
tokens.splice(index, 0, ['{', '{', tokens[index][2], tokens[index][3]]);
detectEnd(tokens, ++i + 1, ok, go);
}
function ok(token, i){
var tag, t1, ref$, ref1$;
switch (tag = token[0]) {
case ',':
break;
case 'NEWLINE':
if (inline) {
return true;
}
break;
case 'DEDENT':
return true;
case 'POST_IF':
case 'FOR':
case 'WHILE':
return inline;
default:
return false;
}
t1 = (ref$ = tokens[i + 1]) != null ? ref$[0] : void 8;
return t1 !== (tag === ',' ? 'NEWLINE' : 'COMMENT') && ':' !== ((ref1$ = tokens[t1 === '('
? 1 + indexOfPair(tokens, i + 1)
: i + 2]) != null ? ref1$[0] : void 8);
}
function go(token, i){
tokens.splice(i, 0, ['}', '', token[2], token[3]]);
}
}
function expandLiterals(tokens){
var i, fromNum, token, sig, ref$, ref1$, lno, cno, ref2$, ref3$, ref4$, char, toNum, tochar, byNum, byp, ref5$, ts, enc, add, i$, n, ref6$, ref7$, len$, word, that;
i = 0;
while (token = tokens[++i]) {
switch (token[0]) {
case 'STRNUM':
if (~'-+'.indexOf(sig = token[1].charAt(0))) {
token[1] = token[1].slice(1);
tokens.splice(i++, 0, ['+-', sig, token[2], token[3]]);
}
if (token.callable) {
continue;
}
break;
case 'TO':
case 'TIL':
if (!(tokens[i - 1][0] === '[' && ((tokens[i + 2][0] === ']' && (((ref$ = tokens[i + 1][1].charAt(0)) === '\'' || ref$ === '"') || +tokens[i + 1][1] >= 0)) || (tokens[i + 2][0] === 'BY' && ((ref$ = tokens[i + 3]) != null ? ref$[0] : void 8) === 'STRNUM' && ((ref1$ = tokens[i + 4]) != null ? ref1$[0] : void 8) === ']')))) {
continue;
}
if (tokens[i + 2][0] === 'BY') {
tokens[i + 2][0] = 'RANGE_BY';
}
token.op = token[1];
fromNum = 0;
// fallthrough
case 'RANGE':
lno = token[2];
cno = token[3];
if (fromNum != null || (tokens[i - 1][0] === '[' && tokens[i + 1][0] === 'STRNUM' && ((tokens[i + 2][0] === ']' && (((ref2$ = tokens[i + 1][1].charAt(0)) === '\'' || ref2$ === '"') || +tokens[i + 1][1] >= 0)) || (tokens[i + 2][0] === 'RANGE_BY' && ((ref2$ = tokens[i + 3]) != null ? ref2$[0] : void 8) === 'STRNUM' && ((ref3$ = tokens[i + 4]) != null ? ref3$[0] : void 8) === ']')))) {
if (fromNum == null) {
ref4$ = decode(token[1], lno), fromNum = ref4$[0], char = ref4$[1];
}
ref4$ = decode(tokens[i + 1][1], lno), toNum = ref4$[0], tochar = ref4$[1];
if (toNum == null || char ^ tochar) {
carp('bad "to" in range', lno);
}
byNum = 1;
if (byp = ((ref4$ = tokens[i + 2]) != null ? ref4$[0] : void 8) === 'RANGE_BY') {
if (!(byNum = +((ref5$ = tokens[i + 3]) != null ? ref5$[1] : void 8))) {
carp('bad "by" in range', tokens[i + 2][2]);
}
} else if (fromNum > toNum) {
byNum = -1;
}
ts = [];
enc = char ? character : String;
add = fn$;
if (token.op === 'to') {
for (i$ = fromNum; byNum < 0 ? i$ >= toNum : i$ <= toNum; i$ += byNum) {
n = i$;
add();
}
} else {
for (i$ = fromNum; byNum < 0 ? i$ > toNum : i$ < toNum; i$ += byNum) {
n = i$;
add();
}
}
ts.pop() || carp('empty range', lno);
tokens.splice.apply(tokens, [i, 2 + 2 * byp].c