adding interpolation to heredocs, using the same rules as for strings

This commit is contained in:
Jeremy Ashkenas 2010-03-17 20:47:27 -04:00
parent 70cfc9500e
commit d880b8b8f2
5 changed files with 30 additions and 12 deletions

View File

@ -11,7 +11,7 @@
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
// The help banner that is printed when `coffee` is called without arguments.
BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee";
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee';
// The list of all the valid option flags that `coffee` knows how to handle.
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
// Top-level objects shared by all the functions.

View File

@ -169,12 +169,13 @@
// Matches heredocs, adjusting indentation to the correct level, as heredocs
// preserve whitespace, but ignore indentation to the left.
Lexer.prototype.heredoc_token = function heredoc_token() {
var doc, match;
var doc, match, quote;
if (!((match = this.chunk.match(HEREDOC)))) {
return false;
}
doc = this.sanitize_heredoc(match[2] || match[4]);
this.token('STRING', "\"" + doc + "\"");
quote = match[1].substr(0, 1);
doc = this.sanitize_heredoc(match[2] || match[4], quote);
this.interpolate_string('' + quote + doc + quote);
this.line += count(match[1], "\n");
this.i += match[1].length;
return true;
@ -383,10 +384,10 @@
};
// Sanitize a heredoc by escaping internal double quotes and erasing all
// external indentation on the left-hand side.
Lexer.prototype.sanitize_heredoc = function sanitize_heredoc(doc) {
Lexer.prototype.sanitize_heredoc = function sanitize_heredoc(doc, quote) {
var indent;
indent = (doc.match(HEREDOC_INDENT) || ['']).sort()[0];
return doc.replace(new RegExp("^" + indent, 'gm'), '').replace(MULTILINER, "\\n").replace(/"/g, '\\"');
return doc.replace(new RegExp("^" + indent, 'gm'), '').replace(MULTILINER, "\\n").replace(new RegExp(quote, 'g'), '\\"');
};
// A source of ambiguity in our grammar used to be parameter lists in function
// definitions versus argument lists in function calls. Walk backwards, tagging

View File

@ -494,7 +494,7 @@
};
__extends(ExtendsNode, BaseNode);
ExtendsNode.prototype.type = 'Extends';
ExtendsNode.prototype.code = "function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n }";
ExtendsNode.prototype.code = 'function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n }';
// Hooks one constructor into another's prototype chain.
ExtendsNode.prototype.compile_node = function compile_node(o) {
var call, ref;

View File

@ -126,8 +126,9 @@ exports.Lexer: class Lexer
# preserve whitespace, but ignore indentation to the left.
heredoc_token: ->
return false unless match = @chunk.match(HEREDOC)
doc: @sanitize_heredoc match[2] or match[4]
@token 'STRING', "\"$doc\""
quote: match[1].substr(0, 1)
doc: @sanitize_heredoc match[2] or match[4], quote
@interpolate_string "$quote$doc$quote"
@line += count match[1], "\n"
@i += match[1].length
true
@ -285,11 +286,11 @@ exports.Lexer: class Lexer
# Sanitize a heredoc by escaping internal double quotes and erasing all
# external indentation on the left-hand side.
sanitize_heredoc: (doc) ->
sanitize_heredoc: (doc, quote) ->
indent: (doc.match(HEREDOC_INDENT) or ['']).sort()[0]
doc.replace(new RegExp("^" +indent, 'gm'), '')
.replace(MULTILINER, "\\n")
.replace(/"/g, '\\"')
.replace(new RegExp(quote, 'g'), '\\"')
# A source of ambiguity in our grammar used to be parameter lists in function
# definitions versus argument lists in function calls. Walk backwards, tagging

View File

@ -49,4 +49,20 @@ ok a is "a\n\n\nb c"
a: '''more"than"one"quote'''
ok a is 'more"than"one"quote'
ok a is 'more"than"one"quote'
val: 10
a: """
basic heredoc $val
on two lines
"""
b: '''
basic heredoc $val
on two lines
'''
ok a is "basic heredoc 10\non two lines"
ok b is "basic heredoc \$val\non two lines"