Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coffee Tags #4346

Closed
wants to merge 46 commits into from
Closed
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
deaaaab
add support for CoffeeTags
shreeve Oct 3, 2016
d257482
add compiled files from /lib
shreeve Oct 3, 2016
247f69b
add compiled browser build
shreeve Oct 3, 2016
e05ce00
typo
shreeve Oct 6, 2016
2177aa4
make some trailing commas implicit
shreeve Oct 6, 2016
5b3643f
update compiled file
shreeve Oct 6, 2016
591dc22
support dotted class names
shreeve Oct 7, 2016
7abb41a
compiled files
shreeve Oct 7, 2016
e227da0
remove old debugging statement
shreeve Oct 7, 2016
2e57083
Add @ support: <div.active@menu> yields <div class="active" id="menu">
shreeve Oct 7, 2016
2c8335f
compiled versions
shreeve Oct 7, 2016
607d22a
make some tweaks for Vuejs -- revisit this to keep us generic
shreeve Oct 7, 2016
8905f7e
compiled file
shreeve Oct 7, 2016
046c754
include the simplified version in the comments
shreeve Oct 7, 2016
4c4bc07
make CSX token handling more like JS token
shreeve Oct 7, 2016
6fb7bcd
compiled version
shreeve Oct 7, 2016
b62b851
be more permissive in matching tags
shreeve Oct 8, 2016
ddcf651
more elegant tag parsing and token generation
shreeve Oct 8, 2016
899bc13
compiled files
shreeve Oct 8, 2016
afae4d1
put #id before .classes
shreeve Oct 8, 2016
6dbd4ad
compiled files
shreeve Oct 8, 2016
a05214c
typo
shreeve Oct 8, 2016
4d69839
compiled file
shreeve Oct 8, 2016
203d6e1
use proper syntax
shreeve Oct 8, 2016
bf2f856
compiled file
shreeve Oct 8, 2016
1c17b5a
allow final "!" to indicate unsafe HTML
shreeve Oct 8, 2016
4ea81a0
add support for rawHTML
shreeve Oct 8, 2016
ed4fe15
compiled files
shreeve Oct 8, 2016
189d353
try simpler, generic approach
shreeve Oct 10, 2016
496db51
compiled file
shreeve Oct 10, 2016
5fd3f41
fix math
shreeve Oct 10, 2016
b73bdbb
compiled file
shreeve Oct 10, 2016
10d95d6
back to simplest approach
shreeve Oct 10, 2016
470a899
compiled file
shreeve Oct 10, 2016
394e66a
use h() instead of coffeeTags() -- better or worse?
shreeve Oct 14, 2016
bffc9bc
compiled file
shreeve Oct 14, 2016
f327cd9
wip - for custom render function
shreeve Oct 25, 2016
0169fa6
allow trailing ? (and the original ! too)
shreeve Oct 25, 2016
627cbb7
compiled file
shreeve Oct 25, 2016
9f89946
Add HERETAG support using <*>
shreeve Nov 2, 2016
b082c98
compiled file
shreeve Nov 2, 2016
ad77113
allow <!fooBar> to set custom render function to fooBar()
shreeve Feb 16, 2017
e25efa6
compiled files
shreeve Feb 16, 2017
824728e
Clarify that <!fooBar!> (a bang on both ends) set the custom render f…
shreeve Feb 16, 2017
faafbe5
merge with live
shreeve Feb 16, 2017
757acef
test empty commit to see if both PRs update
shreeve Feb 17, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions extras/coffee-script.js

Large diffs are not rendered by default.

23 changes: 19 additions & 4 deletions lib/coffee-script/lexer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions lib/coffee-script/rewriter.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ exports.Lexer = class Lexer
@numberToken() or
@regexToken() or
@jsToken() or
@ctToken() or
@literalToken()

# Update position
Expand Down Expand Up @@ -235,12 +236,13 @@ exports.Lexer = class Lexer
when '"' then STRING_DOUBLE
when "'''" then HEREDOC_SINGLE
when '"""' then HEREDOC_DOUBLE
when '<*>' then HERETAG_DOUBLE
heredoc = quote.length is 3

{tokens, index: end} = @matchWithInterpolations regex, quote
$ = tokens.length - 1

delimiter = quote.charAt(0)
delimiter = if quote.charAt(0) is '<' then '"' else quote.charAt(0)
if heredoc
# Find the smallest indentation. It will be removed from all lines later.
indent = null
Expand Down Expand Up @@ -287,6 +289,12 @@ exports.Lexer = class Lexer
@token 'JS', (script = match[0])[1...-1], 0, script.length
script.length

# Matches CoffeeTags.
ctToken: ->
return 0 unless @chunk.charAt(0) is '<' and match = CTTOKEN.exec @chunk
@token 'CT', (ct = match[0])[1...-1], 0, ct.length
ct.length

# Matches regular expression literals, as well as multiline extended ones.
# Lexing regular expressions is difficult to distinguish from division, so we
# borrow some basic heuristics from JavaScript and Ruby.
Expand Down Expand Up @@ -883,13 +891,17 @@ MULTI_DENT = /^(?:\n[^\n\S]*)+/

JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/

# CoffeeTags loosely matches <tag.class1.class2@id>
CTTOKEN = /^<[\w\-.@]*[!?]?>/

# String-matching-regexes.
STRING_START = /^(?:'''|"""|'|")/
STRING_START = /^(?:'''|"""|'|"|<\*>)/

STRING_SINGLE = /// ^(?: [^\\'] | \\[\s\S] )* ///
STRING_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | \#(?!\{) )* ///
HEREDOC_SINGLE = /// ^(?: [^\\'] | \\[\s\S] | '(?!'') )* ///
HEREDOC_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | "(?!"") | \#(?!\{) )* ///
HERETAG_DOUBLE = /// ^(?: [^\\<#] | \\[\s\S] | <(?!\*>)| \#(?!\{) )* ///

STRING_OMIT = ///
((?:\\\\)+) # consume (and preserve) an even number of backslashes
Expand Down
29 changes: 28 additions & 1 deletion src/rewriter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class exports.Rewriter
@closeOpenIndexes()
@normalizeLines()
@tagPostfixConditionals()
@adjustCoffeeTags()
@addImplicitBracesAndParens()
@addLocationDataToGeneratedTokens()
@tokens
Expand Down Expand Up @@ -117,6 +118,15 @@ class exports.Rewriter
return yes if @tag(end + 1) is ':'
no

# Returns `yes` if standing in front of something that can be
# implicitly appended to the prior line with a comma.
looksAppendable: (j, stack) ->
if (@looksObjectish(j) or @indexOfTag(j, IMPLICIT_CALL) > -1)
return not @findTagsBackwards(j - 2, ['CLASS', 'EXTENDS', 'IF',
':', 'FINALLY', # should we also add 'TRY'?
'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
no

# Returns `yes` if current line of tokens contain an element of tags on same
# expression level. Stop searching at LINEBREAKS or explicit start of
# containing balanced expression.
Expand All @@ -131,6 +141,18 @@ class exports.Rewriter
i -= 1
@tag(i) in tags

# Adjust token stream so that CoffeeTags look like normal function calls.
adjustCoffeeTags: ->
@scanTokens (token, i, tokens) ->
if token[0] is 'CT'
f = generate 'IDENTIFIER', 'h'; f.spaced = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can’t merge in this PR if what it does is replace this new coffee tag literal with calls to a mysterious h function that is not defined within CoffeeScript. That makes coffee tags dependant on some external library to supply this h function in the global scope.

s = generate 'STRING', "'#{token[1]}'"
c = generate ',', ',' if tokens[i + 1][0] isnt 'TERMINATOR'
tokens.splice i + 0, 1, f, s
tokens.splice i + 2, 0, c if c
return if c then 3 else 2
return 1

# Look for signs of implicit calls and objects in the token stream and
# add them.
addImplicitBracesAndParens: ->
Expand Down Expand Up @@ -194,8 +216,13 @@ class exports.Rewriter
#
# 1. We have seen a `CONTROL` argument on the line.
# 2. The last token before the indent is part of the list below
# 3. We are able to add this token to the prior line with a comma
#
if prevTag not in ['=>', '->', '[', '(', ',', '{', 'TRY', 'ELSE', '=']
if @looksAppendable(i + 1, stack)
tokens.splice i, 0, generate ',', ',' # insert comma before indent
stack.push [tag, i]
return forward(2)
endImplicitCall() while inImplicitCall()
stack.pop() if inImplicitControl()
stack.push [tag, i]
Expand Down Expand Up @@ -242,7 +269,7 @@ class exports.Rewriter
# b: c
#
# Don't accept implicit calls of this type, when on the same line
# as the control strucutures below as that may misinterpret constructs like:
# as the control structures below as that may misinterpret constructs like:
#
# if f
# a: 1
Expand Down