mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
execution tests still pass -- more lexer block insertion and 2 shift/reduces in the grammar now
This commit is contained in:
parent
c822f96145
commit
9a946d2ac5
5 changed files with 30 additions and 25 deletions
|
@ -1,7 +1,7 @@
|
|||
class Parser
|
||||
|
||||
# Declare tokens produced by the lexer
|
||||
token IF ELSE THEN UNLESS
|
||||
token IF ELSE UNLESS
|
||||
token NUMBER STRING REGEX
|
||||
token TRUE FALSE YES NO ON OFF
|
||||
token IDENTIFIER PROPERTY_ACCESS
|
||||
|
@ -32,15 +32,15 @@ prechigh
|
|||
left '.'
|
||||
right INDENT
|
||||
left OUTDENT
|
||||
right THROW FOR IN WHILE WHEN NEW SUPER THEN ELSE
|
||||
right THROW FOR IN WHILE WHEN NEW SUPER ELSE
|
||||
left UNLESS EXTENDS IF
|
||||
left ASSIGN '||=' '&&='
|
||||
right RETURN '=>'
|
||||
preclow
|
||||
|
||||
# We expect 4 shift/reduce errors for optional syntax.
|
||||
# We expect 2 shift/reduce errors for optional syntax.
|
||||
# There used to be 252 -- greatly improved.
|
||||
expect 4
|
||||
expect 2
|
||||
|
||||
rule
|
||||
|
||||
|
@ -344,9 +344,9 @@ rule
|
|||
|
||||
# An individual when.
|
||||
When:
|
||||
WHEN Expression Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
|
||||
| WHEN Expression
|
||||
THEN Expression Terminator { result = IfNode.new(val[1], val[3], nil, {:statement => true}) }
|
||||
WHEN Expression Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
|
||||
| WHEN Expression Block Terminator { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
|
||||
| Comment
|
||||
;
|
||||
|
||||
# All of the following nutso if-else destructuring is to make the
|
||||
|
@ -354,7 +354,6 @@ rule
|
|||
|
||||
IfBlock:
|
||||
IF Expression Block { result = IfNode.new(val[1], val[2]) }
|
||||
| IF Expression THEN Expression { result = IfNode.new(val[1], val[3]) }
|
||||
;
|
||||
|
||||
# An elsif portion of an if-else block.
|
||||
|
|
|
@ -27,7 +27,7 @@ module CoffeeScript
|
|||
COMMENT = /\A((#[^\n]*\s*)+)/m
|
||||
CODE = /\A(=>)/
|
||||
REGEX = /\A(\/(.*?)[^\\]\/[imgy]{0,4})/
|
||||
MULTI_DENT = /\A((\n+([ \t]*(?=\S)))+)/
|
||||
MULTI_DENT = /\A((\n+([ \t]*(?=\S))?)+)/
|
||||
LAST_DENT = /\n+([ \t]*)\Z/
|
||||
|
||||
# Token cleaning regexes.
|
||||
|
@ -47,7 +47,8 @@ module CoffeeScript
|
|||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
SINGLE_LINERS = [:ELSE, "=>"]
|
||||
SINGLE_LINERS = [:ELSE, "=>", :TRY, :FINALLY, :THEN]
|
||||
SINGLE_CLOSERS = ["\n", :CATCH, :FINALLY, :ELSE]
|
||||
|
||||
# The inverse mappings of token pairs we're trying to fix up.
|
||||
INVERSES = {:INDENT => :OUTDENT, :OUTDENT => :INDENT, '(' => ')', ')' => '('}
|
||||
|
@ -257,13 +258,15 @@ module CoffeeScript
|
|||
if SINGLE_LINERS.include?(token[0]) && post[0] != :INDENT
|
||||
line = token[1].line
|
||||
@tokens.insert(i + 1, [:INDENT, Value.new(2, line)])
|
||||
idx = i + 1
|
||||
loop do
|
||||
i += 1
|
||||
if !@tokens[i] || @tokens[i][0] == "\n"
|
||||
@tokens.insert(i, [:OUTDENT, Value.new(2, line)])
|
||||
idx += 1
|
||||
if !@tokens[idx] || SINGLE_CLOSERS.include?(@tokens[idx][0])
|
||||
@tokens.insert(idx, [:OUTDENT, Value.new(2, line)])
|
||||
break
|
||||
end
|
||||
end
|
||||
@tokens.delete_at(i) if token[0] == :THEN
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,7 @@ result: try
|
|||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
print(result)
|
||||
|
||||
result2: try nonexistent * missing catch error then true
|
||||
|
||||
print(result is true and result2 is true)
|
|
@ -8,7 +8,7 @@ class ParserTest < Test::Unit::TestCase
|
|||
|
||||
def test_parsing_an_empty_string
|
||||
nodes = @par.parse("")
|
||||
assert nodes.is_a? Expressions
|
||||
assert nodes.is_a?(Expressions)
|
||||
assert nodes.expressions.empty?
|
||||
end
|
||||
|
||||
|
@ -16,14 +16,14 @@ class ParserTest < Test::Unit::TestCase
|
|||
nodes = @par.parse("a: 'one'").expressions
|
||||
assert nodes.length == 1
|
||||
assign = nodes.first
|
||||
assert assign.is_a? AssignNode
|
||||
assert assign.is_a?(AssignNode)
|
||||
assert assign.variable.literal == 'a'
|
||||
end
|
||||
|
||||
def test_parsing_an_object_literal
|
||||
nodes = @par.parse("{one : 1\ntwo : 2}").expressions
|
||||
obj = nodes.first.literal
|
||||
assert obj.is_a? ObjectNode
|
||||
assert obj.is_a?(ObjectNode)
|
||||
assert obj.properties.first.variable.literal.value == "one"
|
||||
assert obj.properties.last.variable.literal.value == "two"
|
||||
end
|
||||
|
@ -32,21 +32,21 @@ class ParserTest < Test::Unit::TestCase
|
|||
code = @par.parse("x, y => x * y").expressions.first
|
||||
assert code.params == ['x', 'y']
|
||||
body = code.body.expressions.first
|
||||
assert body.is_a? OpNode
|
||||
assert body.is_a?(OpNode)
|
||||
assert body.operator == '*'
|
||||
end
|
||||
|
||||
def test_parsing_if_statement
|
||||
the_if = @par.parse("clap_your_hands() if happy").expressions.first
|
||||
assert the_if.is_a? IfNode
|
||||
assert the_if.is_a?(IfNode)
|
||||
assert the_if.condition.literal == 'happy'
|
||||
assert the_if.body.is_a? CallNode
|
||||
assert the_if.body.is_a?(CallNode)
|
||||
assert the_if.body.variable.literal == 'clap_your_hands'
|
||||
end
|
||||
|
||||
def test_parsing_array_comprehension
|
||||
nodes = @par.parse("i for x, i in [10, 9, 8, 7, 6, 5] when i % 2 is 0").expressions
|
||||
assert nodes.first.is_a? ForNode
|
||||
assert nodes.first.is_a?(ForNode)
|
||||
assert nodes.first.body.literal == 'i'
|
||||
assert nodes.first.filter.operator == '==='
|
||||
assert nodes.first.source.literal.objects.last.literal.value == "5"
|
||||
|
@ -54,7 +54,7 @@ class ParserTest < Test::Unit::TestCase
|
|||
|
||||
def test_parsing_comment
|
||||
nodes = @par.parse("a: 1\n# comment\nb: 2").expressions
|
||||
assert nodes[1].is_a? CommentNode
|
||||
assert nodes[1].is_a?(CommentNode)
|
||||
end
|
||||
|
||||
def test_parsing_inner_comments
|
||||
|
@ -65,9 +65,9 @@ class ParserTest < Test::Unit::TestCase
|
|||
def test_parsing
|
||||
nodes = @par.parse(File.read('test/fixtures/generation/each.coffee'))
|
||||
assign = nodes.expressions[1]
|
||||
assert assign.is_a? AssignNode
|
||||
assert assign.is_a?(AssignNode)
|
||||
assert assign.variable.literal == '_'
|
||||
assert assign.value.is_a? CodeNode
|
||||
assert assign.value.is_a?(CodeNode)
|
||||
assert assign.value.params == ['obj', 'iterator', 'context']
|
||||
assert nodes.compile == File.read('test/fixtures/generation/each.js')
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue