mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 11:31:20 -05:00
first, totally broken branch of significant whitespace -- it can handle examples/whitespace.cs though
This commit is contained in:
12
examples/whitespace.cs
Normal file
12
examples/whitespace.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# square: x => x * x
|
||||||
|
|
||||||
|
square: x =>
|
||||||
|
x * x
|
||||||
|
|
||||||
|
elements.each(el =>
|
||||||
|
el.click(event =>
|
||||||
|
el.show()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
a: 5
|
||||||
8
examples/whitespace.js
Normal file
8
examples/whitespace.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
(function(){
|
||||||
|
|
||||||
|
// square: x => x * x
|
||||||
|
var square = function(x) {
|
||||||
|
return x * x;
|
||||||
|
};
|
||||||
|
var a = 5;
|
||||||
|
})();
|
||||||
@@ -15,6 +15,7 @@ token SUPER
|
|||||||
token NEWLINE
|
token NEWLINE
|
||||||
token COMMENT
|
token COMMENT
|
||||||
token JS
|
token JS
|
||||||
|
token INDENT OUTDENT
|
||||||
|
|
||||||
# Declare order of operations.
|
# Declare order of operations.
|
||||||
prechigh
|
prechigh
|
||||||
@@ -32,7 +33,8 @@ prechigh
|
|||||||
right THROW FOR IN WHILE NEW
|
right THROW FOR IN WHILE NEW
|
||||||
left UNLESS IF ELSE
|
left UNLESS IF ELSE
|
||||||
left ":" '||:' '&&:'
|
left ":" '||:' '&&:'
|
||||||
right RETURN
|
right RETURN INDENT
|
||||||
|
left OUTDENT
|
||||||
preclow
|
preclow
|
||||||
|
|
||||||
# We expect 4 shift/reduce errors for optional syntax.
|
# We expect 4 shift/reduce errors for optional syntax.
|
||||||
@@ -84,6 +86,11 @@ rule
|
|||||||
| Comment
|
| Comment
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Block:
|
||||||
|
Expression Terminator { result = Expressions.new([val[0]]) }
|
||||||
|
| INDENT Expressions OUTDENT { result = val[1] }
|
||||||
|
;
|
||||||
|
|
||||||
# All tokens that can terminate an expression.
|
# All tokens that can terminate an expression.
|
||||||
Terminator:
|
Terminator:
|
||||||
"\n"
|
"\n"
|
||||||
@@ -191,14 +198,14 @@ rule
|
|||||||
|
|
||||||
# Function definition.
|
# Function definition.
|
||||||
Code:
|
Code:
|
||||||
ParamList "=>" CodeBody "." { result = CodeNode.new(val[0], val[2]) }
|
ParamList "=>" CodeBody { result = CodeNode.new(val[0], val[2]) }
|
||||||
| "=>" CodeBody "." { result = CodeNode.new([], val[1]) }
|
| "=>" CodeBody { result = CodeNode.new([], val[1]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# The body of a function.
|
# The body of a function.
|
||||||
CodeBody:
|
CodeBody:
|
||||||
/* nothing */ { result = Expressions.new([]) }
|
/* nothing */ { result = Expressions.new([]) }
|
||||||
| Expressions { result = val[0] }
|
| Block { result = val[0] }
|
||||||
;
|
;
|
||||||
|
|
||||||
# The parameters to a function definition.
|
# The parameters to a function definition.
|
||||||
@@ -279,15 +286,15 @@ rule
|
|||||||
|
|
||||||
# Try/catch/finally exception handling blocks.
|
# Try/catch/finally exception handling blocks.
|
||||||
Try:
|
Try:
|
||||||
TRY Expressions Catch "." { result = TryNode.new(val[1], val[2][0], val[2][1]) }
|
TRY Expressions Catch { result = TryNode.new(val[1], val[2][0], val[2][1]) }
|
||||||
| TRY Expressions Catch
|
| TRY Expressions Catch
|
||||||
FINALLY Expressions "." { result = TryNode.new(val[1], val[2][0], val[2][1], val[4]) }
|
FINALLY Block { result = TryNode.new(val[1], val[2][0], val[2][1], val[4]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# A catch clause.
|
# A catch clause.
|
||||||
Catch:
|
Catch:
|
||||||
/* nothing */ { result = [nil, nil] }
|
/* nothing */ { result = [nil, nil] }
|
||||||
| CATCH IDENTIFIER Expressions { result = [val[1], val[2]] }
|
| CATCH IDENTIFIER Block { result = [val[1], val[2]] }
|
||||||
;
|
;
|
||||||
|
|
||||||
# Throw an exception.
|
# Throw an exception.
|
||||||
@@ -302,32 +309,31 @@ rule
|
|||||||
|
|
||||||
# The while loop. (there is no do..while).
|
# The while loop. (there is no do..while).
|
||||||
While:
|
While:
|
||||||
WHILE Expression Then
|
WHILE Expression Then Block { result = WhileNode.new(val[1], val[3]) }
|
||||||
Expressions "." { result = WhileNode.new(val[1], val[3]) }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
# Array comprehensions, including guard and current index.
|
# Array comprehensions, including guard and current index.
|
||||||
For:
|
For:
|
||||||
Expression FOR IDENTIFIER
|
Expression FOR IDENTIFIER
|
||||||
IN PureExpression "." { result = ForNode.new(val[0], val[4], val[2], nil) }
|
IN PureExpression { result = ForNode.new(val[0], val[4], val[2], nil) }
|
||||||
| Expression FOR
|
| Expression FOR
|
||||||
IDENTIFIER "," IDENTIFIER
|
IDENTIFIER "," IDENTIFIER
|
||||||
IN PureExpression "." { result = ForNode.new(val[0], val[6], val[2], nil, val[4]) }
|
IN PureExpression { result = ForNode.new(val[0], val[6], val[2], nil, val[4]) }
|
||||||
| Expression FOR IDENTIFIER
|
| Expression FOR IDENTIFIER
|
||||||
IN PureExpression
|
IN PureExpression
|
||||||
IF Expression "." { result = ForNode.new(val[0], val[4], val[2], val[6]) }
|
IF Expression { result = ForNode.new(val[0], val[4], val[2], val[6]) }
|
||||||
| Expression FOR
|
| Expression FOR
|
||||||
IDENTIFIER "," IDENTIFIER
|
IDENTIFIER "," IDENTIFIER
|
||||||
IN PureExpression
|
IN PureExpression
|
||||||
IF Expression "." { result = ForNode.new(val[0], val[6], val[2], val[8], val[4]) }
|
IF Expression { result = ForNode.new(val[0], val[6], val[2], val[8], val[4]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# Switch/When blocks.
|
# Switch/When blocks.
|
||||||
Switch:
|
Switch:
|
||||||
SWITCH Expression Then
|
SWITCH Expression Then
|
||||||
Whens "." { result = val[3].rewrite_condition(val[1]) }
|
Whens { result = val[3].rewrite_condition(val[1]) }
|
||||||
| SWITCH Expression Then
|
| SWITCH Expression Then
|
||||||
Whens ELSE Expressions "." { result = val[3].rewrite_condition(val[1]).add_else(val[5]) }
|
Whens ELSE Block { result = val[3].rewrite_condition(val[1]).add_else(val[5]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# The inner list of whens.
|
# The inner list of whens.
|
||||||
@@ -338,7 +344,7 @@ rule
|
|||||||
|
|
||||||
# An individual when.
|
# An individual when.
|
||||||
When:
|
When:
|
||||||
WHEN Expression Then Expressions { result = IfNode.new(val[1], val[3]) }
|
WHEN Expression Then Block { result = IfNode.new(val[1], val[3]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# All of the following nutso if-else destructuring is to make the
|
# All of the following nutso if-else destructuring is to make the
|
||||||
@@ -358,8 +364,8 @@ rule
|
|||||||
|
|
||||||
# Terminating else bodies are strictly optional.
|
# Terminating else bodies are strictly optional.
|
||||||
ElseBody
|
ElseBody
|
||||||
"." { result = nil }
|
/* nothing */ { result = nil }
|
||||||
| ELSE Expressions "." { result = val[1] }
|
| ELSE Block { result = val[1] }
|
||||||
;
|
;
|
||||||
|
|
||||||
# All the alternatives for ending an if-else block.
|
# All the alternatives for ending an if-else block.
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ module CoffeeScript
|
|||||||
COMMENT = /\A((#[^\n]*\s*)+)/m
|
COMMENT = /\A((#[^\n]*\s*)+)/m
|
||||||
CODE = /\A(=>)/
|
CODE = /\A(=>)/
|
||||||
REGEX = /\A(\/(.*?)[^\\]\/[imgy]{0,4})/
|
REGEX = /\A(\/(.*?)[^\\]\/[imgy]{0,4})/
|
||||||
|
INDENT = /\A\n( *)/
|
||||||
|
|
||||||
# Token cleaning regexes.
|
# Token cleaning regexes.
|
||||||
JS_CLEANER = /(\A`|`\Z)/
|
JS_CLEANER = /(\A`|`\Z)/
|
||||||
@@ -45,6 +46,8 @@ module CoffeeScript
|
|||||||
@code = code.chomp # Cleanup code by remove extra line breaks
|
@code = code.chomp # Cleanup code by remove extra line breaks
|
||||||
@i = 0 # Current character position we're parsing
|
@i = 0 # Current character position we're parsing
|
||||||
@line = 1 # The current line.
|
@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]
|
@tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
|
||||||
while @i < @code.length
|
while @i < @code.length
|
||||||
@chunk = @code[@i..-1]
|
@chunk = @code[@i..-1]
|
||||||
@@ -62,6 +65,7 @@ module CoffeeScript
|
|||||||
return if js_token
|
return if js_token
|
||||||
return if regex_token
|
return if regex_token
|
||||||
return if comment_token
|
return if comment_token
|
||||||
|
return if indent_token
|
||||||
return if whitespace_token
|
return if whitespace_token
|
||||||
return literal_token
|
return literal_token
|
||||||
end
|
end
|
||||||
@@ -118,6 +122,23 @@ module CoffeeScript
|
|||||||
@i += comment.length
|
@i += comment.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def indent_token
|
||||||
|
return false unless indent = @chunk[INDENT, 1]
|
||||||
|
size = indent.size
|
||||||
|
return literal_token if size == @indent
|
||||||
|
if size > @indent
|
||||||
|
tag = :INDENT
|
||||||
|
@indent = size
|
||||||
|
@indents << @indent
|
||||||
|
else
|
||||||
|
tag = :OUTDENT
|
||||||
|
@indents.pop
|
||||||
|
@indent = @indents.first || 0
|
||||||
|
end
|
||||||
|
@i += (size + 1)
|
||||||
|
token(tag, size)
|
||||||
|
end
|
||||||
|
|
||||||
# Matches and consumes non-meaningful whitespace.
|
# Matches and consumes non-meaningful whitespace.
|
||||||
def whitespace_token
|
def whitespace_token
|
||||||
return false unless whitespace = @chunk[WHITESPACE, 1]
|
return false unless whitespace = @chunk[WHITESPACE, 1]
|
||||||
@@ -182,6 +203,13 @@ module CoffeeScript
|
|||||||
@tokens.pop if last_value == "\n"
|
@tokens.pop if last_value == "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Close up all remaining open blocks.
|
||||||
|
def close_indentation
|
||||||
|
while indent = @indents.pop
|
||||||
|
token(:OUTDENT, @indents.first || 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user