fixed over-escaping in here documents and addressed Stan's comments
This commit is contained in:
parent
cdd033ffb0
commit
42a91219cb
95
lib/lexer.js
95
lib/lexer.js
|
@ -103,8 +103,8 @@
|
||||||
if (!(string = this.balancedString(this.chunk, [['"', '"'], ['#{', '}']]))) {
|
if (!(string = this.balancedString(this.chunk, [['"', '"'], ['#{', '}']]))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (~string.indexOf('#{')) {
|
if (0 < string.indexOf('#{', 1)) {
|
||||||
this.interpolateString(string);
|
this.interpolateString(string.slice(1, -1));
|
||||||
} else {
|
} else {
|
||||||
this.token('STRING', this.escapeLines(string));
|
this.token('STRING', this.escapeLines(string));
|
||||||
}
|
}
|
||||||
|
@ -127,12 +127,12 @@
|
||||||
quote: quote,
|
quote: quote,
|
||||||
indent: null
|
indent: null
|
||||||
});
|
});
|
||||||
if (quote === '"' && ~doc.indexOf('#{')) {
|
if (quote === '"' && (0 <= doc.indexOf('#{'))) {
|
||||||
this.interpolateString(quote + doc + quote, {
|
this.interpolateString(doc, {
|
||||||
heredoc: true
|
heredoc: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.token('STRING', quote + this.escapeLines(doc, true) + quote);
|
this.token('STRING', this.makeString(doc, quote, true));
|
||||||
}
|
}
|
||||||
this.line += count(heredoc, '\n');
|
this.line += count(heredoc, '\n');
|
||||||
this.i += heredoc.length;
|
this.i += heredoc.length;
|
||||||
|
@ -186,7 +186,7 @@
|
||||||
var _i, _len, _ref2, _ref3, _this, body, flags, heregex, re, tag, tokens, value;
|
var _i, _len, _ref2, _ref3, _this, body, flags, heregex, re, tag, tokens, value;
|
||||||
_ref2 = match, heregex = _ref2[0], body = _ref2[1], flags = _ref2[2];
|
_ref2 = match, heregex = _ref2[0], body = _ref2[1], flags = _ref2[2];
|
||||||
this.i += heregex.length;
|
this.i += heregex.length;
|
||||||
if (!(~body.indexOf('#{'))) {
|
if (0 > body.indexOf('#{')) {
|
||||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
||||||
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
|
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
|
||||||
return true;
|
return true;
|
||||||
|
@ -194,7 +194,7 @@
|
||||||
this.token('IDENTIFIER', 'RegExp');
|
this.token('IDENTIFIER', 'RegExp');
|
||||||
this.tokens.push(['CALL_START', '(']);
|
this.tokens.push(['CALL_START', '(']);
|
||||||
tokens = [];
|
tokens = [];
|
||||||
_ref2 = this.interpolateString('"' + body + '"', {
|
_ref2 = this.interpolateString(body, {
|
||||||
regex: true
|
regex: true
|
||||||
});
|
});
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||||
|
@ -202,10 +202,11 @@
|
||||||
if (tag === 'TOKENS') {
|
if (tag === 'TOKENS') {
|
||||||
tokens.push.apply(tokens, value);
|
tokens.push.apply(tokens, value);
|
||||||
} else {
|
} else {
|
||||||
if (!(value = value.slice(1, -1).replace(HEREGEX_OMIT, ''))) {
|
if (!(value = value.replace(HEREGEX_OMIT, ''))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tokens.push(['STRING', '"' + value.replace(/[\\\"]/g, '\\$&') + '"']);
|
value = value.replace(/\\/g, '\\\\');
|
||||||
|
tokens.push(['STRING', this.makeString(value, '"', true)]);
|
||||||
}
|
}
|
||||||
tokens.push(['+', '+']);
|
tokens.push(['+', '+']);
|
||||||
}
|
}
|
||||||
|
@ -385,13 +386,13 @@
|
||||||
return accessor ? 'accessor' : false;
|
return accessor ? 'accessor' : false;
|
||||||
};
|
};
|
||||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||||
var _ref2, attempt, herecomment, indent, match, quote;
|
var _ref2, attempt, herecomment, indent, match;
|
||||||
_ref2 = options, indent = _ref2.indent, herecomment = _ref2.herecomment;
|
_ref2 = options, indent = _ref2.indent, herecomment = _ref2.herecomment;
|
||||||
if (herecomment && !include(doc, '\n')) {
|
if (herecomment && 0 > doc.indexOf('\n')) {
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
if (!(herecomment)) {
|
if (!(herecomment)) {
|
||||||
while ((match = HEREDOC_INDENT.exec(doc))) {
|
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||||
attempt = match[1];
|
attempt = match[1];
|
||||||
if (indent === null || (0 < (_ref2 = attempt.length)) && (_ref2 < indent.length)) {
|
if (indent === null || (0 < (_ref2 = attempt.length)) && (_ref2 < indent.length)) {
|
||||||
indent = attempt;
|
indent = attempt;
|
||||||
|
@ -401,17 +402,8 @@
|
||||||
if (indent) {
|
if (indent) {
|
||||||
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
|
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
|
||||||
}
|
}
|
||||||
if (herecomment) {
|
if (!(herecomment)) {
|
||||||
return doc;
|
doc = doc.replace(/^\n/, '');
|
||||||
}
|
|
||||||
quote = options.quote;
|
|
||||||
doc = doc.replace(/^\n/, '');
|
|
||||||
doc = doc.replace(/\\([\s\S])/g, function(m, c) {
|
|
||||||
return ('\n' === c || quote === c) ? c : m;
|
|
||||||
});
|
|
||||||
doc = doc.replace(RegExp("" + quote, "g"), '\\$&');
|
|
||||||
if (quote === "'") {
|
|
||||||
doc = this.escapeLines(doc, true);
|
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
|
@ -487,15 +479,11 @@
|
||||||
return !i ? false : str.slice(0, i);
|
return !i ? false : str.slice(0, i);
|
||||||
};
|
};
|
||||||
Lexer.prototype.interpolateString = function(str, options) {
|
Lexer.prototype.interpolateString = function(str, options) {
|
||||||
var _i, _len, _ref2, _this, char, expr, heredoc, i, inner, interpolated, lexer, nested, pi, regex, tag, tok, tokens, value;
|
var _len, _ref2, _this, char, expr, heredoc, i, inner, interpolated, nested, pi, regex, tag, tokens, value;
|
||||||
if (str.length < 5) {
|
|
||||||
return this.token('STRING', this.escapeLines(str, heredoc));
|
|
||||||
}
|
|
||||||
_ref2 = options || (options = {}), heredoc = _ref2.heredoc, regex = _ref2.regex;
|
_ref2 = options || (options = {}), heredoc = _ref2.heredoc, regex = _ref2.regex;
|
||||||
lexer = new Lexer;
|
|
||||||
tokens = [];
|
tokens = [];
|
||||||
pi = 1;
|
pi = 0;
|
||||||
i = 0;
|
i = -1;
|
||||||
while (char = str.charAt(i += 1)) {
|
while (char = str.charAt(i += 1)) {
|
||||||
if (char === '\\') {
|
if (char === '\\') {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
@ -505,45 +493,39 @@
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pi < i) {
|
if (pi < i) {
|
||||||
tokens.push(['STRING', '"' + str.slice(pi, i) + '"']);
|
tokens.push(['TO_BE_STRING', str.slice(pi, i)]);
|
||||||
}
|
}
|
||||||
inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, '');
|
inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, '');
|
||||||
if (inner.length) {
|
if (inner.length) {
|
||||||
if (heredoc) {
|
nested = new Lexer().tokenize(inner, {
|
||||||
inner = inner.replace(/\\\"/g, '"');
|
line: this.line,
|
||||||
}
|
rewrite: false
|
||||||
nested = lexer.tokenize("(" + inner + "\n)", {
|
|
||||||
line: this.line
|
|
||||||
});
|
});
|
||||||
for (_i = 0, _len = nested.length; _i < _len; _i++) {
|
|
||||||
tok = nested[_i];
|
|
||||||
if (tok[0] === 'CALL_END') {
|
|
||||||
(tok[0] = ')');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nested.pop();
|
nested.pop();
|
||||||
if (nested.length < 5) {
|
if (nested.length > 1) {
|
||||||
nested.pop();
|
nested.unshift(['(', '(']);
|
||||||
nested.shift();
|
nested.push([')', ')']);
|
||||||
}
|
}
|
||||||
tokens.push(['TOKENS', nested]);
|
tokens.push(['TOKENS', nested]);
|
||||||
}
|
}
|
||||||
i += expr.length;
|
i += expr.length;
|
||||||
pi = i + 1;
|
pi = i + 1;
|
||||||
}
|
}
|
||||||
if ((i > pi) && (pi < str.length - 1)) {
|
if ((i > pi) && (pi < str.length)) {
|
||||||
tokens.push(['STRING', '"' + str.slice(pi)]);
|
tokens.push(['TO_BE_STRING', str.slice(pi)]);
|
||||||
}
|
}
|
||||||
if (regex) {
|
if (regex) {
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
interpolated = tokens.length > 1;
|
if (!(tokens.length)) {
|
||||||
if ((((_ref2 = tokens[0]) != null) ? _ref2[0] !== 'STRING' : undefined)) {
|
return this.token('STRING', '""');
|
||||||
tokens.unshift(['STRING', '""']);
|
|
||||||
}
|
}
|
||||||
if (interpolated) {
|
if (interpolated = tokens.length > 1) {
|
||||||
this.token('(', '(');
|
this.token('(', '(');
|
||||||
}
|
}
|
||||||
|
if (tokens[0][0] !== 'TO_BE_STRING') {
|
||||||
|
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||||
|
}
|
||||||
for (i = 0, _len = tokens.length; i < _len; i++) {
|
for (i = 0, _len = tokens.length; i < _len; i++) {
|
||||||
_ref2 = tokens[i], tag = _ref2[0], value = _ref2[1];
|
_ref2 = tokens[i], tag = _ref2[0], value = _ref2[1];
|
||||||
if (i) {
|
if (i) {
|
||||||
|
@ -552,7 +534,7 @@
|
||||||
if (tag === 'TOKENS') {
|
if (tag === 'TOKENS') {
|
||||||
(_this = this.tokens).push.apply(_this, value);
|
(_this = this.tokens).push.apply(_this, value);
|
||||||
} else {
|
} else {
|
||||||
this.token(tag, this.escapeLines(value, heredoc));
|
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (interpolated) {
|
if (interpolated) {
|
||||||
|
@ -584,6 +566,13 @@
|
||||||
Lexer.prototype.escapeLines = function(str, heredoc) {
|
Lexer.prototype.escapeLines = function(str, heredoc) {
|
||||||
return str.replace(MULTILINER, heredoc ? '\\n' : '');
|
return str.replace(MULTILINER, heredoc ? '\\n' : '');
|
||||||
};
|
};
|
||||||
|
Lexer.prototype.makeString = function(body, quote, heredoc) {
|
||||||
|
body = body.replace(/\\([\s\S])/g, function($amp, $1) {
|
||||||
|
return ('\n' === $1 || quote === $1) ? $1 : $amp;
|
||||||
|
});
|
||||||
|
body = body.replace(RegExp("" + quote, "g"), '\\$&');
|
||||||
|
return quote + this.escapeLines(body, heredoc) + quote;
|
||||||
|
};
|
||||||
return Lexer;
|
return Lexer;
|
||||||
})();
|
})();
|
||||||
JS_KEYWORDS = ['if', 'else', 'true', 'false', 'new', 'return', 'try', 'catch', 'finally', 'throw', 'break', 'continue', 'for', 'in', 'while', 'delete', 'instanceof', 'typeof', 'switch', 'super', 'extends', 'class', 'this', 'null', 'debugger'];
|
JS_KEYWORDS = ['if', 'else', 'true', 'false', 'new', 'return', 'try', 'catch', 'finally', 'throw', 'break', 'continue', 'for', 'in', 'while', 'delete', 'instanceof', 'typeof', 'switch', 'super', 'extends', 'class', 'this', 'null', 'debugger'];
|
||||||
|
@ -593,7 +582,7 @@
|
||||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||||
IDENTIFIER = /^[a-zA-Z_$][\w$]*/;
|
IDENTIFIER = /^[a-zA-Z_$][\w$]*/;
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
||||||
HEREDOC = /^("""|''')([\s\S]*?)\n?[ \t]*\1/;
|
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/;
|
||||||
OPERATOR = /^(?:-[-=>]?|\+[+=]?|[*&|\/%=<>^:!?]+)(?=([ \t]*))/;
|
OPERATOR = /^(?:-[-=>]?|\+[+=]?|[*&|\/%=<>^:!?]+)(?=([ \t]*))/;
|
||||||
WHITESPACE = /^[ \t]+/;
|
WHITESPACE = /^[ \t]+/;
|
||||||
COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||||
|
|
58
lib/nodes.js
58
lib/nodes.js
|
@ -220,10 +220,10 @@
|
||||||
var code;
|
var code;
|
||||||
code = this.compileNode(o);
|
code = this.compileNode(o);
|
||||||
if (o.scope.hasAssignments(this)) {
|
if (o.scope.hasAssignments(this)) {
|
||||||
code = ("" + this.tab + "var " + (o.scope.compiledAssignments()) + ";\n" + code);
|
code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments()) + ";\n" + code);
|
||||||
}
|
}
|
||||||
if (!o.globals && o.scope.hasDeclarations(this)) {
|
if (!o.globals && o.scope.hasDeclarations(this)) {
|
||||||
code = ("" + this.tab + "var " + (o.scope.compiledDeclarations()) + ";\n" + code);
|
code = ("" + (this.tab) + "var " + (o.scope.compiledDeclarations()) + ";\n" + code);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
@ -295,7 +295,7 @@
|
||||||
if (this.expression.isStatement(o)) {
|
if (this.expression.isStatement(o)) {
|
||||||
o.asStatement = true;
|
o.asStatement = true;
|
||||||
}
|
}
|
||||||
return "" + this.tab + "return " + (this.expression.compile(o)) + ";";
|
return "" + (this.tab) + "return " + (this.expression.compile(o)) + ";";
|
||||||
};
|
};
|
||||||
return ReturnNode;
|
return ReturnNode;
|
||||||
})();
|
})();
|
||||||
|
@ -588,7 +588,7 @@
|
||||||
a = o.scope.freeVariable('ctor');
|
a = o.scope.freeVariable('ctor');
|
||||||
b = o.scope.freeVariable('ref');
|
b = o.scope.freeVariable('ref');
|
||||||
c = o.scope.freeVariable('result');
|
c = o.scope.freeVariable('result');
|
||||||
return "(function() {\n" + (idt = this.idt(1)) + "var ctor = function() {};\n" + idt + (utility('extends')) + "(ctor, " + a + " = " + (this.variable.compile(o)) + ");\n" + idt + "return typeof (" + c + " = " + a + ".apply(" + b + " = new ctor, " + splatargs + ")) === \"object\" ? " + c + " : " + b + ";\n" + this.tab + "})." + call;
|
return "(function() {\n" + (idt = this.idt(1)) + "var ctor = function() {};\n" + idt + (utility('extends')) + "(ctor, " + a + " = " + (this.variable.compile(o)) + ");\n" + idt + "return typeof (" + c + " = " + a + ".apply(" + b + " = new ctor, " + splatargs + ")) === \"object\" ? " + c + " : " + b + ";\n" + (this.tab) + "})." + call;
|
||||||
};
|
};
|
||||||
return CallNode;
|
return CallNode;
|
||||||
})();
|
})();
|
||||||
|
@ -692,9 +692,9 @@
|
||||||
}
|
}
|
||||||
idx = del(o, 'index');
|
idx = del(o, 'index');
|
||||||
step = del(o, 'step');
|
step = del(o, 'step');
|
||||||
vars = ("" + idx + " = " + this.fromVar);
|
vars = ("" + idx + " = " + (this.fromVar));
|
||||||
intro = ("(" + this.fromVar + " <= " + this.toVar + " ? " + idx);
|
intro = ("(" + (this.fromVar) + " <= " + (this.toVar) + " ? " + idx);
|
||||||
compare = ("" + intro + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar + ")");
|
compare = ("" + intro + " <" + (this.equals) + " " + (this.toVar) + " : " + idx + " >" + (this.equals) + " " + (this.toVar) + ")");
|
||||||
stepPart = step ? step.compile(o) : '1';
|
stepPart = step ? step.compile(o) : '1';
|
||||||
incr = step ? ("" + idx + " += " + stepPart) : ("" + intro + " += " + stepPart + " : " + idx + " -= " + stepPart + ")");
|
incr = step ? ("" + idx + " += " + stepPart) : ("" + intro + " += " + stepPart + " : " + idx + " -= " + stepPart + ")");
|
||||||
return "" + vars + "; " + compare + "; " + incr;
|
return "" + vars + "; " + compare + "; " + incr;
|
||||||
|
@ -705,7 +705,7 @@
|
||||||
idx = del(o, 'index');
|
idx = del(o, 'index');
|
||||||
step = del(o, 'step');
|
step = del(o, 'step');
|
||||||
step && (step = ("" + idx + " += " + (step.compile(o))));
|
step && (step = ("" + idx + " += " + (step.compile(o))));
|
||||||
return from <= to ? ("" + idx + " = " + from + "; " + idx + " <" + this.equals + " " + to + "; " + (step || ("" + idx + "++"))) : ("" + idx + " = " + from + "; " + idx + " >" + this.equals + " " + to + "; " + (step || ("" + idx + "--")));
|
return from <= to ? ("" + idx + " = " + from + "; " + idx + " <" + (this.equals) + " " + to + "; " + (step || ("" + idx + "++"))) : ("" + idx + " = " + from + "; " + idx + " >" + (this.equals) + " " + to + "; " + (step || ("" + idx + "--")));
|
||||||
};
|
};
|
||||||
RangeNode.prototype.compileArray = function(o) {
|
RangeNode.prototype.compileArray = function(o) {
|
||||||
var _i, _ref2, _ref3, _result, body, clause, i, idt, post, pre, range, result, vars;
|
var _i, _ref2, _ref3, _result, body, clause, i, idt, post, pre, range, result, vars;
|
||||||
|
@ -731,8 +731,8 @@
|
||||||
o.index = i;
|
o.index = i;
|
||||||
body = this.compileSimple(o);
|
body = this.compileSimple(o);
|
||||||
} else {
|
} else {
|
||||||
clause = ("" + this.fromVar + " <= " + this.toVar + " ?");
|
clause = ("" + (this.fromVar) + " <= " + (this.toVar) + " ?");
|
||||||
body = ("var " + i + " = " + this.fromVar + "; " + clause + " " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + clause + " " + i + " += 1 : " + i + " -= 1");
|
body = ("var " + i + " = " + (this.fromVar) + "; " + clause + " " + i + " <" + (this.equals) + " " + (this.toVar) + " : " + i + " >" + (this.equals) + " " + (this.toVar) + "; " + clause + " " + i + " += 1 : " + i + " -= 1");
|
||||||
}
|
}
|
||||||
post = ("{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + (o.indent));
|
post = ("{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + (o.indent));
|
||||||
return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).call(this)";
|
return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).call(this)";
|
||||||
|
@ -844,7 +844,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
objects = objects.join('');
|
objects = objects.join('');
|
||||||
return indexOf(objects, '\n') >= 0 ? ("[\n" + (this.idt(1)) + objects + "\n" + this.tab + "]") : ("[" + objects + "]");
|
return indexOf(objects, '\n') >= 0 ? ("[\n" + (this.idt(1)) + objects + "\n" + (this.tab) + "]") : ("[" + objects + "]");
|
||||||
};
|
};
|
||||||
return ArrayNode;
|
return ArrayNode;
|
||||||
})();
|
})();
|
||||||
|
@ -977,7 +977,7 @@
|
||||||
}
|
}
|
||||||
val = ("" + name + " = " + val);
|
val = ("" + name + " = " + val);
|
||||||
if (stmt) {
|
if (stmt) {
|
||||||
return ("" + this.tab + val + ";");
|
return ("" + (this.tab) + val + ";");
|
||||||
}
|
}
|
||||||
return top || this.parenthetical ? val : ("(" + val + ")");
|
return top || this.parenthetical ? val : ("(" + val + ")");
|
||||||
};
|
};
|
||||||
|
@ -1127,7 +1127,7 @@
|
||||||
code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : '';
|
code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : '';
|
||||||
func = ("function(" + (params.join(', ')) + ") {" + code + (code && this.tab) + "}");
|
func = ("function(" + (params.join(', ')) + ") {" + code + (code && this.tab) + "}");
|
||||||
if (this.bound) {
|
if (this.bound) {
|
||||||
return ("(" + (utility('bind')) + "(" + func + ", " + this.context + "))");
|
return ("(" + (utility('bind')) + "(" + func + ", " + (this.context) + "))");
|
||||||
}
|
}
|
||||||
return top ? ("(" + func + ")") : func;
|
return top ? ("(" + func + ")") : func;
|
||||||
};
|
};
|
||||||
|
@ -1203,7 +1203,7 @@
|
||||||
o.scope.assign(trailing.compile(o), "arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]");
|
o.scope.assign(trailing.compile(o), "arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "" + name + " = " + (utility('slice')) + ".call(arguments, " + this.index + end + ")";
|
return "" + name + " = " + (utility('slice')) + ".call(arguments, " + (this.index) + end + ")";
|
||||||
};
|
};
|
||||||
SplatNode.prototype.compileValue = function(o, name, index, trailings) {
|
SplatNode.prototype.compileValue = function(o, name, index, trailings) {
|
||||||
var trail;
|
var trail;
|
||||||
|
@ -1271,12 +1271,12 @@
|
||||||
set = '';
|
set = '';
|
||||||
if (!(top)) {
|
if (!(top)) {
|
||||||
rvar = o.scope.freeVariable('result');
|
rvar = o.scope.freeVariable('result');
|
||||||
set = ("" + this.tab + rvar + " = [];\n");
|
set = ("" + (this.tab) + rvar + " = [];\n");
|
||||||
if (this.body) {
|
if (this.body) {
|
||||||
this.body = PushNode.wrap(rvar, this.body);
|
this.body = PushNode.wrap(rvar, this.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pre = ("" + set + this.tab + "while (" + cond + ")");
|
pre = ("" + set + (this.tab) + "while (" + cond + ")");
|
||||||
if (this.guard) {
|
if (this.guard) {
|
||||||
this.body = Expressions.wrap([new IfNode(this.guard, this.body)]);
|
this.body = Expressions.wrap([new IfNode(this.guard, this.body)]);
|
||||||
}
|
}
|
||||||
|
@ -1287,7 +1287,7 @@
|
||||||
} else {
|
} else {
|
||||||
post = '';
|
post = '';
|
||||||
}
|
}
|
||||||
return "" + pre + " {\n" + (this.body.compile(o)) + "\n" + this.tab + "}" + post;
|
return "" + pre + " {\n" + (this.body.compile(o)) + "\n" + (this.tab) + "}" + post;
|
||||||
};
|
};
|
||||||
return WhileNode;
|
return WhileNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1377,7 +1377,7 @@
|
||||||
shared = this.first.unwrap().second;
|
shared = this.first.unwrap().second;
|
||||||
_ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
|
_ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
|
||||||
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref2[0], second = _ref2[1], shared = _ref2[2];
|
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref2[0], second = _ref2[1], shared = _ref2[2];
|
||||||
return "(" + first + ") && (" + shared + " " + this.operator + " " + second + ")";
|
return "(" + first + ") && (" + shared + " " + (this.operator) + " " + second + ")";
|
||||||
};
|
};
|
||||||
OpNode.prototype.compileAssignment = function(o) {
|
OpNode.prototype.compileAssignment = function(o) {
|
||||||
var _ref2, left, rite;
|
var _ref2, left, rite;
|
||||||
|
@ -1446,7 +1446,7 @@
|
||||||
}), this.arr1 = _ref2[0], this.arr2 = _ref2[1];
|
}), this.arr1 = _ref2[0], this.arr2 = _ref2[1];
|
||||||
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')], i = _ref2[0], l = _ref2[1];
|
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')], i = _ref2[0], l = _ref2[1];
|
||||||
prefix = this.obj1 !== this.obj2 ? this.obj1 + '; ' : '';
|
prefix = this.obj1 !== this.obj2 ? this.obj1 + '; ' : '';
|
||||||
return "(function(){ " + prefix + "for (var " + i + "=0, " + l + "=" + this.arr1 + ".length; " + i + "<" + l + "; " + i + "++) { if (" + this.arr2 + "[" + i + "] === " + this.obj2 + ") return true; } return false; }).call(this)";
|
return "(function(){ " + prefix + "for (var " + i + "=0, " + l + "=" + (this.arr1) + ".length; " + i + "<" + l + "; " + i + "++) { if (" + (this.arr2) + "[" + i + "] === " + (this.obj2) + ") return true; } return false; }).call(this)";
|
||||||
};
|
};
|
||||||
return InNode;
|
return InNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1478,9 +1478,9 @@
|
||||||
o.top = true;
|
o.top = true;
|
||||||
attemptPart = this.attempt.compile(o);
|
attemptPart = this.attempt.compile(o);
|
||||||
errorPart = this.error ? (" (" + (this.error.compile(o)) + ") ") : ' ';
|
errorPart = this.error ? (" (" + (this.error.compile(o)) + ") ") : ' ';
|
||||||
catchPart = this.recovery ? (" catch" + errorPart + "{\n" + (this.recovery.compile(o)) + "\n" + this.tab + "}") : '';
|
catchPart = this.recovery ? (" catch" + errorPart + "{\n" + (this.recovery.compile(o)) + "\n" + (this.tab) + "}") : '';
|
||||||
finallyPart = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o)) + ("\n" + this.tab + "}");
|
finallyPart = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o)) + ("\n" + (this.tab) + "}");
|
||||||
return "" + this.tab + "try {\n" + attemptPart + "\n" + this.tab + "}" + catchPart + finallyPart;
|
return "" + (this.tab) + "try {\n" + attemptPart + "\n" + (this.tab) + "}" + catchPart + finallyPart;
|
||||||
};
|
};
|
||||||
return TryNode;
|
return TryNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1496,7 +1496,7 @@
|
||||||
ThrowNode.prototype.isStatement = YES;
|
ThrowNode.prototype.isStatement = YES;
|
||||||
ThrowNode.prototype.makeReturn = THIS;
|
ThrowNode.prototype.makeReturn = THIS;
|
||||||
ThrowNode.prototype.compileNode = function(o) {
|
ThrowNode.prototype.compileNode = function(o) {
|
||||||
return "" + this.tab + "throw " + (this.expression.compile(o)) + ";";
|
return "" + (this.tab) + "throw " + (this.expression.compile(o)) + ";";
|
||||||
};
|
};
|
||||||
return ThrowNode;
|
return ThrowNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1651,7 +1651,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourcePart = (rvar ? ("" + rvar + " = []; ") : '') + sourcePart;
|
sourcePart = (rvar ? ("" + rvar + " = []; ") : '') + sourcePart;
|
||||||
sourcePart = sourcePart ? ("" + this.tab + sourcePart + "\n" + this.tab) : this.tab;
|
sourcePart = sourcePart ? ("" + (this.tab) + sourcePart + "\n" + (this.tab)) : this.tab;
|
||||||
returnResult = this.compileReturnValue(rvar, o);
|
returnResult = this.compileReturnValue(rvar, o);
|
||||||
if (!(topLevel)) {
|
if (!(topLevel)) {
|
||||||
body = PushNode.wrap(rvar, body);
|
body = PushNode.wrap(rvar, body);
|
||||||
|
@ -1686,7 +1686,7 @@
|
||||||
top: true
|
top: true
|
||||||
}));
|
}));
|
||||||
vars = range ? name : ("" + name + ", " + ivar);
|
vars = range ? name : ("" + name + ", " + ivar);
|
||||||
return "" + sourcePart + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + this.tab + "}" + returnResult;
|
return "" + sourcePart + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + returnResult;
|
||||||
};
|
};
|
||||||
return ForNode;
|
return ForNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1720,7 +1720,7 @@
|
||||||
var _i, _j, _len, _len2, _ref2, _ref3, block, code, condition, conditions, exprs, idt, pair;
|
var _i, _j, _len, _len2, _ref2, _ref3, block, code, condition, conditions, exprs, idt, pair;
|
||||||
idt = (o.indent = this.idt(2));
|
idt = (o.indent = this.idt(2));
|
||||||
o.top = true;
|
o.top = true;
|
||||||
code = ("" + this.tab + "switch (" + (this.subject.compile(o)) + ") {");
|
code = ("" + (this.tab) + "switch (" + (this.subject.compile(o)) + ") {");
|
||||||
_ref2 = this.cases;
|
_ref2 = this.cases;
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||||
pair = _ref2[_i];
|
pair = _ref2[_i];
|
||||||
|
@ -1742,7 +1742,7 @@
|
||||||
if (this.otherwise) {
|
if (this.otherwise) {
|
||||||
code += ("\n" + (this.idt(1)) + "default:\n" + (this.otherwise.compile(o)));
|
code += ("\n" + (this.idt(1)) + "default:\n" + (this.otherwise.compile(o)));
|
||||||
}
|
}
|
||||||
code += ("\n" + this.tab + "}");
|
code += ("\n" + (this.tab) + "}");
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
return SwitchNode;
|
return SwitchNode;
|
||||||
|
@ -1828,14 +1828,14 @@
|
||||||
ifDent = child || (top && !this.isStatement(o)) ? '' : this.idt();
|
ifDent = child || (top && !this.isStatement(o)) ? '' : this.idt();
|
||||||
comDent = child ? this.idt() : '';
|
comDent = child ? this.idt() : '';
|
||||||
body = this.body.compile(o);
|
body = this.body.compile(o);
|
||||||
ifPart = ("" + ifDent + "if (" + (this.compileCondition(condO)) + ") {\n" + body + "\n" + this.tab + "}");
|
ifPart = ("" + ifDent + "if (" + (this.compileCondition(condO)) + ") {\n" + body + "\n" + (this.tab) + "}");
|
||||||
if (!(this.elseBody)) {
|
if (!(this.elseBody)) {
|
||||||
return ifPart;
|
return ifPart;
|
||||||
}
|
}
|
||||||
elsePart = this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, {
|
elsePart = this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, {
|
||||||
indent: this.idt(),
|
indent: this.idt(),
|
||||||
chainChild: true
|
chainChild: true
|
||||||
})) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + this.tab + "}");
|
})) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}");
|
||||||
return "" + ifPart + elsePart;
|
return "" + ifPart + elsePart;
|
||||||
};
|
};
|
||||||
IfNode.prototype.compileTernary = function(o) {
|
IfNode.prototype.compileTernary = function(o) {
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
var _i, _len, _ref, letPart, lines, rule, spaces;
|
var _i, _len, _ref, letPart, lines, rule, spaces;
|
||||||
lines = ['Available options:'];
|
lines = ['Available options:'];
|
||||||
if (this.banner) {
|
if (this.banner) {
|
||||||
lines.unshift("" + this.banner + "\n");
|
lines.unshift("" + (this.banner) + "\n");
|
||||||
}
|
}
|
||||||
_ref = this.rules;
|
_ref = this.rules;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
} else {
|
} else {
|
||||||
tokens.splice(i, 0, after);
|
tokens.splice(i, 0, after);
|
||||||
}
|
}
|
||||||
} else if (!('TERMINATOR' === (_ref = ((prev != null) ? prev[0] : undefined)) || 'INDENT' === _ref || 'OUTDENT' === _ref)) {
|
} else if (prev && !('TERMINATOR' === (_ref = prev[0]) || 'INDENT' === _ref || 'OUTDENT' === _ref)) {
|
||||||
if (((post != null) ? post[0] === 'TERMINATOR' : undefined) && ((after != null) ? after[0] === 'OUTDENT' : undefined)) {
|
if (((post != null) ? post[0] === 'TERMINATOR' : undefined) && ((after != null) ? after[0] === 'OUTDENT' : undefined)) {
|
||||||
tokens.splice.apply(tokens, [i + 2, 0].concat(tokens.splice(i, 2)));
|
tokens.splice.apply(tokens, [i + 2, 0].concat(tokens.splice(i, 2)));
|
||||||
if (tokens[i + 2][0] !== 'TERMINATOR') {
|
if (tokens[i + 2][0] !== 'TERMINATOR') {
|
||||||
|
|
|
@ -125,8 +125,8 @@ exports.Lexer = class Lexer
|
||||||
@token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
|
@token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
|
||||||
when '"'
|
when '"'
|
||||||
return false unless string = @balancedString @chunk, [['"', '"'], ['#{', '}']]
|
return false unless string = @balancedString @chunk, [['"', '"'], ['#{', '}']]
|
||||||
if ~string.indexOf '#{'
|
if 0 < string.indexOf '#{', 1
|
||||||
@interpolateString string
|
@interpolateString string.slice 1, -1
|
||||||
else
|
else
|
||||||
@token 'STRING', @escapeLines string
|
@token 'STRING', @escapeLines string
|
||||||
else
|
else
|
||||||
|
@ -142,10 +142,10 @@ exports.Lexer = class Lexer
|
||||||
heredoc = match[0]
|
heredoc = match[0]
|
||||||
quote = heredoc.charAt 0
|
quote = heredoc.charAt 0
|
||||||
doc = @sanitizeHeredoc match[2], {quote, indent: null}
|
doc = @sanitizeHeredoc match[2], {quote, indent: null}
|
||||||
if quote is '"' and ~doc.indexOf '#{'
|
if quote is '"' and 0 <= doc.indexOf '#{'
|
||||||
@interpolateString quote + doc + quote, heredoc: yes
|
@interpolateString doc, heredoc: yes
|
||||||
else
|
else
|
||||||
@token 'STRING', quote + @escapeLines(doc, yes) + quote
|
@token 'STRING', @makeString doc, quote, yes
|
||||||
@line += count heredoc, '\n'
|
@line += count heredoc, '\n'
|
||||||
@i += heredoc.length
|
@i += heredoc.length
|
||||||
true
|
true
|
||||||
|
@ -185,19 +185,20 @@ exports.Lexer = class Lexer
|
||||||
heregexToken: (match) ->
|
heregexToken: (match) ->
|
||||||
[heregex, body, flags] = match
|
[heregex, body, flags] = match
|
||||||
@i += heregex.length
|
@i += heregex.length
|
||||||
unless ~body.indexOf '#{'
|
if 0 > body.indexOf '#{'
|
||||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/')
|
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/')
|
||||||
@token 'REGEX', "/#{ re or '(?:)' }/#{flags}"
|
@token 'REGEX', "/#{ re or '(?:)' }/#{flags}"
|
||||||
return true
|
return true
|
||||||
@token 'IDENTIFIER', 'RegExp'
|
@token 'IDENTIFIER', 'RegExp'
|
||||||
@tokens.push ['CALL_START', '(']
|
@tokens.push ['CALL_START', '(']
|
||||||
tokens = []
|
tokens = []
|
||||||
for [tag, value] in @interpolateString('"' + body + '"', regex: yes)
|
for [tag, value] in @interpolateString(body, regex: yes)
|
||||||
if tag is 'TOKENS'
|
if tag is 'TOKENS'
|
||||||
tokens.push value...
|
tokens.push value...
|
||||||
else
|
else
|
||||||
continue unless value = value.slice(1, -1).replace HEREGEX_OMIT, ''
|
continue unless value = value.replace HEREGEX_OMIT, ''
|
||||||
tokens.push ['STRING', '"' + value.replace(/[\\\"]/g, '\\$&') + '"']
|
value = value.replace /\\/g, '\\\\'
|
||||||
|
tokens.push ['STRING', @makeString(value, '"', yes)]
|
||||||
tokens.push ['+', '+']
|
tokens.push ['+', '+']
|
||||||
tokens.pop()
|
tokens.pop()
|
||||||
@tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING'
|
@tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING'
|
||||||
|
@ -344,22 +345,17 @@ exports.Lexer = class Lexer
|
||||||
prev[0] is '@'
|
prev[0] is '@'
|
||||||
if accessor then 'accessor' else false
|
if accessor then 'accessor' else false
|
||||||
|
|
||||||
# Sanitize a heredoc or herecomment by escaping internal double quotes and
|
# Sanitize a heredoc or herecomment by
|
||||||
# erasing all external indentation on the left-hand side.
|
# erasing all external indentation on the left-hand side.
|
||||||
sanitizeHeredoc: (doc, options) ->
|
sanitizeHeredoc: (doc, options) ->
|
||||||
{indent, herecomment} = options
|
{indent, herecomment} = options
|
||||||
return doc if herecomment and not include doc, '\n'
|
return doc if herecomment and 0 > doc.indexOf '\n'
|
||||||
unless herecomment
|
unless herecomment
|
||||||
while (match = HEREDOC_INDENT.exec doc)
|
while match = HEREDOC_INDENT.exec doc
|
||||||
attempt = match[1]
|
attempt = match[1]
|
||||||
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
||||||
doc = doc.replace /// \n #{indent} ///g, '\n' if indent
|
doc = doc.replace /// \n #{indent} ///g, '\n' if indent
|
||||||
return doc if herecomment
|
doc = doc.replace /^\n/, '' unless herecomment
|
||||||
{quote} = options
|
|
||||||
doc = doc.replace /^\n/, ''
|
|
||||||
doc = doc.replace /\\([\s\S])/g, (m, c) -> if c in ['\n', quote] then c else m
|
|
||||||
doc = doc.replace /// #{quote} ///g, '\\$&'
|
|
||||||
doc = @escapeLines doc, yes if quote is "'"
|
|
||||||
doc
|
doc
|
||||||
|
|
||||||
# A source of ambiguity in our grammar used to be parameter lists in function
|
# A source of ambiguity in our grammar used to be parameter lists in function
|
||||||
|
@ -429,12 +425,10 @@ exports.Lexer = class Lexer
|
||||||
# new Lexer, tokenize the interpolated contents, and merge them into the
|
# new Lexer, tokenize the interpolated contents, and merge them into the
|
||||||
# token stream.
|
# token stream.
|
||||||
interpolateString: (str, options) ->
|
interpolateString: (str, options) ->
|
||||||
return @token 'STRING', @escapeLines(str, heredoc) if str.length < 5 # "#{}"
|
|
||||||
{heredoc, regex} = options or= {}
|
{heredoc, regex} = options or= {}
|
||||||
lexer = new Lexer
|
|
||||||
tokens = []
|
tokens = []
|
||||||
pi = 1
|
pi = 0
|
||||||
i = 0
|
i = -1
|
||||||
while char = str.charAt i += 1
|
while char = str.charAt i += 1
|
||||||
if char is '\\'
|
if char is '\\'
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -442,28 +436,28 @@ exports.Lexer = class Lexer
|
||||||
unless char is '#' and str.charAt(i+1) is '{' and
|
unless char is '#' and str.charAt(i+1) is '{' and
|
||||||
(expr = @balancedString str[i+1..], [['{', '}']])
|
(expr = @balancedString str[i+1..], [['{', '}']])
|
||||||
continue
|
continue
|
||||||
tokens.push ['STRING', '"' + str[pi...i] + '"'] if pi < i
|
tokens.push ['TO_BE_STRING', str[pi...i]] if pi < i
|
||||||
inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, '')
|
inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, '')
|
||||||
if inner.length
|
if inner.length
|
||||||
inner = inner.replace /\\\"/g, '"' if heredoc
|
nested = new Lexer().tokenize inner, line: @line, rewrite: off
|
||||||
nested = lexer.tokenize "(#{inner}\n)", line: @line
|
|
||||||
(tok[0] = ')') for tok in nested when tok[0] is 'CALL_END'
|
|
||||||
nested.pop()
|
nested.pop()
|
||||||
if nested.length < 5 then nested.pop(); nested.shift()
|
if nested.length > 1
|
||||||
|
nested.unshift ['(', '(']
|
||||||
|
nested.push [')', ')']
|
||||||
tokens.push ['TOKENS', nested]
|
tokens.push ['TOKENS', nested]
|
||||||
i += expr.length
|
i += expr.length
|
||||||
pi = i + 1
|
pi = i + 1
|
||||||
tokens.push ['STRING', '"' + str.slice pi] if i > pi < str.length - 1
|
tokens.push ['TO_BE_STRING', str[pi..]] if i > pi < str.length
|
||||||
return tokens if regex
|
return tokens if regex
|
||||||
interpolated = tokens.length > 1
|
return @token 'STRING', '""' unless tokens.length
|
||||||
tokens.unshift ['STRING', '""'] unless tokens[0]?[0] is 'STRING'
|
@token '(', '(' if interpolated = tokens.length > 1
|
||||||
@token '(', '(' if interpolated
|
@tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0][0] is 'TO_BE_STRING'
|
||||||
for [tag, value], i in tokens
|
for [tag, value], i in tokens
|
||||||
@token '+', '+' if i
|
@token '+', '+' if i
|
||||||
if tag is 'TOKENS'
|
if tag is 'TOKENS'
|
||||||
@tokens.push value...
|
@tokens.push value...
|
||||||
else
|
else
|
||||||
@token tag, @escapeLines value, heredoc
|
@token 'STRING', @makeString value, '"', heredoc
|
||||||
@token ')', ')' if interpolated
|
@token ')', ')' if interpolated
|
||||||
tokens
|
tokens
|
||||||
|
|
||||||
|
@ -494,6 +488,13 @@ exports.Lexer = class Lexer
|
||||||
escapeLines: (str, heredoc) ->
|
escapeLines: (str, heredoc) ->
|
||||||
str.replace MULTILINER, if heredoc then '\\n' else ''
|
str.replace MULTILINER, if heredoc then '\\n' else ''
|
||||||
|
|
||||||
|
# Constructs a string token by escaping quotes and newlines.
|
||||||
|
makeString: (body, quote, heredoc) ->
|
||||||
|
body = body.replace /\\([\s\S])/g, ($amp, $1) ->
|
||||||
|
if $1 in ['\n', quote] then $1 else $amp
|
||||||
|
body = body.replace /// #{quote} ///g, '\\$&'
|
||||||
|
quote + @escapeLines(body, heredoc) + quote
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
# ---------
|
# ---------
|
||||||
|
|
||||||
|
@ -535,7 +536,7 @@ JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
|
||||||
# Token matching regexes.
|
# Token matching regexes.
|
||||||
IDENTIFIER = /^[a-zA-Z_$][\w$]*/
|
IDENTIFIER = /^[a-zA-Z_$][\w$]*/
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i
|
||||||
HEREDOC = /^("""|''')([\s\S]*?)\n?[ \t]*\1/
|
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/
|
||||||
OPERATOR = /^(?:-[-=>]?|\+[+=]?|[*&|\/%=<>^:!?]+)(?=([ \t]*))/
|
OPERATOR = /^(?:-[-=>]?|\+[+=]?|[*&|\/%=<>^:!?]+)(?=([ \t]*))/
|
||||||
WHITESPACE = /^[ \t]+/
|
WHITESPACE = /^[ \t]+/
|
||||||
COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
||||||
|
|
|
@ -73,7 +73,7 @@ class exports.Rewriter
|
||||||
tokens.splice i - 2, 1
|
tokens.splice i - 2, 1
|
||||||
else
|
else
|
||||||
tokens.splice i, 0, after
|
tokens.splice i, 0, after
|
||||||
else if prev?[0] not in ['TERMINATOR', 'INDENT', 'OUTDENT']
|
else if prev and prev[0] not in ['TERMINATOR', 'INDENT', 'OUTDENT']
|
||||||
if post?[0] is 'TERMINATOR' and after?[0] is 'OUTDENT'
|
if post?[0] is 'TERMINATOR' and after?[0] is 'OUTDENT'
|
||||||
tokens.splice i + 2, 0, tokens.splice(i, 2)...
|
tokens.splice i + 2, 0, tokens.splice(i, 2)...
|
||||||
if tokens[i + 2][0] isnt 'TERMINATOR'
|
if tokens[i + 2][0] isnt 'TERMINATOR'
|
||||||
|
|
|
@ -89,8 +89,7 @@ a = """
|
||||||
"""
|
"""
|
||||||
ok a is "one\ntwo\n"
|
ok a is "one\ntwo\n"
|
||||||
|
|
||||||
|
eq ''' line 0
|
||||||
equal ''' line 0
|
|
||||||
should not be relevant
|
should not be relevant
|
||||||
to the indent level
|
to the indent level
|
||||||
''', '
|
''', '
|
||||||
|
@ -99,10 +98,14 @@ should not be relevant\n
|
||||||
to the indent level
|
to the indent level
|
||||||
'
|
'
|
||||||
|
|
||||||
|
eq ''' '\\\' ''', " '\\' "
|
||||||
|
eq """ "\\\" """, ' "\\" '
|
||||||
|
|
||||||
equal 'multiline nested interpolations work', """multiline #{
|
eq ''' <- keep these spaces -> ''', ' <- keep these spaces -> '
|
||||||
|
|
||||||
|
eq 'multiline nested "interpolations" work', """multiline #{
|
||||||
"nested #{(->
|
"nested #{(->
|
||||||
ok yes
|
ok yes
|
||||||
"interpolations"
|
"\"interpolations\""
|
||||||
)()}"
|
)()}"
|
||||||
} work"""
|
} work"""
|
||||||
|
|
|
@ -25,11 +25,12 @@ ok (obj.width()/id - obj.height()/id) is -5
|
||||||
eq /^I'm\s+Heregex?\/\/\//gim + '', ///
|
eq /^I'm\s+Heregex?\/\/\//gim + '', ///
|
||||||
^ I'm \s+ Heregex? / // # or not
|
^ I'm \s+ Heregex? / // # or not
|
||||||
///gim + ''
|
///gim + ''
|
||||||
eq '\\\\#{}', ///
|
eq '\\\\#{}\\\\\\\"', ///
|
||||||
#{
|
#{
|
||||||
"#{ '\\' }" # normal comment
|
"#{ '\\' }" # normal comment
|
||||||
}
|
}
|
||||||
# regex comment
|
# regex comment
|
||||||
\#{}
|
\#{}
|
||||||
|
\\ \"
|
||||||
///.source
|
///.source
|
||||||
eq /// /// + '', '/(?:)/'
|
eq /// /// + '', '/(?:)/'
|
||||||
|
|
Loading…
Reference in New Issue