From 477c5103454e7b4d2ad076cf80aa2c0766f77e5a Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 11 Jan 2010 23:53:50 -0500 Subject: [PATCH] adding heredocs, with tests --- .../Syntaxes/CoffeeScript.tmLanguage | 24 ++++++++++++++++ lib/coffee_script/lexer.rb | 20 ++++++++++--- test/fixtures/execution/test_heredocs.coffee | 28 +++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/execution/test_heredocs.coffee diff --git a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage index 5a60ab24..31187244 100644 --- a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +++ b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage @@ -93,6 +93,30 @@ name constant.numeric.coffee + + name + string.quoted.heredoc.coffee + begin + ("""|''') + end + ("""|''') + beginCaptures + + 0 + + name + punctuation.definition.string.begin.coffee + + + endCaptures + + 0 + + name + punctuation.definition.string.end.coffee + + + begin ' diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb index 2abe4b8a..6c41dde1 100644 --- a/lib/coffee_script/lexer.rb +++ b/lib/coffee_script/lexer.rb @@ -22,6 +22,7 @@ module CoffeeScript IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/ NUMBER = /\A(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m + HEREDOC = /\A("{6}|'{6}|"{3}\n?(\s*)(.*?)\n?(\s*)"{3}|'{3}\n?(\s*)(.*?)\n?(\s*)'{3})/m JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/ WHITESPACE = /\A([ \t]+)/ @@ -69,6 +70,7 @@ module CoffeeScript def extract_next_token return if identifier_token return if number_token + return if heredoc_token return if string_token return if js_token return if regex_token @@ -103,14 +105,24 @@ module CoffeeScript # Matches strings, including multi-line strings. def string_token return false unless string = @chunk[STRING, 1] - escaped = string.gsub(MULTILINER) do |match| - @line += 1 - " \\\n" - end + escaped = string.gsub(MULTILINER, " \\\n") token(:STRING, escaped) + @line += string.count("\n") @i += string.length end + # Matches heredocs, adjusting indentation to the correct level. + def heredoc_token + return false unless match = @chunk.match(HEREDOC) + indent = match[2] || match[5] + doc = match[3] || match[6] + doc.gsub!(/\n#{indent}/, "\\n") + doc.gsub!('"', '\\"') + token(:STRING, "\"#{doc}\"") + @line += match[1].count("\n") + @i += match[1].length + end + # Matches interpolated JavaScript. def js_token return false unless script = @chunk[JS, 1] diff --git a/test/fixtures/execution/test_heredocs.coffee b/test/fixtures/execution/test_heredocs.coffee new file mode 100644 index 00000000..07a55d05 --- /dev/null +++ b/test/fixtures/execution/test_heredocs.coffee @@ -0,0 +1,28 @@ +a: """ + basic heredoc + on two lines + """ + +print(a is "basic heredoc\non two lines") + + +a: ''' + a + b + c + ''' + +print(a is "a\n b\nc") + + +a: '''one-liner''' + +print(a is 'one-liner') + + +a: """ + out + here +""" + +print(a is "out\nhere") \ No newline at end of file