diff --git a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
index 31187244..8d651fe3 100644
--- a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
+++ b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
@@ -64,7 +64,7 @@
comment
match stuff like: a => …
match
- ([a-zA-Z0-9_?., $:*]*)\s*(=>)
+ ([a-zA-Z0-9_?., $*]*)\s*(=>)
name
meta.inline.function.coffee
diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb
index 6c41dde1..9541548f 100644
--- a/lib/coffee_script/lexer.rb
+++ b/lib/coffee_script/lexer.rb
@@ -22,7 +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
+ HEREDOC = /\A("{6}|'{6}|"{3}\n?(.*?)\n?(\s*)"{3}|'{3}\n?(.*?)\n?(\s*)'{3})/m
JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m
OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
WHITESPACE = /\A([ \t]+)/
@@ -38,6 +38,7 @@ module CoffeeScript
MULTILINER = /\n/
COMMENT_CLEANER = /(^\s*#|\n\s*$)/
NO_NEWLINE = /\A([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)\Z/
+ HEREDOC_INDENT = /^\s+/
# Tokens which a regular expression will never immediately follow, but which
# a division operator might.
@@ -50,12 +51,12 @@ module CoffeeScript
# Scan by attempting to match tokens one character at a time. Slow and steady.
def tokenize(code)
- @code = code.chomp # Cleanup code by remove extra line breaks
- @i = 0 # Current character position we're parsing
- @line = 1 # The current line.
- @indent = 0 # The current indent level.
- @indents = [] # The stack of all indent levels we are currently within.
- @tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
+ @code = code.chomp # Cleanup code by remove extra line breaks
+ @i = 0 # Current character position we're parsing
+ @line = 1 # The current line.
+ @indent = 0 # The current indent level.
+ @indents = [] # The stack of all indent levels we are currently within.
+ @tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
while @i < @code.length
@chunk = @code[@i..-1]
extract_next_token
@@ -114,9 +115,10 @@ module CoffeeScript
# 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 = match[2] || match[4]
+ indent = doc.scan(HEREDOC_INDENT).min
+ doc.gsub!(/^#{indent}/, "")
+ doc.gsub!("\n", "\\n")
doc.gsub!('"', '\\"')
token(:STRING, "\"#{doc}\"")
@line += match[1].count("\n")
diff --git a/test/fixtures/execution/test_heredocs.coffee b/test/fixtures/execution/test_heredocs.coffee
index c28ddb5d..b5dcaabd 100644
--- a/test/fixtures/execution/test_heredocs.coffee
+++ b/test/fixtures/execution/test_heredocs.coffee
@@ -25,4 +25,13 @@ a: """
here
"""
-print(a is "out\nhere")
\ No newline at end of file
+print(a is "out\nhere")
+
+
+a: '''
+ a
+ b
+ c
+ '''
+
+print(a is " a\n b\nc")
\ No newline at end of file