parser-2.7.0.2/ 0000755 0000041 0000041 00000000000 13617025313 013205 5 ustar www-data www-data parser-2.7.0.2/.travis.yml 0000644 0000041 0000041 00000002614 13617025313 015321 0 ustar www-data www-data dist: trusty
language: ruby
matrix:
include:
- name: 2.0.0 / Parser tests
rvm: 2.0.0
script: bundle exec rake test_cov
- name: 2.2.10 / Parser tests
rvm: 2.2.10
script: bundle exec rake test_cov
- name: 2.3.8 / Parser tests
rvm: 2.3.8
script: bundle exec rake test_cov
- name: 2.4.9 / Parser tests
rvm: 2.4.9
script: bundle exec rake test_cov
- name: 2.5.7 / Parser tests
rvm: 2.5.7
script: bundle exec rake test_cov
- name: 2.6.5 / Parser tests
rvm: 2.6.5
script: bundle exec rake test_cov
- name: 2.7.0 / Parser tests
rvm: 2.7.0
script: bundle exec rake test_cov
- name: ruby-head / Parser tests
rvm: ruby-head
script: bundle exec rake test_cov
- name: jruby-9.1.15.0 / Parser tests
rvm: jruby-9.1.15.0
script: bundle exec rake test_cov
- name: rbx-2 / Parser tests
rvm: rbx-2
script: bundle exec rake test_cov
- name: 2.5.7 / Rubocop tests
rvm: 2.5.7
script: ./ci/run_rubocop_specs
- name: 2.6.5 / Rubocop tests
rvm: 2.6.5
script: ./ci/run_rubocop_specs
- name: 2.7.0 / Rubocop tests
rvm: 2.7.0
script: ./ci/run_rubocop_specs
allow_failures:
- rvm: ruby-head
- rvm: rbx-2
- script: ./ci/run_rubocop_specs
before_install:
- gem install bundler -v '< 2'
- bundle --version
- gem --version
parser-2.7.0.2/test/ 0000755 0000041 0000041 00000000000 13617025313 014164 5 ustar www-data www-data parser-2.7.0.2/test/test_source_range.rb 0000644 0000041 0000041 00000011255 13617025313 020230 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestSourceRange < Minitest::Test
def setup
@buf = Parser::Source::Buffer.new('(string)')
@buf.source = "foobar\nbaz"
@sr1_3 = Parser::Source::Range.new(@buf, 1, 3)
@sr2_2 = Parser::Source::Range.new(@buf, 2, 2)
@sr3_3 = Parser::Source::Range.new(@buf, 3, 3)
@sr2_6 = Parser::Source::Range.new(@buf, 2, 6)
@sr5_8 = Parser::Source::Range.new(@buf, 5, 8)
@sr5_7 = Parser::Source::Range.new(@buf, 5, 7)
@sr6_7 = Parser::Source::Range.new(@buf, 6, 7)
end
def test_initialize
assert_equal 1, @sr1_3.begin_pos
assert_equal 3, @sr1_3.end_pos
assert @sr1_3.frozen?
end
def test_size
assert_equal 4, @sr2_6.size
end
def test_bad_size
assert_raises ArgumentError do
Parser::Source::Range.new(@buf, 2, 1)
end
end
def test_join
sr = @sr1_3.join(@sr5_8)
assert_equal 1, sr.begin_pos
assert_equal 8, sr.end_pos
end
def test_intersect
assert_equal 2, @sr1_3.intersect(@sr2_6).begin_pos
assert_equal 3, @sr1_3.intersect(@sr2_6).end_pos
assert_equal 5, @sr2_6.intersect(@sr5_8).begin_pos
assert_equal 6, @sr2_6.intersect(@sr5_8).end_pos
assert @sr1_3.intersect(@sr5_8) == nil
assert_equal 2, @sr1_3.intersect(@sr2_2).begin_pos
assert_equal 2, @sr1_3.intersect(@sr2_2).end_pos
assert_equal 2, @sr2_2.intersect(@sr2_2).begin_pos
assert_equal 2, @sr2_2.intersect(@sr2_2).end_pos
end
def test_overlaps
assert !@sr1_3.overlaps?(@sr5_8)
assert @sr1_3.overlaps?(@sr2_6)
assert @sr2_6.overlaps?(@sr5_8)
assert @sr1_3.overlaps?(@sr2_2)
assert !@sr2_6.overlaps?(@sr2_2)
assert @sr2_2.overlaps?(@sr2_2)
end
def check_relationship(relationship, sr1, sr2, reflexive_relationship = relationship)
# Double check equality
assert_equal true, sr1 == sr1.dup
assert_equal true, sr1 != sr2
# Check relationships and reflexivity
assert_equal true, sr1.send(relationship, sr2)
assert_equal true, sr2.send(reflexive_relationship, sr1)
# Check it's not true for itself
assert_equal false, sr1.send(relationship, sr1)
# Check other relationships return false
others = %i[disjoint? crossing? contains? contained?] - [relationship, reflexive_relationship]
others.each do |other_rel|
assert_equal false, sr1.send(other_rel, sr2), other_rel
assert_equal false, sr2.send(other_rel, sr1), other_rel
end
end
def test_disjoint
check_relationship(:disjoint?, @sr1_3, @sr5_8)
check_relationship(:disjoint?, @sr2_2, @sr2_6)
check_relationship(:disjoint?, @sr2_2, @sr3_3)
check_relationship(:disjoint?, @sr2_6, @sr6_7)
end
def test_crossing
check_relationship(:crossing?, @sr1_3, @sr2_6)
end
def test_containment
check_relationship(:contained?, @sr2_2, @sr1_3, :contains?)
check_relationship(:contained?, @sr5_7, @sr5_8, :contains?)
check_relationship(:contained?, @sr6_7, @sr5_8, :contains?)
end
def test_order
assert_equal 0, @sr1_3 <=> @sr1_3
assert_equal -1, @sr1_3 <=> @sr5_8
assert_equal -1, @sr2_2 <=> @sr2_6
assert_equal +1, @sr2_6 <=> @sr2_2
assert_equal -1, @sr1_3 <=> @sr2_6
assert_equal +1, @sr2_2 <=> @sr1_3
assert_equal -1, @sr1_3 <=> @sr2_2
assert_equal -1, @sr5_7 <=> @sr5_8
assert_nil @sr1_3 <=> Parser::Source::Range.new(@buf.dup, 1, 3)
assert_nil @sr1_3 <=> 4
end
def test_empty
assert !@sr1_3.empty?
assert @sr2_2.empty?
end
def test_line
sr = Parser::Source::Range.new(@buf, 7, 8)
assert_equal 2, sr.line
end
def test_source_line
sr = Parser::Source::Range.new(@buf, 7, 8)
assert_equal 'baz', sr.source_line
end
def test_columns
sr = Parser::Source::Range.new(@buf, 7, 8)
assert_equal 0, sr.begin.column
assert_equal 1, sr.end.column
assert_equal 0...1, sr.column_range
end
def test_begin_end
sr_beg = @sr2_6.begin
assert_equal 2, sr_beg.begin_pos
assert_equal 2, sr_beg.end_pos
sr_end = @sr2_6.end
assert_equal 6, sr_end.begin_pos
assert_equal 6, sr_end.end_pos
end
def test_source
sr = Parser::Source::Range.new(@buf, 0, 3)
assert_equal 'foo', sr.source
sr_multi = Parser::Source::Range.new(@buf, 0, 10)
assert_equal "foobar\nbaz", sr_multi.source
end
def test_is?
sr = Parser::Source::Range.new(@buf, 0, 3)
assert sr.is?('foo')
refute sr.is?('bar')
end
def test_to_s
sr = Parser::Source::Range.new(@buf, 8, 9)
assert_equal '(string):2:2', sr.to_s
end
def test_with
sr2 = @sr1_3.with(begin_pos: 2)
sr3 = @sr1_3.with(end_pos: 4)
assert_equal 2, sr2.begin_pos
assert_equal 3, sr2.end_pos
assert_equal 1, sr3.begin_pos
assert_equal 4, sr3.end_pos
end
end
parser-2.7.0.2/test/parse_helper.rb 0000644 0000041 0000041 00000022170 13617025313 017164 0 ustar www-data www-data # frozen_string_literal: true
module ParseHelper
include AST::Sexp
require 'parser/all'
require 'parser/macruby'
require 'parser/rubymotion'
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 mac ios)
def setup
@diagnostics = []
super if defined?(super)
end
def parser_for_ruby_version(version)
case version
when '1.8' then parser = Parser::Ruby18.new
when '1.9' then parser = Parser::Ruby19.new
when '2.0' then parser = Parser::Ruby20.new
when '2.1' then parser = Parser::Ruby21.new
when '2.2' then parser = Parser::Ruby22.new
when '2.3' then parser = Parser::Ruby23.new
when '2.4' then parser = Parser::Ruby24.new
when '2.5' then parser = Parser::Ruby25.new
when '2.6' then parser = Parser::Ruby26.new
when '2.7' then parser = Parser::Ruby27.new
when 'mac' then parser = Parser::MacRuby.new
when 'ios' then parser = Parser::RubyMotion.new
else raise "Unrecognized Ruby version #{version}"
end
parser.diagnostics.consumer = lambda do |diagnostic|
@diagnostics << diagnostic
end
parser
end
def with_versions(versions)
(versions & ALL_VERSIONS).each do |version|
@diagnostics.clear
parser = parser_for_ruby_version(version)
yield version, parser
end
end
def assert_source_range(begin_pos, end_pos, range, version, what)
assert range.is_a?(Parser::Source::Range),
"(#{version}) #{range.inspect}.is_a?(Source::Range) for #{what}"
assert_equal begin_pos, range.begin_pos,
"(#{version}) begin of #{what}"
assert_equal end_pos, range.end_pos,
"(#{version}) end of #{what}"
end
# Use like this:
# ~~~
# assert_parses(
# s(:send, s(:lit, 10), :+, s(:lit, 20))
# %q{10 + 20},
# %q{~~~~~~~ expression
# | ^ operator
# | ~~ expression (lit)
# },
# %w(1.8 1.9) # optional
# )
# ~~~
def assert_parses(ast, code, source_maps='', versions=ALL_VERSIONS)
with_versions(versions) do |version, parser|
try_parsing(ast, code, parser, source_maps, version)
end
# Also try parsing with lexer set to use UTF-32LE internally
with_versions(versions) do |version, parser|
parser.instance_eval { @lexer.force_utf32 = true }
try_parsing(ast, code, parser, source_maps, version)
end
end
def try_parsing(ast, code, parser, source_maps, version)
source_file = Parser::Source::Buffer.new('(assert_parses)')
source_file.source = code
begin
parsed_ast = parser.parse(source_file)
rescue => exc
backtrace = exc.backtrace
Exception.instance_method(:initialize).bind(exc).
call("(#{version}) #{exc.message}")
exc.set_backtrace(backtrace)
raise
end
if ast.nil?
assert_nil parsed_ast, "(#{version}) AST equality"
return
end
assert_equal ast, parsed_ast,
"(#{version}) AST equality"
parse_source_map_descriptions(source_maps) \
do |begin_pos, end_pos, map_field, ast_path, line|
astlet = traverse_ast(parsed_ast, ast_path)
if astlet.nil?
# This is a testsuite bug.
raise "No entity with AST path #{ast_path} in #{parsed_ast.inspect}"
end
assert astlet.frozen?
assert astlet.location.respond_to?(map_field),
"(#{version}) #{astlet.location.inspect}.respond_to?(#{map_field.inspect}) for:\n#{parsed_ast.inspect}"
range = astlet.location.send(map_field)
assert_source_range(begin_pos, end_pos, range, version, line.inspect)
end
assert parser.instance_eval { @lexer }.cmdarg.empty?,
"(#{version}) expected cmdarg to be empty after parsing"
assert_equal 0, parser.instance_eval { @lexer.instance_eval { @paren_nest } },
"(#{version}) expected paren_nest to be 0 after parsing"
end
# Use like this:
# ~~~
# assert_diagnoses(
# [:warning, :ambiguous_prefix, { prefix: '*' }],
# %q{foo *bar},
# %q{ ^ location
# | ~~~ highlights (0)})
# ~~~
def assert_diagnoses(diagnostic, code, source_maps='', versions=ALL_VERSIONS)
with_versions(versions) do |version, parser|
source_file = Parser::Source::Buffer.new('(assert_diagnoses)')
source_file.source = code
begin
parser = parser.parse(source_file)
rescue Parser::SyntaxError
# do nothing; the diagnostic was reported
end
assert_equal 1, @diagnostics.count,
"(#{version}) emits a single diagnostic, not\n" \
"#{@diagnostics.map(&:render).join("\n")}"
emitted_diagnostic = @diagnostics.first
level, reason, arguments = diagnostic
arguments ||= {}
message = Parser::MESSAGES[reason] % arguments
assert_equal level, emitted_diagnostic.level
assert_equal reason, emitted_diagnostic.reason
assert_equal arguments, emitted_diagnostic.arguments
assert_equal message, emitted_diagnostic.message
parse_source_map_descriptions(source_maps) \
do |begin_pos, end_pos, map_field, ast_path, line|
case map_field
when 'location'
assert_source_range begin_pos, end_pos,
emitted_diagnostic.location,
version, 'location'
when 'highlights'
index = ast_path.first.to_i
assert_source_range begin_pos, end_pos,
emitted_diagnostic.highlights[index],
version, "#{index}th highlight"
else
raise "Unknown diagnostic range #{map_field}"
end
end
end
end
# Use like this:
# ~~~
# assert_diagnoses_many(
# [
# [:warning, :ambiguous_literal],
# [:error, :unexpected_token, { :token => :tLCURLY }]
# ],
# %q{m /foo/ {}},
# SINCE_2_4)
# ~~~
def assert_diagnoses_many(diagnostics, code, versions=ALL_VERSIONS)
with_versions(versions) do |version, parser|
source_file = Parser::Source::Buffer.new('(assert_diagnoses_many)')
source_file.source = code
begin
parser = parser.parse(source_file)
rescue Parser::SyntaxError
# do nothing; the diagnostic was reported
end
assert_equal diagnostics.count, @diagnostics.count
diagnostics.zip(@diagnostics) do |expected_diagnostic, actual_diagnostic|
level, reason, arguments = expected_diagnostic
arguments ||= {}
message = Parser::MESSAGES[reason] % arguments
assert_equal level, actual_diagnostic.level
assert_equal reason, actual_diagnostic.reason
assert_equal arguments, actual_diagnostic.arguments
assert_equal message, actual_diagnostic.message
end
end
end
def refute_diagnoses(code, versions=ALL_VERSIONS)
with_versions(versions) do |version, parser|
source_file = Parser::Source::Buffer.new('(refute_diagnoses)')
source_file.source = code
begin
parser = parser.parse(source_file)
rescue Parser::SyntaxError
# do nothing; the diagnostic was reported
end
assert_empty @diagnostics,
"(#{version}) emits no diagnostics, not\n" \
"#{@diagnostics.map(&:render).join("\n")}"
end
end
def assert_context(context, code, versions=ALL_VERSIONS)
with_versions(versions) do |version, parser|
source_file = Parser::Source::Buffer.new('(assert_context)')
source_file.source = code
begin
parser.parse(source_file)
rescue Parser::SyntaxError
# do nothing; the diagnostic was reported
end
assert_equal parser.context.stack, context, "(#{version}) parsing context"
end
end
SOURCE_MAP_DESCRIPTION_RE =
/(?x)
^(?# $1 skip) ^(\s*)
(?# $2 highlight) ([~\^]+)
\s+
(?# $3 source_map_field) ([a-z_]+)
(?# $5 ast_path) (\s+\(([a-z_.\/0-9]+)\))?
$/
def parse_source_map_descriptions(descriptions)
unless block_given?
return to_enum(:parse_source_map_descriptions, descriptions)
end
descriptions.each_line do |line|
# Remove leading " |", if it exists.
line = line.sub(/^\s*\|/, '').rstrip
next if line.empty?
if (match = SOURCE_MAP_DESCRIPTION_RE.match(line))
begin_pos = match[1].length
end_pos = begin_pos + match[2].length
source_map_field = match[3]
if match[5]
ast_path = match[5].split('.')
else
ast_path = []
end
yield begin_pos, end_pos, source_map_field, ast_path, line
else
raise "Cannot parse source map description line: #{line.inspect}."
end
end
end
def traverse_ast(ast, path)
path.inject(ast) do |astlet, path_component|
# Split "dstr/2" to :dstr and 1
type_str, index_str = path_component.split('/')
type = type_str.to_sym
if index_str.nil?
index = 0
else
index = index_str.to_i - 1
end
matching_children = \
astlet.children.select do |child|
AST::Node === child && child.type == type
end
matching_children[index]
end
end
end
parser-2.7.0.2/test/test_diagnostic.rb 0000644 0000041 0000041 00000005207 13617025313 017700 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestDiagnostic < Minitest::Test
def setup
@buffer = Parser::Source::Buffer.new('(string)')
@buffer.source = 'if (this is some bad code + bugs)'
@range1 = Parser::Source::Range.new(@buffer, 0, 2) # if
@range2 = Parser::Source::Range.new(@buffer, 4, 8) # this
end
def test_verifies_levels
error = assert_raises ArgumentError do
Parser::Diagnostic.new(:foobar, :escape_eof, {}, @range1)
end
assert_match /level/, error.message
end
def test_freezes
string = 'foo'.dup
highlights = [@range2]
diag = Parser::Diagnostic.new(:error, :escape_eof, @range1, highlights)
assert diag.frozen?
assert diag.arguments.frozen?
assert diag.highlights.frozen?
refute string.frozen?
refute highlights.frozen?
end
def test_render
location = Parser::Source::Range.new(@buffer, 26, 27)
highlights = [
Parser::Source::Range.new(@buffer, 21, 25),
Parser::Source::Range.new(@buffer, 28, 32)
]
diag = Parser::Diagnostic.new(:error, :unexpected, { :character => '+' },
location, highlights)
assert_equal([
"(string):1:27: error: unexpected `+'",
'(string):1: if (this is some bad code + bugs)',
'(string):1: ~~~~ ^ ~~~~ '
], diag.render)
end
def test_multiline_render
@buffer = Parser::Source::Buffer.new('(string)')
@buffer.source = "abc abc abc\ndef def def\nghi ghi ghi\n"
location = Parser::Source::Range.new(@buffer, 4, 27)
highlights = [
Parser::Source::Range.new(@buffer, 0, 3),
Parser::Source::Range.new(@buffer, 28, 31)
]
diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'ghi' },
location, highlights)
assert_equal([
"(string):1:5-3:3: error: unexpected token ghi",
'(string):1: abc abc abc',
'(string):1: ~~~ ^~~~~~~...',
'(string):3: ghi ghi ghi',
'(string):3: ~~~ ~~~ '
], diag.render)
end
def test_bug_error_on_newline
# regression test; see GitHub issue 273
source = <<-CODE
{
foo: ->() # I forgot my brace
}
}
CODE
@buffer = Parser::Source::Buffer.new('(string)')
@buffer.source = source
location = Parser::Source::Range.new(@buffer, 33, 34)
diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'tNL' },
location)
assert_equal([
'(string):2:32: error: unexpected token tNL',
'(string):2: foo: ->() # I forgot my brace',
'(string):2: ^'
], diag.render)
end
end
parser-2.7.0.2/test/helper.rb 0000644 0000041 0000041 00000002440 13617025313 015770 0 ustar www-data www-data # frozen_string_literal: true
require 'tempfile'
require 'minitest/test'
require 'simplecov'
if ENV.include?('COVERAGE') && SimpleCov.usable?
require_relative 'racc_coverage_helper'
RaccCoverage.start(
%w(
ruby18.y
ruby19.y
ruby20.y
ruby21.y
ruby22.y
ruby23.y
ruby24.y
ruby25.y
ruby26.y
ruby27.y
),
File.expand_path('../../lib/parser', __FILE__))
# Report results faster.
at_exit { RaccCoverage.stop }
SimpleCov.start do
self.formatter = SimpleCov::Formatter::MultiFormatter[
SimpleCov::Formatter::HTMLFormatter,
]
add_group 'Grammars' do |source_file|
source_file.filename =~ %r{\.y$}
end
# Exclude the testsuite itself.
add_filter '/test/'
# Exclude generated files.
add_filter do |source_file|
source_file.filename =~ %r{/lib/parser/(lexer|ruby\d+|macruby|rubymotion)\.rb$}
end
end
end
# minitest/autorun must go after SimpleCov to preserve
# correct order of at_exit hooks.
require 'minitest/autorun'
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
require 'parser'
class Parser::AST::Node
def initialize(type, *)
raise "Type #{type} missing from Parser::Meta::NODE_TYPES" unless Parser::Meta::NODE_TYPES.include?(type)
super
end
end
parser-2.7.0.2/test/test_diagnostic_engine.rb 0000644 0000041 0000041 00000002571 13617025313 021226 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestDiagnosticEngine < Minitest::Test
def setup
@buffer = Parser::Source::Buffer.new('(source)')
@buffer.source = 'foobar'
@engine = Parser::Diagnostic::Engine.new
@queue = []
@engine.consumer = lambda { |diag| @queue << diag }
end
def test_process_warnings
warn = Parser::Diagnostic.new(:warning, :invalid_escape, @buffer, 1..2)
@engine.process(warn)
assert_equal [warn], @queue
end
def test_ignore_warnings
@engine.ignore_warnings = true
warn = Parser::Diagnostic.new(:warning, :invalid_escape, @buffer, 1..2)
@engine.process(warn)
assert_equal [], @queue
end
def test_all_errors_are_fatal
@engine.all_errors_are_fatal = true
error = Parser::Diagnostic.new(:error, :invalid_escape, @buffer, 1..2)
err = assert_raises Parser::SyntaxError do
@engine.process(error)
end
assert_equal error, err.diagnostic
assert_equal [error], @queue
end
def test_all_errors_are_collected
error = Parser::Diagnostic.new(:error, :invalid_escape, @buffer, 1..2)
@engine.process(error)
assert_equal [error], @queue
end
def test_fatal_error
fatal = Parser::Diagnostic.new(:fatal, :invalid_escape, @buffer, 1..2)
assert_raises Parser::SyntaxError do
@engine.process(fatal)
end
assert_equal [fatal], @queue
end
end
parser-2.7.0.2/test/test_source_rewriter.rb 0000644 0000041 0000041 00000033122 13617025313 020774 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestSourceRewriter < Minitest::Test
def setup
@buf = Parser::Source::Buffer.new('(rewriter)')
@buf.source = 'foo bar baz'
Parser::Source::Rewriter.warned_of_deprecation = true
@rewriter = Parser::Source::Rewriter.new(@buf)
end
def range(from, len)
Parser::Source::Range.new(@buf, from, from + len)
end
def test_remove
assert_equal 'foo baz',
@rewriter.
remove(range(4, 3)).
process
end
def test_insert_before
assert_equal 'foo quux bar baz',
@rewriter.
insert_before(range(4, 3), 'quux ').
process
end
def test_insert_after
assert_equal 'foo bar quux baz',
@rewriter.
insert_after(range(4, 3), ' quux').
process
end
def test_replace
assert_equal 'foo quux baz',
@rewriter.
replace(range(4, 3), 'quux').
process
end
def test_composing_asc
assert_equal 'foo---bar---baz',
@rewriter.
replace(range(3, 1), '---').
replace(range(7, 1), '---').
process
end
def test_composing_desc
assert_equal 'foo---bar---baz',
@rewriter.
replace(range(7, 1), '---').
replace(range(3, 1), '---').
process
end
#
# Merging/clobbering of overlapping edits
#
def test_insertion_just_before_replace
assert_equal 'foostrawberry jam---bar baz',
@rewriter.
replace(range(3, 1), '---').
insert_before(range(3, 1), 'strawberry jam').
process
end
def test_insertion_just_after_replace
assert_equal 'foo---strawberry jam baz',
@rewriter.
replace(range(3, 4), '---').
insert_after(range(3, 4), 'strawberry jam').
process
end
def test_insertion_just_before_remove
assert_equal 'foostrawberry jambar baz',
@rewriter.
remove(range(3, 1)).
insert_before(range(3, 1), 'strawberry jam').
process
end
def test_insertion_just_after_remove
assert_equal 'foostrawberry jam baz',
@rewriter.
remove(range(3, 4)).
insert_after(range(3, 4), 'strawberry jam').
process
end
def test_insertion_just_before_replace_at_buffer_start
assert_equal 'strawberry jam--- bar baz',
@rewriter.
replace(range(0, 3), '---').
insert_before(range(0, 1), 'strawberry jam').
process
end
def test_insertion_just_after_replace_at_buffer_end
assert_equal 'foo bar ---strawberry jam',
@rewriter.
replace(range(8, 3), '---').
insert_after(range(9, 2), 'strawberry jam').
process
end
def test_insertion_just_before_remove_at_buffer_start
assert_equal 'strawberry bar baz',
@rewriter.
remove(range(0, 3)).
insert_before(range(0, 1), 'strawberry').
process
end
def test_insertion_just_after_remove_at_buffer_end
assert_equal 'foo bar strawberry',
@rewriter.
remove(range(8, 3)).
insert_after(range(10, 1), 'strawberry').
process
end
def test_multiple_insertions_at_same_location_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_before(range(0, 11), '<').
insert_after( range(0, 11), '>').
insert_before(range(0, 7), '(')
end
end
def test_intentional_multiple_insertions_at_same_location
assert_equal 'foo [(bar)] baz',
@rewriter.
insert_before_multi(range(4, 0), '(').
insert_after_multi(range(7, 0), ')').
insert_before_multi(range(4, 0), '[').
insert_after_multi(range(7, 0), ']').
process
end
def test_insertion_within_replace_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(3, 2), '<').
insert_after(range(3, 1), '>')
end
end
def test_insertion_within_remove_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
remove(range(3, 2)).
insert_after(range(3, 1), '>')
end
end
def test_replace_overlapping_insertion_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_after(range(3, 1), '>').
replace(range(3, 2), '<')
end
end
def test_remove_overlapping_insertion_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_after(range(3, 1), '>').
remove(range(3, 2))
end
end
def test_multi_insertion_within_replace_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(3, 2), '<').
insert_after_multi(range(3, 1), '>')
end
end
def test_multi_insertion_within_remove_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
remove(range(3, 2)).
insert_after_multi(range(3, 1), '>')
end
end
def test_replace_overlapping_multi_insertion_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_after_multi(range(3, 1), '>').
replace(range(3, 2), '<')
end
end
def test_remove_overlapping_multi_insertion_clobber
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_after_multi(range(3, 1), '>').
remove(range(3, 2))
end
end
def test_insertion_on_merged_insertion_clobber
# 2 insertions at the same point clobber each other, even if the 1st one
# was merged with an adjacent edit, and even if the same text is being
# inserted
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
insert_before(range(3, 1), '>').
remove(range(3, 2)).
insert_after(range(2, 1), '>')
end
end
def test_insertion_merge_with_overlapping_replace
assert_equal 'fo abc bar baz',
@rewriter.
insert_before(range(3, 1), 'abc').
replace(range(2, 2), ' abc ').
process
end
def test_replace_merge_with_overlapped_insertion
assert_equal 'fo abc bar baz',
@rewriter.
replace(range(2, 2), ' abc ').
insert_before(range(3, 1), 'abc').
process
end
def test_replace_same_begin_larger_than_replaced_range_matching
assert_equal 'foo supercalifragilistic baz',
@rewriter.
replace(range(4, 3), 'super').
replace(range(4, 3), 'supercalifragilistic').
process
end
def test_replace_same_begin_larger_than_replaced_range_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(4, 3), 'super!').
replace(range(4, 3), 'supercalifragilistic')
end
end
def test_overlapping_replace_left_smaller_than_replaced_matching
assert_equal 'superbaz',
@rewriter.
replace(range(0, 7), 'super').
replace(range(2, 6), 'per').
process
end
def test_overlapping_replace_left_smaller_than_replaced_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(0, 7), 'super').
replace(range(2, 8), 'perk')
end
end
def test_overlapping_replace_left_larger_right_smaller_matching
assert_equal 'foods baz',
@rewriter.
replace(range(1, 3), 'oods ').
replace(range(3, 6), 'ds b').
process
end
def test_overlapping_replace_left_larger_right_larger_matching
assert_equal 'foods abcdefghijklm',
@rewriter.
replace(range(1, 3), 'oods ').
replace(range(3, 8), 'ds abcdefghijklm').
process
end
def test_overlapping_replace_left_larger_right_smaller_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(1, 3), 'oods ').
replace(range(3, 6), 'ds')
end
end
def test_overlapping_replace_left_larger_right_larger_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(1, 3), 'oods b').
replace(range(3, 8), 'ds abcdefghijklm')
end
end
def test_subsuming_replace_both_smaller_matching
assert_equal 'food baz',
@rewriter.
replace(range(0, 7), 'food').
replace(range(3, 3), 'd').
process
end
def test_subsuming_replace_both_smaller_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(0, 7), 'foo').
replace(range(3, 3), 'd')
end
end
def test_subsuming_replace_both_larger_matching
assert_equal 'foo barr baz',
@rewriter.
replace(range(0, 7), 'foo barr').
replace(range(3, 3), ' bar').
process
end
def test_subsuming_replace_both_larger_non_matching
silence_diagnostics
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(0, 7), 'foo barr').
replace(range(3, 3), ' bar ')
end
end
def test_replaced_ranges_merge_when_furthest_right_range_is_not_furthest_left
# regression test; previously, when actions were merged, the resulting
# replaced range could be too small sometimes
assert_equal 'foo_***_***',
@rewriter.
replace(range(3, 1), '_').
replace(range(7, 1), '_').
replace(range(4, 7), '***_***').
process
end
def test_clobber
diagnostics = []
@rewriter.diagnostics.consumer = lambda do |diag|
diagnostics << diag
end
assert_raises Parser::ClobberingError do
@rewriter.
replace(range(3, 1), '---').
remove(range(3, 1))
end
assert_equal 2, diagnostics.count
assert_equal :error, diagnostics.first.level
assert_equal 'cannot remove 1 character(s)',
diagnostics.first.message
assert_equal range(3, 1), diagnostics.first.location
assert_equal :note, diagnostics.last.level
assert_equal "clobbered by: replace 1 character(s) with \"---\"",
diagnostics.last.message
assert_equal range(3, 1), diagnostics.last.location
end
def test_clobbering_error_backward_compatibility
silence_diagnostics
rescued = false
# We use begin..rescue..end here rather than #assert_raises
# since #assert_raises expects exact error class.
begin
@rewriter.
replace(range(3, 1), '---').
remove(range(3, 1))
rescue RuntimeError => error
rescued = true if error.message.include?('clobber')
end
assert rescued
end
def test_crossing_delete
assert_equal 'faz',
@rewriter.
remove(range(1, 4)).
remove(range(6, 3)).
remove(range(4, 3)).
process
end
def test_overlapping_replace
assert_equal 'flippin flyin flapjackz',
@rewriter.
replace(range(1, 4), 'lippin f').
replace(range(4, 4), 'pin flyin flap').
replace(range(7, 3), ' flyin flapjack').
process
end
def test_subsuming_delete
assert_equal 'foo',
@rewriter.
remove(range(6, 3)).
remove(range(7, 2)).
remove(range(3, 8)).
process
end
def test_subsuming_replace
assert_equal 'freebie',
@rewriter.
replace(range(3, 3), 'ebi').
replace(range(1, 10), 'reebie').
replace(range(5, 2), 'ie').
process
end
def test_equivalent_delete_insert_replace
# A deletion + insertion just before or after the deleted range is
# identical in every way to a replacement! So logically, they shouldn't
# conflict.
assert_equal 'tin bar baz',
@rewriter.
remove(range(0, 3)). # ' bar baz'
insert_before(range(0, 1), 'tin'). # 'tin bar baz'
replace(range(0, 3), 'tin').
process
end
def test_transaction_returns_self
assert_equal @rewriter, @rewriter.transaction {}
end
def test_transaction_commit
silence_diagnostics
# Original: 'foo bar baz'
# Rewrite as 'foo BAR baz'
@rewriter.replace(range(4, 3), 'BAR')
# Rewrite as '( bar )'
@rewriter.transaction do
@rewriter.replace(range(0, 3), '(')
@rewriter.replace(range(8, 3), ')')
end
@rewriter.replace(range(3, 1), '_')
@rewriter.replace(range(7, 1), '_')
assert_equal '(_BAR_)', @rewriter.process
end
def test_transaction_rollback
silence_diagnostics
# Original: 'foo bar baz'
# Rewrite as 'foo bar BAZ'
@rewriter.replace(range(8, 3), 'BAZ')
assert_raises Parser::ClobberingError do
# Trying to rewrite as '( bar )', but it fails
@rewriter.transaction do
@rewriter.replace(range(0, 3), '(')
@rewriter.replace(range(8, 3), ')')
end
end
@rewriter.replace(range(0, 3), 'FOO')
assert_equal 'FOO bar BAZ', @rewriter.process
end
def test_nested_transaction_raises_error
error = assert_raises RuntimeError do
@rewriter.transaction do
@rewriter.transaction do
end
end
end
assert_match /nested/i, error.message
end
def test_process_in_transaction_raises_error
error = assert_raises RuntimeError do
@rewriter.transaction do
@rewriter.process
end
end
assert_match /transaction/, error.message
end
def silence_diagnostics
@rewriter.diagnostics.consumer = proc {}
end
end
parser-2.7.0.2/test/test_base.rb 0000644 0000041 0000041 00000001312 13617025313 016457 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
require 'parser/current'
class TestBase < Minitest::Test
include AST::Sexp
def test_parse
ast = Parser::CurrentRuby.parse('1')
assert_equal s(:int, 1), ast
end
def test_parse_with_comments
ast, comments = Parser::CurrentRuby.parse_with_comments('1 # foo')
assert_equal s(:int, 1), ast
assert_equal 1, comments.size
assert_equal '# foo', comments.first.text
end
def test_loc_to_node
ast = Parser::CurrentRuby.parse('1')
assert_equal ast.loc.node, ast
end
def test_loc_dup
ast = Parser::CurrentRuby.parse('1')
assert_nil ast.loc.dup.node
Parser::AST::Node.new(:root, [], :location => ast.loc)
end
end
parser-2.7.0.2/test/bug_163/ 0000755 0000041 0000041 00000000000 13617025313 015332 5 ustar www-data www-data parser-2.7.0.2/test/bug_163/fixtures/ 0000755 0000041 0000041 00000000000 13617025313 017203 5 ustar www-data www-data parser-2.7.0.2/test/bug_163/fixtures/output.rb 0000644 0000041 0000041 00000000102 13617025313 021061 0 ustar www-data www-data # frozen_string_literal: true
if true
puts "Hello, world!"
end
parser-2.7.0.2/test/bug_163/fixtures/input.rb 0000644 0000041 0000041 00000000103 13617025313 020661 0 ustar www-data www-data # frozen_string_literal: true
if(true)
puts "Hello, world!"
end
parser-2.7.0.2/test/bug_163/rewriter.rb 0000644 0000041 0000041 00000001250 13617025313 017520 0 ustar www-data www-data # frozen_string_literal: true
class Rewriter < Parser::Rewriter
def on_if(node)
# Crude, totally-not-usable-in-the-real-world code to remove optional
# parens from control keywords.
#
# In a perfect test scenario we'd simply make this a no-op, to demonstrate
# that the bug happens when any rewriter is loaded regardless of whether it
# actually changes anything but that makes assertions much harder to get
# right. It's much easier to just show that the file did, or did not
# get changed.
if node.children[0].type == :begin
replace node.children[0].loc.begin, ' '
remove node.children[0].loc.end
end
super
end
end
parser-2.7.0.2/test/test_encoding.rb 0000644 0000041 0000041 00000004637 13617025313 017350 0 ustar www-data www-data # encoding: binary
# frozen_string_literal: true
require 'helper'
class TestEncoding < Minitest::Test
include AST::Sexp
def recognize(string)
Parser::Source::Buffer.recognize_encoding(string)
end
require 'parser/all'
def test_default
assert_nil recognize('foobar')
end
def test_bom
assert_equal Encoding::UTF_8, recognize("\xef\xbb\xbf\nfoobar")
assert_equal Encoding::UTF_8, recognize("\xef\xbb\xbf# coding:koi8-r\nfoobar")
end
def test_magic_comment
assert_equal Encoding::KOI8_R, recognize("# coding:koi8-r\nfoobar")
end
def test_shebang
assert_equal Encoding::KOI8_R, recognize("#!/bin/foo\n# coding:koi8-r\nfoobar")
assert_nil recognize("#!/bin/foo\n")
end
def test_case
assert_equal Encoding::KOI8_R, recognize("# coding:KoI8-r\nfoobar")
end
def test_space
assert_equal Encoding::KOI8_R, recognize("# coding : koi8-r\nfoobar")
end
def test_empty
assert_nil recognize('')
end
def test_no_comment
assert_nil recognize(%{require 'cane/encoding_aware_iterator'})
end
def test_adjacent
assert_nil recognize('# codingkoi8-r')
assert_nil recognize('# coding koi8-r')
end
def test_utf8_mac
assert_equal Encoding::UTF8_MAC, recognize('# coding: utf8-mac')
end
def test_suffix
assert_equal Encoding::UTF_8, recognize('# coding: utf-8-dos')
assert_equal Encoding::UTF_8, recognize('# coding: utf-8-unix')
assert_equal Encoding::UTF_8, recognize('# coding: utf-8-mac')
assert_raises(ArgumentError) do
assert_nil recognize('# coding: utf-8-dicks')
end
end
def test_parse_18_invalid_enc
ast = Parser::Ruby18.parse("# encoding:feynman-diagram\n1")
assert_equal ast, s(:int, 1)
end
def test_parse_19_invalid_enc
assert_raises(ArgumentError) do
Parser::Ruby19.parse("# encoding:feynman-diagram\n1")
end
end
def test_ending_comment
assert_nil recognize('foo # coding: koi8-r')
end
def test_wrong_prefix
assert_nil recognize('# decoding: koi8-r')
end
def test_no_spaces
assert_equal Encoding::KOI8_R, recognize('#encoding:koi8-r')
assert_equal Encoding::KOI8_R, recognize('#coding:koi8-r')
end
def test_underscore_and_star_characters
assert_equal Encoding::KOI8_R, recognize('# -*- encoding: koi8-r -*-')
end
def test_garbage_around_encoding_comment
assert_equal Encoding::KOI8_R, recognize('# 1$# -*- &)* encoding: koi8-r 1$# -*- &)*')
end
end
parser-2.7.0.2/test/test_source_buffer.rb 0000644 0000041 0000041 00000007710 13617025313 020406 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestSourceBuffer < Minitest::Test
def setup
@buffer = Parser::Source::Buffer.new('(string)')
end
def test_initialize
buffer = Parser::Source::Buffer.new(nil)
assert_equal '', buffer.name
buffer = Parser::Source::Buffer.new(Pathname('a/b'))
assert_equal 'a/b', buffer.name
buffer = Parser::Source::Buffer.new('(string)')
assert_equal '(string)', buffer.name
assert_equal 1, buffer.first_line
buffer = Parser::Source::Buffer.new('(string)', 5)
assert_equal 5, buffer.first_line
end
def test_source_setter
@buffer.source = 'foo'
assert_equal 'foo', @buffer.source
assert @buffer.source.frozen?
end
def test_source_double_setter
@buffer.source = 'foo'
assert_raises(ArgumentError) do
@buffer.source = 'bar'
end
end
def test_source_setter_encoding_error
error = assert_raises EncodingError do
@buffer.source = [
'# encoding: utf-8',
"# \xf9"
].join("\n")
end
assert_match /invalid byte sequence in UTF\-8/, error.message
end
def test_read
tempfile = Tempfile.new('parser')
tempfile.write('foobar')
tempfile.flush
buffer = Parser::Source::Buffer.new(tempfile.path)
buffer.read
assert_equal 'foobar', buffer.source
assert buffer.source.frozen?
end
def test_uninitialized
assert_raises RuntimeError do
@buffer.source
end
end
def test_decompose_position
@buffer.source = "1\nfoo\nbar"
assert_equal [1, 0], @buffer.decompose_position(0)
assert_equal [1, 1], @buffer.decompose_position(1)
assert_equal [2, 0], @buffer.decompose_position(2)
assert_equal [3, 1], @buffer.decompose_position(7)
end
def test_decompose_position_mapped
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = "1\nfoo\nbar"
assert_equal [5, 0], @buffer.decompose_position(0)
assert_equal [6, 0], @buffer.decompose_position(2)
end
def test_line
@buffer.source = "1\nfoo\nbar"
assert_equal '1', @buffer.source_line(1)
assert_equal 'foo', @buffer.source_line(2)
end
def test_line_mutate
@buffer.source = "1\nfoo\nbar"
assert_equal '1', @buffer.source_line(1)
@buffer.source_line(1)[0] = '2'
assert_equal '1', @buffer.source_line(1)
end
def test_line_mapped
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = "1\nfoo\nbar"
assert_equal '1', @buffer.source_line(5)
assert_equal 'foo', @buffer.source_line(6)
end
def test_line_range
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = "abc\ndef\nghi\n"
assert_raises IndexError do
@buffer.line_range(4)
end
assert_equal 'abc', @buffer.line_range(5).source
assert_equal 'def', @buffer.line_range(6).source
assert_equal 'ghi', @buffer.line_range(7).source
assert_equal '', @buffer.line_range(8).source
assert_raises IndexError do
@buffer.line_range(9)
end
end
def test_source_range
@buffer = Parser::Source::Buffer.new('(string)', 5)
assert_raises RuntimeError do
@buffer.source_range
end
@buffer.source = "abc\ndef\nghi\n"
assert_equal Parser::Source::Range.new(@buffer, 0, @buffer.source.size), @buffer.source_range
end
def test_last_line
@buffer.source = "1\nfoo\nbar"
assert_equal 3, @buffer.last_line
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = ""
assert_equal 5, @buffer.last_line
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = "abc\n"
assert_equal 6, @buffer.last_line
end
def test_source_lines
@buffer.source = "1\nfoo\nbar\n"
assert_equal ['1', 'foo', 'bar', ''], @buffer.source_lines
assert @buffer.source_lines.frozen?
assert @buffer.source_lines.all?(&:frozen?)
@buffer = Parser::Source::Buffer.new('(string)', 5)
@buffer.source = "foo\nbar"
assert_equal ['foo', 'bar'], @buffer.source_lines
end
end
parser-2.7.0.2/test/test_lexer_stack_state.rb 0000644 0000041 0000041 00000002514 13617025313 021256 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestLexerStackState < Minitest::Test
def setup
@state = Parser::Lexer::StackState.new('state')
end
def test_push
refute @state.active?
assert_equal true, @state.push(true)
assert @state.active?
assert_equal false, @state.push(false)
refute @state.active?
end
def test_clear
@state.push true
@state.clear
refute @state.active?
end
def test_pop
@state.push(true)
assert_equal true, @state.pop
refute @state.active?
end
def test_pop_empty
assert_equal false, @state.pop
refute @state.active?
end
def test_lexpop_10
@state.push(true)
@state.push(false)
assert_equal true, @state.lexpop
assert_equal true, @state.pop
end
def test_lexpop_01
@state.push(false)
@state.push(true)
assert_equal true, @state.lexpop
assert_equal true, @state.pop
end
def test_lexpop_00
@state.push(false)
@state.push(false)
assert_equal false, @state.lexpop
assert_equal false, @state.pop
end
def test_dup
@state.push(true)
new_state = @state.dup
assert_equal true, @state.pop
assert_equal true, new_state.pop
end
def test_to_s
@state.push(true)
@state.push(false)
@state.push(false)
assert_equal '[100 <= state]', @state.to_s
end
end
parser-2.7.0.2/test/test_source_tree_rewriter.rb 0000644 0000041 0000041 00000012730 13617025313 022015 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestSourceTreeRewriter < Minitest::Test
def setup
@buf = Parser::Source::Buffer.new('(rewriter)')
@buf.source = 'puts(:hello, :world)'
@hello = range(5, 6)
@comma_space = range(11,2)
@world = range(13,6)
end
def range(from, len)
Parser::Source::Range.new(@buf, from, from + len)
end
# Returns either:
# - String (Normal operation)
# - [diagnostic, ...] (Diagnostics)
# - Parser::ClobberingError
#
def apply(actions, **policy)
diagnostics = []
diags = -> { diagnostics.flatten.map(&:strip).join("\n") }
rewriter = Parser::Source::TreeRewriter.new(@buf, **policy)
rewriter.diagnostics.consumer = -> diag { diagnostics << diag.render }
actions.each do |action, range, *args|
rewriter.public_send(action, range, *args)
end
if diagnostics.empty?
rewriter.process
else
diags.call
end
rescue ::Parser::ClobberingError => e
[::Parser::ClobberingError, diags.call]
end
# Expects ordered actions to be grouped together
def check_actions(expected, grouped_actions, **policy)
grouped_actions.permutation do |sequence|
# [action, [action, action]] => [action, action, action]
# except we can't use flatten because "action" are arrays themselves
actions = sequence.flat_map { |group| group.first.is_a?(Array) ? group : [group] }
assert_equal(expected, apply(actions, **policy))
end
end
def assert_actions_result(expected, *actions, **rest)
if expected == :raise
diagnostic = rest.values.first
check_actions([::Parser::ClobberingError, diagnostic], actions)
elsif rest.empty?
check_actions(expected, actions)
else
policy, diagnostic = rest.first
check_actions(expected, actions, policy => :accept)
check_actions(diagnostic, actions, policy => :warn)
diagnostic.gsub!(/warning: /, 'error: ')
check_actions([::Parser::ClobberingError, diagnostic], actions, policy => :raise)
end
end
### Simple cases
def test_remove
assert_actions_result 'puts(, :world)', [:remove, @hello]
end
def test_insert_before
assert_actions_result 'puts(:hello, 42, :world)', [:insert_before, @world, '42, ']
end
def test_insert_after
assert_actions_result 'puts(:hello, 42, :world)', [:insert_after, @hello, ', 42']
end
def test_wrap
assert_actions_result 'puts([:hello], :world)', [:wrap, @hello, '[', ']']
end
def test_replace
assert_actions_result 'puts(:hi, :world)', [:replace, @hello, ':hi']
end
#
# All other cases, as per doc
#
def test_crossing_non_deletions
check = [
[:wrap, '(', ')'],
[:remove],
[:replace, 'xx'],
]
check.combination(2) do |(action, *args), (action_b, *args_b)|
next if action == :remove && action_b == :remove
assert_actions_result :raise,
[[action, @hello.join(@comma_space), *args],
[action_b, @world.join(@comma_space), *args_b]],
diagnostic: <<-DIAGNOSTIC.chomp
(rewriter):1:12: error: the rewriting action on:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~~~
(rewriter):1:6: error: is crossing that on:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~~~
DIAGNOSTIC
end
end
def test_crossing_deletions
assert_actions_result 'puts()',
[[:remove, @hello.join(@comma_space)],
[:remove, @world.join(@comma_space)]],
crossing_deletions: <<-DIAGNOSTIC.chomp
(rewriter):1:12: warning: the deletion of:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~~~
(rewriter):1:6: warning: is crossing:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~~~
DIAGNOSTIC
end
def test_multiple_actions
assert_actions_result 'puts({:hello => [:everybody]})',
[:replace, @comma_space, ' => '],
[:wrap, @hello.join(@world), '{', '}'],
[:replace, @world, ':everybody'],
[:wrap, @world, '[', ']']
end
def test_wraps_same_range
assert_actions_result 'puts([(:hello)], :world)',
[[:wrap, @hello, '(', ')'],
[:wrap, @hello, '[', ']']]
end
def test_replace_same_range
assert_actions_result 'puts(:hey, :world)',
[[:replace, @hello, ':hi'],
[:replace, @hello, ':hey']],
different_replacements: <<-DIAGNOSTIC.chomp
(rewriter):1:6: warning: different replacements: :hey vs :hi
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~
DIAGNOSTIC
end
def test_swallowed_insertions
assert_actions_result 'puts(:hi)',
[[:wrap, @hello.adjust(begin_pos: 1), '__', '__'],
[:replace, @world.adjust(end_pos: -2), 'xx'],
[:replace, @hello.join(@world), ':hi']],
swallowed_insertions: <<-DIAGNOSTIC.chomp
(rewriter):1:6: warning: this replacement:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~~~~~~~~~~
(rewriter):1:7: warning: swallows some inner rewriting actions:
(rewriter):1: puts(:hello, :world)
(rewriter):1: ^~~~~ ~~~~
DIAGNOSTIC
end
def test_out_of_range_ranges
rewriter = Parser::Source::TreeRewriter.new(@buf)
assert_raises(IndexError) { rewriter.insert_before(range(0, 100), 'hola') }
end
end
parser-2.7.0.2/test/test_runner_parse.rb 0000644 0000041 0000041 00000001442 13617025313 020254 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
require 'open3'
class TestRunnerParse < Minitest::Test
PATH_TO_RUBY_PARSE = File.expand_path('../bin/ruby-parse', __dir__).freeze
def assert_prints(argv, expected_output)
stdout, stderr, status = Open3.capture3(PATH_TO_RUBY_PARSE, *argv)
assert_equal 0, status.to_i
assert_includes(stdout, expected_output)
end
def test_emit_ruby
assert_prints ['--emit-ruby', '-e 123'],
's(:int, 123)'
end
def test_emit_json
assert_prints ['--emit-json', '-e', '123'],
'["int",123]'
end
def test_emit_ruby_empty
assert_prints ['--emit-ruby', '-e', ''],
"\n"
end
def test_emit_json_empty
assert_prints ['--emit-json', '-e', ''],
"\n"
end
end
parser-2.7.0.2/test/using_tree_rewriter/ 0000755 0000041 0000041 00000000000 13617025313 020253 5 ustar www-data www-data parser-2.7.0.2/test/using_tree_rewriter/fixtures/ 0000755 0000041 0000041 00000000000 13617025313 022124 5 ustar www-data www-data parser-2.7.0.2/test/using_tree_rewriter/fixtures/output.rb 0000644 0000041 0000041 00000000051 13617025313 024005 0 ustar www-data www-data # frozen_string_literal: true
([6] * 7)
parser-2.7.0.2/test/using_tree_rewriter/fixtures/input.rb 0000644 0000041 0000041 00000000045 13617025313 023607 0 ustar www-data www-data # frozen_string_literal: true
6 * 7
parser-2.7.0.2/test/using_tree_rewriter/using_tree_rewriter.rb 0000644 0000041 0000041 00000000322 13617025313 024664 0 ustar www-data www-data # frozen_string_literal: true
class UsingTreeRewriter < Parser::TreeRewriter
def on_send(node)
wrap(node.loc.expression, '(', ')')
wrap(node.children[0].loc.expression, '[', ']')
super
end
end
parser-2.7.0.2/test/test_source_comment.rb 0000644 0000041 0000041 00000001453 13617025313 020575 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
class TestSourceComment < Minitest::Test
def setup
@buf = Parser::Source::Buffer.new('(string)')
@buf.source = "# foo\n=begin foo\nbar\n=end baz\n"
end
def range(s, e)
Parser::Source::Range.new(@buf, s, e)
end
def test_initialize
comment = Parser::Source::Comment.new(range(0, 5))
assert comment.frozen?
end
def test_text
comment = Parser::Source::Comment.new(range(0, 5))
assert_equal '# foo', comment.text
end
def test_inline
comment = Parser::Source::Comment.new(range(0, 5))
assert_equal :inline, comment.type
assert comment.inline?
end
def test_document
comment = Parser::Source::Comment.new(range(6, 25))
assert_equal :document, comment.type
assert comment.document?
end
end
parser-2.7.0.2/test/test_runner_rewrite.rb 0000644 0000041 0000041 00000002777 13617025313 020637 0 ustar www-data www-data # frozen_string_literal: true
require 'pathname'
require 'fileutils'
require 'shellwords'
require 'open3'
BASE_DIR = Pathname.new(__FILE__) + '..'
require (BASE_DIR + 'helper').expand_path
class TestRunnerRewrite < Minitest::Test
def assert_rewriter_output(path, args, input: 'input.rb', output: 'output.rb', expected_output: '', expected_error: '')
@ruby_rewrite = BASE_DIR.expand_path + '../bin/ruby-rewrite'
@test_dir = BASE_DIR + path
@fixtures_dir = @test_dir + 'fixtures'
Dir.mktmpdir("parser", BASE_DIR.expand_path.to_s) do |tmp_dir|
tmp_dir = Pathname.new(tmp_dir)
sample_file = tmp_dir + "#{path}.rb"
sample_file_expanded = sample_file.expand_path
expected_file = @fixtures_dir + output
FileUtils.cp(@fixtures_dir + input, sample_file_expanded)
stdout, stderr, exit_code = Dir.chdir @test_dir do
Open3.capture3 %Q{
#{Shellwords.escape(@ruby_rewrite.to_s)} #{args} \
#{Shellwords.escape(sample_file_expanded.to_s)}
}
end
assert_equal expected_output.chomp, stdout.chomp
assert_match expected_error.chomp, stderr.chomp
assert_equal File.read(expected_file.expand_path), File.read(sample_file)
end
end
def test_rewriter_bug_163
assert_rewriter_output('bug_163',
'--modify -l rewriter.rb',
expected_error: Parser::Rewriter::DEPRECATION_WARNING
)
end
def test_tree_rewriter
assert_rewriter_output('using_tree_rewriter', '-l using_tree_rewriter.rb --modify')
end
end
parser-2.7.0.2/test/test_source_map.rb 0000644 0000041 0000041 00000000552 13617025313 017707 0 ustar www-data www-data # frozen_string_literal: true
require 'helper'
require 'parse_helper'
class TestSourceMap < Minitest::Test
include ParseHelper
def test_to_hash
buf = Parser::Source::Buffer.new("")
buf.source = "1"
ast = parser_for_ruby_version('1.8').parse(buf)
assert_equal [:expression, :operator], ast.loc.to_hash.keys.sort_by(&:to_s)
end
end
parser-2.7.0.2/test/test_parser.rb 0000644 0000041 0000041 00000647212 13617025313 017060 0 ustar www-data www-data # encoding: utf-8
# frozen_string_literal: true
require 'helper'
require 'parse_helper'
Parser::Builders::Default.modernize
class TestParser < Minitest::Test
include ParseHelper
def parser_for_ruby_version(version)
parser = super
parser.diagnostics.all_errors_are_fatal = true
%w(foo bar baz).each do |metasyntactic_var|
parser.static_env.declare(metasyntactic_var)
end
parser
end
SINCE_1_9 = ALL_VERSIONS - %w(1.8)
SINCE_2_0 = SINCE_1_9 - %w(1.9 mac ios)
SINCE_2_1 = SINCE_2_0 - %w(2.0)
SINCE_2_2 = SINCE_2_1 - %w(2.1)
SINCE_2_3 = SINCE_2_2 - %w(2.2)
SINCE_2_4 = SINCE_2_3 - %w(2.3)
SINCE_2_5 = SINCE_2_4 - %w(2.4)
SINCE_2_6 = SINCE_2_5 - %w(2.5)
SINCE_2_7 = SINCE_2_6 - %w(2.6)
# Guidelines for test naming:
# * Test structure follows structure of AST_FORMAT.md.
# * Test names follow node names.
# * Structurally similar sources may be grouped into one test.
# * If, following the guidelines above, names clash, append
# an abbreviated disambiguator. E.g. `test_class` and
# `test_class_super`.
# * When writing a test for a bug, append unabbreviated (but
# concise) bug description. E.g. `test_class_bug_missing_newline`.
# * Do not append Ruby language version to the name.
# * When in doubt, look at existing test names.
#
# Guidelines for writing assertions:
# * Don't check for structurally same source mapping information
# more than once or twice in the entire file. It clutters the
# source for no reason.
# * Don't forget to check for optional delimiters. `()`, `then`, etc.
# * When in doubt, look at existing assertions.
#
# Literals
#
def test_empty_stmt
assert_parses(
nil,
%q{})
end
def test_nil
assert_parses(
s(:nil),
%q{nil},
%q{~~~ expression})
end
def test_nil_expression
assert_parses(
s(:begin),
%q{()},
%q{^ begin
| ^ end
|~~ expression})
assert_parses(
s(:kwbegin),
%q{begin end},
%q{~~~~~ begin
| ~~~ end
|~~~~~~~~~ expression})
end
def test_true
assert_parses(
s(:true),
%q{true},
%q{~~~~ expression})
end
def test_false
assert_parses(
s(:false),
%q{false},
%q{~~~~~ expression})
end
def test_int
assert_parses(
s(:int, 42),
%q{42},
%q{~~ expression})
assert_parses(
s(:int, 42),
%q{+42},
%q{^ operator
|~~~ expression})
assert_parses(
s(:int, -42),
%q{-42},
%q{^ operator
|~~~ expression})
end
def test_int___LINE__
assert_parses(
s(:int, 1),
%q{__LINE__},
%q{~~~~~~~~ expression})
end
def test_float
assert_parses(
s(:float, 1.33),
%q{1.33},
%q{~~~~ expression})
assert_parses(
s(:float, -1.33),
%q{-1.33},
%q{^ operator
|~~~~~ expression})
end
def test_rational
assert_parses(
s(:rational, Rational(42)),
%q{42r},
%q{~~~ expression},
SINCE_2_1)
assert_parses(
s(:rational, Rational(421, 10)),
%q{42.1r},
%q{~~~~~ expression},
SINCE_2_1)
end
def test_complex
assert_parses(
s(:complex, Complex(0, 42)),
%q{42i},
%q{~~~ expression},
SINCE_2_1)
assert_parses(
s(:complex, Complex(0, Rational(42))),
%q{42ri},
%q{~~~~ expression},
SINCE_2_1)
assert_parses(
s(:complex, Complex(0, 42.1)),
%q{42.1i},
%q{~~~~~ expression},
SINCE_2_1)
assert_parses(
s(:complex, Complex(0, Rational(421, 10))),
%q{42.1ri},
%q{~~~~~~ expression},
SINCE_2_1)
end
# Strings
def test_string_plain
assert_parses(
s(:str, 'foobar'),
%q{'foobar'},
%q{^ begin
| ^ end
|~~~~~~~~ expression})
assert_parses(
s(:str, 'foobar'),
%q{%q(foobar)},
%q{^^^ begin
| ^ end
|~~~~~~~~~~ expression})
end
def test_string_interp
assert_parses(
s(:dstr,
s(:str, 'foo'),
s(:begin, s(:lvar, :bar)),
s(:str, 'baz')),
%q{"foo#{bar}baz"},
%q{^ begin
| ^ end
| ^^ begin (begin)
| ^ end (begin)
| ~~~~~~ expression (begin)
|~~~~~~~~~~~~~~ expression})
end
def test_string_dvar
assert_parses(
s(:dstr,
s(:ivar, :@a),
s(:str, ' '),
s(:cvar, :@@a),
s(:str, ' '),
s(:gvar, :$a)),
%q{"#@a #@@a #$a"})
end
def test_string_concat
assert_parses(
s(:dstr,
s(:dstr,
s(:str, 'foo'),
s(:ivar, :@a)),
s(:str, 'bar')),
%q{"foo#@a" "bar"},
%q{^ begin (dstr)
| ^ end (dstr)
| ^ begin (str)
| ^ end (str)
|~~~~~~~~~~~~~~ expression})
end
def test_string___FILE__
assert_parses(
s(:str, '(assert_parses)'),
%q{__FILE__},
%q{~~~~~~~~ expression})
end
def test_character
assert_parses(
s(:str, 'a'),
%q{?a},
%q{^ begin
|~~ expression},
SINCE_1_9)
assert_parses(
s(:int, 97),
%q{?a},
%q{~~ expression},
%w(1.8))
end
def test_heredoc
assert_parses(
s(:dstr, s(:str, "foo\n"), s(:str, "bar\n")),
%Q{< e
message = e.message
end
assert_diagnoses(
[:error, :invalid_regexp, {:message => message}],
%q[/?/],
%q(~~~ location),
SINCE_1_9)
assert_diagnoses(
[:error, :invalid_regexp, {:message => message}],
%q[/#{""}?/],
%q(~~~~~~~~ location),
SINCE_1_9)
end
# Arrays
def test_array_plain
assert_parses(
s(:array, s(:int, 1), s(:int, 2)),
%q{[1, 2]},
%q{^ begin
| ^ end
|~~~~~~ expression})
end
def test_array_splat
assert_parses(
s(:array,
s(:int, 1),
s(:splat, s(:lvar, :foo)),
s(:int, 2)),
%q{[1, *foo, 2]},
%q{^ begin
| ^ end
| ^ operator (splat)
| ~~~~ expression (splat)
|~~~~~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:array,
s(:int, 1),
s(:splat, s(:lvar, :foo))),
%q{[1, *foo]},
%q{^ begin
| ^ end
| ^ operator (splat)
| ~~~~ expression (splat)
|~~~~~~~~~ expression})
assert_parses(
s(:array,
s(:splat, s(:lvar, :foo))),
%q{[*foo]})
end
def test_array_assocs
assert_parses(
s(:array,
s(:hash, s(:pair, s(:int, 1), s(:int, 2)))),
%q{[ 1 => 2 ]},
%q{ ~~ operator (hash.pair)
| ~~~~~~ expression (hash.pair)
| ~~~~~~ expression (hash)})
assert_parses(
s(:array,
s(:int, 1),
s(:hash, s(:pair, s(:int, 2), s(:int, 3)))),
%q{[ 1, 2 => 3 ]},
%q{},
SINCE_1_9)
end
def test_array_words
assert_parses(
s(:array, s(:str, 'foo'), s(:str, 'bar')),
%q{%w[foo bar]},
%q{^^^ begin
| ^ end
| ~~~ expression (str)
|~~~~~~~~~~~ expression})
end
def test_array_words_interp
assert_parses(
s(:array,
s(:str, 'foo'),
s(:dstr, s(:begin, s(:lvar, :bar)))),
%q{%W[foo #{bar}]},
%q{^^^ begin
| ^^ begin (dstr.begin)
| ^ end (dstr.begin)
| ~~~~~~ expression (dstr.begin)
| ^ end
| ~~~ expression (str)
| ~~~ expression (dstr.begin.lvar)
|~~~~~~~~~~~~~~ expression})
assert_parses(
s(:array,
s(:str, 'foo'),
s(:dstr,
s(:begin, s(:lvar, :bar)),
s(:str, 'foo'),
s(:ivar, :@baz))),
%q{%W[foo #{bar}foo#@baz]})
end
def test_array_words_empty
assert_parses(
s(:array),
%q{%w[]},
%q{^^^ begin
| ^ end
|~~~~ expression})
assert_parses(
s(:array),
%q{%W()})
end
def test_array_symbols
assert_parses(
s(:array, s(:sym, :foo), s(:sym, :bar)),
%q{%i[foo bar]},
%q{^^^ begin
| ^ end
| ~~~ expression (sym)
|~~~~~~~~~~~ expression},
SINCE_2_0)
end
def test_array_symbols_interp
assert_parses(
s(:array,
s(:sym, :foo),
s(:dsym, s(:begin, s(:lvar, :bar)))),
%q{%I[foo #{bar}]},
%q{^^^ begin
| ^ end
| ~~~ expression (sym)
| ^^ begin (dsym.begin)
| ^ end (dsym.begin)
| ~~~~~~ expression (dsym.begin)
| ~~~ expression (dsym.begin.lvar)
|~~~~~~~~~~~~~~ expression},
SINCE_2_0)
assert_parses(
s(:array,
s(:dsym,
s(:str, 'foo'),
s(:begin, s(:lvar, :bar)))),
%q{%I[foo#{bar}]},
%q{},
SINCE_2_0)
end
def test_array_symbols_empty
assert_parses(
s(:array),
%q{%i[]},
%q{^^^ begin
| ^ end
|~~~~ expression},
SINCE_2_0)
assert_parses(
s(:array),
%q{%I()},
%q{},
SINCE_2_0)
end
# Hashes
def test_hash_empty
assert_parses(
s(:hash),
%q[{ }],
%q{^ begin
| ^ end
|~~~ expression})
end
def test_hash_hashrocket
assert_parses(
s(:hash, s(:pair, s(:int, 1), s(:int, 2))),
%q[{ 1 => 2 }],
%q{^ begin
| ^ end
| ^^ operator (pair)
| ~~~~~~ expression (pair)
|~~~~~~~~~~ expression})
assert_parses(
s(:hash,
s(:pair, s(:int, 1), s(:int, 2)),
s(:pair, s(:sym, :foo), s(:str, 'bar'))),
%q[{ 1 => 2, :foo => "bar" }])
end
def test_hash_label
assert_parses(
s(:hash, s(:pair, s(:sym, :foo), s(:int, 2))),
%q[{ foo: 2 }],
%q{^ begin
| ^ end
| ^ operator (pair)
| ~~~ expression (pair.sym)
| ~~~~~~ expression (pair)
|~~~~~~~~~~ expression},
SINCE_1_9)
end
def test_hash_label_end
assert_parses(
s(:hash, s(:pair, s(:sym, :foo), s(:int, 2))),
%q[{ 'foo': 2 }],
%q{^ begin
| ^ end
| ^ operator (pair)
| ^ begin (pair.sym)
| ^ end (pair.sym)
| ~~~~~ expression (pair.sym)
| ~~~~~~~~ expression (pair)
|~~~~~~~~~~~~ expression},
SINCE_2_2)
assert_parses(
s(:hash,
s(:pair, s(:sym, :foo), s(:int, 2)),
s(:pair, s(:sym, :bar), s(:hash))),
%q[{ 'foo': 2, 'bar': {}}],
%q{},
SINCE_2_2)
assert_parses(
s(:send, nil, :f,
s(:if, s(:send, nil, :a),
s(:str, "a"),
s(:int, 1))),
%q{f(a ? "a":1)},
%q{},
SINCE_2_2)
end
def test_hash_kwsplat
assert_parses(
s(:hash,
s(:pair, s(:sym, :foo), s(:int, 2)),
s(:kwsplat, s(:lvar, :bar))),
%q[{ foo: 2, **bar }],
%q{ ^^ operator (kwsplat)
| ~~~~~ expression (kwsplat)},
SINCE_2_0)
end
def test_hash_no_hashrocket
assert_parses(
s(:hash, s(:pair, s(:int, 1), s(:int, 2))),
%q[{ 1, 2 }],
%q{^ begin
| ^ end
| ~~~~ expression (pair)
|~~~~~~~~ expression},
%w(1.8))
end
def test_hash_no_hashrocket_odd
assert_diagnoses(
[:error, :odd_hash],
%q[{ 1, 2, 3 }],
%q( ~ location),
%w(1.8))
end
# Range
def test_range_inclusive
assert_parses(
s(:irange, s(:int, 1), s(:int, 2)),
%q{1..2},
%q{ ~~ operator
|~~~~ expression})
end
def test_range_exclusive
assert_parses(
s(:erange, s(:int, 1), s(:int, 2)),
%q{1...2},
%q{ ~~~ operator
|~~~~~ expression})
end
def test_range_endless
assert_parses(
s(:irange,
s(:int, 1), nil),
%q{1..},
%q{~~~ expression
| ~~ operator},
SINCE_2_6)
assert_parses(
s(:erange,
s(:int, 1), nil),
%q{1...},
%q{~~~~ expression
| ~~~ operator},
SINCE_2_6)
end
def test_beginless_range_before_27
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT2' }],
%q{..42},
%q{^^ location},
ALL_VERSIONS - SINCE_2_7
)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT3' }],
%q{...42},
%q{^^^ location},
ALL_VERSIONS - SINCE_2_7
)
end
def test_beginless_range
assert_parses(
s(:irange, nil,
s(:int, 100)),
%q{..100},
%q{~~~~~ expression
|~~ operator},
SINCE_2_7
)
assert_parses(
s(:erange, nil,
s(:int, 100)),
%q{...100},
%q{~~~~~~ expression
|~~~ operator},
SINCE_2_7
)
end
#
# Access
#
# Variables and pseudovariables
def test_self
assert_parses(
s(:self),
%q{self},
%q{~~~~ expression})
end
def test_lvar
assert_parses(
s(:lvar, :foo),
%q{foo},
%q{~~~ expression})
end
def test_ivar
assert_parses(
s(:ivar, :@foo),
%q{@foo},
%q{~~~~ expression})
end
def test_cvar
assert_parses(
s(:cvar, :@@foo),
%q{@@foo},
%q{~~~~~ expression})
end
def test_gvar
assert_parses(
s(:gvar, :$foo),
%q{$foo},
%q{~~~~ expression})
end
def test_gvar_dash_empty
assert_diagnoses(
[:fatal, :unexpected, { :character => '$' }],
%q{$- },
%q{^ location},
%w(2.1))
end
def test_back_ref
assert_parses(
s(:back_ref, :$+),
%q{$+},
%q{~~ expression})
end
def test_nth_ref
assert_parses(
s(:nth_ref, 10),
%q{$10},
%q{~~~ expression})
end
# Constants
def test_const_toplevel
assert_parses(
s(:const, s(:cbase), :Foo),
%q{::Foo},
%q{ ~~~ name
|~~ double_colon
|~~~~~ expression})
end
def test_const_scoped
assert_parses(
s(:const, s(:const, nil, :Bar), :Foo),
%q{Bar::Foo},
%q{ ~~~ name
| ~~ double_colon
|~~~~~~~~ expression})
end
def test_const_unscoped
assert_parses(
s(:const, nil, :Foo),
%q{Foo},
%q{~~~ name
|~~~ expression})
end
def test___ENCODING__
assert_parses(
s(:__ENCODING__),
%q{__ENCODING__},
%q{~~~~~~~~~~~~ expression},
SINCE_1_9)
end
def test___ENCODING___legacy_
Parser::Builders::Default.emit_encoding = false
assert_parses(
s(:const, s(:const, nil, :Encoding), :UTF_8),
%q{__ENCODING__},
%q{~~~~~~~~~~~~ expression},
SINCE_1_9)
ensure
Parser::Builders::Default.emit_encoding = true
end
# defined?
def test_defined
assert_parses(
s(:defined?, s(:lvar, :foo)),
%q{defined? foo},
%q{~~~~~~~~ keyword
|~~~~~~~~~~~~ expression})
assert_parses(
s(:defined?, s(:lvar, :foo)),
%q{defined?(foo)},
%q{~~~~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~~~~~~~ expression})
assert_parses(
s(:defined?, s(:ivar, :@foo)),
%q{defined? @foo})
end
#
# Assignment
#
# Variables
def test_lvasgn
assert_parses(
s(:begin,
s(:lvasgn, :var, s(:int, 10)),
s(:lvar, :var)),
%q{var = 10; var},
%q{~~~ name (lvasgn)
| ^ operator (lvasgn)
|~~~~~~~~ expression (lvasgn)
})
end
def test_ivasgn
assert_parses(
s(:ivasgn, :@var, s(:int, 10)),
%q{@var = 10},
%q{~~~~ name
| ^ operator
|~~~~~~~~~ expression
})
end
def test_cvasgn
assert_parses(
s(:cvasgn, :@@var, s(:int, 10)),
%q{@@var = 10},
%q{~~~~~ name
| ^ operator
|~~~~~~~~~~ expression
})
end
def test_gvasgn
assert_parses(
s(:gvasgn, :$var, s(:int, 10)),
%q{$var = 10},
%q{~~~~ name
| ^ operator
|~~~~~~~~~ expression
})
end
def test_asgn_cmd
assert_parses(
s(:lvasgn, :foo, s(:send, nil, :m, s(:lvar, :foo))),
%q{foo = m foo})
assert_parses(
s(:lvasgn, :foo,
s(:lvasgn, :bar,
s(:send, nil, :m, s(:lvar, :foo)))),
%q{foo = bar = m foo},
%q{},
ALL_VERSIONS - %w(1.8 mac ios))
end
def test_asgn_keyword_invalid
assert_diagnoses(
[:error, :invalid_assignment],
%q{nil = foo},
%q{~~~ location})
assert_diagnoses(
[:error, :invalid_assignment],
%q{self = foo},
%q{~~~~ location})
assert_diagnoses(
[:error, :invalid_assignment],
%q{true = foo},
%q{~~~~ location})
assert_diagnoses(
[:error, :invalid_assignment],
%q{false = foo},
%q{~~~~~ location})
assert_diagnoses(
[:error, :invalid_assignment],
%q{__FILE__ = foo},
%q{~~~~~~~~ location})
assert_diagnoses(
[:error, :invalid_assignment],
%q{__LINE__ = foo},
%q{~~~~~~~~ location})
end
def test_asgn_backref_invalid
assert_diagnoses(
[:error, :backref_assignment],
%q{$1 = foo},
%q{~~ location})
end
# Constants
def test_casgn_toplevel
assert_parses(
s(:casgn, s(:cbase), :Foo, s(:int, 10)),
%q{::Foo = 10},
%q{ ~~~ name
| ^ operator
|~~ double_colon
|~~~~~~~~~~ expression
})
end
def test_casgn_scoped
assert_parses(
s(:casgn, s(:const, nil, :Bar), :Foo, s(:int, 10)),
%q{Bar::Foo = 10},
%q{ ~~~ name
| ^ operator
| ~~ double_colon
|~~~~~~~~~~~~~ expression
})
end
def test_casgn_unscoped
assert_parses(
s(:casgn, nil, :Foo, s(:int, 10)),
%q{Foo = 10},
%q{~~~ name
| ^ operator
|~~~~~~~~ expression
})
end
def test_casgn_invalid
assert_diagnoses(
[:error, :dynamic_const],
%q{def f; Foo = 1; end},
%q{ ~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def f; Foo::Bar = 1; end},
%q{ ~~~~~~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def f; ::Bar = 1; end},
%q{ ~~~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def self.f; Foo = 1; end},
%q{ ~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def self.f; Foo::Bar = 1; end},
%q{ ~~~~~~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def self.f; ::Bar = 1; end},
%q{ ~~~~~ location})
end
# Multiple assignment
def test_masgn
assert_parses(
s(:masgn,
s(:mlhs, s(:lvasgn, :foo), s(:lvasgn, :bar)),
s(:array, s(:int, 1), s(:int, 2))),
%q{foo, bar = 1, 2},
%q{ ^ operator
|~~~~~~~~ expression (mlhs)
| ~~~~ expression (array)
|~~~~~~~~~~~~~~~ expression
})
assert_parses(
s(:masgn,
s(:mlhs, s(:lvasgn, :foo), s(:lvasgn, :bar)),
s(:array, s(:int, 1), s(:int, 2))),
%q{(foo, bar) = 1, 2},
%q{^ begin (mlhs)
| ^ end (mlhs)
|~~~~~~~~~~ expression (mlhs)
|~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :foo),
s(:lvasgn, :bar),
s(:lvasgn, :baz)),
s(:array, s(:int, 1), s(:int, 2))),
%q{foo, bar, baz = 1, 2})
end
def test_masgn_splat
assert_parses(
s(:masgn,
s(:mlhs, s(:ivasgn, :@foo), s(:cvasgn, :@@bar)),
s(:array, s(:splat, s(:lvar, :foo)))),
%q{@foo, @@bar = *foo},
%q{ ^ operator (array.splat)
| ~~~~ expression (array.splat)
})
assert_parses(
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)),
s(:array, s(:splat, s(:lvar, :foo)), s(:lvar, :bar))),
%q{a, b = *foo, bar},
%q{},
SINCE_1_9)
assert_parses(
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:splat, s(:lvasgn, :b))),
s(:lvar, :bar)),
%q{a, *b = bar})
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :a),
s(:splat, s(:lvasgn, :b)),
s(:lvasgn, :c)),
s(:lvar, :bar)),
%q{a, *b, c = bar},
%q{},
SINCE_1_9)
assert_parses(
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:splat)),
s(:lvar, :bar)),
%q{a, * = bar})
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :a),
s(:splat),
s(:lvasgn, :c)),
s(:lvar, :bar)),
%q{a, *, c = bar},
%q{},
SINCE_1_9)
assert_parses(
s(:masgn,
s(:mlhs, s(:splat, s(:lvasgn, :b))),
s(:lvar, :bar)),
%q{*b = bar})
assert_parses(
s(:masgn,
s(:mlhs,
s(:splat, s(:lvasgn, :b)),
s(:lvasgn, :c)),
s(:lvar, :bar)),
%q{*b, c = bar},
%q{},
SINCE_1_9)
assert_parses(
s(:masgn,
s(:mlhs, s(:splat)),
s(:lvar, :bar)),
%q{* = bar})
assert_parses(
s(:masgn,
s(:mlhs,
s(:splat),
s(:lvasgn, :c),
s(:lvasgn, :d)),
s(:lvar, :bar)),
%q{*, c, d = bar},
%q{},
SINCE_1_9)
end
def test_masgn_nested
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :a),
s(:mlhs,
s(:lvasgn, :b),
s(:lvasgn, :c))),
s(:lvar, :foo)),
%q{a, (b, c) = foo},
%q{ ^ begin (mlhs.mlhs)
| ^ end (mlhs.mlhs)
| ~~~~~~ expression (mlhs.mlhs)
})
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :b)),
s(:lvar, :foo)),
%q{((b, )) = foo},
%q{^ begin (mlhs)
| ^ end (mlhs)})
end
def test_masgn_attr
assert_parses(
s(:masgn,
s(:mlhs,
s(:send, s(:self), :a=),
s(:indexasgn, s(:self), s(:int, 1), s(:int, 2))),
s(:lvar, :foo)),
%q{self.a, self[1, 2] = foo},
%q{~~~~~~ expression (mlhs.send)
| ~ selector (mlhs.send)
| ^ begin (mlhs.indexasgn)
| ^ end (mlhs.indexasgn)
| ~~~~~~~~~~ expression (mlhs.indexasgn)})
assert_parses(
s(:masgn,
s(:mlhs,
s(:send, s(:self), :a=),
s(:lvasgn, :foo)),
s(:lvar, :foo)),
%q{self::a, foo = foo})
assert_parses(
s(:masgn,
s(:mlhs,
s(:send, s(:self), :A=),
s(:lvasgn, :foo)),
s(:lvar, :foo)),
%q{self.A, foo = foo})
end
def test_masgn_const
assert_parses(
s(:masgn,
s(:mlhs,
s(:casgn, s(:self), :A),
s(:lvasgn, :foo)),
s(:lvar, :foo)),
%q{self::A, foo = foo})
assert_parses(
s(:masgn,
s(:mlhs,
s(:casgn, s(:cbase), :A),
s(:lvasgn, :foo)),
s(:lvar, :foo)),
%q{::A, foo = foo})
end
def test_masgn_cmd
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :foo),
s(:lvasgn, :bar)),
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo, bar = m foo})
end
def test_asgn_mrhs
assert_parses(
s(:lvasgn, :foo,
s(:array, s(:lvar, :bar), s(:int, 1))),
%q{foo = bar, 1},
%q{ ~~~~~~ expression (array)
|~~~~~~~~~~~~ expression})
assert_parses(
s(:lvasgn, :foo,
s(:array, s(:splat, s(:lvar, :bar)))),
%q{foo = *bar})
assert_parses(
s(:lvasgn, :foo,
s(:array,
s(:lvar, :baz),
s(:splat, s(:lvar, :bar)))),
%q{foo = baz, *bar})
end
def test_masgn_keyword_invalid
assert_diagnoses(
[:error, :invalid_assignment],
%q{nil, foo = bar},
%q{~~~ location})
end
def test_masgn_backref_invalid
assert_diagnoses(
[:error, :backref_assignment],
%q{$1, = foo},
%q{~~ location})
end
def test_masgn_const_invalid
assert_diagnoses(
[:error, :dynamic_const],
%q{def f; self::A, foo = foo; end},
%q{ ~~~~~~~ location})
assert_diagnoses(
[:error, :dynamic_const],
%q{def f; ::A, foo = foo; end},
%q{ ~~~ location})
end
# Variable binary operator-assignment
def test_var_op_asgn
assert_parses(
s(:op_asgn, s(:lvasgn, :a), :+, s(:int, 1)),
%q{a += 1},
%q{ ^^ operator
|~~~~~~ expression})
assert_parses(
s(:op_asgn, s(:ivasgn, :@a), :|, s(:int, 1)),
%q{@a |= 1},
%q{ ^^ operator
|~~~~~~~ expression})
assert_parses(
s(:op_asgn, s(:cvasgn, :@@var), :|, s(:int, 10)),
%q{@@var |= 10})
assert_parses(
s(:def, :a, s(:args),
s(:op_asgn, s(:cvasgn, :@@var), :|, s(:int, 10))),
%q{def a; @@var |= 10; end})
end
def test_var_op_asgn_cmd
assert_parses(
s(:op_asgn,
s(:lvasgn, :foo), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo += m foo})
end
def test_var_op_asgn_keyword_invalid
assert_diagnoses(
[:error, :invalid_assignment],
%q{nil += foo},
%q{~~~ location})
end
def test_const_op_asgn
assert_parses(
s(:op_asgn,
s(:casgn, nil, :A), :+,
s(:int, 1)),
%q{A += 1})
assert_parses(
s(:op_asgn,
s(:casgn, s(:cbase), :A), :+,
s(:int, 1)),
%q{::A += 1},
%q{},
SINCE_2_0)
assert_parses(
s(:op_asgn,
s(:casgn, s(:const, nil, :B), :A), :+,
s(:int, 1)),
%q{B::A += 1},
%q{},
SINCE_2_0)
assert_parses(
s(:def, :x, s(:args),
s(:or_asgn,
s(:casgn, s(:self), :A),
s(:int, 1))),
%q{def x; self::A ||= 1; end},
%q{},
SINCE_2_0)
assert_parses(
s(:def, :x, s(:args),
s(:or_asgn,
s(:casgn, s(:cbase), :A),
s(:int, 1))),
%q{def x; ::A ||= 1; end},
%q{},
SINCE_2_0)
end
def test_const_op_asgn_invalid
assert_diagnoses(
[:error, :dynamic_const],
%q{Foo::Bar += 1},
%q{ ~~~ location},
%w(1.8 1.9 mac ios))
assert_diagnoses(
[:error, :dynamic_const],
%q{::Bar += 1},
%q{ ~~~ location},
%w(1.8 1.9 mac ios))
assert_diagnoses(
[:error, :dynamic_const],
%q{def foo; Foo::Bar += 1; end},
%q{ ~~~ location},
%w(1.8 1.9 mac ios))
assert_diagnoses(
[:error, :dynamic_const],
%q{def foo; ::Bar += 1; end},
%q{ ~~~ location},
%w(1.8 1.9 mac ios))
end
# Method binary operator-assignment
def test_op_asgn
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :a), :+,
s(:int, 1)),
%q{foo.a += 1},
%q{ ^^ operator
| ~ selector (send)
|~~~~~ expression (send)
|~~~~~~~~~~ expression})
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :a), :+,
s(:int, 1)),
%q{foo::a += 1})
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :A), :+,
s(:int, 1)),
%q{foo.A += 1})
end
def test_op_asgn_cmd
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :a), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo.a += m foo})
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :a), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo::a += m foo})
assert_parses(
s(:op_asgn,
s(:send, s(:lvar, :foo), :A), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo.A += m foo})
assert_diagnoses(
[:error, :const_reassignment],
%q{foo::A += m foo},
%q{ ~~ location},
%w(1.9 mac))
assert_parses(
s(:op_asgn,
s(:casgn, s(:lvar, :foo), :A), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo::A += m foo},
%q{},
SINCE_2_0)
end
def test_op_asgn_index
assert_parses(
s(:op_asgn,
s(:indexasgn, s(:lvar, :foo),
s(:int, 0), s(:int, 1)), :+,
s(:int, 2)),
%q{foo[0, 1] += 2},
%q{ ^^ operator
| ^ begin (indexasgn)
| ^ end (indexasgn)
|~~~~~~~~~ expression (indexasgn)
|~~~~~~~~~~~~~~ expression})
end
def test_op_asgn_index_cmd
assert_parses(
s(:op_asgn,
s(:indexasgn, s(:lvar, :foo),
s(:int, 0), s(:int, 1)), :+,
s(:send, nil, :m, s(:lvar, :foo))),
%q{foo[0, 1] += m foo})
end
def test_op_asgn_invalid
assert_diagnoses(
[:error, :backref_assignment],
%q{$1 |= 1},
%q{~~ location})
assert_diagnoses(
[:error, :backref_assignment],
%q{$+ |= 1},
%q{~~ location})
assert_diagnoses(
[:error, :backref_assignment],
%q{$+ |= m foo},
%q{~~ location})
end
# Variable logical operator-assignment
def test_var_or_asgn
assert_parses(
s(:or_asgn, s(:lvasgn, :a), s(:int, 1)),
%q{a ||= 1},
%q{ ^^^ operator
|~~~~~~~ expression})
end
def test_var_and_asgn
assert_parses(
s(:and_asgn, s(:lvasgn, :a), s(:int, 1)),
%q{a &&= 1},
%q{ ^^^ operator
|~~~~~~~ expression})
end
# Method logical operator-assignment
def test_or_asgn
assert_parses(
s(:or_asgn,
s(:send, s(:lvar, :foo), :a),
s(:int, 1)),
%q{foo.a ||= 1},
%q{ ^^^ operator
| ~ selector (send)
|~~~~~ expression (send)
|~~~~~~~~~~~ expression})
assert_parses(
s(:or_asgn,
s(:indexasgn, s(:lvar, :foo),
s(:int, 0), s(:int, 1)),
s(:int, 2)),
%q{foo[0, 1] ||= 2},
%q{ ^^^ operator
| ^ begin (indexasgn)
| ^ end (indexasgn)
|~~~~~~~~~ expression (indexasgn)
|~~~~~~~~~~~~~~~ expression})
end
def test_and_asgn
assert_parses(
s(:and_asgn,
s(:send, s(:lvar, :foo), :a),
s(:int, 1)),
%q{foo.a &&= 1},
%q{ ^^^ operator
| ~ selector (send)
|~~~~~ expression (send)
|~~~~~~~~~~~ expression})
assert_parses(
s(:and_asgn,
s(:indexasgn, s(:lvar, :foo),
s(:int, 0), s(:int, 1)),
s(:int, 2)),
%q{foo[0, 1] &&= 2},
%q{ ^^^ operator
| ^ begin (indexasgn)
| ^ end (indexasgn)
|~~~~~~~~~ expression (indexasgn)
|~~~~~~~~~~~~~~~ expression})
end
def test_log_asgn_invalid
assert_diagnoses(
[:error, :backref_assignment],
%q{$1 &&= 1},
%q{~~ location})
assert_diagnoses(
[:error, :backref_assignment],
%q{$+ ||= 1},
%q{~~ location})
end
#
# Class and module definitions
#
def test_module
assert_parses(
s(:module,
s(:const, nil, :Foo),
nil),
%q{module Foo; end},
%q{~~~~~~ keyword
| ~~~ name
| ~~~ end})
end
def test_module_invalid
assert_diagnoses(
[:error, :module_in_def],
%q{def a; module Foo; end; end},
%q{ ^^^^^^ location})
end
def test_cpath
assert_parses(
s(:module,
s(:const, s(:cbase), :Foo),
nil),
%q{module ::Foo; end})
assert_parses(
s(:module,
s(:const, s(:const, nil, :Bar), :Foo),
nil),
%q{module Bar::Foo; end})
end
def test_cpath_invalid
assert_diagnoses(
[:error, :module_name_const],
%q{module foo; end})
end
def test_class
assert_parses(
s(:class,
s(:const, nil, :Foo),
nil,
nil),
%q{class Foo; end},
%q{~~~~~ keyword
| ~~~ name
| ~~~ end})
assert_parses(
s(:class,
s(:const, nil, :Foo),
nil,
nil),
%q{class Foo end},
%q{},
SINCE_2_3)
end
def test_class_super
assert_parses(
s(:class,
s(:const, nil, :Foo),
s(:const, nil, :Bar),
nil),
%q{class Foo < Bar; end},
%q{~~~~~ keyword
| ^ operator
| ~~~ end})
end
def test_class_super_label
assert_parses(
s(:class,
s(:const, nil, :Foo),
s(:send, nil, :a,
s(:sym, :b)),
nil),
%q{class Foo < a:b; end},
%q{},
SINCE_2_0)
end
def test_class_invalid
assert_diagnoses(
[:error, :class_in_def],
%q{def a; class Foo; end; end},
%q{ ^^^^^ location})
assert_diagnoses(
[:error, :class_in_def],
%q{def self.a; class Foo; end; end},
%q{ ^^^^^ location})
end
def test_sclass
assert_parses(
s(:sclass,
s(:lvar, :foo),
s(:nil)),
%q{class << foo; nil; end},
%q{~~~~~ keyword
| ^^ operator
| ~~~ end})
end
#
# Method (un)definition
#
def test_def
assert_parses(
s(:def, :foo, s(:args), nil),
%q{def foo; end},
%q{~~~ keyword
| ~~~ name
| ~~~ end})
assert_parses(
s(:def, :String, s(:args), nil),
%q{def String; end})
assert_parses(
s(:def, :String=, s(:args), nil),
%q{def String=; end})
assert_parses(
s(:def, :until, s(:args), nil),
%q{def until; end})
assert_parses(
s(:def, :BEGIN, s(:args), nil),
%q{def BEGIN; end})
assert_parses(
s(:def, :END, s(:args), nil),
%q{def END; end})
end
def test_defs
assert_parses(
s(:defs, s(:self), :foo, s(:args), nil),
%q{def self.foo; end},
%q{~~~ keyword
| ^ operator
| ~~~ name
| ~~~ end})
assert_parses(
s(:defs, s(:self), :foo, s(:args), nil),
%q{def self::foo; end},
%q{~~~ keyword
| ^^ operator
| ~~~ name
| ~~~ end})
assert_parses(
s(:defs, s(:lvar, :foo), :foo, s(:args), nil),
%q{def (foo).foo; end})
assert_parses(
s(:defs, s(:const, nil, :String), :foo,
s(:args), nil),
%q{def String.foo; end})
assert_parses(
s(:defs, s(:const, nil, :String), :foo,
s(:args), nil),
%q{def String::foo; end})
end
def test_defs_invalid
assert_diagnoses(
[:error, :singleton_literal],
%q{def (1).foo; end},
%q{ ~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def ("foo").foo; end},
%q{ ~~~~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def ("foo#{bar}").foo; end},
%q{ ~~~~~~~~~~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def (:foo).foo; end},
%q{ ~~~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def (:"foo#{bar}").foo; end},
%q{ ~~~~~~~~~~~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def ([]).foo; end},
%q{ ~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def ({}).foo; end},
%q{ ~~ location})
assert_diagnoses(
[:error, :singleton_literal],
%q{def (/foo/).foo; end},
%q{ ~~~~~ location})
end
def test_undef
assert_parses(
s(:undef,
s(:sym, :foo),
s(:sym, :bar),
s(:dsym, s(:str, 'foo'), s(:begin, s(:int, 1)))),
%q{undef foo, :bar, :"foo#{1}"},
%q{~~~~~ keyword
| ~~~ expression (sym/1)
| ~~~~ expression (sym/2)
|~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
#
# Aliasing
#
def test_alias
assert_parses(
s(:alias, s(:sym, :foo), s(:sym, :bar)),
%q{alias :foo bar},
%q{~~~~~ keyword
| ~~~~ expression (sym/1)
| ~~~ expression (sym/2)
|~~~~~~~~~~~~~~ expression})
end
def test_alias_gvar
assert_parses(
s(:alias, s(:gvar, :$a), s(:gvar, :$b)),
%q{alias $a $b},
%q{ ~~ expression (gvar/1)})
assert_parses(
s(:alias, s(:gvar, :$a), s(:back_ref, :$+)),
%q{alias $a $+},
%q{ ~~ expression (back_ref)})
end
def test_alias_nth_ref
assert_diagnoses(
[:error, :nth_ref_alias],
%q{alias $a $1},
%q{ ~~ location})
end
#
# Formal arguments
#
def test_arg
assert_parses(
s(:def, :f,
s(:args, s(:arg, :foo)),
nil),
%q{def f(foo); end},
%q{ ~~~ name (args.arg)
| ~~~ expression (args.arg)
| ^ begin (args)
| ^ end (args)
| ~~~~~ expression (args)})
assert_parses(
s(:def, :f,
s(:args, s(:arg, :foo), s(:arg, :bar)),
nil),
%q{def f(foo, bar); end})
end
def test_optarg
assert_parses(
s(:def, :f,
s(:args, s(:optarg, :foo, s(:int, 1))),
nil),
%q{def f foo = 1; end},
%q{ ~~~ name (args.optarg)
| ^ operator (args.optarg)
| ~~~~~~~ expression (args.optarg)
| ~~~~~~~ expression (args)})
assert_parses(
s(:def, :f,
s(:args,
s(:optarg, :foo, s(:int, 1)),
s(:optarg, :bar, s(:int, 2))),
nil),
%q{def f(foo=1, bar=2); end})
end
def test_restarg_named
assert_parses(
s(:def, :f,
s(:args, s(:restarg, :foo)),
nil),
%q{def f(*foo); end},
%q{ ~~~ name (args.restarg)
| ~~~~ expression (args.restarg)})
end
def test_restarg_unnamed
assert_parses(
s(:def, :f,
s(:args, s(:restarg)),
nil),
%q{def f(*); end},
%q{ ~ expression (args.restarg)})
end
def test_kwarg
assert_parses(
s(:def, :f,
s(:args, s(:kwarg, :foo)),
nil),
%q{def f(foo:); end},
%q{ ~~~ name (args.kwarg)
| ~~~~ expression (args.kwarg)},
SINCE_2_1)
end
def test_kwoptarg
assert_parses(
s(:def, :f,
s(:args, s(:kwoptarg, :foo, s(:int, 1))),
nil),
%q{def f(foo: 1); end},
%q{ ~~~ name (args.kwoptarg)
| ~~~~~~ expression (args.kwoptarg)},
SINCE_2_0)
end
def test_kwrestarg_named
assert_parses(
s(:def, :f,
s(:args, s(:kwrestarg, :foo)),
nil),
%q{def f(**foo); end},
%q{ ~~~ name (args.kwrestarg)
| ~~~~~ expression (args.kwrestarg)},
SINCE_2_0)
end
def test_kwrestarg_unnamed
assert_parses(
s(:def, :f,
s(:args, s(:kwrestarg)),
nil),
%q{def f(**); end},
%q{ ~~ expression (args.kwrestarg)},
SINCE_2_0)
end
def test_kwnilarg
assert_parses(
s(:def, :f,
s(:args, s(:kwnilarg)),
nil),
%q{def f(**nil); end},
%q{ ~~~~~ expression (args.kwnilarg)
| ~~~ name (args.kwnilarg)},
SINCE_2_7)
assert_parses(
s(:block,
s(:send, nil, :m),
s(:args,
s(:kwnilarg)), nil),
%q{m { |**nil| }},
%q{ ~~~~~ expression (args.kwnilarg)
| ~~~ name (args.kwnilarg)},
SINCE_2_7)
assert_parses(
s(:block,
s(:lambda),
s(:args,
s(:kwnilarg)), nil),
%q{->(**nil) {}},
%q{ ~~~~~ expression (args.kwnilarg)
| ~~~ name (args.kwnilarg)},
SINCE_2_7)
end
def test_blockarg
assert_parses(
s(:def, :f,
s(:args, s(:blockarg, :block)),
nil),
%q{def f(&block); end},
%q{ ~~~~~ name (args.blockarg)
| ~~~~~~ expression (args.blockarg)})
end
def test_objc_arg
assert_parses(
s(:def, :f,
s(:args, s(:arg, :a), s(:objc_kwarg, :b, :c)),
nil),
%q{def f(a, b: c); end},
%q{ ~ keyword (args.objc_kwarg)
| ~ operator (args.objc_kwarg)
| ~ argument (args.objc_kwarg)
| ~~~~ expression (args.objc_kwarg)},
%w(mac))
assert_parses(
s(:def, :f,
s(:args, s(:arg, :a), s(:objc_kwarg, :b, :c)),
nil),
%q{def f(a, b => c); end},
%q{ ~ keyword (args.objc_kwarg)
| ~~ operator (args.objc_kwarg)
| ~ argument (args.objc_kwarg)
| ~~~~~~ expression (args.objc_kwarg)},
%w(mac))
end
def test_arg_scope
# [ruby-core:61299] [Bug #9593]
assert_parses(
s(:def, :f,
s(:args, s(:optarg, :var, s(:defined?, s(:lvar, :var)))),
s(:lvar, :var)),
%q{def f(var = defined?(var)) var end},
%q{},
SINCE_2_7 - SINCE_2_1)
assert_parses(
s(:def, :f,
s(:args, s(:kwoptarg, :var, s(:defined?, s(:lvar, :var)))),
s(:lvar, :var)),
%q{def f(var: defined?(var)) var end},
%q{},
SINCE_2_7 - SINCE_2_1)
assert_parses(
s(:block,
s(:send, nil, :lambda),
s(:args, s(:shadowarg, :a)),
s(:lvar, :a)),
%q{lambda{|;a|a}},
%q{},
SINCE_1_9)
end
def assert_parses_args(ast, code, versions=ALL_VERSIONS)
assert_parses(
s(:def, :f, ast, nil),
%Q{def f #{code}; end},
%q{},
versions)
end
def test_arg_combinations
# f_arg tCOMMA f_optarg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:blockarg, :b)),
%q{a, o=1, *r, &b})
# f_arg tCOMMA f_optarg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{a, o=1, *r, p, &b},
SINCE_1_9)
# f_arg tCOMMA f_optarg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:blockarg, :b)),
%q{a, o=1, &b})
# f_arg tCOMMA f_optarg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:arg, :p),
s(:blockarg, :b)),
%q{a, o=1, p, &b},
SINCE_1_9)
# f_arg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:restarg, :r),
s(:blockarg, :b)),
%q{a, *r, &b})
# f_arg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{a, *r, p, &b},
SINCE_1_9)
# f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:arg, :a),
s(:blockarg, :b)),
%q{a, &b})
# f_optarg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:blockarg, :b)),
%q{o=1, *r, &b})
# f_optarg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{o=1, *r, p, &b},
SINCE_1_9)
# f_optarg opt_f_block_arg
assert_parses_args(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:blockarg, :b)),
%q{o=1, &b})
# f_optarg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:arg, :p),
s(:blockarg, :b)),
%q{o=1, p, &b},
SINCE_1_9)
# f_rest_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:restarg, :r),
s(:blockarg, :b)),
%q{*r, &b})
# f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_args(
s(:args,
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{*r, p, &b},
SINCE_1_9)
# f_block_arg
assert_parses_args(
s(:args,
s(:blockarg, :b)),
%q{&b})
# (nothing)
assert_parses_args(
s(:args),
%q{})
end
def test_kwarg_combinations
# f_kwarg tCOMMA f_kwrest opt_f_block_arg
assert_parses_args(
s(:args,
s(:kwoptarg, :foo, s(:int, 1)),
s(:kwoptarg, :bar, s(:int, 2)),
s(:kwrestarg, :baz),
s(:blockarg, :b)),
%q{(foo: 1, bar: 2, **baz, &b)},
SINCE_2_0)
# f_kwarg opt_f_block_arg
assert_parses_args(
s(:args,
s(:kwoptarg, :foo, s(:int, 1)),
s(:blockarg, :b)),
%q{(foo: 1, &b)},
SINCE_2_0)
# f_kwrest opt_f_block_arg
assert_parses_args(
s(:args,
s(:kwrestarg, :baz),
s(:blockarg, :b)),
%q{**baz, &b},
SINCE_2_0)
assert_parses_args(
s(:args,
s(:restarg),
s(:kwrestarg)),
%q{*, **},
SINCE_2_0)
end
def test_kwarg_no_paren
assert_parses_args(
s(:args,
s(:kwarg, :foo)),
%Q{foo:\n},
SINCE_2_1)
assert_parses_args(
s(:args,
s(:kwoptarg, :foo, s(:int, -1))),
%Q{foo: -1\n},
SINCE_2_1)
end
def assert_parses_margs(ast, code, versions=SINCE_1_9)
assert_parses_args(
s(:args, ast),
%Q{(#{code})},
versions)
end
def test_marg_combinations
# tLPAREN f_margs rparen
assert_parses_margs(
s(:mlhs,
s(:mlhs, s(:arg, :a))),
%q{((a))})
# f_marg_list
assert_parses_margs(
s(:mlhs, s(:arg, :a), s(:arg, :a1)),
%q{(a, a1)})
# f_marg_list tCOMMA tSTAR f_norm_arg
assert_parses_margs(
s(:mlhs, s(:arg, :a), s(:restarg, :r)),
%q{(a, *r)})
# f_marg_list tCOMMA tSTAR f_norm_arg tCOMMA f_marg_list
assert_parses_margs(
s(:mlhs, s(:arg, :a), s(:restarg, :r), s(:arg, :p)),
%q{(a, *r, p)})
# f_marg_list tCOMMA tSTAR
assert_parses_margs(
s(:mlhs, s(:arg, :a), s(:restarg)),
%q{(a, *)})
# f_marg_list tCOMMA tSTAR tCOMMA f_marg_list
assert_parses_margs(
s(:mlhs, s(:arg, :a), s(:restarg), s(:arg, :p)),
%q{(a, *, p)})
# tSTAR f_norm_arg
assert_parses_margs(
s(:mlhs, s(:restarg, :r)),
%q{(*r)})
# tSTAR f_norm_arg tCOMMA f_marg_list
assert_parses_margs(
s(:mlhs, s(:restarg, :r), s(:arg, :p)),
%q{(*r, p)})
# tSTAR
assert_parses_margs(
s(:mlhs, s(:restarg)),
%q{(*)})
# tSTAR tCOMMA f_marg_list
assert_parses_margs(
s(:mlhs, s(:restarg), s(:arg, :p)),
%q{(*, p)})
end
def test_marg_objc_restarg
assert_parses(
s(:def, :f,
s(:args,
s(:arg, :a),
s(:mlhs,
s(:objc_restarg, s(:objc_kwarg, :b, :c)))),
nil),
%Q{def f(a, (*b: c)); end},
%q{ ~ operator (args.mlhs.objc_restarg)
| ~~~~~ expression (args.mlhs.objc_restarg)},
%w(mac))
end
def assert_parses_blockargs(ast, code, versions=ALL_VERSIONS)
assert_parses(
s(:block,
s(:send, nil, :f),
ast, nil),
%Q{f{ #{code} }},
%q{},
versions)
end
def test_block_arg_combinations
# none
assert_parses_blockargs(
s(:args),
%q{})
# tPIPE tPIPE
# tPIPE opt_bv_decl tPIPE
assert_parses_blockargs(
s(:args),
%q{| |})
assert_parses_blockargs(
s(:args, s(:shadowarg, :a)),
%q{|;a|},
SINCE_1_9)
assert_parses_blockargs(
s(:args, s(:shadowarg, :a)),
%Q{|;\na\n|},
SINCE_2_0)
# tOROP before 2.7 / tPIPE+tPIPE after
assert_parses_blockargs(
s(:args),
%q{||})
# block_par
# block_par tCOMMA
# block_par tCOMMA tAMPER lhs
# f_arg opt_f_block_arg
# f_arg tCOMMA
assert_parses_blockargs(
s(:args, s(:procarg0, s(:arg, :a))),
%q{|a|},
SINCE_1_9)
assert_parses_blockargs(
s(:args, s(:arg, :a)),
%q{|a|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:arg, :c)),
%q{|a, c|})
assert_parses_blockargs(
s(:args, s(:arg_expr, s(:ivasgn, :@a))),
%q{|@a|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:arg, :a)),
%q{|a,|}
)
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:blockarg, :b)),
%q{|a, &b|})
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|a, &@b|},
%w(1.8))
# block_par tCOMMA tSTAR lhs tCOMMA tAMPER lhs
# block_par tCOMMA tSTAR tCOMMA tAMPER lhs
# block_par tCOMMA tSTAR lhs
# block_par tCOMMA tSTAR
# f_arg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:restarg, :s), s(:blockarg, :b)),
%q{|a, *s, &b|})
assert_parses_blockargs(
s(:args, s(:arg, :a),
s(:restarg_expr, s(:ivasgn, :@s)),
s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|a, *@s, &@b|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:restarg), s(:blockarg, :b)),
%q{|a, *, &b|})
assert_parses_blockargs(
s(:args, s(:arg, :a),
s(:restarg),
s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|a, *, &@b|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:restarg, :s)),
%q{|a, *s|})
assert_parses_blockargs(
s(:args, s(:arg, :a),
s(:restarg_expr, s(:ivasgn, :@s))),
%q{|a, *@s|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:arg, :a), s(:restarg)),
%q{|a, *|})
# tSTAR lhs tCOMMA tAMPER lhs
# tSTAR lhs
# tSTAR
# tSTAR tCOMMA tAMPER lhs
# f_rest_arg opt_f_block_arg
assert_parses_blockargs(
s(:args, s(:restarg, :s), s(:blockarg, :b)),
%q{|*s, &b|})
assert_parses_blockargs(
s(:args,
s(:restarg_expr, s(:ivasgn, :@s)),
s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|*@s, &@b|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:restarg), s(:blockarg, :b)),
%q{|*, &b|})
assert_parses_blockargs(
s(:args,
s(:restarg),
s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|*, &@b|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:restarg, :s)),
%q{|*s|})
assert_parses_blockargs(
s(:args,
s(:restarg_expr, s(:ivasgn, :@s))),
%q{|*@s|},
%w(1.8))
assert_parses_blockargs(
s(:args, s(:restarg)),
%q{|*|})
# tAMPER lhs
# f_block_arg
assert_parses_blockargs(
s(:args, s(:blockarg, :b)),
%q{|&b|})
assert_parses_blockargs(
s(:args,
s(:blockarg_expr, s(:ivasgn, :@b))),
%q{|&@b|},
%w(1.8))
# f_arg tCOMMA f_block_optarg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:optarg, :o1, s(:int, 2)),
s(:restarg, :r),
s(:blockarg, :b)),
%q{|a, o=1, o1=2, *r, &b|},
SINCE_1_9)
# f_arg tCOMMA f_block_optarg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{|a, o=1, *r, p, &b|},
SINCE_1_9)
# f_arg tCOMMA f_block_optarg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:blockarg, :b)),
%q{|a, o=1, &b|},
SINCE_1_9)
# f_arg tCOMMA f_block_optarg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:optarg, :o, s(:int, 1)),
s(:arg, :p),
s(:blockarg, :b)),
%q{|a, o=1, p, &b|},
SINCE_1_9)
# f_arg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{|a, *r, p, &b|},
SINCE_1_9)
# f_block_optarg tCOMMA f_rest_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:blockarg, :b)),
%q{|o=1, *r, &b|},
SINCE_1_9)
# f_block_optarg tCOMMA f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{|o=1, *r, p, &b|},
SINCE_1_9)
# f_block_optarg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:blockarg, :b)),
%q{|o=1, &b|},
SINCE_1_9)
# f_block_optarg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:optarg, :o, s(:int, 1)),
s(:arg, :p),
s(:blockarg, :b)),
%q{|o=1, p, &b|},
SINCE_1_9)
# f_rest_arg tCOMMA f_arg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:restarg, :r),
s(:arg, :p),
s(:blockarg, :b)),
%q{|*r, p, &b|},
SINCE_1_9)
end
def test_multiple_args_with_trailing_comma
assert_parses_blockargs(
s(:args,
s(:arg, :a),
s(:arg, :b)),
%q(|a, b,|)
)
end
def test_procarg0_legacy
Parser::Builders::Default.emit_procarg0 = false
assert_parses_blockargs(
s(:args,
s(:arg, :a)),
%q{|a|}
)
ensure
Parser::Builders::Default.emit_procarg0 = true
end
def test_emit_arg_inside_procarg0_legacy
Parser::Builders::Default.emit_arg_inside_procarg0 = false
assert_parses_blockargs(
s(:args,
s(:procarg0, :a)),
%q{|a|},
SINCE_1_9)
ensure
Parser::Builders::Default.emit_arg_inside_procarg0 = true
end
def test_procarg0
assert_parses(
s(:block,
s(:send, nil, :m),
s(:args,
s(:procarg0, s(:arg, :foo))), nil),
%q{m { |foo| } },
%q{ ^^^ expression (args.procarg0)},
SINCE_1_9)
assert_parses(
s(:block,
s(:send, nil, :m),
s(:args,
s(:procarg0, s(:arg, :foo), s(:arg, :bar))), nil),
%q{m { |(foo, bar)| } },
%q{ ^ begin (args.procarg0)
| ^ end (args.procarg0)
| ^^^^^^^^^^ expression (args.procarg0)},
SINCE_1_9)
end
def test_block_kwarg_combinations
# f_block_kwarg tCOMMA f_kwrest opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:kwoptarg, :foo, s(:int, 1)),
s(:kwoptarg, :bar, s(:int, 2)),
s(:kwrestarg, :baz),
s(:blockarg, :b)),
%q{|foo: 1, bar: 2, **baz, &b|},
SINCE_2_0)
# f_block_kwarg opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:kwoptarg, :foo, s(:int, 1)),
s(:blockarg, :b)),
%q{|foo: 1, &b|},
SINCE_2_0)
# f_kwrest opt_f_block_arg
assert_parses_blockargs(
s(:args,
s(:kwrestarg, :baz),
s(:blockarg, :b)),
%q{|**baz, &b|},
SINCE_2_0)
end
def test_block_kwarg
assert_parses_blockargs(
s(:args,
s(:kwarg, :foo)),
%q{|foo:|},
SINCE_2_1)
end
def test_arg_invalid
assert_diagnoses(
[:error, :argument_const],
%q{def foo(Abc); end},
%q{ ~~~ location})
assert_diagnoses(
[:error, :argument_ivar],
%q{def foo(@abc); end},
%q{ ~~~~ location})
assert_diagnoses(
[:error, :argument_gvar],
%q{def foo($abc); end},
%q{ ~~~~ location})
assert_diagnoses(
[:error, :argument_cvar],
%q{def foo(@@abc); end},
%q{ ~~~~~ location})
end
def test_arg_duplicate
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, aa); end},
%q{ ^^ location
| ~~ highlights (0)})
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, aa=1); end},
%q{ ^^ location
| ~~ highlights (0)})
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, *aa); end},
%q{ ^^ location
| ~~ highlights (0)})
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, &aa); end},
%q{ ^^ location
| ~~ highlights (0)})
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, (bb, aa)); end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_1_9)
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, *r, aa); end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_1_9)
assert_diagnoses(
[:error, :duplicate_argument],
%q{lambda do |aa; aa| end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_1_9)
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, aa: 1); end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_2_0)
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, **aa); end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_2_0)
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(aa, aa:); end},
%q{ ^^ location
| ~~ highlights (0)},
SINCE_2_1)
end
def test_arg_duplicate_ignored
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(_, _); end},
%q{},
%w(1.8))
assert_parses(
s(:def, :foo,
s(:args, s(:arg, :_), s(:arg, :_)),
nil),
%q{def foo(_, _); end},
%q{},
SINCE_1_9)
assert_diagnoses(
[:error, :duplicate_argument],
%q{def foo(_a, _a); end},
%q{},
%w(1.8 1.9 mac ios))
assert_parses(
s(:def, :foo,
s(:args, s(:arg, :_a), s(:arg, :_a)),
nil),
%q{def foo(_a, _a); end},
%q{},
SINCE_2_0)
end
def test_arg_duplicate_proc
assert_parses(
s(:block, s(:send, nil, :proc),
s(:args, s(:arg, :a), s(:arg, :a)),
nil),
%q{proc{|a,a|}},
%q{},
%w(1.8))
assert_diagnoses(
[:error, :duplicate_argument],
%q{proc{|a,a|}},
%q{},
SINCE_1_9)
end
def test_kwarg_invalid
assert_diagnoses(
[:error, :argument_const],
%q{def foo(Abc: 1); end},
%q{ ~~~~ location},
SINCE_2_0)
assert_diagnoses(
[:error, :argument_const],
%q{def foo(Abc:); end},
%q{ ~~~~ location},
SINCE_2_1)
end
def test_arg_label
assert_parses(
s(:def, :foo, s(:args),
s(:send, nil, :a, s(:sym, :b))),
%q{def foo() a:b end},
%q{},
SINCE_1_9)
assert_parses(
s(:def, :foo, s(:args),
s(:send, nil, :a, s(:sym, :b))),
%Q{def foo\n a:b end},
%q{},
SINCE_1_9)
assert_parses(
s(:block,
s(:send, nil, :f),
s(:args),
s(:send, nil, :a,
s(:sym, :b))),
%Q{f { || a:b }},
%q{},
SINCE_1_9)
end
#
# Sends
#
# To self
def test_send_self
assert_parses(
s(:send, nil, :fun),
%q{fun},
%q{~~~ selector
|~~~ expression})
assert_parses(
s(:send, nil, :fun!),
%q{fun!},
%q{~~~~ selector
|~~~~ expression})
assert_parses(
s(:send, nil, :fun, s(:int, 1)),
%q{fun(1)},
%q{~~~ selector
| ^ begin
| ^ end
|~~~~~~ expression})
end
def test_send_self_block
assert_parses(
s(:block, s(:send, nil, :fun), s(:args), nil),
%q{fun { }})
assert_parses(
s(:block, s(:send, nil, :fun), s(:args), nil),
%q{fun() { }})
assert_parses(
s(:block, s(:send, nil, :fun, s(:int, 1)), s(:args), nil),
%q{fun(1) { }})
assert_parses(
s(:block, s(:send, nil, :fun), s(:args), nil),
%q{fun do end})
end
def test_send_block_blockarg
assert_diagnoses(
[:error, :block_and_blockarg],
%q{fun(&bar) do end},
%q{ ~~~~ location
| ~~ highlights (0)})
end
def test_send_objc_vararg
assert_parses(
s(:send, nil, :fun,
s(:int, 1),
s(:hash,
s(:pair, s(:sym, :bar), s(:objc_varargs, s(:int, 2), s(:int, 3), s(:nil))))),
%q{fun(1, bar: 2, 3, nil)},
%q{ ~~~~~~~~~ expression (hash.pair.objc_varargs)},
%w(mac))
end
# To receiver
def test_send_plain
assert_parses(
s(:send, s(:lvar, :foo), :fun),
%q{foo.fun},
%q{ ~~~ selector
| ^ dot
|~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :fun),
%q{foo::fun},
%q{ ~~~ selector
| ^^ dot
|~~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :Fun),
%q{foo::Fun()},
%q{ ~~~ selector
| ^^ dot
|~~~~~~~~~~ expression})
end
def test_send_plain_cmd
assert_parses(
s(:send, s(:lvar, :foo), :fun, s(:lvar, :bar)),
%q{foo.fun bar},
%q{ ~~~ selector
| ^ dot
|~~~~~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :fun, s(:lvar, :bar)),
%q{foo::fun bar},
%q{ ~~~ selector
| ^^ dot
|~~~~~~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :Fun, s(:lvar, :bar)),
%q{foo::Fun bar},
%q{ ~~~ selector
| ^^ dot
|~~~~~~~~~~~~ expression})
end
def test_send_plain_cmd_ambiguous_literal
assert_diagnoses(
[:warning, :ambiguous_literal],
%q{m /foo/},
%q{ ^ location})
refute_diagnoses(
%q{m %[1]})
end
def test_send_plain_cmd_ambiguous_prefix
assert_diagnoses(
[:warning, :ambiguous_prefix, { :prefix => '+' }],
%q{m +foo},
%q{ ^ location})
assert_diagnoses(
[:warning, :ambiguous_prefix, { :prefix => '-' }],
%q{m -foo},
%q{ ^ location})
assert_diagnoses(
[:warning, :ambiguous_prefix, { :prefix => '&' }],
%q{m &foo},
%q{ ^ location})
assert_diagnoses(
[:warning, :ambiguous_prefix, { :prefix => '*' }],
%q{m *foo},
%q{ ^ location})
assert_diagnoses(
[:warning, :ambiguous_prefix, { :prefix => '**' }],
%q{m **foo},
%q{ ^^ location},
SINCE_2_0)
end
def test_send_block_chain_cmd
assert_parses(
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
%q{meth 1 do end.fun bar},
%q{ ~~~ selector
| ^ dot
|~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
%q{meth 1 do end.fun(bar)},
%q{ ~~~ selector
| ^ dot
| ^ begin
| ^ end
|~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
%q{meth 1 do end::fun bar},
%q{ ~~~ selector
| ^^ dot
|~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
%q{meth 1 do end::fun(bar)},
%q{ ~~~ selector
| ^ begin
| ^ end
| ^^ dot
|~~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:block,
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
s(:args), nil),
%q{meth 1 do end.fun bar do end},
%q{},
SINCE_2_0)
assert_parses(
s(:block,
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun, s(:lvar, :bar)),
s(:args), nil),
%q{meth 1 do end.fun(bar) {}},
%q{},
SINCE_2_0)
assert_parses(
s(:block,
s(:send,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil),
:fun),
s(:args), nil),
%q{meth 1 do end.fun {}},
%q{},
SINCE_2_0)
end
def test_send_paren_block_cmd
assert_parses(
s(:send, nil, :foo,
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil)),
%q{foo(meth 1 do end)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :foo,
s(:int, 1),
s(:block,
s(:send, nil, :meth, s(:int, 1)),
s(:args), nil)),
%q{foo(1, meth 1 do end)},
%q{},
%w(1.8))
end
def test_send_binary_op
assert_parses(
s(:send, s(:lvar, :foo), :+, s(:int, 1)),
%q{foo + 1},
%q{ ~ selector
|~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :-, s(:int, 1)),
%q{foo - 1})
assert_parses(
s(:send, s(:lvar, :foo), :*, s(:int, 1)),
%q{foo * 1})
assert_parses(
s(:send, s(:lvar, :foo), :/, s(:int, 1)),
%q{foo / 1})
assert_parses(
s(:send, s(:lvar, :foo), :%, s(:int, 1)),
%q{foo % 1})
assert_parses(
s(:send, s(:lvar, :foo), :**, s(:int, 1)),
%q{foo ** 1})
assert_parses(
s(:send, s(:lvar, :foo), :|, s(:int, 1)),
%q{foo | 1})
assert_parses(
s(:send, s(:lvar, :foo), :^, s(:int, 1)),
%q{foo ^ 1})
assert_parses(
s(:send, s(:lvar, :foo), :&, s(:int, 1)),
%q{foo & 1})
assert_parses(
s(:send, s(:lvar, :foo), :<=>, s(:int, 1)),
%q{foo <=> 1})
assert_parses(
s(:send, s(:lvar, :foo), :<, s(:int, 1)),
%q{foo < 1})
assert_parses(
s(:send, s(:lvar, :foo), :<=, s(:int, 1)),
%q{foo <= 1})
assert_parses(
s(:send, s(:lvar, :foo), :>, s(:int, 1)),
%q{foo > 1})
assert_parses(
s(:send, s(:lvar, :foo), :>=, s(:int, 1)),
%q{foo >= 1})
assert_parses(
s(:send, s(:lvar, :foo), :==, s(:int, 1)),
%q{foo == 1})
assert_parses(
s(:not, s(:send, s(:lvar, :foo), :==, s(:int, 1))),
%q{foo != 1},
%q{},
%w(1.8))
assert_parses(
s(:send, s(:lvar, :foo), :'!=', s(:int, 1)),
%q{foo != 1},
%q{},
SINCE_1_9)
assert_parses(
s(:send, s(:lvar, :foo), :===, s(:int, 1)),
%q{foo === 1})
assert_parses(
s(:send, s(:lvar, :foo), :=~, s(:int, 1)),
%q{foo =~ 1})
assert_parses(
s(:not, s(:send, s(:lvar, :foo), :=~, s(:int, 1))),
%q{foo !~ 1},
%q{},
%w(1.8))
assert_parses(
s(:send, s(:lvar, :foo), :'!~', s(:int, 1)),
%q{foo !~ 1},
%q{},
SINCE_1_9)
assert_parses(
s(:send, s(:lvar, :foo), :<<, s(:int, 1)),
%q{foo << 1})
assert_parses(
s(:send, s(:lvar, :foo), :>>, s(:int, 1)),
%q{foo >> 1})
end
def test_send_unary_op
assert_parses(
s(:send, s(:lvar, :foo), :-@),
%q{-foo},
%q{~ selector
|~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :+@),
%q{+foo})
assert_parses(
s(:send, s(:lvar, :foo), :~),
%q{~foo})
end
def test_bang
assert_parses(
s(:not, s(:lvar, :foo)),
%q{!foo},
%{},
%w(1.8))
assert_parses(
s(:send, s(:lvar, :foo), :'!'),
%q{!foo},
%{},
SINCE_1_9)
end
def test_bang_cmd
assert_parses(
s(:not, s(:send, nil, :m, s(:lvar, :foo))),
%q{!m foo},
%{},
%w(1.8))
assert_parses(
s(:send, s(:send, nil, :m, s(:lvar, :foo)), :'!'),
%q{!m foo},
%{},
SINCE_1_9)
end
def test_not
assert_parses(
s(:not, s(:lvar, :foo)),
%q{not foo},
%{},
%w(1.8))
assert_parses(
s(:send, s(:lvar, :foo), :'!'),
%q{not foo},
%{},
SINCE_1_9)
assert_parses(
s(:send, s(:lvar, :foo), :'!'),
%q{not(foo)},
%q{~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:send, s(:begin), :'!'),
%q{not()},
%q{~~~~~ expression},
SINCE_1_9)
end
def test_not_cmd
assert_parses(
s(:not, s(:send, nil, :m, s(:lvar, :foo))),
%q{not m foo},
%{},
%w(1.8))
assert_parses(
s(:send, s(:send, nil, :m, s(:lvar, :foo)), :'!'),
%q{not m foo},
%{},
SINCE_1_9)
end
def test_unary_num_pow_precedence
assert_parses(
s(:send,
s(:send,
s(:int, 2), :**, s(:int, 10)),
:+@),
%q{+2 ** 10},
%{},
%w{2.1})
assert_parses(
s(:send,
s(:send,
s(:float, 2.0), :**, s(:int, 10)),
:+@),
%q{+2.0 ** 10})
assert_parses(
s(:send,
s(:send,
s(:int, 2), :**, s(:int, 10)),
:-@),
%q{-2 ** 10})
assert_parses(
s(:send,
s(:send,
s(:float, 2.0), :**, s(:int, 10)),
:-@),
%q{-2.0 ** 10})
end
def test_send_attr_asgn
assert_parses(
s(:send, s(:lvar, :foo), :a=, s(:int, 1)),
%q{foo.a = 1},
%q{ ~ selector
| ^ dot
| ^ operator
|~~~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :a=, s(:int, 1)),
%q{foo::a = 1},
%q{ ~ selector
| ^^ dot
| ^ operator
|~~~~~~~~~~ expression})
assert_parses(
s(:send, s(:lvar, :foo), :A=, s(:int, 1)),
%q{foo.A = 1},
%q{ ~ selector
| ^ dot
| ^ operator
|~~~~~~~~~ expression})
assert_parses(
s(:casgn, s(:lvar, :foo), :A, s(:int, 1)),
%q{foo::A = 1},
%q{ ~ name
| ^^ double_colon
| ^ operator
|~~~~~~~~~~ expression})
end
def test_send_index
assert_parses(
s(:index, s(:lvar, :foo),
s(:int, 1), s(:int, 2)),
%q{foo[1, 2]},
%q{ ^ begin
| ^ end
|~~~~~~~~~ expression})
end
def test_send_index_legacy
Parser::Builders::Default.emit_index = false
assert_parses(
s(:send, s(:lvar, :foo), :[],
s(:int, 1), s(:int, 2)),
%q{foo[1, 2]},
%q{ ~~~~~~ selector
|~~~~~~~~~ expression})
ensure
Parser::Builders::Default.emit_index = true
end
def test_send_index_cmd
assert_parses(
s(:index, s(:lvar, :foo),
s(:send, nil, :m, s(:lvar, :bar))),
%q{foo[m bar]})
end
def test_send_index_asgn
assert_parses(
s(:indexasgn, s(:lvar, :foo),
s(:int, 1), s(:int, 2), s(:int, 3)),
%q{foo[1, 2] = 3},
%q{ ^ begin
| ^ end
| ^ operator
|~~~~~~~~~~~~~ expression})
end
def test_send_index_asgn_legacy
Parser::Builders::Default.emit_index = false
assert_parses(
s(:send, s(:lvar, :foo), :[]=,
s(:int, 1), s(:int, 2), s(:int, 3)),
%q{foo[1, 2] = 3},
%q{ ~~~~~~ selector
| ^ operator
|~~~~~~~~~~~~~ expression})
ensure
Parser::Builders::Default.emit_index = true
end
def test_send_lambda
assert_parses(
s(:block, s(:lambda),
s(:args), nil),
%q{->{ }},
%q{~~ expression (lambda)
| ^ begin
| ^ end
|~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:block, s(:lambda),
s(:args, s(:restarg)), nil),
%q{-> * { }},
%q{~~ expression (lambda)
| ^ begin
| ^ end
| ^ expression (args.restarg)
|~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:block, s(:lambda),
s(:args), nil),
%q{-> do end},
%q{~~ expression (lambda)
| ^^ begin
| ^^^ end
|~~~~~~~~~ expression},
SINCE_1_9)
end
def test_send_lambda_args
assert_parses(
s(:block, s(:lambda),
s(:args,
s(:arg, :a)),
nil),
%q{->(a) { }},
%q{~~ expression (lambda)
| ^ begin (args)
| ^ end (args)
| ^ begin
| ^ end
|~~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:block, s(:lambda),
s(:args,
s(:arg, :a)),
nil),
%q{-> (a) { }},
%q{},
SINCE_2_0)
end
def test_send_lambda_args_shadow
assert_parses(
s(:block, s(:lambda),
s(:args,
s(:arg, :a),
s(:shadowarg, :foo),
s(:shadowarg, :bar)),
nil),
%q{->(a; foo, bar) { }},
%q{ ~~~ expression (args.shadowarg)},
SINCE_1_9)
end
def test_send_lambda_args_noparen
assert_parses(
s(:block, s(:lambda),
s(:args,
s(:kwoptarg, :a, s(:int, 1))),
nil),
%q{-> a: 1 { }},
%q{},
SINCE_2_0)
assert_parses(
s(:block, s(:lambda),
s(:args,
s(:kwarg, :a)),
nil),
%q{-> a: { }},
%q{},
SINCE_2_1)
end
def test_send_lambda_legacy
Parser::Builders::Default.emit_lambda = false
assert_parses(
s(:block, s(:send, nil, :lambda),
s(:args), nil),
%q{->{ }},
%q{~~ selector (send)
| ^ begin
| ^ end
|~~~~~ expression},
SINCE_1_9)
ensure
Parser::Builders::Default.emit_lambda = true
end
def test_send_call
assert_parses(
s(:send, s(:lvar, :foo), :call,
s(:int, 1)),
%q{foo.(1)},
%q{ ^ begin
| ^ end
| ^ dot
|~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:send, s(:lvar, :foo), :call,
s(:int, 1)),
%q{foo::(1)},
%q{ ^ begin
| ^ end
| ^^ dot
|~~~~~~~~ expression},
SINCE_1_9)
end
def test_send_conditional
assert_parses(
s(:csend, s(:send, nil, :a), :b),
%q{a&.b},
%q{ ^^ dot},
SINCE_2_3 + %w{ios})
end
def test_send_attr_asgn_conditional
assert_parses(
s(:csend, s(:send, nil, :a), :b=, s(:int, 1)),
%q{a&.b = 1},
%q{ ^^ dot},
SINCE_2_3 + %w{ios})
end
def test_send_block_conditional
assert_parses(
s(:block,
s(:csend,
s(:lvar, :foo), :bar),
s(:args), nil),
%q{foo&.bar {}},
%q{},
SINCE_2_3 + %w{ios})
end
def test_send_op_asgn_conditional
assert_parses(
s(:and_asgn, s(:csend, s(:send, nil, :a), :b), s(:int, 1)),
%q{a&.b &&= 1},
%q{},
SINCE_2_3 + %w{ios})
end
def test_lvar_injecting_match
assert_parses(
s(:begin,
s(:match_with_lvasgn,
s(:regexp,
s(:str, '(?bar)'),
s(:regopt)),
s(:str, 'bar')),
s(:lvar, :match)),
%q{/(?bar)/ =~ 'bar'; match},
%q{ ~~ selector (match_with_lvasgn)
|~~~~~~~~~~~~~~~~~~~~~~~~ expression (match_with_lvasgn)},
SINCE_1_9)
end
def test_non_lvar_injecting_match
assert_parses(
s(:send,
s(:regexp,
s(:begin, s(:int, 1)),
s(:str, '(?bar)'),
s(:regopt)),
:=~,
s(:str, 'bar')),
%q{/#{1}(?bar)/ =~ 'bar'})
end
# To superclass
def test_super
assert_parses(
s(:super, s(:lvar, :foo)),
%q{super(foo)},
%q{~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~~~~ expression})
assert_parses(
s(:super, s(:lvar, :foo)),
%q{super foo},
%q{~~~~~ keyword
|~~~~~~~~~ expression})
assert_parses(
s(:super),
%q{super()},
%q{~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~ expression})
end
def test_zsuper
assert_parses(
s(:zsuper),
%q{super},
%q{~~~~~ keyword
|~~~~~ expression})
end
def test_super_block
assert_parses(
s(:block,
s(:super, s(:lvar, :foo), s(:lvar, :bar)),
s(:args), nil),
%q{super foo, bar do end})
assert_parses(
s(:block,
s(:zsuper),
s(:args), nil),
%q{super do end})
end
# To block argument
def test_yield
assert_parses(
s(:yield, s(:lvar, :foo)),
%q{yield(foo)},
%q{~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~~~~ expression})
assert_parses(
s(:yield, s(:lvar, :foo)),
%q{yield foo},
%q{~~~~~ keyword
|~~~~~~~~~ expression})
assert_parses(
s(:yield),
%q{yield()},
%q{~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~ expression})
assert_parses(
s(:yield),
%q{yield},
%q{~~~~~ keyword
|~~~~~ expression})
end
def test_yield_block
assert_diagnoses(
[:error, :block_given_to_yield],
%q{yield foo do end},
%q{~~~~~ location
| ~~ highlights (0)})
assert_diagnoses(
[:error, :block_given_to_yield],
%q{yield(&foo)},
%q{~~~~~ location
| ~~~~ highlights (0)})
end
# Call arguments
def test_args_cmd
assert_parses(
s(:send, nil, :fun,
s(:send, nil, :f, s(:lvar, :bar))),
%q{fun(f bar)})
end
def test_args_args_star
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:splat, s(:lvar, :bar))),
%q{fun(foo, *bar)})
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun(foo, *bar, &baz)})
end
def test_args_star
assert_parses(
s(:send, nil, :fun,
s(:splat, s(:lvar, :bar))),
%q{fun(*bar)})
assert_parses(
s(:send, nil, :fun,
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun(*bar, &baz)})
end
def test_args_block_pass
assert_parses(
s(:send, nil, :fun,
s(:block_pass, s(:lvar, :bar))),
%q{fun(&bar)})
end
def test_args_args_comma
assert_parses(
s(:index, s(:lvar, :foo),
s(:lvar, :bar)),
%q{foo[bar,]},
%q{},
SINCE_1_9)
end
def test_args_assocs
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1)))),
%q{fun(:foo => 1)})
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:block_pass, s(:lvar, :baz))),
%q{fun(:foo => 1, &baz)})
end
def test_args_assocs_star
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar))),
%q{fun(:foo => 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun(:foo => 1, *bar, &baz)},
%q{},
%w(1.8))
end
def test_args_assocs_comma
assert_parses(
s(:index, s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :baz), s(:int, 1)))),
%q{foo[:baz => 1,]},
%q{},
SINCE_1_9)
end
def test_args_args_assocs
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1)))),
%q{fun(foo, :foo => 1)})
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:block_pass, s(:lvar, :baz))),
%q{fun(foo, :foo => 1, &baz)})
end
def test_args_args_assocs_comma
assert_parses(
s(:index, s(:lvar, :foo),
s(:lvar, :bar),
s(:hash, s(:pair, s(:sym, :baz), s(:int, 1)))),
%q{foo[bar, :baz => 1,]},
%q{},
SINCE_1_9)
end
def test_args_args_assocs_star
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar))),
%q{fun(foo, :foo => 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun(foo, :foo => 1, *bar, &baz)},
%q{},
%w(1.8))
end
# Call arguments with whitespace
def test_space_args_cmd
assert_parses(
s(:send, nil, :fun,
s(:begin, s(:send, nil, :f, s(:lvar, :bar)))),
%q{fun (f bar)})
end
def test_space_args_arg
assert_parses(
s(:send, nil, :fun, s(:begin, s(:int, 1))),
%q{fun (1)})
end
def test_space_args_arg_newline
assert_parses(
s(:send, nil, :fun, s(:begin, s(:int, 1))),
%Q{fun (1\n)},
%q{},
ALL_VERSIONS - %w(mac))
end
def test_space_args_arg_block
assert_parses(
s(:block,
s(:send, nil, :fun, s(:begin, s(:int, 1))),
s(:args), nil),
%q{fun (1) {}})
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun, s(:int, 1)),
s(:args), nil),
%q{foo.fun (1) {}},
%q{},
%w(1.8))
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun, s(:begin, s(:int, 1))),
s(:args), nil),
%q{foo.fun (1) {}},
%q{},
SINCE_1_9)
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun, s(:int, 1)),
s(:args), nil),
%q{foo::fun (1) {}},
%q{},
%w(1.8))
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun, s(:begin, s(:int, 1))),
s(:args), nil),
%q{foo::fun (1) {}},
%q{},
SINCE_1_9)
end
def test_space_args_hash_literal_then_block
# This code only parses if the lexer enters expr_endarg state correctly
assert_parses(
s(:block,
s(:send, nil, :f, s(:int, 1), s(:hash, s(:pair, s(:int, 1), s(:int, 2)))),
s(:args),
s(:int, 1)),
%q{f 1, {1 => 2} {1}},
%q{},
ALL_VERSIONS - SINCE_2_5)
end
def test_space_args_arg_call
assert_parses(
s(:send, nil, :fun,
s(:send, s(:begin, s(:int, 1)), :to_i)),
%q{fun (1).to_i})
end
def test_space_args_block_pass
assert_parses(
s(:send, nil, :fun,
s(:block_pass, s(:lvar, :foo))),
%q{fun (&foo)},
%q{},
%w(1.8))
end
def test_space_args_arg_block_pass
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:block_pass, s(:lvar, :bar))),
%q{fun (foo, &bar)},
%q{},
%w(1.8))
end
def test_space_args_args_star
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:splat, s(:lvar, :bar))),
%q{fun (foo, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, *bar, &baz)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:splat, s(:lvar, :bar))),
%q{fun (foo, 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, 1, *bar, &baz)},
%q{},
%w(1.8))
end
def test_space_args_star
assert_parses(
s(:send, nil, :fun,
s(:splat, s(:lvar, :bar))),
%q{fun (*bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (*bar, &baz)},
%q{},
%w(1.8))
end
def test_space_args_assocs
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1)))),
%q{fun (:foo => 1)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:block_pass, s(:lvar, :baz))),
%q{fun (:foo => 1, &baz)},
%q{},
%w(1.8))
end
def test_space_args_assocs_star
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar))),
%q{fun (:foo => 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (:foo => 1, *bar, &baz)},
%q{},
%w(1.8))
end
def test_space_args_args_assocs
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1)))),
%q{fun (foo, :foo => 1)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, :foo => 1, &baz)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1)))),
%q{fun (foo, 1, :foo => 1)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, 1, :foo => 1, &baz)},
%q{},
%w(1.8))
end
def test_space_args_args_assocs_star
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar))),
%q{fun (foo, :foo => 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, :foo => 1, *bar, &baz)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar))),
%q{fun (foo, 1, :foo => 1, *bar)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :fun,
s(:lvar, :foo), s(:int, 1),
s(:hash, s(:pair, s(:sym, :foo), s(:int, 1))),
s(:splat, s(:lvar, :bar)),
s(:block_pass, s(:lvar, :baz))),
%q{fun (foo, 1, :foo => 1, *bar, &baz)},
%q{},
%w(1.8))
end
def test_space_args_arg_arg
assert_parses(
s(:send, nil, :fun, s(:int, 1), s(:int, 2)),
%q{fun (1, 2)},
%q{},
%w(1.8))
end
def test_space_args_none
assert_parses(
s(:send, nil, :fun),
%q{fun ()},
%q{},
%w(1.8))
end
def test_space_args_block
assert_parses(
s(:block,
s(:send, nil, :fun),
s(:args), nil),
%q{fun () {}},
%q{ ^ begin (send)
| ^ end (send)},
%w(1.8))
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun),
s(:args), nil),
%q{foo.fun () {}},
%q{ ^ begin (send)
| ^ end (send)},
%w(1.8))
assert_parses(
s(:block,
s(:send, s(:lvar, :foo), :fun),
s(:args), nil),
%q{foo::fun () {}},
%q{ ^ begin (send)
| ^ end (send)},
%w(1.8))
assert_parses(
s(:block,
s(:send, nil, :fun,
s(:begin)),
s(:args), nil),
%q{fun () {}},
%q{ ~~ expression (send.begin)},
SINCE_2_0)
end
#
# Control flow
#
# Operators
def test_and
assert_parses(
s(:and, s(:lvar, :foo), s(:lvar, :bar)),
%q{foo and bar},
%q{ ~~~ operator
|~~~~~~~~~~~ expression})
assert_parses(
s(:and, s(:lvar, :foo), s(:lvar, :bar)),
%q{foo && bar},
%q{ ~~ operator
|~~~~~~~~~~ expression})
end
def test_or
assert_parses(
s(:or, s(:lvar, :foo), s(:lvar, :bar)),
%q{foo or bar},
%q{ ~~ operator
|~~~~~~~~~~ expression})
assert_parses(
s(:or, s(:lvar, :foo), s(:lvar, :bar)),
%q{foo || bar},
%q{ ~~ operator
|~~~~~~~~~~ expression})
end
def test_and_or_masgn
assert_parses(
s(:and,
s(:lvar, :foo),
s(:begin,
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)),
s(:lvar, :bar)))),
%q{foo && (a, b = bar)})
assert_parses(
s(:or,
s(:lvar, :foo),
s(:begin,
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)),
s(:lvar, :bar)))),
%q{foo || (a, b = bar)})
end
# Branching
def test_if
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), nil),
%q{if foo then bar; end},
%q{~~ keyword
| ~~~~ begin
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), nil),
%q{if foo; bar; end},
%q{~~ keyword
| ~~~ end
|~~~~~~~~~~~~~~~~ expression})
end
def test_if_nl_then
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), nil),
%Q{if foo\nthen bar end},
%q{ ~~~~ begin})
end
def test_if_mod
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), nil),
%q{bar if foo},
%q{ ~~ keyword
|~~~~~~~~~~ expression})
end
def test_unless
assert_parses(
s(:if, s(:lvar, :foo), nil, s(:lvar, :bar)),
%q{unless foo then bar; end},
%q{~~~~~~ keyword
| ~~~~ begin
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:if, s(:lvar, :foo), nil, s(:lvar, :bar)),
%q{unless foo; bar; end},
%q{~~~~~~ keyword
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_unless_mod
assert_parses(
s(:if, s(:lvar, :foo), nil, s(:lvar, :bar)),
%q{bar unless foo},
%q{ ~~~~~~ keyword
|~~~~~~~~~~~~~~ expression})
end
def test_if_else
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), s(:lvar, :baz)),
%q{if foo then bar; else baz; end},
%q{~~ keyword
| ~~~~ begin
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar), s(:lvar, :baz)),
%q{if foo; bar; else baz; end},
%q{~~ keyword
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_unless_else
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :baz), s(:lvar, :bar)),
%q{unless foo then bar; else baz; end},
%q{~~~~~~ keyword
| ~~~~ begin
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :baz), s(:lvar, :bar)),
%q{unless foo; bar; else baz; end},
%q{~~~~~~ keyword
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_if_elsif
assert_parses(
s(:if, s(:lvar, :foo), s(:lvar, :bar),
s(:if, s(:lvar, :baz), s(:int, 1), s(:int, 2))),
%q{if foo; bar; elsif baz; 1; else 2; end},
%q{~~ keyword
| ~~~~~ else
| ~~~~~ keyword (if)
| ~~~~ else (if)
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_ternary
assert_parses(
s(:if, s(:lvar, :foo), s(:int, 1), s(:int, 2)),
%q{foo ? 1 : 2},
%q{ ^ question
| ^ colon
|~~~~~~~~~~~ expression})
end
def test_ternary_ambiguous_symbol
assert_parses(
s(:begin,
s(:lvasgn, :t, s(:int, 1)),
s(:if, s(:begin, s(:lvar, :foo)),
s(:lvar, :t),
s(:const, nil, :T))),
%q{t=1;(foo)?t:T},
%q{},
SINCE_1_9)
end
def test_if_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{if (a, b = foo); end},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_if_masgn__24
assert_parses(
s(:if,
s(:begin,
s(:masgn,
s(:mlhs,
s(:lvasgn, :a),
s(:lvasgn, :b)),
s(:lvar, :foo))), nil, nil),
%q{if (a, b = foo); end},
%q{},
SINCE_2_4)
end
def test_if_mod_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{1 if (a, b = foo)},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_tern_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{(a, b = foo) ? 1 : 2},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_not_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{!(a, b = foo)},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_not_masgn__24
assert_parses(
s(:send,
s(:begin,
s(:masgn,
s(:mlhs,
s(:lvasgn, :a),
s(:lvasgn, :b)),
s(:lvar, :foo))), :'!'),
%q{!(a, b = foo)},
%q{},
SINCE_2_4)
end
def test_cond_begin
assert_parses(
s(:if,
s(:begin, s(:lvar, :bar)),
s(:lvar, :foo),
nil),
%q{if (bar); foo; end})
end
def test_cond_begin_masgn
assert_parses(
s(:if,
s(:begin,
s(:lvar, :bar),
s(:masgn,
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)),
s(:lvar, :foo))),
nil, nil),
%q{if (bar; a, b = foo); end})
end
def test_cond_begin_and_or_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{if foo && (a, b = bar); end},
%q{ ~~~~~~~~~~ location},
%w(1.9 2.0 2.1 2.2 2.3 ios mac))
assert_diagnoses(
[:error, :masgn_as_condition],
%q{if foo || (a, b = bar); end},
%q{ ~~~~~~~~~~ location},
%w(1.9 2.0 2.1 2.2 2.3 ios mac))
assert_parses(
s(:if,
s(:and,
s(:begin,
s(:masgn,
s(:mlhs,
s(:lvasgn, :a), s(:lvasgn, :b)),
s(:lvar, :foo))),
s(:lvar, :bar)),
nil, nil),
%q{if (a, b = foo) && bar; end},
%q{},
%w(1.8))
end
def test_cond_iflipflop
assert_parses(
s(:if, s(:iflipflop, s(:lvar, :foo), s(:lvar, :bar)),
nil, nil),
%q{if foo..bar; end},
%q{ ~~~~~~~~ expression (iflipflop)
| ~~ operator (iflipflop)})
assert_parses(
s(:not, s(:begin, s(:iflipflop, s(:lvar, :foo), s(:lvar, :bar)))),
%q{!(foo..bar)},
%q{ ~~~~~~~~ expression (begin.iflipflop)
| ~~ operator (begin.iflipflop)},
%w(1.8))
assert_parses(
s(:send, s(:begin, s(:iflipflop, s(:lvar, :foo), s(:lvar, :bar))), :'!'),
%q{!(foo..bar)},
%q{ ~~~~~~~~ expression (begin.iflipflop)
| ~~ operator (begin.iflipflop)},
SINCE_1_9)
end
def test_cond_eflipflop
assert_parses(
s(:if, s(:eflipflop, s(:lvar, :foo), s(:lvar, :bar)),
nil, nil),
%q{if foo...bar; end},
%q{ ~~~~~~~~~ expression (eflipflop)
| ~~~ operator (eflipflop)})
assert_parses(
s(:not, s(:begin, s(:eflipflop, s(:lvar, :foo), s(:lvar, :bar)))),
%q{!(foo...bar)},
%q{ ~~~~~~~~~ expression (begin.eflipflop)
| ~~~ operator (begin.eflipflop)},
%w(1.8))
assert_parses(
s(:send, s(:begin, s(:eflipflop, s(:lvar, :foo), s(:lvar, :bar))), :'!'),
%q{!(foo...bar)},
%q{ ~~~~~~~~~ expression (begin.eflipflop)
| ~~~ operator (begin.eflipflop)},
SINCE_1_9)
end
def test_cond_match_current_line
assert_parses(
s(:if,
s(:match_current_line,
s(:regexp,
s(:str, 'wat'),
s(:regopt))),
nil, nil),
%q{if /wat/; end},
%q{ ~~~~~ expression (match_current_line)})
assert_parses(
s(:not,
s(:match_current_line,
s(:regexp,
s(:str, 'wat'),
s(:regopt)))),
%q{!/wat/},
%q{ ~~~~~ expression (match_current_line)},
%w(1.8))
assert_parses(
s(:send,
s(:match_current_line,
s(:regexp,
s(:str, 'wat'),
s(:regopt))),
:'!'),
%q{!/wat/},
%q{ ~~~~~ expression (match_current_line)},
SINCE_1_9)
end
# Case matching
def test_case_expr
assert_parses(
s(:case, s(:lvar, :foo),
s(:when, s(:str, 'bar'),
s(:lvar, :bar)),
nil),
%q{case foo; when 'bar'; bar; end},
%q{~~~~ keyword
| ~~~~ keyword (when)
| ~~~ end
| ~~~~~~~~~~~~~~~ expression (when)
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_case_expr_else
assert_parses(
s(:case, s(:lvar, :foo),
s(:when, s(:str, 'bar'),
s(:lvar, :bar)),
s(:lvar, :baz)),
%q{case foo; when 'bar'; bar; else baz; end},
%q{~~~~ keyword
| ~~~~ keyword (when)
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_case_cond
assert_parses(
s(:case, nil,
s(:when, s(:lvar, :foo),
s(:str, 'foo')),
nil),
%q{case; when foo; 'foo'; end},
%q{~~~~ keyword
| ~~~~ keyword (when)
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_case_cond_else
assert_parses(
s(:case, nil,
s(:when, s(:lvar, :foo),
s(:str, 'foo')),
s(:str, 'bar')),
%q{case; when foo; 'foo'; else 'bar'; end},
%q{~~~~ keyword
| ~~~~ keyword (when)
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_case_cond_just_else
assert_parses(
s(:case, nil,
s(:str, 'bar')),
%q{case; else 'bar'; end},
%q{~~~~ keyword
| ~~~~ else
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~ expression},
%w(1.8))
end
def test_when_then
assert_parses(
s(:case, s(:lvar, :foo),
s(:when, s(:str, 'bar'),
s(:lvar, :bar)),
nil),
%q{case foo; when 'bar' then bar; end},
%q{ ~~~~ keyword (when)
| ~~~~ begin (when)
| ~~~~~~~~~~~~~~~~~~~ expression (when)})
end
def test_when_multi
assert_parses(
s(:case, s(:lvar, :foo),
s(:when, s(:str, 'bar'), s(:str, 'baz'),
s(:lvar, :bar)),
nil),
%q{case foo; when 'bar', 'baz'; bar; end})
end
def test_when_splat
assert_parses(
s(:case, s(:lvar, :foo),
s(:when,
s(:int, 1),
s(:splat, s(:lvar, :baz)),
s(:lvar, :bar)),
s(:when,
s(:splat, s(:lvar, :foo)),
nil),
nil),
%q{case foo; when 1, *baz; bar; when *foo; end},
%q{ ^ operator (when/1.splat)
| ~~~~ expression (when/1.splat)
| ^ operator (when/2.splat)
| ~~~~ expression (when/2.splat)})
end
# Looping
def test_while
assert_parses(
s(:while, s(:lvar, :foo), s(:send, nil, :meth)),
%q{while foo do meth end},
%q{~~~~~ keyword
| ~~ begin
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:while, s(:lvar, :foo), s(:send, nil, :meth)),
%q{while foo; meth end},
%q{~~~~~ keyword
| ~~~ end
|~~~~~~~~~~~~~~~~~~~ expression})
end
def test_while_mod
assert_parses(
s(:while, s(:lvar, :foo), s(:send, nil, :meth)),
%q{meth while foo},
%q{ ~~~~~ keyword})
end
def test_until
assert_parses(
s(:until, s(:lvar, :foo), s(:send, nil, :meth)),
%q{until foo do meth end},
%q{~~~~~ keyword
| ~~ begin
| ~~~ end})
assert_parses(
s(:until, s(:lvar, :foo), s(:send, nil, :meth)),
%q{until foo; meth end},
%q{~~~~~ keyword
| ~~~ end})
end
def test_until_mod
assert_parses(
s(:until, s(:lvar, :foo), s(:send, nil, :meth)),
%q{meth until foo},
%q{ ~~~~~ keyword})
end
def test_while_post
assert_parses(
s(:while_post, s(:lvar, :foo),
s(:kwbegin, s(:send, nil, :meth))),
%q{begin meth end while foo},
%q{ ~~~~~ keyword})
end
def test_until_post
assert_parses(
s(:until_post, s(:lvar, :foo),
s(:kwbegin, s(:send, nil, :meth))),
%q{begin meth end until foo},
%q{ ~~~~~ keyword})
end
def test_while_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{while (a, b = foo); end},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_while_mod_masgn
assert_diagnoses(
[:error, :masgn_as_condition],
%q{foo while (a, b = foo)},
%q{ ~~~~~~~~~~ location},
%w(1.8 1.9 2.0 2.1 2.2 2.3 ios mac))
end
def test_for
assert_parses(
s(:for,
s(:lvasgn, :a),
s(:lvar, :foo),
s(:send, nil, :p, s(:lvar, :a))),
%q{for a in foo do p a; end},
%q{~~~ keyword
| ~~ in
| ~~ begin
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~ expression})
assert_parses(
s(:for,
s(:lvasgn, :a),
s(:lvar, :foo),
s(:send, nil, :p, s(:lvar, :a))),
%q{for a in foo; p a; end})
end
def test_for_mlhs
assert_parses(
s(:for,
s(:mlhs,
s(:lvasgn, :a),
s(:lvasgn, :b)),
s(:lvar, :foo),
s(:send, nil, :p, s(:lvar, :a), s(:lvar, :b))),
%q{for a, b in foo; p a, b; end},
%q{ ~~~~ expression (mlhs)})
end
# Control flow commands
def test_break
assert_parses(
s(:break, s(:begin, s(:lvar, :foo))),
%q{break(foo)},
%q{~~~~~ keyword
|~~~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:break, s(:begin, s(:lvar, :foo))),
%q{break(foo)},
%q{~~~~~ keyword
|~~~~~~~~~~ expression},
%w(1.8))
assert_parses(
s(:break, s(:lvar, :foo)),
%q{break foo},
%q{~~~~~ keyword
|~~~~~~~~~ expression})
assert_parses(
s(:break, s(:begin)),
%q{break()},
%q{~~~~~ keyword
|~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:break),
%q{break},
%q{~~~~~ keyword
|~~~~~ expression})
end
def test_break_block
assert_parses(
s(:break,
s(:block,
s(:send, nil, :fun, s(:lvar, :foo)),
s(:args), nil)),
%q{break fun foo do end},
%q{ ~~~~~~~~~~~~~~ expression (block)
|~~~~~~~~~~~~~~~~~~~~ expression},
ALL_VERSIONS - %w(1.8 ios))
end
def test_return
assert_parses(
s(:return, s(:begin, s(:lvar, :foo))),
%q{return(foo)},
%q{~~~~~~ keyword
|~~~~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:return, s(:begin, s(:lvar, :foo))),
%q{return(foo)},
%q{~~~~~~ keyword
|~~~~~~~~~~~ expression},
%w(1.8))
assert_parses(
s(:return, s(:lvar, :foo)),
%q{return foo},
%q{~~~~~~ keyword
|~~~~~~~~~~ expression})
assert_parses(
s(:return, s(:begin)),
%q{return()},
%q{~~~~~~ keyword
|~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:return),
%q{return},
%q{~~~~~~ keyword
|~~~~~~ expression})
end
def test_return_block
assert_parses(
s(:return,
s(:block,
s(:send, nil, :fun, s(:lvar, :foo)),
s(:args), nil)),
%q{return fun foo do end},
%q{ ~~~~~~~~~~~~~~ expression (block)
|~~~~~~~~~~~~~~~~~~~~~ expression},
ALL_VERSIONS - %w(1.8 ios))
end
def test_next
assert_parses(
s(:next, s(:begin, s(:lvar, :foo))),
%q{next(foo)},
%q{~~~~ keyword
|~~~~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:next, s(:begin, s(:lvar, :foo))),
%q{next(foo)},
%q{~~~~ keyword
|~~~~~~~~~ expression},
%w(1.8))
assert_parses(
s(:next, s(:lvar, :foo)),
%q{next foo},
%q{~~~~ keyword
|~~~~~~~~ expression})
assert_parses(
s(:next, s(:begin)),
%q{next()},
%q{~~~~ keyword
|~~~~~~ expression},
SINCE_1_9)
assert_parses(
s(:next),
%q{next},
%q{~~~~ keyword
|~~~~ expression})
end
def test_next_block
assert_parses(
s(:next,
s(:block,
s(:send, nil, :fun, s(:lvar, :foo)),
s(:args), nil)),
%q{next fun foo do end},
%q{ ~~~~~~~~~~~~~~ expression (block)
|~~~~~~~~~~~~~~~~~~~ expression},
ALL_VERSIONS - %w(1.8 ios))
end
def test_redo
assert_parses(
s(:redo),
%q{redo},
%q{~~~~ keyword
|~~~~ expression})
end
# Exception handling
def test_rescue
assert_parses(
s(:kwbegin,
s(:rescue, s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :foo)),
nil)),
%q{begin; meth; rescue; foo; end},
%q{~~~~~ begin
| ~~~~~~ keyword (rescue.resbody)
| ~~~~~~~~~~~ expression (rescue.resbody)
| ~~~~~~~~~~~~~~~~~ expression (rescue)
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_rescue_else
assert_parses(
s(:kwbegin,
s(:rescue, s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :foo)),
s(:lvar, :bar))),
%q{begin; meth; rescue; foo; else; bar; end},
%q{ ~~~~ else (rescue)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression (rescue)})
end
def test_rescue_else_useless
assert_parses(
s(:kwbegin,
s(:begin,
s(:int, 2))),
%q{begin; else; 2; end},
%q{ ~~~~ begin (begin)},
ALL_VERSIONS - SINCE_2_6)
assert_parses(
s(:kwbegin,
s(:int, 1),
s(:begin,
s(:int, 2))),
%q{begin; 1; else; 2; end},
%q{ ~~~~ begin (begin)},
ALL_VERSIONS - SINCE_2_6)
assert_parses(
s(:kwbegin,
s(:int, 1),
s(:int, 2),
s(:begin,
s(:int, 3))),
%q{begin; 1; 2; else; 3; end},
%q{ ~~~~ begin (begin)},
ALL_VERSIONS - SINCE_2_6)
assert_diagnoses(
[:warning, :useless_else],
%q{begin; 1; else; 2; end},
%q{ ~~~~ location},
ALL_VERSIONS - SINCE_2_6)
assert_diagnoses(
[:error, :useless_else],
%q{begin; 1; else; 2; end},
%q{ ~~~~ location},
SINCE_2_6)
assert_diagnoses(
[:error, :useless_else],
%q{begin; 1; else; end},
%q{ ~~~~ location},
SINCE_2_6)
end
def test_ensure
assert_parses(
s(:kwbegin,
s(:ensure, s(:send, nil, :meth),
s(:lvar, :bar))),
%q{begin; meth; ensure; bar; end},
%q{~~~~~ begin
| ~~~~~~ keyword (ensure)
| ~~~~~~~~~~~~~~~~~ expression (ensure)
| ~~~ end
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_ensure_empty
assert_parses(
s(:kwbegin,
s(:ensure, nil, nil)),
%q{begin ensure end},
%q{~~~~~ begin
| ~~~~~~ keyword (ensure)
| ~~~~~~ expression (ensure)
| ~~~ end
|~~~~~~~~~~~~~~~~ expression})
end
def test_rescue_ensure
assert_parses(
s(:kwbegin,
s(:ensure,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :baz)),
nil),
s(:lvar, :bar))),
%q{begin; meth; rescue; baz; ensure; bar; end},
%q{ ~~~~~~ keyword (ensure)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression (ensure)
| ~~~~~~ keyword (ensure.rescue.resbody)
| ~~~~~~~~~~~~~~~~~ expression (ensure.rescue)})
end
def test_rescue_else_ensure
assert_parses(
s(:kwbegin,
s(:ensure,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :baz)),
s(:lvar, :foo)),
s(:lvar, :bar))),
%q{begin; meth; rescue; baz; else foo; ensure; bar end},
%q{ ~~~~~~ keyword (ensure)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression (ensure)
| ~~~~~~ keyword (ensure.rescue.resbody)
| ~~~~ else (ensure.rescue)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression (ensure.rescue)})
end
def test_rescue_mod
assert_parses(
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :bar)),
nil),
%q{meth rescue bar},
%q{ ~~~~~~ keyword (resbody)
| ~~~~~~~~~~ expression (resbody)
|~~~~~~~~~~~~~~~ expression})
end
def test_rescue_mod_asgn
assert_parses(
s(:lvasgn, :foo,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :bar)),
nil)),
%q{foo = meth rescue bar},
%q{ ~~~~~~ keyword (rescue.resbody)
| ~~~~~~~~~~ expression (rescue.resbody)
| ~~~~~~~~~~~~~~~ expression (rescue)
|~~~~~~~~~~~~~~~~~~~~~ expression})
end
def test_rescue_mod_masgn
assert_parses(
s(:masgn,
s(:mlhs,
s(:lvasgn, :foo),
s(:lvasgn, :bar)),
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil,
s(:array,
s(:int, 1),
s(:int, 2))), nil)),
%q{foo, bar = meth rescue [1, 2]},
%q{ ~~~~~~ keyword (rescue.resbody)
| ~~~~~~~~~~~~~ expression (rescue.resbody)
| ~~~~~~~~~~~~~~~~~~ expression (rescue)
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_2_7)
end
def test_rescue_mod_op_assign
assert_parses(
s(:op_asgn,
s(:lvasgn, :foo), :+,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, nil, s(:lvar, :bar)),
nil)),
%q{foo += meth rescue bar},
%q{ ~~~~~~ keyword (rescue.resbody)
| ~~~~~~~~~~ expression (rescue.resbody)
| ~~~~~~~~~~~~~~~ expression (rescue)
|~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_1_9)
end
def test_rescue_without_begin_end
assert_parses(
s(:block,
s(:send, nil, :meth),
s(:args),
s(:rescue,
s(:lvar, :foo),
s(:resbody, nil, nil,
s(:lvar, :bar)),
nil)),
%q{meth do; foo; rescue; bar; end},
%q{ ~~~~~~ keyword (rescue.resbody)
| ~~~~~~~~~~~ expression (rescue.resbody)
| ~~~~~~~~~~~~~~~~ expression (rescue)},
SINCE_2_5)
end
def test_resbody_list
assert_parses(
s(:kwbegin,
s(:rescue,
s(:send, nil, :meth),
s(:resbody,
s(:array, s(:const, nil, :Exception)),
nil,
s(:lvar, :bar)),
nil)),
%q{begin; meth; rescue Exception; bar; end})
end
def test_resbody_list_mrhs
assert_parses(
s(:kwbegin,
s(:rescue,
s(:send, nil, :meth),
s(:resbody,
s(:array,
s(:const, nil, :Exception),
s(:lvar, :foo)),
nil,
s(:lvar, :bar)),
nil)),
%q{begin; meth; rescue Exception, foo; bar; end})
end
def test_resbody_var
assert_parses(
s(:kwbegin,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, s(:lvasgn, :ex), s(:lvar, :bar)),
nil)),
%q{begin; meth; rescue => ex; bar; end})
assert_parses(
s(:kwbegin,
s(:rescue,
s(:send, nil, :meth),
s(:resbody, nil, s(:ivasgn, :@ex), s(:lvar, :bar)),
nil)),
%q{begin; meth; rescue => @ex; bar; end})
end
def test_resbody_list_var
assert_parses(
s(:kwbegin,
s(:rescue,
s(:send, nil, :meth),
s(:resbody,
s(:array, s(:lvar, :foo)),
s(:lvasgn, :ex),
s(:lvar, :bar)),
nil)),
%q{begin; meth; rescue foo => ex; bar; end})
end
def test_retry
assert_parses(
s(:retry),
%q{retry},
%q{~~~~~ keyword
|~~~~~ expression})
end
# BEGIN and END
def test_preexe
assert_parses(
s(:preexe, s(:int, 1)),
%q{BEGIN { 1 }},
%q{~~~~~ keyword
| ^ begin
| ^ end
|~~~~~~~~~~~ expression})
end
def test_preexe_invalid
assert_diagnoses(
[:error, :begin_in_method],
%q{def f; BEGIN{}; end},
%q{ ~~~~~ location},
# Yes. *Exclude 1.9*. Sigh.
ALL_VERSIONS - %w(1.9 mac ios))
end
def test_postexe
assert_parses(
s(:postexe, s(:int, 1)),
%q{END { 1 }},
%q{~~~ keyword
| ^ begin
| ^ end
|~~~~~~~~~ expression})
end
#
# Miscellanea
#
def test_kwbegin_compstmt
assert_parses(
s(:kwbegin,
s(:send, nil, :foo!),
s(:send, nil, :bar!)),
%q{begin foo!; bar! end})
end
def test_crlf_line_endings
with_versions(ALL_VERSIONS) do |_ver, parser|
source_file = Parser::Source::Buffer.new('(comments)')
source_file.source = "\r\nfoo"
range = lambda do |from, to|
Parser::Source::Range.new(source_file, from, to)
end
ast = parser.parse(source_file)
assert_equal s(:lvar, :foo),
ast
assert_equal range.call(1, 4),
ast.loc.expression
end
end
def test_begin_cmdarg
assert_parses(
s(:send, nil, :p,
s(:kwbegin,
s(:block,
s(:send, s(:int, 1), :times),
s(:args),
s(:int, 1)))),
%q{p begin 1.times do 1 end end},
%{},
SINCE_2_0)
end
def test_bug_cmdarg
assert_parses(
s(:send, nil, :meth,
s(:begin,
s(:block,
s(:send, nil, :lambda),
s(:args), nil))),
%q{meth (lambda do end)},
%q{},
%w(1.8))
assert_parses(
s(:send, nil, :assert,
s(:send, nil, :dogs)),
%q{assert dogs})
assert_parses(
s(:send, nil, :assert,
s(:hash,
s(:pair, s(:sym, :do), s(:true)))),
%q{assert do: true},
%q{},
SINCE_1_9)
assert_parses(
s(:send, nil, :f,
s(:hash,
s(:pair,
s(:sym, :x),
s(:block,
s(:lambda),
s(:args),
s(:block,
s(:send, nil, :meth),
s(:args), nil))))),
%q{f x: -> do meth do end end},
%q{},
SINCE_1_9)
end
def test_file_line_non_literals
with_versions(ALL_VERSIONS) do |_ver, parser|
parser.builder.emit_file_line_as_literals = false
source_file = Parser::Source::Buffer.new('(comments)')
source_file.source = "[__FILE__, __LINE__]"
ast = parser.parse(source_file)
assert_equal s(:array, s(:__FILE__), s(:__LINE__)), ast
end
end
def test_bom
assert_parses(
s(:int, 1),
%Q{\xef\xbb\xbf1}.b,
%q{},
%w(1.9 2.0 2.1))
end
def test_magic_encoding_comment
assert_parses(
s(:begin,
s(:lvasgn, :"проверка", s(:int, 42)),
s(:send, nil, :puts, s(:lvar, :"проверка"))),
%Q{# coding:koi8-r
\xd0\xd2\xcf\xd7\xc5\xd2\xcb\xc1 = 42
puts \xd0\xd2\xcf\xd7\xc5\xd2\xcb\xc1}.b,
%q{},
%w(1.9 2.0 2.1))
end
def test_regexp_encoding
assert_parses(
s(:match_with_lvasgn,
s(:regexp,
s(:str, "\\xa8"),
s(:regopt, :n)),
s(:str, "")),
%q{/\xa8/n =~ ""}.dup.force_encoding(Encoding::UTF_8),
%{},
SINCE_1_9)
end
#
# Error recovery
#
def test_unknown_percent_str
assert_diagnoses(
[:error, :unexpected_percent_str, { :type => '%k' }],
%q{%k[foo]},
%q{~~ location})
end
def test_unterminated_embedded_doc
assert_diagnoses(
[:fatal, :embedded_document],
%Q{=begin\nfoo\nend},
%q{~~~~~~ location})
assert_diagnoses(
[:fatal, :embedded_document],
%Q{=begin\nfoo\nend\n},
%q{~~~~~~ location})
end
def test_codepoint_too_large
assert_diagnoses(
[:error, :unicode_point_too_large],
%q{"\u{120 120000}"},
%q{ ~~~~~~ location},
SINCE_1_9)
end
def test_on_error
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tIDENTIFIER' }],
%q{def foo(bar baz); end},
%q{ ~~~ location})
end
#
# Token and comment extraction
#
def assert_parses_with_comments(ast_pattern, source, comments_pattern)
with_versions(ALL_VERSIONS) do |_ver, parser|
source_file = Parser::Source::Buffer.new('(comments)')
source_file.source = source
comments_pattern_here = comments_pattern.map do |(from, to)|
range = Parser::Source::Range.new(source_file, from, to)
Parser::Source::Comment.new(range)
end
ast, comments = parser.parse_with_comments(source_file)
assert_equal ast_pattern, ast
assert_equal comments_pattern_here, comments
end
end
def test_comment_interleaved
assert_parses_with_comments(
s(:send, s(:int, 1), :+, s(:int, 2)),
%Q{1 + # foo\n 2},
[ [4, 9] ])
end
def test_comment_single
assert_parses_with_comments(
s(:send, nil, :puts),
%Q{puts # whatever},
[ [5, 15] ])
end
def test_tokenize
with_versions(ALL_VERSIONS) do |_ver, parser|
source_file = Parser::Source::Buffer.new('(tokenize)')
source_file.source = "1 + # foo\n 2"
range = lambda do |from, to|
Parser::Source::Range.new(source_file, from, to)
end
ast, comments, tokens = parser.tokenize(source_file)
assert_equal s(:send, s(:int, 1), :+, s(:int, 2)),
ast
assert_equal [
Parser::Source::Comment.new(range.call(4, 9))
], comments
assert_equal [
[:tINTEGER, [ 1, range.call(0, 1) ]],
[:tPLUS, [ '+', range.call(2, 3) ]],
[:tCOMMENT, [ '# foo', range.call(4, 9) ]],
[:tINTEGER, [ 2, range.call(11, 12) ]],
], tokens
end
end
def test_tokenize_recover
with_versions(ALL_VERSIONS) do |_ver, parser|
source_file = Parser::Source::Buffer.new('(tokenize)')
source_file.source = "1 + # foo\n "
range = lambda do |from, to|
Parser::Source::Range.new(source_file, from, to)
end
ast, comments, tokens = parser.tokenize(source_file, true)
assert_nil ast
assert_equal [
Parser::Source::Comment.new(range.call(4, 9))
], comments
assert_equal [
[:tINTEGER, [ 1, range.call(0, 1) ]],
[:tPLUS, [ '+', range.call(2, 3) ]],
[:tCOMMENT, [ '# foo', range.call(4, 9) ]],
], tokens
end
end
#
# Bug-specific tests
#
def test_bug_cmd_string_lookahead
assert_parses(
s(:block,
s(:send, nil, :desc,
s(:str, 'foo')),
s(:args), nil),
%q{desc "foo" do end})
end
def test_bug_do_block_in_call_args
# [ruby-core:59342] [Bug #9308]
assert_parses(
s(:send, nil, :bar,
s(:def, :foo,
s(:args),
s(:block,
s(:send, s(:self), :each),
s(:args),
nil))),
%q{bar def foo; self.each do end end},
%q{},
SINCE_1_9)
end
def test_bug_do_block_in_cmdarg
# [ruby-core:61950] [Bug #9726]
assert_parses(
s(:send, nil, :tap,
s(:begin,
s(:block,
s(:send, nil, :proc),
s(:args), nil))),
%q{tap (proc do end)},
%q{},
ALL_VERSIONS - %w(1.8 mac ios))
end
def test_bug_interp_single
assert_parses(
s(:dstr, s(:begin, s(:int, 1))),
%q{"#{1}"})
assert_parses(
s(:array, s(:dstr, s(:begin, s(:int, 1)))),
%q{%W"#{1}"})
end
def test_bug_def_no_paren_eql_begin
assert_parses(
s(:def, :foo, s(:args), nil),
%Q{def foo\n=begin\n=end\nend})
end
def test_bug_while_not_parens_do
assert_parses(
s(:while, s(:send, s(:begin, s(:true)), :"!"), nil),
%q{while not (true) do end},
%q{},
SINCE_1_9)
end
def test_bug_rescue_empty_else
assert_parses(
s(:kwbegin,
s(:rescue, nil,
s(:resbody,
s(:array,
s(:const, nil, :LoadError)), nil, nil), nil)),
%q{begin; rescue LoadError; else; end},
%q{ ~~~~ else (rescue)
| ~~~~~~~~~~~~~~~~~~~~~~ expression (rescue)})
end
def test_bug_def_empty_else
assert_parses(
s(:def, :foo, s(:args),
s(:begin,
s(:begin, nil))),
%q{def foo; else; end},
%q{},
ALL_VERSIONS - SINCE_2_6)
end
def test_bug_heredoc_do
assert_parses(
s(:block,
s(:send, nil, :f,
s(:dstr)),
s(:args), nil),
%Q{f <<-TABLE do\nTABLE\nend})
end
def test_bug_ascii_8bit_in_literal
assert_diagnoses(
[:error, :invalid_encoding],
%q{".\xc3."},
%q{^^^^^^^^ location},
ALL_VERSIONS)
assert_diagnoses(
[:error, :invalid_encoding],
%q{%W"x .\xc3."},
%q{ ^^^^^^ location},
ALL_VERSIONS)
assert_diagnoses(
[:error, :invalid_encoding],
%q{:".\xc3."},
%q{ ^^^^^^ location},
ALL_VERSIONS)
assert_diagnoses(
[:error, :invalid_encoding],
%q{%I"x .\xc3."},
%q{ ^^^^^^ location},
ALL_VERSIONS - %w(1.8 1.9 ios mac))
assert_parses(
s(:int, 0xc3),
%q{?\xc3},
%q{},
%w(1.8))
assert_diagnoses(
[:error, :invalid_encoding],
%q{?\xc3},
%q{^^^^^ location},
SINCE_1_9)
assert_parses(
s(:str, "проверка"),
%q{# coding:utf-8
"\xD0\xBF\xD1\x80\xD0\xBE\xD0\xB2\xD0\xB5\xD1\x80\xD0\xBA\xD0\xB0"},
%q{},
SINCE_1_9)
end
def test_ruby_bug_9669
assert_parses(
s(:def, :a, s(:args, s(:kwarg, :b)), s(:return)),
%Q{def a b:\nreturn\nend},
%q{},
SINCE_2_1)
assert_parses(
s(:lvasgn, :o,
s(:hash,
s(:pair, s(:sym, :a), s(:int, 1)))),
%Q{o = {\na:\n1\n}},
%q{},
SINCE_2_1)
end
def test_ruby_bug_10279
assert_parses(
s(:hash,
s(:pair, s(:sym, :a),
s(:if, s(:true), s(:int, 42), nil))),
%q{{a: if true then 42 end}},
%q{},
SINCE_2_1)
end
def test_ruby_bug_10653
assert_parses(
s(:if,
s(:true),
s(:block,
s(:send,
s(:int, 1), :tap),
s(:args,
s(:procarg0, s(:arg, :n))),
s(:send, nil, :p,
s(:lvar, :n))),
s(:int, 0)),
%q{true ? 1.tap do |n| p n end : 0},
%q{},
SINCE_1_9)
assert_parses(
s(:if,
s(:true),
s(:block,
s(:send,
s(:int, 1), :tap),
s(:args,
s(:arg, :n)),
s(:send, nil, :p,
s(:lvar, :n))),
s(:int, 0)),
%q{true ? 1.tap do |n| p n end : 0},
%q{},
%w(1.8))
assert_parses(
s(:if,
s(:false),
s(:block,
s(:send, nil, :raise),
s(:args), nil),
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
%q{false ? raise {} : tap {}},
%q{},
ALL_VERSIONS)
assert_parses(
s(:if,
s(:false),
s(:block,
s(:send, nil, :raise),
s(:args), nil),
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
%q{false ? raise do end : tap do end},
%q{},
ALL_VERSIONS)
end
def test_ruby_bug_11107
assert_parses(
s(:send, nil, :p,
s(:block,
s(:lambda),
s(:args),
s(:block, s(:send, nil, :a), s(:args), nil))),
%q{p ->() do a() do end end},
%q{},
SINCE_2_1) # no 1.9 backport
end
def test_ruby_bug_11380
assert_parses(
s(:block,
s(:send, nil, :p,
s(:block,
s(:lambda),
s(:args),
s(:sym, :hello)),
s(:hash,
s(:pair, s(:sym, :a), s(:int, 1)))),
s(:args),
nil),
%q{p -> { :hello }, a: 1 do end},
%q{},
SINCE_2_1) # no 1.9 backport
end
def test_ruby_bug_11873_a
[[":e", s(:sym, :e)],
["1", s(:int, 1)],
["1.0", s(:float, 1.0)],
["1.0r", s(:rational, Rational(1, 1))],
["1.0i", s(:complex, Complex(0.0, 1.0))]].each do |code, node|
expect_a = \
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c,
s(:send, nil, :d))),
node),
s(:args), nil)
assert_parses(
expect_a,
%Q{a b{c d}, #{code} do end},
%q{},
SINCE_2_4)
assert_parses(
expect_a,
%Q{a b{c(d)}, #{code} do end},
%q{},
SINCE_2_4)
expect_b = \
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
node),
s(:args), nil)
assert_parses(
expect_b,
%Q{a b(c d), #{code} do end},
%q{},
SINCE_2_4)
assert_parses(
expect_b,
%Q{a b(c(d)), #{code} do end},
%q{},
SINCE_2_4)
end
end
def test_ruby_bug_11873_b
assert_parses(
s(:block,
s(:send, nil, :p,
s(:block,
s(:send, nil, :p),
s(:args),
s(:begin,
s(:send, nil, :p,
s(:send, nil, :p)),
s(:send, nil, :p,
s(:send, nil, :p)))),
s(:send, nil, :tap)),
s(:args), nil),
%q{p p{p(p);p p}, tap do end},
%q{},
SINCE_2_4)
end
def test_ruby_bug_11989
assert_parses(
s(:send, nil, :p,
s(:str, "x\n y\n")),
%Q{p <<~"E"\n x\\n y\nE},
%q{},
SINCE_2_3)
end
def test_ruby_bug_11990
assert_parses(
s(:send, nil, :p,
s(:dstr,
s(:str, "x\n"),
s(:str, " y"))),
%Q{p <<~E " y"\n x\nE},
%q{},
SINCE_2_3)
end
def test_ruby_bug_12073
assert_parses(
s(:begin,
s(:lvasgn, :a,
s(:int, 1)),
s(:send, nil, :a,
s(:hash,
s(:pair,
s(:sym, :b),
s(:int, 1))))),
%q{a = 1; a b: 1},
%q{},
SINCE_1_9)
assert_parses(
s(:def, :foo,
s(:args,
s(:arg, :raise)),
s(:send, nil, :raise,
s(:const,
s(:const, nil, :A), :B),
s(:str, ""))),
%q{def foo raise; raise A::B, ''; end},
%q{},
SINCE_1_9)
end
def test_ruby_bug_12402
assert_parses(
s(:lvasgn, :foo,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo = raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:lvasgn, :foo), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo += raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:indexasgn,
s(:lvar, :foo),
s(:int, 0)), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo[0] += raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :m), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo.m += raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :m), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo::m += raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :C), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo.C += raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:or_asgn,
s(:casgn,
s(:lvar, :foo), :C),
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo::C ||= raise(bar) rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:lvasgn, :foo,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo = raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:lvasgn, :foo), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo += raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:indexasgn,
s(:lvar, :foo),
s(:int, 0)), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo[0] += raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :m), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo.m += raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :m), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo::m += raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn,
s(:send,
s(:lvar, :foo), :C), :+,
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo.C += raise bar rescue nil},
%q{},
SINCE_2_4)
assert_parses(
s(:or_asgn,
s(:casgn,
s(:lvar, :foo), :C),
s(:rescue,
s(:send, nil, :raise,
s(:lvar, :bar)),
s(:resbody, nil, nil,
s(:nil)), nil)),
%q{foo::C ||= raise bar rescue nil},
%q{},
SINCE_2_4)
end
def test_ruby_bug_12669
assert_parses(
s(:lvasgn, :a,
s(:lvasgn, :b,
s(:send, nil, :raise,
s(:sym, :x)))),
%q{a = b = raise :x},
%q{},
SINCE_2_0)
assert_parses(
s(:op_asgn, s(:lvasgn, :a), :+,
s(:lvasgn, :b,
s(:send, nil, :raise,
s(:sym, :x)))),
%q{a += b = raise :x},
%q{},
SINCE_2_4)
assert_parses(
s(:lvasgn, :a,
s(:op_asgn, s(:lvasgn, :b), :+,
s(:send, nil, :raise,
s(:sym, :x)))),
%q{a = b += raise :x},
%q{},
SINCE_2_4)
assert_parses(
s(:op_asgn, s(:lvasgn, :a), :+,
s(:op_asgn, s(:lvasgn, :b), :+,
s(:send, nil, :raise,
s(:sym, :x)))),
%q{a += b += raise :x},
%q{},
SINCE_2_4)
end
def test_ruby_bug_12686
assert_parses(
s(:send, nil, :f,
s(:begin,
s(:rescue,
s(:send, nil, :g),
s(:resbody, nil, nil,
s(:nil)), nil))),
%q{f (g rescue nil)},
%q{},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, {:token => 'kRESCUE_MOD'}],
%q{f(g rescue nil)},
%q{ ^^^^^^ location})
end
def test_ruby_bug_11873
# strings
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c, s(:send, nil, :d))),
s(:str, "x")),
s(:args),
nil),
%q{a b{c d}, "x" do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:str, "x")),
s(:args),
nil),
%q{a b(c d), "x" do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c,
s(:send, nil, :d))),
s(:str, "x")),
s(:args), nil),
%q{a b{c(d)}, "x" do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:str, "x")),
s(:args), nil),
%q{a b(c(d)), "x" do end},
%q{},
SINCE_2_4)
# regexps without options
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c, s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt))),
s(:args),
nil),
%q{a b{c d}, /x/ do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt))),
s(:args),
nil),
%q{a b(c d), /x/ do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt))),
s(:args), nil),
%q{a b{c(d)}, /x/ do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt))),
s(:args), nil),
%q{a b(c(d)), /x/ do end},
%q{},
SINCE_2_4)
# regexps with options
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c, s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt, :m))),
s(:args),
nil),
%q{a b{c d}, /x/m do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt, :m))),
s(:args),
nil),
%q{a b(c d), /x/m do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:block,
s(:send, nil, :b),
s(:args),
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt, :m))),
s(:args), nil),
%q{a b{c(d)}, /x/m do end},
%q{},
SINCE_2_4)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:send, nil, :b,
s(:send, nil, :c,
s(:send, nil, :d))),
s(:regexp, s(:str, "x"), s(:regopt, :m))),
s(:args), nil),
%q{a b(c(d)), /x/m do end},
%q{},
SINCE_2_4)
end
def test_parser_bug_198
assert_parses(
s(:array,
s(:regexp,
s(:str, "()\\1"),
s(:regopt)),
s(:str, "#")),
%q{[/()\\1/, ?#]},
%q{},
SINCE_1_9)
end
def test_parser_bug_272
assert_parses(
s(:block,
s(:send, nil, :a,
s(:ivar, :@b)),
s(:args,
s(:procarg0, s(:arg, :c))), nil),
%q{a @b do |c|;end},
%q{},
SINCE_1_9)
assert_parses(
s(:block,
s(:send, nil, :a,
s(:ivar, :@b)),
s(:args,
s(:arg, :c)), nil),
%q{a @b do |c|;end},
%q{},
%w(1.8))
end
def test_bug_lambda_leakage
assert_parses(
s(:begin,
s(:block,
s(:lambda),
s(:args,
s(:arg, :scope)), nil),
s(:send, nil, :scope)),
%q{->(scope) {}; scope},
%q{},
SINCE_1_9)
end
def test_bug_regex_verification
assert_parses(
s(:regexp, s(:str, "#)"), s(:regopt, :x)),
%Q{/#)/x})
end
def test_bug_do_block_in_hash_brace
assert_parses(
s(:send, nil, :p,
s(:sym, :foo),
s(:hash,
s(:pair,
s(:sym, :a),
s(:block,
s(:send, nil, :proc),
s(:args), nil)),
s(:pair,
s(:sym, :b),
s(:block,
s(:send, nil, :proc),
s(:args), nil)))),
%q{p :foo, {a: proc do end, b: proc do end}},
%q{},
SINCE_2_3)
assert_parses(
s(:send, nil, :p,
s(:sym, :foo),
s(:hash,
s(:pair,
s(:sym, :a),
s(:block,
s(:send, nil, :proc),
s(:args), nil)),
s(:pair,
s(:sym, :b),
s(:block,
s(:send, nil, :proc),
s(:args), nil)))),
%q{p :foo, {:a => proc do end, b: proc do end}},
%q{},
SINCE_2_3)
assert_parses(
s(:send, nil, :p,
s(:sym, :foo),
s(:hash,
s(:pair,
s(:sym, :a),
s(:block,
s(:send, nil, :proc),
s(:args), nil)),
s(:pair,
s(:sym, :b),
s(:block,
s(:send, nil, :proc),
s(:args), nil)))),
%q{p :foo, {"a": proc do end, b: proc do end}},
%q{},
SINCE_2_3)
assert_parses(
s(:send, nil, :p,
s(:sym, :foo),
s(:hash,
s(:pair,
s(:block,
s(:send, nil, :proc),
s(:args), nil),
s(:block,
s(:send, nil, :proc),
s(:args), nil)),
s(:pair,
s(:sym, :b),
s(:block,
s(:send, nil, :proc),
s(:args), nil)))),
%q{p :foo, {proc do end => proc do end, b: proc do end}},
%q{},
SINCE_2_3)
assert_parses(
s(:send, nil, :p,
s(:sym, :foo),
s(:hash,
s(:kwsplat,
s(:block,
s(:send, nil, :proc),
s(:args), nil)),
s(:pair,
s(:sym, :b),
s(:block,
s(:send, nil, :proc),
s(:args), nil)))),
%q{p :foo, {** proc do end, b: proc do end}},
%q{},
SINCE_2_3)
end
def test_lparenarg_after_lvar__since_25
assert_parses(
s(:send, nil, :meth,
s(:send,
s(:begin,
s(:float, -1.3)), :abs)),
%q{meth (-1.3).abs},
%q{},
ALL_VERSIONS - SINCE_2_5)
assert_parses(
s(:send,
s(:send, nil, :foo,
s(:float, -1.3)), :abs),
%q{foo (-1.3).abs},
%q{},
ALL_VERSIONS - SINCE_2_5)
assert_parses(
s(:send, nil, :meth,
s(:send,
s(:begin,
s(:float, -1.3)), :abs)),
%q{meth (-1.3).abs},
%q{},
SINCE_2_5)
assert_parses(
s(:send, nil, :foo,
s(:send,
s(:begin,
s(:float, -1.3)), :abs)),
%q{foo (-1.3).abs},
%q{},
SINCE_2_5)
end
def test_context_class
[
%q{class A;},
%q{class A < B;}
].each do |code|
assert_context([:class], code, ALL_VERSIONS)
end
end
def test_context_sclass
assert_context(
[:sclass],
%q{class << foo;},
ALL_VERSIONS)
end
def test_context_def
assert_context(
[:def],
%q{def m;},
ALL_VERSIONS)
end
def test_context_defs
assert_context(
[:defs],
%q{def foo.m;},
ALL_VERSIONS)
end
def test_context_cmd_brace_block
[
'tap foo {',
'foo.tap foo {',
'foo::tap foo {'
].each do |code|
assert_context([:block], code, ALL_VERSIONS)
end
end
def test_context_brace_block
[
'tap {',
'foo.tap {',
'foo::tap {',
'tap do',
'foo.tap do',
'foo::tap do'
].each do |code|
assert_context([:block], code, ALL_VERSIONS)
end
end
def test_context_do_block
[
%q{tap 1 do},
%q{foo.tap do},
%q{foo::tap do}
].each do |code|
assert_context([:block], code, ALL_VERSIONS)
end
end
def test_context_lambda
[
'->() {',
'->() do'
].each do |code|
assert_context([:lambda], code, SINCE_1_9)
end
end
def test_context_nested
assert_context(
[:class, :sclass, :defs, :def, :block],
%q{class A; class << foo; def bar.m; def m; tap do},
ALL_VERSIONS)
assert_context(
[:class, :sclass, :defs, :def, :lambda, :block],
%q{class A; class << foo; def bar.m; def m; -> do; tap do},
SINCE_1_9)
assert_context(
[],
%q{
class A
class << foo
def bar.m
def m
tap do
end
end
end
end
end
},
ALL_VERSIONS)
assert_context(
[],
%q{
class A
class << foo
def bar.m
def m
-> do
tap do
end
end
end
end
end
end
},
SINCE_1_9)
end
def test_return_in_class
assert_parses(
s(:class,
s(:const, nil, :A), nil,
s(:return)),
%q{class A; return; end},
%q{},
ALL_VERSIONS - SINCE_2_5)
assert_diagnoses(
[:error, :invalid_return, {}],
%q{class A; return; end},
%q{ ^^^^^^ location},
SINCE_2_5)
[
%q{class << foo; return; end},
%q{def m; return; end},
%q{tap { return }},
%q{class A; class << self; return; end; end},
%q{class A; def m; return; end; end},
].each do |code|
refute_diagnoses(code, ALL_VERSIONS)
end
[
%q{-> do return end},
%q{class A; -> do return end; end},
].each do |code|
refute_diagnoses(code, SINCE_1_9)
end
end
def test_method_definition_in_while_cond
assert_parses(
s(:while,
s(:def, :foo,
s(:args),
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
s(:break)),
%q{while def foo; tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:defs,
s(:self), :foo,
s(:args),
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
s(:break)),
%q{while def self.foo; tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:def, :foo,
s(:args,
s(:optarg, :a,
s(:block,
s(:send, nil, :tap),
s(:args), nil))), nil),
s(:break)),
%q{while def foo a = tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:defs,
s(:self), :foo,
s(:args,
s(:optarg, :a,
s(:block,
s(:send, nil, :tap),
s(:args), nil))), nil),
s(:break)),
%q{while def self.foo a = tap do end; end; break; end},
%q{},
SINCE_2_5)
end
def test_class_definition_in_while_cond
assert_parses(
s(:while,
s(:class,
s(:const, nil, :Foo), nil,
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
s(:break)),
%q{while class Foo; tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:class,
s(:const, nil, :Foo), nil,
s(:lvasgn, :a,
s(:block,
s(:send, nil, :tap),
s(:args), nil))),
s(:break)),
%q{while class Foo a = tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:sclass,
s(:self),
s(:block,
s(:send, nil, :tap),
s(:args), nil)),
s(:break)),
%q{while class << self; tap do end; end; break; end},
%q{},
SINCE_2_5)
assert_parses(
s(:while,
s(:sclass,
s(:self),
s(:lvasgn, :a,
s(:block,
s(:send, nil, :tap),
s(:args), nil))),
s(:break)),
%q{while class << self; a = tap do end; end; break; end},
%q{},
SINCE_2_5)
end
def test_rescue_in_lambda_block
assert_diagnoses(
[:error, :unexpected_token, { :token => 'kRESCUE'}],
%q{-> do rescue; end},
%q{ ~~~~~~ location},
SINCE_1_9 - SINCE_2_6)
assert_parses(
s(:block,
s(:lambda),
s(:args),
s(:rescue, nil,
s(:resbody, nil, nil, nil), nil)),
%q{-> do rescue; end},
%q{ ~~~~~~ keyword (rescue.resbody)},
SINCE_2_6)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'kRESCUE'}],
%q{-> { rescue; }},
%q{ ~~~~~~ location},
SINCE_1_9)
end
def test_ruby_bug_13547
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m "x" {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m "#{'x'}" {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 1 {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 1.0 {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 1r {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 1i {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m :m {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m :"#{m}" {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m %[] {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 0..1 {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m 0...1 {}},
%q{ ^ location},
SINCE_2_4)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLCURLY' }],
%q{m [] {}},
%q{ ^ location},
SINCE_2_5)
assert_parses(
s(:block,
s(:index,
s(:send, nil, :meth)),
s(:args), nil),
%q{meth[] {}},
%q{},
SINCE_2_5
)
assert_diagnoses_many(
[
[:warning, :ambiguous_literal],
[:error, :unexpected_token, { :token => 'tLCURLY' }]
],
%q{m /foo/ {}},
SINCE_2_4)
assert_diagnoses_many(
[
[:warning, :ambiguous_literal],
[:error, :unexpected_token, { :token => 'tLCURLY' }]
],
%q{m /foo/x {}},
SINCE_2_4)
end
def test_bug_447
assert_parses(
s(:block,
s(:send, nil, :m,
s(:array)),
s(:args), nil),
%q{m [] do end},
%q{},
ALL_VERSIONS)
assert_parses(
s(:block,
s(:send, nil, :m,
s(:array),
s(:int, 1)),
s(:args), nil),
%q{m [], 1 do end},
%q{},
ALL_VERSIONS)
end
def test_bug_435
assert_parses(
s(:dstr,
s(:begin,
s(:block,
s(:lambda),
s(:args,
s(:arg, :foo)), nil))),
%q{"#{-> foo {}}"},
%q{},
SINCE_1_9)
end
def test_bug_452
assert_parses(
s(:begin,
s(:send, nil, :td,
s(:send,
s(:begin,
s(:int, 1500)), :toString)),
s(:block,
s(:send,
s(:send, nil, :td), :num),
s(:args), nil)),
%q{td (1_500).toString(); td.num do; end},
%q{},
ALL_VERSIONS)
end
def test_bug_466
assert_parses(
s(:block,
s(:send, nil, :foo,
s(:dstr,
s(:begin,
s(:send,
s(:begin,
s(:send,
s(:int, 1), :+,
s(:int, 1))), :to_i)))),
s(:args), nil),
%q{foo "#{(1+1).to_i}" do; end},
%q{},
ALL_VERSIONS)
end
def test_bug_473
assert_parses(
s(:send, nil, :m,
s(:dstr,
s(:begin,
s(:array)))),
%q{m "#{[]}"},
%q{},
ALL_VERSIONS)
end
def test_bug_480
assert_parses(
s(:send, nil, :m,
s(:dstr,
s(:begin),
s(:begin,
s(:begin)))),
%q{m "#{}#{()}"},
%q{},
ALL_VERSIONS)
end
def test_bug_481
assert_parses(
s(:begin,
s(:send, nil, :m,
s(:def, :x,
s(:args), nil)),
s(:block,
s(:send,
s(:int, 1), :tap),
s(:args), nil)),
%q{m def x(); end; 1.tap do end},
%q{},
ALL_VERSIONS)
end
def test_parser_bug_490
assert_parses(
s(:def, :m,
s(:args),
s(:sclass,
s(:self),
s(:class,
s(:const, nil, :C), nil, nil))),
%q{def m; class << self; class C; end; end; end},
%q{},
ALL_VERSIONS)
assert_parses(
s(:def, :m,
s(:args),
s(:sclass,
s(:self),
s(:module,
s(:const, nil, :M), nil))),
%q{def m; class << self; module M; end; end; end},
%q{},
ALL_VERSIONS)
assert_parses(
s(:def, :m,
s(:args),
s(:sclass,
s(:self),
s(:casgn, nil, :A,
s(:nil)))),
%q{def m; class << self; A = nil; end; end},
%q{},
ALL_VERSIONS)
end
def test_slash_newline_in_heredocs
assert_parses(
s(:dstr,
s(:str, "1 2\n"),
s(:str, "3\n")),
%Q{<<~E\n 1 \\\n 2\n 3\nE\n},
%q{},
SINCE_2_3)
assert_parses(
s(:dstr,
s(:str, " 1 2\n"),
s(:str, " 3\n")),
%Q{<<-E\n 1 \\\n 2\n 3\nE\n},
%q{},
ALL_VERSIONS)
end
def test_ambiuous_quoted_label_in_ternary_operator
assert_parses(
s(:if,
s(:send, nil, :a),
s(:send,
s(:send, nil, :b), :&,
s(:str, '')),
s(:nil)),
%q{a ? b & '': nil},
%q{},
ALL_VERSIONS)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLABEL_END' }],
%q{a ? b | '': nil},
%q{ ^~ location},
SINCE_2_2)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tTILDE' }],
%q{a ? b ~ '': nil},
%q{ ^ location},
SINCE_2_2)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBANG' }],
%q{a ? b ! '': nil},
%q{ ^ location},
SINCE_2_2)
end
def test_lbrace_arg_after_command_args
assert_parses(
s(:block,
s(:send, nil, :let,
s(:begin,
s(:sym, :a))),
s(:args),
s(:block,
s(:send, nil, :m),
s(:args), nil)),
%q{let (:a) { m do; end }},
%q{},
ALL_VERSIONS)
end
def test_ruby_bug_14690
assert_parses(
s(:block,
s(:send, nil, :let,
s(:begin)),
s(:args),
s(:block,
s(:send, nil, :m,
s(:send, nil, :a)),
s(:args), nil)),
%q{let () { m(a) do; end }},
%q{},
SINCE_2_0)
end
def test_parser_bug_507
assert_parses(
s(:lvasgn, :m,
s(:block,
s(:lambda),
s(:args,
s(:restarg, :args)), nil)),
%q{m = -> *args do end},
%q{},
SINCE_1_9)
end
def test_parser_bug_518
assert_parses(
s(:class,
s(:const, nil, :A),
s(:const, nil, :B), nil),
"class A < B\nend",
%q{},
ALL_VERSIONS)
end
def test_parser_bug_525
assert_parses(
s(:block,
s(:send, nil, :m1,
s(:hash,
s(:pair,
s(:sym, :k),
s(:send, nil, :m2)))),
s(:args),
s(:block,
s(:send, nil, :m3),
s(:args), nil)),
'm1 :k => m2 do; m3() do end; end',
%q{},
ALL_VERSIONS)
end
def test_parser_slash_slash_n_escaping_in_literals
[
["'", "'", s(:dstr, s(:str, "a\\\n"), s(:str, "b")) ],
["<<-'HERE'\n", "\nHERE", s(:dstr, s(:str, "a\\\n"), s(:str, "b\n"))],
["%q{", "}", s(:dstr, s(:str, "a\\\n"), s(:str, "b")) ],
['"', '"', s(:str, "ab") ],
["<<-\"HERE\"\n", "\nHERE", s(:str, "ab\n") ],
["%{", "}", s(:str, "ab") ],
["%Q{", "}", s(:str, "ab") ],
["%w{", "}", s(:array, s(:str, "a\nb")) ],
["%W{", "}", s(:array, s(:str, "a\nb")) ],
["%i{", "}", s(:array, s(:sym, :"a\nb")) ],
["%I{", "}", s(:array, s(:sym, :"a\nb")) ],
[":'", "'", s(:dsym, s(:str, "a\\\n"), s(:str, "b")) ],
["%s{", "}", s(:dsym, s(:str, "a\\\n"), s(:str, "b")) ],
[':"', '"', s(:sym, :ab) ],
['/', '/', s(:regexp, s(:str, "ab"), s(:regopt)) ],
['%r{', '}', s(:regexp, s(:str, "ab"), s(:regopt)) ],
['%x{', '}', s(:xstr, s(:str, "ab")) ],
['`', '`', s(:xstr, s(:str, "ab")) ],
["<<-`HERE`\n", "\nHERE", s(:xstr, s(:str, "ab\n")) ],
].each do |literal_s, literal_e, expected|
source = literal_s + "a\\\nb" + literal_e
assert_parses(
expected,
source,
%q{},
SINCE_2_0)
end
end
def test_unterimated_heredoc_id__27
assert_diagnoses(
[:error, :unterminated_heredoc_id],
%Q{<<\"EOS\n\nEOS\n},
%q{^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unterminated_heredoc_id],
%Q{<<\"EOS\n\"\nEOS\n},
%q{^ location},
SINCE_2_7)
%W[\r\n \n].each do |nl|
assert_diagnoses(
[:error, :unterminated_heredoc_id],
%Q{<<\"\r\"#{nl}\r#{nl}},
%q{^ location},
SINCE_2_7)
end
end
def test_numbered_args_after_27
assert_parses(
s(:numblock,
s(:send, nil, :m),
9,
s(:send,
s(:lvar, :_1), :+,
s(:lvar, :_9))),
%q{m { _1 + _9 }},
%q{^^^^^^^^^^^^^ expression
| ^^ name (send/2.lvar/1)
| ^^ expression (send/2.lvar/1)
| ^^ name (send/2.lvar/2)
| ^^ expression (send/2.lvar/2)},
SINCE_2_7)
assert_parses(
s(:numblock,
s(:send, nil, :m),
9,
s(:send,
s(:lvar, :_1), :+,
s(:lvar, :_9))),
%q{m do _1 + _9 end},
%q{^^^^^^^^^^^^^^^^ expression
| ^^ name (send/2.lvar/1)
| ^^ expression (send/2.lvar/1)
| ^^ name (send/2.lvar/2)
| ^^ expression (send/2.lvar/2)},
SINCE_2_7)
# Lambdas
assert_parses(
s(:numblock,
s(:lambda),
9,
s(:send,
s(:lvar, :_1), :+,
s(:lvar, :_9))),
%q{-> { _1 + _9}},
%q{^^^^^^^^^^^^^ expression
| ^^ name (send.lvar/1)
| ^^ expression (send.lvar/1)
| ^^ name (send.lvar/2)
| ^^ expression (send.lvar/2)},
SINCE_2_7)
assert_parses(
s(:numblock,
s(:lambda),
9,
s(:send,
s(:lvar, :_1), :+,
s(:lvar, :_9))),
%q{-> do _1 + _9 end},
%q{^^^^^^^^^^^^^^^^^ expression
| ^^ name (send.lvar/1)
| ^^ expression (send.lvar/1)
| ^^ name (send.lvar/2)
| ^^ expression (send.lvar/2)},
SINCE_2_7)
end
def test_numbered_and_ordinary_parameters
# Blocks
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m { || _1 } },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m { |a| _1 } },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m do || _1 end },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m do |a, b| _1 end },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m { |x = _1| }},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{m { |x: _1| }},
%q{ ^^ location},
SINCE_2_7)
# Lambdas
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->() { _1 } },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->(a) { _1 } },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->() do _1 end },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->(a, b) do _1 end},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->(x=_1) {}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{->(x: _1) {}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
%q{proc {|;a| _1}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ordinary_param_defined],
"proc {|\n| _1}",
%q{ ^^ location},
SINCE_2_7)
end
def test_numparam_outside_block
assert_parses(
s(:class,
s(:const, nil, :A), nil,
s(:send, nil, :_1)),
%q{class A; _1; end},
%q{},
SINCE_2_7)
assert_parses(
s(:module,
s(:const, nil, :A),
s(:send, nil, :_1)),
%q{module A; _1; end},
%q{},
SINCE_2_7)
assert_parses(
s(:sclass,
s(:lvar, :foo),
s(:send, nil, :_1)),
%q{class << foo; _1; end},
%q{},
SINCE_2_7)
assert_parses(
s(:defs,
s(:self), :m,
s(:args),
s(:send, nil, :_1)),
%q{def self.m; _1; end},
%q{},
SINCE_2_7)
assert_parses(
s(:send, nil, :_1),
%q{_1},
%q{},
SINCE_2_7)
end
def test_assignment_to_numparams
assert_parses(
s(:block,
s(:send, nil, :proc),
s(:args),
s(:lvasgn, :_1,
s(:nil))),
%q{proc {_1 = nil}},
%q{},
SINCE_2_7)
assert_diagnoses(
[:error, :cant_assign_to_numparam, { :name => '_1' }],
%q{proc {_1; _1 = nil}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :cant_assign_to_numparam, { :name => '_1' }],
%q{proc {_1; _1, foo = [nil, nil]}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :cant_assign_to_numparam, { :name => '_1' }],
%q{proc {_9; _1 = nil}},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :cant_assign_to_numparam, { :name => '_9' }],
%q{proc {_1; _9 = nil}},
%q{ ^^ location},
SINCE_2_7)
refute_diagnoses(
%q{proc { _1 = nil; _1}},
SINCE_2_7)
end
def test_numparams_in_nested_blocks
assert_diagnoses(
[:error, :numparam_used_in_outer_scope],
%q{foo { _1; bar { _2 }; }},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :numparam_used_in_outer_scope],
%q{-> { _1; -> { _2 }; }},
%q{ ^^ location},
SINCE_2_7)
[
['class A', 'end'],
['class << foo', 'end'],
['def m', 'end'],
['def self.m', 'end']
].each do |open_scope, close_scope|
refute_diagnoses(
"proc { _1; #{open_scope}; proc { _2 }; #{close_scope}; }",
SINCE_2_7)
refute_diagnoses(
"-> { _1; #{open_scope}; -> { _2 }; #{close_scope}; }",
SINCE_2_7)
end
end
def test_ruby_bug_15789
assert_parses(
s(:send, nil, :m,
s(:block,
s(:lambda),
s(:args,
s(:optarg, :a,
s(:numblock,
s(:lambda), 1,
s(:lvar, :_1)))),
s(:lvar, :a))),
%q{m ->(a = ->{_1}) {a}},
%q{},
SINCE_2_7)
assert_parses(
s(:send, nil, :m,
s(:block,
s(:lambda),
s(:args,
s(:kwoptarg, :a,
s(:numblock,
s(:lambda), 1,
s(:lvar, :_1)))),
s(:lvar, :a))),
%q{m ->(a: ->{_1}) {a}},
%q{},
SINCE_2_7)
end
def test_ruby_bug_15839
assert_diagnoses(
[:error, :invalid_encoding],
%q{# encoding: cp932
<<-TEXT
\xe9\x9d\u1234
TEXT
})
assert_diagnoses(
[:error, :invalid_encoding],
%q{
# encoding: cp932
<<-TEXT
\xe9\x9d
\u1234
TEXT
})
assert_diagnoses(
[:error, :invalid_encoding],
%q{
# encoding: cp932
<<-TEXT
\u1234\xe9\x9d
TEXT
})
assert_diagnoses(
[:error, :invalid_encoding],
%q{
# encoding: cp932
<<-TEXT
\u1234
\xe9\x9d
TEXT
})
end
def test_numparam_as_symbols
assert_diagnoses(
[:error, :ivar_name, { :name => '@' }],
%q{:@},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{:@1},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@' }],
%q{:@@},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{:@@1},
%q{ ^^^ location},
SINCE_2_7)
end
def test_csend_inside_lhs_of_masgn__since_27
assert_diagnoses(
[:error, :csend_in_lhs_of_masgn],
%q{*a&.x = 0},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :csend_in_lhs_of_masgn],
%q{a&.x, = 0},
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :csend_in_lhs_of_masgn],
%q{*a&.A = 0},
%q{ ^^ location},
SINCE_2_7)
end
def test_parser_bug_604
assert_parses(
s(:block,
s(:send, nil, :m,
s(:send,
s(:send, nil, :a), :+,
s(:send, nil, :b))),
s(:args), nil),
%q{m a + b do end},
%q{},
ALL_VERSIONS)
end
def test_comments_before_leading_dot__27
assert_parses(
s(:send,
s(:send, nil, :a), :foo),
%Q{a #\n#\n.foo\n},
%q{},
SINCE_2_7)
assert_parses(
s(:csend,
s(:send, nil, :a), :foo),
%Q{a #\n#\n&.foo\n},
%q{},
SINCE_2_7)
end
def test_comments_before_leading_dot__before_27
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT' }],
%q{a #!#!.foo!}.gsub('!', "\n"),
%q{ ^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tAMPER' }],
%q{a #!#!&.foo!}.gsub('!', "\n"),
%q{ ^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT' }],
%q{a #!#!.:foo!}.gsub('!', "\n"),
%q{ ^ location},
ALL_VERSIONS - SINCE_2_7)
end
def test_circular_argument_reference_error
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{def m(foo = foo) end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{def m(foo: foo) end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{m { |foo = foo| } },
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{m { |foo: foo| } },
%q{ ^^^ location},
SINCE_2_7)
# Traversing
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{def m(foo = class << foo; end) end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{def m(foo = def foo.m; end); end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :circular_argument_reference, { :var_name => 'foo' }],
%q{m { |foo = proc { 1 + foo }| } },
%q{ ^^^ location},
SINCE_2_7)
# Valid cases
[
'm { |foo = class A; foo; end| }',
'm { |foo = class << self; foo; end| }',
'm { |foo = def m(foo = bar); foo; end| }',
'm { |foo = def m(bar = foo); foo; end| }',
'm { |foo = def self.m(bar = foo); foo; end| }',
'def m(foo = def m; foo; end) end',
'def m(foo = def self.m; foo; end) end',
'm { |foo = proc { |bar| 1 + foo }| }',
'm { |foo = proc { || 1 + foo }| }'
].each do |code|
refute_diagnoses(code, SINCE_2_7)
end
end
def test_forward_args
assert_parses(
s(:def, :foo,
s(:forward_args),
s(:send, nil, :bar,
s(:forwarded_args))),
%q{def foo(...); bar(...); end},
%q{ ~ begin (forward_args)
| ~~~~~ expression (forward_args)
| ~ end (forward_args)
| ~~~ expression (send.forwarded_args)},
SINCE_2_7)
assert_parses(
s(:def, :foo,
s(:forward_args),
s(:super,
s(:forwarded_args))),
%q{def foo(...); super(...); end},
%q{ ~ begin (forward_args)
| ~~~~~ expression (forward_args)
| ~ end (forward_args)
| ~~~ expression (super.forwarded_args)},
SINCE_2_7)
assert_parses(
s(:def, :foo,
s(:forward_args),
nil),
%q{def foo(...); end},
%q{},
SINCE_2_7)
assert_diagnoses(
[:error, :block_and_blockarg],
%q{def foo(...) bar(...) { }; end},
%q{ ^^^ location
| ~ highlights (0)},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBDOT3' }],
%q{foo do |...| end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBDOT3' }],
%q{foo { |...| }},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBDOT3' }],
%q{def foo(x,y,z); bar(...); end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBDOT3' }],
%q{def foo(x,y,z); super(...); end},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT3' }],
%q{->... {}},
%q{ ^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tBDOT3' }],
%q{->(...) {}},
%q{ ^^^ location},
SINCE_2_7)
# Here and below the parser asssumes that
# it can be a beginningless range, so the error comes after reducing right paren
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRPAREN' }],
%q{def foo(...); yield(...); end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRPAREN' }],
%q{def foo(...); return(...); end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRPAREN' }],
%q{def foo(...); a = (...); end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRBRACK' }],
%q{def foo(...); [...]; end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRBRACK' }],
%q{def foo(...) bar[...]; end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRBRACK' }],
%q{def foo(...) bar[...] = x; end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tRPAREN' }],
%q{def foo(...) defined?(...); end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tDOT3' }],
%q{def foo ...; end},
%q{ ^^^ location},
SINCE_2_7)
end
def test_erange_without_parentheses_at_eol
assert_diagnoses(
[:warning, :triple_dot_at_eol],
%Q{1...\n2},
%q{ ^^^ location},
SINCE_2_7)
refute_diagnoses('(1...)', SINCE_2_7)
refute_diagnoses("(1...\n)", SINCE_2_7)
refute_diagnoses("[1...\n]", SINCE_2_7)
refute_diagnoses("{a: 1...\n2}", SINCE_2_7)
end
def test_embedded_document_with_eof
refute_diagnoses("=begin\n""=end", SINCE_2_7)
refute_diagnoses("=begin\n""=end\0", SINCE_2_7)
refute_diagnoses("=begin\n""=end\C-d", SINCE_2_7)
refute_diagnoses("=begin\n""=end\C-z", SINCE_2_7)
assert_diagnoses(
[:fatal, :embedded_document],
"=begin\n",
%q{},
SINCE_2_7)
assert_diagnoses(
[:fatal, :embedded_document],
"=begin",
%q{},
SINCE_2_7)
end
def test_interp_digit_var
# '#@1'
assert_parses(
s(:str, '#@1'),
%q{ '#@1' },
%q{},
ALL_VERSIONS)
assert_parses(
s(:str, '#@@1'),
%q{ '#@@1' },
%q{},
ALL_VERSIONS)
# <<-'HERE'
# #@1
# HERE
assert_parses(
s(:str, '#@1' + "\n"),
%q{<<-'HERE'!#@1!HERE}.gsub('!', "\n"),
%q{},
ALL_VERSIONS)
assert_parses(
s(:str, '#@@1' + "\n"),
%q{<<-'HERE'!#@@1!HERE}.gsub('!', "\n"),
%q{},
ALL_VERSIONS)
# %q{#@1}
assert_parses(
s(:str, '#@1'),
%q{ %q{#@1} },
%q{},
ALL_VERSIONS)
assert_parses(
s(:str, '#@@1'),
%q{ %q{#@@1} },
%q{},
ALL_VERSIONS)
# "#@1"
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ "#@1" },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ "#@@1" },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:str, '#@1'),
%q{ "#@1" },
%q{},
SINCE_2_7)
assert_parses(
s(:str, '#@@1'),
%q{ "#@@1" },
%q{},
SINCE_2_7)
# <<-"HERE"
# #@1
# HERE
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ <<-"HERE"!#@1!HERE }.gsub('!', "\n"),
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ <<-"HERE"!#@@1!HERE }.gsub('!', "\n"),
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:str, '#@1' + "\n"),
%q{<<-"HERE"!#@1!HERE}.gsub('!', "\n"),
%q{},
SINCE_2_7)
assert_parses(
s(:str, '#@@1' + "\n"),
%q{<<-"HERE"!#@@1!HERE}.gsub('!', "\n"),
%q{},
SINCE_2_7)
# %{#@1}
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %{#@1} },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %{#@@1} },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:str, '#@1'),
%q{ %{#@1} },
%q{},
SINCE_2_7)
assert_parses(
s(:str, '#@@1'),
%q{ %{#@@1} },
%q{},
SINCE_2_7)
# %Q{#@1}
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %Q{#@1} },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %Q{#@@1} },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:str, '#@1'),
%q{ %Q{#@1} },
%q{},
SINCE_2_7)
assert_parses(
s(:str, '#@@1'),
%q{ %Q{#@@1} },
%q{},
SINCE_2_7)
# %w[#@1]
assert_parses(
s(:array,
s(:str, '#@1')),
%q{ %w[ #@1 ] },
%q{},
ALL_VERSIONS)
assert_parses(
s(:array,
s(:str, '#@@1')),
%q{ %w[ #@@1 ] },
%q{},
ALL_VERSIONS)
# %W[#@1]
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %W[#@1] },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %W[#@@1] },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:array,
s(:str, '#@1')),
%q{ %W[#@1] },
%q{},
SINCE_2_7)
assert_parses(
s(:array,
s(:str, '#@@1')),
%q{ %W[#@@1] },
%q{},
SINCE_2_7)
# %i[#@1]
assert_parses(
s(:array,
s(:sym, :'#@1')),
%q{ %i[ #@1 ] },
%q{},
SINCE_2_0)
assert_parses(
s(:array,
s(:sym, :'#@@1')),
%q{ %i[ #@@1 ] },
%q{},
SINCE_2_0)
# %I[#@1]
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %I[#@1] },
%q{ ^^ location},
SINCE_2_0 - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %I[#@@1] },
%q{ ^^^ location},
SINCE_2_0 - SINCE_2_7)
assert_parses(
s(:array,
s(:sym, :'#@1')),
%q{ %I[#@1] },
%q{},
SINCE_2_7)
assert_parses(
s(:array,
s(:sym, :'#@@1')),
%q{ %I[#@@1] },
%q{},
SINCE_2_7)
# :'#@1'
assert_parses(
s(:sym, :'#@1'),
%q{ :'#@1' },
%q{},
ALL_VERSIONS)
assert_parses(
s(:sym, :'#@@1'),
%q{ :'#@@1' },
%q{},
ALL_VERSIONS)
# %s{#@1}
assert_parses(
s(:sym, :'#@1'),
%q{ %s{#@1} },
%q{},
ALL_VERSIONS)
assert_parses(
s(:sym, :'#@@1'),
%q{ %s{#@@1} },
%q{},
ALL_VERSIONS)
# :"#@1"
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ :"#@1" },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ :"#@@1" },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:sym, :'#@1'),
%q{ :"#@1" },
%q{},
SINCE_2_7)
assert_parses(
s(:sym, :'#@@1'),
%q{ :"#@@1" },
%q{},
SINCE_2_7)
# /#@1/
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ /#@1/ },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ /#@@1/ },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:regexp,
s(:str, '#@1'),
s(:regopt)),
%q{ /#@1/ },
%q{},
SINCE_2_7)
assert_parses(
s(:regexp,
s(:str, '#@@1'),
s(:regopt)),
%q{ /#@@1/ },
%q{},
SINCE_2_7)
# %r{#@1}
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %r{#@1} },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %r{#@@1} },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:regexp,
s(:str, '#@1'),
s(:regopt)),
%q{ %r{#@1} },
%q{},
SINCE_2_7)
assert_parses(
s(:regexp,
s(:str, '#@@1'),
s(:regopt)),
%q{ %r{#@@1} },
%q{},
SINCE_2_7)
# %x{#@1}
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ %x{#@1} },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ %x{#@@1} },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@1')),
%q{ %x{#@1} },
%q{},
SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@@1')),
%q{ %x{#@@1} },
%q{},
SINCE_2_7)
# `#@1`
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ `#@1` },
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ `#@@1` },
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@1')),
%q{ `#@1` },
%q{},
SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@@1')),
%q{ `#@@1` },
%q{},
SINCE_2_7)
# <<-`HERE`
# #@1
# HERE
assert_diagnoses(
[:error, :ivar_name, { :name => '@1' }],
%q{ <<-`HERE`!#@1!HERE }.gsub('!', "\n"),
%q{ ^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_diagnoses(
[:error, :cvar_name, { :name => '@@1' }],
%q{ <<-`HERE`!#@@1!HERE }.gsub('!', "\n"),
%q{ ^^^ location},
ALL_VERSIONS - SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@1' + "\n")),
%q{<<-`HERE`!#@1!HERE}.gsub('!', "\n"),
%q{},
SINCE_2_7)
assert_parses(
s(:xstr,
s(:str, '#@@1' + "\n")),
%q{<<-`HERE`!#@@1!HERE}.gsub('!', "\n"),
%q{},
SINCE_2_7)
end
def assert_parses_pattern_match(ast, code, source_maps = '', versions = SINCE_2_7)
case_pre = "case foo; "
source_maps_offset = case_pre.length
source_maps_prefix = ' ' * source_maps_offset
source_maps = source_maps
.lines
.map { |line| source_maps_prefix + line.sub(/^\s*\|/, '') }
.join("\n")
assert_parses(
s(:case_match,
s(:lvar, :foo),
ast,
nil),
"#{case_pre}#{code}; end",
source_maps,
SINCE_2_7
)
end
def test_pattern_matching_single_match
assert_parses_pattern_match(
s(:in_pattern,
s(:match_var, :x),
nil,
s(:lvar, :x)),
%q{in x then x},
%q{~~ keyword (in_pattern)
|~~~~~~~~~~~ expression (in_pattern)
| ~~~~ begin (in_pattern)
| ~ expression (in_pattern.match_var)
| ~ name (in_pattern.match_var)}
)
end
def test_pattern_matching_no_body
assert_parses_pattern_match(
s(:in_pattern,
s(:int, 1), nil, nil),
%q{in 1}
)
end
def test_pattern_matching_if_unless_modifiers
assert_parses_pattern_match(
s(:in_pattern,
s(:match_var, :x),
s(:if_guard, s(:true)),
s(:nil)
),
%q{in x if true; nil},
%q{~~ keyword (in_pattern)
|~~~~~~~~~~~~~~~~~ expression (in_pattern)
| ~ begin (in_pattern)
| ~~ keyword (in_pattern.if_guard)
| ~~~~~~~ expression (in_pattern.if_guard)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:match_var, :x),
s(:unless_guard, s(:true)),
s(:nil)
),
%q{in x unless true; nil},
%q{~~ keyword (in_pattern)
|~~~~~~~~~~~~~~~~~~~~~ expression (in_pattern)
| ~ begin (in_pattern)
| ~~~~~~ keyword (in_pattern.unless_guard)
| ~~~~~~~~~~~ expression (in_pattern.unless_guard)}
)
end
def test_pattern_matching_pin_variable
assert_parses_pattern_match(
s(:in_pattern,
s(:pin, s(:lvar, :foo)),
nil,
s(:nil)),
%q{in ^foo then nil},
%q{ ~ selector (in_pattern.pin)
| ~~~~ expression (in_pattern.pin)
| ~~~ name (in_pattern.pin.lvar)}
)
end
def test_pattern_matching_implicit_array_match
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern_with_tail,
s(:match_var, :x)),
nil,
s(:nil)),
%q{in x, then nil},
%q{ ~ expression (in_pattern.array_pattern_with_tail)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_rest,
s(:match_var, :x))),
nil,
s(:nil)),
%q{in *x then nil},
%q{ ~~ expression (in_pattern.array_pattern)
| ~ operator (in_pattern.array_pattern.match_rest)
| ~ name (in_pattern.array_pattern.match_rest.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_rest)),
nil,
s(:nil)),
%q{in * then nil},
%q{ ~ expression (in_pattern.array_pattern)
| ~ operator (in_pattern.array_pattern.match_rest)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_var, :y)),
nil,
s(:nil)),
%q{in x, y then nil},
%q{ ~~~~ expression (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern_with_tail,
s(:match_var, :x),
s(:match_var, :y)),
nil,
s(:nil)),
%q{in x, y, then nil},
%q{ ~~~~ expression (in_pattern.array_pattern_with_tail)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_rest, s(:match_var, :y)),
s(:match_var, :z)),
nil,
s(:nil)),
%q{in x, *y, z then nil},
%q{ ~~~~~~~~ expression (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_rest, s(:match_var, :x)),
s(:match_var, :y),
s(:match_var, :z)),
nil,
s(:nil)),
%q{in *x, y, z then nil},
%q{ ~~~~~~~~ expression (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:int, 1),
s(:str, 'a'),
s(:array_pattern),
s(:hash_pattern)),
nil,
s(:nil)),
%q{in 1, "a", [], {} then nil},
%q{ ~~~~~~~~~~~~~~ expression (in_pattern.array_pattern)}
)
end
def test_pattern_matching_explicit_array_match
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x)),
nil,
s(:nil)),
%q{in [x] then nil},
%q{ ~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern_with_tail,
s(:match_var, :x)),
nil,
s(:nil)),
%q{in [x,] then nil},
%q{ ~~~~ expression (in_pattern.array_pattern_with_tail)
| ~ begin (in_pattern.array_pattern_with_tail)
| ~ end (in_pattern.array_pattern_with_tail)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_var, :y)),
nil,
s(:true)),
%q{in [x, y] then true},
%q{ ~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern_with_tail,
s(:match_var, :x),
s(:match_var, :y)),
nil,
s(:true)),
%q{in [x, y,] then true},
%q{ ~~~~~~~ expression (in_pattern.array_pattern_with_tail)
| ~ begin (in_pattern.array_pattern_with_tail)
| ~ end (in_pattern.array_pattern_with_tail)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_var, :y),
s(:match_rest)),
nil,
s(:true)),
%q{in [x, y, *] then true},
%q{ ~~~~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_var, :y),
s(:match_rest, s(:match_var, :z))),
nil,
s(:true)),
%q{in [x, y, *z] then true},
%q{ ~~~~~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_rest, s(:match_var, :y)),
s(:match_var, :z)),
nil,
s(:true)),
%q{in [x, *y, z] then true},
%q{ ~~~~~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_var, :x),
s(:match_rest),
s(:match_var, :y)),
nil,
s(:true)),
%q{in [x, *, y] then true},
%q{ ~~~~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_rest, s(:match_var, :x)),
s(:match_var, :y)),
nil,
s(:true)),
%q{in [*x, y] then true},
%q{ ~~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:array_pattern,
s(:match_rest),
s(:match_var, :x)),
nil,
s(:true)),
%q{in [*, x] then true},
%q{ ~~~~~~ expression (in_pattern.array_pattern)
| ~ begin (in_pattern.array_pattern)
| ~ end (in_pattern.array_pattern)}
)
end
def test_pattern_matching_hash
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern),
nil,
s(:true)),
%q{in {} then true},
%q{ ~~ expression (in_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair, s(:sym, :a), s(:int, 1))),
nil,
s(:true)),
%q{in a: 1 then true},
%q{ ~~~~ expression (in_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair, s(:sym, :a), s(:int, 1))),
nil,
s(:true)),
%q{in { a: 1 } then true},
%q{ ~~~~~~~~ expression (in_pattern.hash_pattern)
| ~ begin (in_pattern.hash_pattern)
| ~ end (in_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a)),
nil,
s(:true)),
%q{in a: then true},
%q{ ~~ expression (in_pattern.hash_pattern)
| ~ name (in_pattern.hash_pattern.match_var)
| ~~ expression (in_pattern.hash_pattern.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_rest, s(:match_var, :a))),
nil,
s(:true)),
%q{in **a then true},
%q{ ~~~ expression (in_pattern.hash_pattern)
| ~~~ expression (in_pattern.hash_pattern.match_rest)
| ~~ operator (in_pattern.hash_pattern.match_rest)
| ~ expression (in_pattern.hash_pattern.match_rest.match_var)
| ~ name (in_pattern.hash_pattern.match_rest.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_rest)),
nil,
s(:true)),
%q{in ** then true},
%q{ ~~ expression (in_pattern.hash_pattern)
| ~~ expression (in_pattern.hash_pattern.match_rest)
| ~~ operator (in_pattern.hash_pattern.match_rest)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair, s(:sym, :a), s(:int, 1)),
s(:pair, s(:sym, :b), s(:int, 2))),
nil,
s(:true)),
%q{in a: 1, b: 2 then true},
%q{ ~~~~~~~~~~ expression (in_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a),
s(:match_var, :b)),
nil,
s(:true)),
%q{in a:, b: then true},
%q{ ~~~~~~ expression (in_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair, s(:sym, :a), s(:int, 1)),
s(:match_var, :_a),
s(:match_rest)),
nil,
s(:true)),
%q{in a: 1, _a:, ** then true},
%q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern)}
)
end
def test_pattern_matching_hash_with_string_keys
# Match + assign
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a)),
nil,
s(:true)),
%q{in "a": then true},
%q{ ~~~~ expression (in_pattern.hash_pattern.match_var)
| ~ name (in_pattern.hash_pattern.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a)),
nil,
s(:true)),
%q{in "#{ 'a' }": then true},
%q{ ~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
| ~ name (in_pattern.hash_pattern.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a)),
nil,
s(:true)),
%q{in "#{ %q{a} }": then true},
%q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
| ~ name (in_pattern.hash_pattern.match_var)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_var, :a)),
nil,
s(:true)),
%q{in "#{ %Q{a} }": then true},
%q{ ~~~~~~~~~~~~~ expression (in_pattern.hash_pattern.match_var)
| ~ name (in_pattern.hash_pattern.match_var)}
)
# Only match
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair, s(:sym, :a), s(:int, 1))),
nil,
s(:true)),
%q{in "a": 1 then true},
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair,
s(:dsym, s(:begin, s(:str, "a"))),
s(:int, 1))),
nil,
s(:true)),
%q{in "#{ 'a' }": 1 then true},
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair,
s(:dsym, s(:begin, s(:str, "a"))),
s(:int, 1))),
nil,
s(:true)),
%q{in "#{ %q{a} }": 1 then true},
)
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:pair,
s(:dsym, s(:begin, s(:str, "a"))),
s(:int, 1))),
nil,
s(:true)),
%q{in "#{ %Q{a} }": 1 then true},
)
end
def test_pattern_matching_hash_with_heredoc_keys
# Ruby <3, the following case is acceptable by the MRI's grammar,
# so it has to be reducable by parser.
# We have a code for that in the builder.rb that reject it via
# diagnostic error because of the wrong lvar name
assert_diagnoses(
[:error, :lvar_name, { name: "a\n" }],
%Q{case nil; in "\#{ <<-HERE }":;\na\nHERE\nelse\nend},
%q{ ~~~~~~~ location},
SINCE_2_7
)
end
def test_pattern_matching_keyword_variable
assert_parses_pattern_match(
s(:in_pattern,
s(:self),
nil,
s(:true)),
%q{in self then true}
)
end
def test_pattern_matching_lambda
assert_parses_pattern_match(
s(:in_pattern,
s(:block,
s(:lambda),
s(:args),
s(:int, 42)),
nil,
s(:true)),
%q{in ->{ 42 } then true}
)
end
def test_pattern_matching_ranges
assert_parses_pattern_match(
s(:in_pattern,
s(:irange, s(:int, 1), s(:int, 2)),
nil,
s(:true)),
%q{in 1..2 then true}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:irange, s(:int, 1), nil),
nil,
s(:true)),
%q{in 1.. then true}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:irange, nil, s(:int, 2)),
nil,
s(:true)),
%q{in ..2 then true}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:erange, s(:int, 1), s(:int, 2)),
nil,
s(:true)),
%q{in 1...2 then true}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:erange, s(:int, 1), nil),
nil,
s(:true)),
%q{in 1... then true}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:erange, nil, s(:int, 2)),
nil,
s(:true)),
%q{in ...2 then true}
)
end
def test_pattern_matching_expr_in_paren
assert_parses_pattern_match(
s(:in_pattern,
s(:begin, s(:int, 1)),
nil,
s(:true)),
%q{in (1) then true},
%q{ ~~~ expression (in_pattern.begin)
| ~ begin (in_pattern.begin)
| ~ end (in_pattern.begin)}
)
end
def test_pattern_matching_constants
assert_parses_pattern_match(
s(:in_pattern,
s(:const, nil, :A),
nil,
s(:true)),
%q{in A then true},
%q{ ~ expression (in_pattern.const)
| ~ name (in_pattern.const)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const, s(:const, nil, :A), :B),
nil,
s(:true)),
%q{in A::B then true},
%q{ ~~~~ expression (in_pattern.const)
| ~~ double_colon (in_pattern.const)
| ~ name (in_pattern.const)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const, s(:cbase), :A),
nil,
s(:true)),
%q{in ::A then true},
%q{ ~~~ expression (in_pattern.const)
| ~~ double_colon (in_pattern.const)
| ~ name (in_pattern.const)}
)
end
def test_pattern_matching_const_pattern
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
s(:array_pattern,
s(:int, 1),
s(:int, 2))),
nil,
s(:true)),
%q{in A(1, 2) then true},
%q{ ~~~~~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)
| ~ expression (in_pattern.const_pattern.const)
| ~~~~ expression (in_pattern.const_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
s(:hash_pattern,
s(:match_var, :x))),
nil,
s(:true)),
%q{in A(x:) then true},
%q{ ~~~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)
| ~ expression (in_pattern.const_pattern.const)
| ~~ expression (in_pattern.const_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
nil),
nil,
s(:true)),
%q{in A() then true},
%q{ ~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
s(:array_pattern,
s(:int, 1),
s(:int, 2))),
nil,
s(:true)),
%q{in A[1, 2] then true},
%q{ ~~~~~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)
| ~ expression (in_pattern.const_pattern.const)
| ~~~~ expression (in_pattern.const_pattern.array_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
s(:hash_pattern,
s(:match_var, :x))),
nil,
s(:true)),
%q{in A[x:] then true},
%q{ ~~~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)
| ~ expression (in_pattern.const_pattern.const)
| ~~ expression (in_pattern.const_pattern.hash_pattern)}
)
assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :A),
nil),
nil,
s(:true)),
%q{in A[] then true},
%q{ ~~ expression (in_pattern.const_pattern)
| ~ begin (in_pattern.const_pattern)
| ~ end (in_pattern.const_pattern)}
)
end
def test_pattern_matching_match_alt
assert_parses_pattern_match(
s(:in_pattern,
s(:match_alt, s(:int, 1), s(:int, 2)),
nil,
s(:true)),
%q{in 1 | 2 then true},
%q{ ~~~~~ expression (in_pattern.match_alt)
| ~ operator (in_pattern.match_alt)}
)
end
def test_pattern_matching_match_as
assert_parses_pattern_match(
s(:in_pattern,
s(:match_as,
s(:int, 1),
s(:match_var, :a)),
nil,
s(:true)),
%q{in 1 => a then true},
%q{ ~~~~~~ expression (in_pattern.match_as)
| ~~ operator (in_pattern.match_as)}
)
end
def test_pattern_matching_else
assert_parses(
s(:case_match,
s(:int, 1),
s(:in_pattern,
s(:int, 2), nil,
s(:int, 3)),
s(:int, 4)),
%q{case 1; in 2; 3; else; 4; end},
%q{ ~~~~ else},
SINCE_2_7
)
end
def assert_pattern_matching_defines_local_variables(match_code, lvar_names, versions = SINCE_2_7)
code = "case 1; #{match_code}; then [#{lvar_names.join(', ')}]; end"
with_versions(versions) do |version, parser|
source_file = Parser::Source::Buffer.new('(assert_context)')
source_file.source = code
lvar_names.each do |lvar_name|
refute parser.static_env.declared?(lvar_name),
"(#{version}) local variable #{lvar_name.to_s.inspect} has to be undefined before asserting"
end
before = parser.static_env.instance_variable_get(:@variables).to_a
begin
parsed_ast = parser.parse(source_file)
rescue Parser::SyntaxError => exc
backtrace = exc.backtrace
Exception.instance_method(:initialize).bind(exc).
call("(#{version}) #{exc.message}")
exc.set_backtrace(backtrace)
raise
end
lvar_names.each do |lvar_name|
assert parser.static_env.declared?(lvar_name),
"(#{version}) expected local variable #{lvar_name.to_s.inspect} to be defined after parsing"
end
after = parser.static_env.instance_variable_get(:@variables).to_a
extra = after - before - lvar_names
assert extra.empty?,
"(#{version}) expected only #{lvar_names.inspect} " \
"to be defined during parsing, but also got #{extra.inspect}"
end
end
def test_pattern_matching_creates_locals
assert_pattern_matching_defines_local_variables(
%q{in a, *b, c},
[:a, :b, :c]
)
assert_pattern_matching_defines_local_variables(
%q{in d | e | f},
[:d, :e, :f]
)
assert_pattern_matching_defines_local_variables(
%q{in { g:, **h }},
[:g, :h]
)
assert_pattern_matching_defines_local_variables(
%q{in A(i, *j, k)},
[:i, :j, :k]
)
assert_pattern_matching_defines_local_variables(
%q{in 1 => l},
[:l]
)
assert_pattern_matching_defines_local_variables(
%q{in "m":},
[:m]
)
end
def test_pattern_matching__FILE__LINE_literals
assert_parses(
s(:case_match,
s(:array,
s(:str, "(assert_parses)"),
s(:send,
s(:int, 1), :+,
s(:int, 1)),
s(:__ENCODING__)),
s(:in_pattern,
s(:array_pattern,
s(:str, "(assert_parses)"),
s(:int, 2),
s(:__ENCODING__)), nil, nil), nil),
<<-RUBY,
case [__FILE__, __LINE__ + 1, __ENCODING__]
in [__FILE__, __LINE__, __ENCODING__]
end
RUBY
%q{},
SINCE_2_7)
end
def test_pattern_matching_nil_pattern
assert_parses_pattern_match(
s(:in_pattern,
s(:hash_pattern,
s(:match_nil_pattern)),
nil,
s(:true)),
%q{in **nil then true},
%q{ ~~~~~ expression (in_pattern.hash_pattern.match_nil_pattern)
| ~~~ name (in_pattern.hash_pattern.match_nil_pattern)}
)
end
def test_pattern_matching_single_line
assert_parses(
s(:begin,
s(:in_match,
s(:int, 1),
s(:array_pattern,
s(:match_var, :a))),
s(:lvar, :a)),
%q{1 in [a]; a},
%q{~~~~~~~~ expression (in_match)
| ~~ operator (in_match)},
SINCE_2_7)
end
def test_ruby_bug_pattern_matching_restore_in_kwarg_flag
refute_diagnoses(
"p(({} in {a:}), a:\n 1)",
SINCE_2_7)
end
def test_pattern_matching_duplicate_variable_name
assert_diagnoses(
[:error, :duplicate_variable_name, { :name => 'a' }],
%q{case 0; in a, a; end},
%q{ ^ location},
SINCE_2_7)
refute_diagnoses(
%q{case [0, 1, 2, 3]; in _, _, _a, _a; end},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_variable_name, { :name => 'a' }],
%q{case 0; in a, {a:}; end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_variable_name, { :name => 'a' }],
%q{case 0; in a, {"a":}; end},
%q{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_variable_name, { :name => 'a' }],
%q{0 in [a, a]},
%q{ ^ location},
SINCE_2_7)
end
def test_pattern_matching_duplicate_hash_keys
assert_diagnoses(
[:error, :duplicate_pattern_key, { :name => 'a' }],
%q{ case 0; in a: 1, a: 2; end },
%q{ ^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_pattern_key, { :name => 'a' }],
%q{ case 0; in a: 1, "a": 2; end },
%q{ ^^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_pattern_key, { :name => 'a' }],
%q{ case 0; in "a": 1, "a": 2; end },
%q{ ^^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_pattern_key, { :name => "a\0" }],
%q{ case 0; in "a\x0":a1, "a\0":a2; end },
%q{ ^^^^^^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :duplicate_pattern_key, { :name => "abc" }],
%q{ case 0; in "abc":a1, "a#{"b"}c":a2; end },
%q{ ^^^^^^^^^^^ location},
SINCE_2_7)
end
def test_pattern_matching_required_parentheses_for_in_match
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tCOMMA' }],
%{1 in a, b},
%{ ^ location},
SINCE_2_7)
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tLABEL' }],
%{1 in a:},
%{ ^^ location},
SINCE_2_7)
end
def test_parser_bug_645
assert_parses(
s(:block,
s(:lambda),
s(:args,
s(:optarg, :arg,
s(:hash))), nil),
'-> (arg={}) {}',
%{},
SINCE_1_9)
end
end
parser-2.7.0.2/test/test_lexer.rb 0000644 0000041 0000041 00000320456 13617025313 016701 0 ustar www-data www-data # encoding: ascii-8bit
# frozen_string_literal: true
require 'helper'
require 'complex'
class TestLexer < Minitest::Test
def setup_lexer(version)
@lex = Parser::Lexer.new(version)
@lex.comments = []
@lex.diagnostics = Parser::Diagnostic::Engine.new
@lex.diagnostics.all_errors_are_fatal = true
# @lex.diagnostics.consumer = lambda { |diag| $stderr.puts "", diag.render }
end
def setup
setup_lexer 18
end
#
# Tools
#
def utf(str)
str.dup.force_encoding(Encoding::UTF_8)
end
#
# Additional matchers
#
def refute_scanned(s, *args)
assert_raises Parser::SyntaxError do
assert_scanned(s, *args)
end
end
def assert_escape(expected, input)
source_buffer = Parser::Source::Buffer.new('(assert_escape)')
source_buffer.source = "\"\\#{input}\"".encode(input.encoding)
@lex.reset
@lex.source_buffer = source_buffer
lex_token, (lex_value, *) = @lex.advance
lex_value.force_encoding(Encoding::BINARY)
assert_equal [:tSTRING, expected],
[lex_token, lex_value],
source_buffer.source
end
def refute_escape(input)
err = assert_raises Parser::SyntaxError do
@lex.state = :expr_beg
assert_scanned "%Q[\\#{input}]"
end
assert_equal :fatal, err.diagnostic.level
end
def assert_lex_fname(name, type, range)
begin_pos, end_pos = range
assert_scanned("def #{name} ",
:kDEF, 'def', [0, 3],
type, name, [begin_pos + 4, end_pos + 4])
assert_equal :expr_endfn, @lex.state
end
def assert_scanned(input, *args)
source_buffer = Parser::Source::Buffer.new('(assert_scanned)')
source_buffer.source = input
@lex.reset(false)
@lex.source_buffer = source_buffer
until args.empty? do
token, value, (begin_pos, end_pos) = args.shift(3)
lex_token, (lex_value, lex_range) = @lex.advance
assert lex_token, 'no more tokens'
assert_operator [lex_token, lex_value], :eql?, [token, value], input
assert_equal begin_pos, lex_range.begin_pos
assert_equal end_pos, lex_range.end_pos
end
lex_token, (lex_value, *) = @lex.advance
refute lex_token, "must be empty, but had #{[lex_token, lex_value].inspect}"
end
#
# Tests
#
def test_read_escape
assert_escape "\\", "\\"
assert_escape "\n", "n"
assert_escape "\t", "t"
assert_escape "\r", "r"
assert_escape "\f", "f"
assert_escape "\13", "v"
assert_escape "\0", "0"
assert_escape "\07", "a"
assert_escape "\007", "a"
assert_escape "\033", "e"
assert_escape "\377", "377"
assert_escape "\377", "xff"
assert_escape "\010", "b"
assert_escape " ", "s"
assert_escape "q", "q" # plain vanilla escape
end
def test_read_escape_c
assert_escape "\030", "C-x"
assert_escape "\030", "cx"
assert_escape "\230", 'C-\M-x'
assert_escape "\230", 'c\M-x'
assert_escape "\177", "C-?"
assert_escape "\177", "c?"
assert_escape "\r", "cM"
end
def test_read_escape_m
assert_escape "\370", "M-x"
assert_escape "\230", 'M-\C-x'
assert_escape "\230", 'M-\cx'
end
def test_read_escape_errors
refute_escape ""
refute_escape "M"
refute_escape "M-"
refute_escape "Mx"
refute_escape "Cx"
refute_escape "C"
refute_escape "C-"
refute_escape "c"
refute_escape "x"
end
def test_read_escape_unicode__19
assert_escape "\x09", 'u{9}'
assert_escape "\x31", 'u{31}'
assert_escape "\x09\x01", 'u{9 1}'
assert_escape "\xc4\xa3", utf('u0123')
assert_escape "\xc4\xa3\xc3\xb0\xeb\x84\xa3", utf('u{123 f0 B123}')
end
def test_read_escape_unicode_bad__19
refute_escape 'u123'
refute_escape 'u{}'
refute_escape 'u{123 f0h}'
refute_escape 'u{123 f0'
end
def test_read_escape_whitespaces__27
setup_lexer 27
[ *(0..8), *(14..31) ].each do |code|
@lex.reset
refute_scanned "\"\\C-" + code.chr + "\""
@lex.reset
refute_scanned "\"\\M-" + code.chr + "\""
@lex.reset
refute_scanned "\"\\C-\\M-" + code.chr + "\""
@lex.reset
refute_scanned "\"\\M-\\C-" + code.chr + "\""
end
end
def test_ambiguous_uminus
assert_scanned("m -3",
:tIDENTIFIER, "m", [0, 1],
:tUNARY_NUM, "-", [2, 3],
:tINTEGER, 3, [3, 4])
end
def test_ambiguous_uplus
assert_scanned("m +3",
:tIDENTIFIER, "m", [0, 1],
:tUNARY_NUM, "+", [2, 3],
:tINTEGER, 3, [3, 4])
end
def test_and
assert_scanned "&", :tAMPER, "&", [0, 1]
end
def test_and2
@lex.state = :expr_end
assert_scanned "&&", :tANDOP, "&&", [0, 2]
end
def test_and2_equals
@lex.state = :expr_end
assert_scanned "&&=", :tOP_ASGN, "&&", [0, 3]
end
def test_and_arg
@lex.state = :expr_arg
assert_scanned(" &y",
:tAMPER, "&", [1, 2],
:tIDENTIFIER, "y", [2, 3])
end
def test_and_equals
@lex.state = :expr_end
assert_scanned "&=", :tOP_ASGN, "&", [0, 2]
end
def test_and_expr
@lex.state = :expr_arg
assert_scanned("x & y",
:tIDENTIFIER, "x", [0, 1],
:tAMPER2, "&", [2, 3],
:tIDENTIFIER, "y", [4, 5])
end
def test_and_meth
assert_lex_fname "&", :tAMPER2, [0, 1]
end
def test_and_dot_arg
@lex.state = :expr_arg
assert_scanned "&.", :tANDDOT, "&.", [0, 2]
end
def test_and_dot_cmdarg
@lex.state = :expr_cmdarg
assert_scanned "&.", :tANDDOT, "&.", [0, 2]
end
def test_assoc
assert_scanned "=>", :tASSOC, "=>", [0, 2]
end
def test_label__18
assert_scanned("{a:b",
:tLBRACE, "{", [0, 1],
:tIDENTIFIER, "a", [1, 2],
:tSYMBOL, "b", [2, 4])
end
def test_label_in_params__18
assert_scanned("foo(a:b",
:tIDENTIFIER, "foo", [0, 3],
:tLPAREN2, "(", [3, 4],
:tIDENTIFIER, "a", [4, 5],
:tSYMBOL, "b", [5, 7])
end
def test_label__19
setup_lexer 19
assert_scanned("{a:b",
:tLBRACE, "{", [0, 1],
:tLABEL, "a", [1, 3],
:tIDENTIFIER, "b", [3, 4])
end
def test_label_in_params__19
setup_lexer 19
assert_scanned("foo(a:b",
:tIDENTIFIER, "foo", [0, 3],
:tLPAREN2, "(", [3, 4],
:tLABEL, "a", [4, 6],
:tIDENTIFIER, "b", [6, 7])
end
def test_label_fid__19
setup_lexer 19
assert_scanned("{a?:true",
:tLBRACE, '{', [0, 1],
:tLABEL, 'a?', [1, 4],
:kTRUE, 'true', [4, 8])
end
def test_label__22
setup_lexer 22
assert_scanned("{'a':",
:tLBRACE, '{', [0, 1],
:tSTRING_BEG, "'", [1, 2],
:tSTRING_CONTENT, 'a', [2, 3],
:tLABEL_END, "'", [3, 5])
end
def test_label_nested__22
setup_lexer 22
assert_scanned("{'a\":':",
:tLBRACE, '{', [0, 1],
:tSTRING_BEG, "'", [1, 2],
:tSTRING_CONTENT, 'a":', [2, 5],
:tLABEL_END, "'", [5, 7])
end
def test_label_colon2__22
setup_lexer 22
assert_scanned("{'a'::",
:tLBRACE, '{', [0, 1],
:tSTRING, "a", [1, 4],
:tCOLON2, '::', [4, 6])
end
def test_pct_string_colon__22
setup_lexer 22
assert_scanned("{%'a':",
:tLBRACE, '{', [0, 1],
:tSTRING_BEG, "%'", [1, 3],
:tSTRING_CONTENT, 'a', [3, 4],
:tSTRING_END, "'", [4, 5],
:tCOLON, ':', [5, 6])
end
def test_command_start__19
setup_lexer 19
%w[case elsif for in until when while
if unless and or].each do |keyword|
token = "k#{keyword.upcase}".to_sym
@lex.reset
assert_scanned("#{keyword} a:b",
token, keyword, [0, keyword.length],
:tIDENTIFIER, "a", [keyword.length + 1, keyword.length + 2],
:tSYMBOL, "b", [keyword.length + 2, keyword.length + 4])
end
end
def test_mod_not_command_start__19
setup_lexer 19
%w[if unless while until rescue].each do |keyword|
token = "k#{keyword.upcase}_MOD".to_sym
@lex.state = :expr_end
assert_scanned("#{keyword} a:b",
token, keyword, [0, keyword.length],
:tLABEL, "a", [keyword.length + 1, keyword.length + 3],
:tIDENTIFIER, "b", [keyword.length + 3, keyword.length + 4])
end
end
def test_back_ref
assert_scanned("[$&, $`, $', $+]",
:tLBRACK, "[", [0, 1],
:tBACK_REF, "$&", [1, 3], :tCOMMA, ",", [3, 4],
:tBACK_REF, "$`", [5, 7], :tCOMMA, ",", [7, 8],
:tBACK_REF, "$'", [9, 11], :tCOMMA, ",", [11, 12],
:tBACK_REF, "$+", [13, 15],
:tRBRACK, "]", [15, 16])
end
def test_backslash
assert_scanned("1 \\\n+ 2",
:tINTEGER, 1, [0, 1],
:tPLUS, "+", [4, 5],
:tINTEGER, 2, [6, 7])
end
def test_backslash_bad
refute_scanned("1 \\ + 2",
:tINTEGER, 1, [0, 1])
end
def test_backtick
assert_scanned("`ls`",
:tXSTRING_BEG, "`", [0, 1],
:tSTRING_CONTENT, "ls", [1, 3],
:tSTRING_END, "`", [3, 4])
end
def test_backtick_cmdarg
@lex.state = :expr_dot
assert_scanned("\n`", :tBACK_REF2, "`", [1, 2]) # \n ensures expr_cmd
assert_equal :expr_arg, @lex.state
end
def test_backtick_dot
@lex.state = :expr_dot
assert_scanned("a.`(3)",
:tIDENTIFIER, "a", [0, 1],
:tDOT, ".", [1, 2],
:tBACK_REF2, "`", [2, 3],
:tLPAREN2, "(", [3, 4],
:tINTEGER, 3, [4, 5],
:tRPAREN, ")", [5, 6])
end
def test_backtick_method
@lex.state = :expr_fname
assert_scanned("`", :tBACK_REF2, "`", [0, 1])
assert_equal :expr_endfn, @lex.state
end
def test_bad_char
refute_scanned(" \010 ")
end
def test_bang
assert_scanned "!", :tBANG, "!", [0, 1]
end
def test_bang_equals
assert_scanned "!=", :tNEQ, "!=", [0, 2]
end
def test_bang_tilde
assert_scanned "!~", :tNMATCH, "!~", [0, 2]
end
def test_def_ubang
setup_lexer(20)
@lex.state = :expr_fname
assert_scanned '!@', :tBANG, '!@', [0, 2]
end
def test_carat
assert_scanned "^", :tCARET, "^", [0, 1]
end
def test_carat_equals
assert_scanned "^=", :tOP_ASGN, "^", [0, 2]
end
def test_colon2
assert_scanned("A::B",
:tCONSTANT, "A", [0, 1],
:tCOLON2, "::", [1, 3],
:tCONSTANT, "B", [3, 4])
@lex.state = :expr_arg
assert_scanned("::Array",
:tCOLON2, "::", [0, 2],
:tCONSTANT, "Array", [2, 7])
end
def test_colon3
assert_scanned("::Array",
:tCOLON3, "::", [0, 2],
:tCONSTANT, "Array", [2, 7])
@lex.state = :expr_arg
assert_scanned(" ::Array",
:tCOLON3, "::", [1, 3],
:tCONSTANT, "Array", [3, 8])
end
def test_comma
assert_scanned ",", :tCOMMA, ",", [0, 1]
end
def test_comment
[26, 27].each do |version|
setup_lexer(version)
assert_scanned("1 # one\n# two\n2",
:tINTEGER, 1, [0, 1],
:tNL, nil, [7, 8],
:tINTEGER, 2, [14, 15])
assert_equal 2, @lex.comments.length
assert_equal '# one', @lex.comments[0].text
assert_equal '# two', @lex.comments[1].text
end
end
def test_comment_expr_beg
assert_scanned("{#1\n}",
:tLBRACE, "{", [0, 1],
:tRCURLY, "}", [4, 5])
end
def test_comment_begin
assert_scanned("=begin\nblah\nblah\n=end\n42",
:tINTEGER, 42, [22, 24])
assert_equal 1, @lex.comments.length
assert_equal "=begin\nblah\nblah\n=end\n", @lex.comments[0].text
end
def test_comment_begin_bad
refute_scanned("=begin\nblah\nblah\n")
end
def test_comment_begin_not_comment
assert_scanned("beginfoo = 5\np x \\\n=beginfoo",
:tIDENTIFIER, "beginfoo", [0, 8],
:tEQL, "=", [9, 10],
:tINTEGER, 5, [11, 12],
:tNL, nil, [12, 13],
:tIDENTIFIER, "p", [13, 14],
:tIDENTIFIER, "x", [15, 16],
:tEQL, "=", [19, 20],
:tIDENTIFIER, "beginfoo", [20, 28])
end
def test_comment_begin_space
assert_scanned("=begin blah\nblah\n=end\n")
assert_equal 1, @lex.comments.length
assert_equal "=begin blah\nblah\n=end\n", @lex.comments[0].text
end
def test_comment_end_space_and_text
assert_scanned("=begin blah\nblah\n=end blab\n")
assert_equal 1, @lex.comments.length
assert_equal "=begin blah\nblah\n=end blab\n", @lex.comments[0].text
end
def test_comment_eos
assert_scanned("# comment")
end
def test_constant
assert_scanned("ArgumentError",
:tCONSTANT, "ArgumentError", [0, 13])
end
def test_constant_semi
assert_scanned("ArgumentError;",
:tCONSTANT, "ArgumentError", [0, 13],
:tSEMI, ";", [13, 14])
end
def test_cvar
assert_scanned "@@blah", :tCVAR, "@@blah", [0, 6]
end
def test_cvar_bad
refute_scanned "@@1"
end
def test_div
assert_scanned("a / 2",
:tIDENTIFIER, "a", [0, 1],
:tDIVIDE, "/", [2, 3],
:tINTEGER, 2, [4, 5])
end
def test_div_equals
assert_scanned("a /= 2",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, "/", [2, 4],
:tINTEGER, 2, [5, 6])
end
def test_do
assert_scanned("x do 42 end",
:tIDENTIFIER, "x", [0, 1],
:kDO, "do", [2, 4],
:tINTEGER, 42, [5, 7],
:kEND, "end", [8, 11])
end
def test_do_block
@lex.state = :expr_endarg
assert_scanned("do 42 end",
:kDO_BLOCK, "do", [0, 2],
:tINTEGER, 42, [3, 5],
:kEND, "end", [6, 9])
end
def test_do_cond
@lex.cond.push true
assert_scanned("x do 42 end",
:tIDENTIFIER, "x", [0, 1],
:kDO_COND, "do", [2, 4],
:tINTEGER, 42, [5, 7],
:kEND, "end", [8, 11])
end
def test_dot
assert_scanned ".", :tDOT, ".", [0, 1]
end
def test_dot2
assert_scanned "..", :tDOT2, "..", [0, 2]
end
def test_dot3
assert_scanned "...", :tDOT3, "...", [0, 3]
end
def test_equals
assert_scanned "=", :tEQL, "=", [0, 1]
end
def test_equals2
assert_scanned "==", :tEQ, "==", [0, 2]
end
def test_equals3
assert_scanned "===", :tEQQ, "===", [0, 3]
end
def test_equals_tilde
assert_scanned "=~", :tMATCH, "=~", [0, 2]
end
def test_float
assert_scanned "1.0", :tFLOAT, 1.0, [0, 3]
end
def test_float_bad_no_underscores
refute_scanned "1__0.0"
end
def test_float_bad_no_zero_leading
refute_scanned ".0"
end
def test_float_bad_trailing_underscore
refute_scanned "123_.0"
end
def test_float_call
assert_scanned("1.0.to_s",
:tFLOAT, 1.0, [0, 3],
:tDOT, ".", [3, 4],
:tIDENTIFIER, "to_s", [4, 8])
end
def test_float_dot_E
assert_scanned "1.0E10", :tFLOAT, 1.0e10, [0, 6]
end
def test_float_dot_E_neg
assert_scanned("-1.0E10",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1.0e10, [1, 7])
end
def test_float_dot_E_pos
assert_scanned("+1.0E10",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1.0e10, [1, 7])
end
def test_float_dot_e
assert_scanned "1.0e10", :tFLOAT, 1.0e10, [0, 6]
end
def test_float_dot_e_neg
assert_scanned("-1.0e10",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1.0e10, [1, 7])
end
def test_float_dot_e_pos
assert_scanned("+1.0e10",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1.0e10, [1, 7])
end
def test_float_e
assert_scanned "1e10", :tFLOAT, 1e10, [0, 4]
end
def test_float_e_bad_trailing_underscore
refute_scanned "123_e10"
end
def test_float_e_minus
assert_scanned "1e-10", :tFLOAT, 1e-10, [0, 5]
end
def test_float_e_neg
assert_scanned("-1e10",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1e10, [1, 5])
end
def test_float_e_neg_minus
assert_scanned("-1e-10",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1e-10, [1, 6])
end
def test_float_e_neg_plus
assert_scanned("-1e+10",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1e10, [1, 6])
end
def test_float_e_pos
assert_scanned("+1e10",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1e10, [1, 5])
end
def test_float_e_pos_minus
assert_scanned("+1e-10",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1e-10, [1, 6])
end
def test_float_e_pos_plus
assert_scanned("+1e+10",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1e10, [1, 6])
end
def test_float_e_plus
assert_scanned "1e+10", :tFLOAT, 1e10, [0, 5]
end
def test_float_e_zero
assert_scanned "0e0", :tFLOAT, 0e0, [0, 3]
end
def test_float_e_nothing
[18, 19, 20].each do |version|
setup_lexer version
refute_scanned "1end"
refute_scanned "1.1end"
end
setup_lexer 21
assert_scanned("1end",
:tINTEGER, 1, [0, 1],
:kEND, 'end', [1, 4])
assert_scanned("1.1end",
:tFLOAT, 1.1, [0, 3],
:kEND, 'end', [3, 6])
end
def test_float_neg
assert_scanned("-1.0",
:tUNARY_NUM, "-", [0, 1],
:tFLOAT, 1.0, [1, 4])
end
def test_float_pos
assert_scanned("+1.0",
:tUNARY_NUM, "+", [0, 1],
:tFLOAT, 1.0, [1, 4])
end
def test_ge
assert_scanned("a >= 2",
:tIDENTIFIER, "a", [0, 1],
:tGEQ, ">=", [2, 4],
:tINTEGER, 2, [5, 6])
end
def test_global
assert_scanned("$blah", :tGVAR, "$blah", [0, 5])
end
def test_global_backref
assert_scanned("$`", :tBACK_REF, "$`", [0, 2])
end
# This was removed in 2.1.
# def test_global_dash_nothing
# assert_scanned("$- ", :tGVAR, "$-")
# end
def test_global_dash_something
assert_scanned("$-x", :tGVAR, "$-x", [0, 3])
end
def test_global_number
assert_scanned("$10", :tNTH_REF, 10, [0, 3])
end
def test_global_other
assert_scanned("[$~, $*, $$, $?, $!, $@, $/, $\\, $;, $,, $., $=, $:, $<, $>, $\"]",
:tLBRACK, "[", [0, 1],
:tGVAR, "$~", [1, 3], :tCOMMA, ",", [3, 4],
:tGVAR, "$*", [5, 7], :tCOMMA, ",", [7, 8],
:tGVAR, "$$", [9, 11], :tCOMMA, ",", [11, 12],
:tGVAR, "$\?", [13, 15], :tCOMMA, ",", [15, 16],
:tGVAR, "$!", [17, 19], :tCOMMA, ",", [19, 20],
:tGVAR, "$@", [21, 23], :tCOMMA, ",", [23, 24],
:tGVAR, "$/", [25, 27], :tCOMMA, ",", [27, 28],
:tGVAR, "$\\", [29, 31], :tCOMMA, ",", [31, 32],
:tGVAR, "$;", [33, 35], :tCOMMA, ",", [35, 36],
:tGVAR, "$,", [37, 39], :tCOMMA, ",", [39, 40],
:tGVAR, "$.", [41, 43], :tCOMMA, ",", [43, 44],
:tGVAR, "$=", [45, 47], :tCOMMA, ",", [47, 48],
:tGVAR, "$:", [49, 51], :tCOMMA, ",", [51, 52],
:tGVAR, "$<", [53, 55], :tCOMMA, ",", [55, 56],
:tGVAR, "$>", [57, 59], :tCOMMA, ",", [59, 60],
:tGVAR, "$\"", [61, 63],
:tRBRACK, "]", [63, 64])
end
def test_global_underscore
assert_scanned("$_",
:tGVAR, "$_", [0, 2])
end
def test_global_weird
assert_scanned("$__blah",
:tGVAR, "$__blah", [0, 7])
end
def test_global_zero
assert_scanned("$0", :tGVAR, "$0", [0, 2])
end
def test_gt
assert_scanned("a > 2",
:tIDENTIFIER, "a", [0, 1],
:tGT, ">", [2, 3],
:tINTEGER, 2, [4, 5])
end
def test_heredoc_backtick
assert_scanned("a = <<`EOF`\n blah blah\nEOF\n",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tXSTRING_BEG, "<<`", [4, 11],
:tSTRING_CONTENT, " blah blah\n", [12, 24],
:tSTRING_END, "EOF", [24, 27],
:tNL, nil, [11, 12])
end
def test_heredoc_double
assert_scanned("a = <<\"EOF\"\n blah blah\nEOF\n",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tSTRING_BEG, "<<\"", [4, 11],
:tSTRING_CONTENT, " blah blah\n", [12, 24],
:tSTRING_END, "EOF", [24, 27],
:tNL, nil, [11, 12])
end
def test_heredoc_double_dash
assert_scanned("a = <<-\"EOF\"\n blah blah\n EOF\n",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tSTRING_BEG, "<<\"", [4, 12],
:tSTRING_CONTENT, " blah blah\n", [13, 25],
:tSTRING_END, "EOF", [25, 30],
:tNL, nil, [12, 13])
end
def test_heredoc_double_eos
refute_scanned("a = <<\"EOF\"\nblah",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tSTRING_BEG, "<<\"", [4, 7])
end
def test_heredoc_double_eos_nl
refute_scanned("a = <<\"EOF\"\nblah\n",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tSTRING_BEG, "<<\"", [4, 7])
end
def test_heredoc_double_interp
assert_scanned("a = <<\"EOF\"\n#x a \#@a b \#$b c \#{3} \nEOF\n",
:tIDENTIFIER, "a", [0, 1],
:tEQL, "=", [2, 3],
:tSTRING_BEG, "<<\"", [4, 11],
:tSTRING_CONTENT, "#x a ", [12, 17],
:tSTRING_DVAR, nil, [17, 18],
:tIVAR, "@a", [18, 20],
:tSTRING_CONTENT, " b ", [20, 23],
:tSTRING_DVAR, nil, [23, 24],
:tGVAR, "$b", [24, 26],
:tSTRING_CONTENT, " c ", [26, 29],
:tSTRING_DBEG, '#{', [29, 31],
:tINTEGER, 3, [31, 32],
:tRCURLY, "}", [32, 33],
:tSTRING_CONTENT, " \n", [33, 35],
:tSTRING_END, "EOF", [35, 38],
:tNL, nil, [11, 12])
end
def test_heredoc_empty
assert_scanned("<<\"\"\n\#{x}\nblah2\n\n",
:tSTRING_BEG, "<<\"", [0, 4],
:tSTRING_DBEG, "\#{", [5, 7],
:tIDENTIFIER, "x", [7, 8],
:tRCURLY, "}", [8, 9],
:tSTRING_CONTENT, "\n", [9, 10],
:tSTRING_CONTENT, "blah2\n", [10, 16],
:tSTRING_END, "", [16, 16],
:tNL, nil, [4, 5])
end
def test_heredoc_none
assert_scanned("a = <", :tCMP, [0, 3]
end
def test_identifier_def
assert_lex_fname "identifier", :tIDENTIFIER, [0, 10]
end
def test_identifier_equals_arrow
assert_scanned(":blah==>",
:tSYMBOL, "blah=", [0, 6],
:tASSOC, "=>", [6, 8])
end
def test_identifier_equals3
assert_scanned(":a===b",
:tSYMBOL, "a", [0, 2],
:tEQQ, "===", [2, 5],
:tIDENTIFIER, "b", [5, 6])
end
def test_identifier_equals_equals_arrow
assert_scanned(":a==>b",
:tSYMBOL, "a=", [0, 3],
:tASSOC, "=>", [3, 5],
:tIDENTIFIER, "b", [5, 6])
end
def test_identifier_equals_caret
assert_lex_fname "^", :tCARET, [0, 1]
end
def test_identifier_equals_def
assert_lex_fname "identifier=", :tIDENTIFIER, [0, 11]
end
def test_identifier_equals_def2
assert_lex_fname "==", :tEQ, [0, 2]
end
def test_identifier_equals_expr
@lex.state = :expr_dot
assert_scanned("y = arg",
:tIDENTIFIER, "y", [0, 1],
:tEQL, "=", [2, 3],
:tIDENTIFIER, "arg", [4, 7])
assert_equal :expr_arg, @lex.state
end
def test_identifier_equals_or
assert_lex_fname "|", :tPIPE, [0, 1]
end
def test_identifier_equals_slash
assert_lex_fname "/", :tDIVIDE, [0, 1]
end
def test_identifier_equals_tilde
@lex.state = :expr_fname
assert_scanned("identifier=~",
:tIDENTIFIER, "identifier=", [0, 11],
:tTILDE, "~", [11, 12])
end
def test_identifier_gt
assert_lex_fname ">", :tGT, [0, 1]
end
def test_identifier_le
assert_lex_fname "<=", :tLEQ, [0, 2]
end
def test_identifier_lt
assert_lex_fname "<", :tLT, [0, 1]
end
def test_identifier_tilde
assert_lex_fname "~", :tTILDE, [0, 1]
end
def test_identifier_defined?
assert_lex_fname "defined?", :kDEFINED, [0, 8]
end
def test_index
assert_lex_fname "[]", :tAREF, [0, 2]
end
def test_index_equals
assert_lex_fname "[]=", :tASET, [0, 3]
end
def test_integer
assert_scanned "42", :tINTEGER, 42, [0, 2]
end
def test_integer_bin
assert_scanned "0b101010", :tINTEGER, 42, [0, 8]
end
def test_integer_bin_bad_none
refute_scanned "0b "
end
def test_integer_bin_bad_underscores
refute_scanned "0b10__01"
end
def test_integer_dec
assert_scanned "42", :tINTEGER, 42, [0, 2]
end
def test_integer_dec_bad_underscores
refute_scanned "42__24"
end
def test_integer_dec_d
assert_scanned "0d42", :tINTEGER, 42, [0, 4]
end
def test_integer_dec_d_bad_none
refute_scanned "0d"
end
def test_integer_dec_d_bad_underscores
refute_scanned "0d42__24"
end
def test_question_eh_a__18
setup_lexer 18
assert_scanned "?a", :tINTEGER, 97, [0, 2]
end
def test_question_eh_a__19
setup_lexer 19
assert_scanned '?a', :tCHARACTER, "a", [0, 2]
end
def test_question_eh_escape_M_escape_C__18
setup_lexer 18
assert_scanned '?\M-\C-a', :tINTEGER, 129, [0, 8]
end
def test_question_eh_escape_M_escape_C__19
setup_lexer 19
assert_scanned '?\M-\C-a', :tCHARACTER, "\M-\C-a", [0, 8]
end
def test_question_eh_escape_u_1_digit
setup_lexer 19
refute_scanned '?\\u1'
end
def test_question_eh_escape_u_2_digits
setup_lexer 19
refute_scanned '?\\u12'
end
def test_question_eh_escape_u_3_digits
setup_lexer 19
refute_scanned '?\\u123'
end
def test_question_eh_escape_u_4_digits
setup_lexer 19
assert_scanned '?\\u0001', :tCHARACTER, "\u0001", [0, 7]
end
def test_question_eh_single_unicode_point
setup_lexer 19
assert_scanned '?\\u{123}', :tCHARACTER, "\u0123", [0, 8]
setup_lexer 19
assert_scanned '?\\u{a}', :tCHARACTER, "\n", [0, 6]
end
def test_question_eh_multiple_unicode_points
setup_lexer 19
refute_scanned '?\\u{1 2 3}'
setup_lexer 19
refute_scanned '?\\u{a b}'
end
def test_question_eh_escape_u_unclosed_bracket
setup_lexer 19
refute_scanned '?\\u{123'
end
def test_question_eh_escape_space_around_unicode_point__19
setup_lexer 19
refute_scanned '"\\u{1 }"'
setup_lexer 19
refute_scanned '"\\u{ 1}"'
setup_lexer 19
refute_scanned '"\\u{ 1 }"'
setup_lexer 19
refute_scanned '"\\u{1 2 }"'
setup_lexer 19
refute_scanned '"\\u{ 1 2}"'
setup_lexer 19
refute_scanned '"\\u{1 2}"'
end
def test_question_eh_escape_space_around_unicode_point__24
setup_lexer 24
assert_scanned '"\\u{ 1}"', :tSTRING, "\u0001", [0, 8]
setup_lexer 24
assert_scanned '"\\u{1 }"', :tSTRING, "\u0001", [0, 8]
setup_lexer 24
assert_scanned '"\\u{ 1 }"', :tSTRING, "\u0001", [0, 9]
setup_lexer 24
assert_scanned '"\\u{1 2 }"', :tSTRING, "\u0001\u0002", [0, 10]
setup_lexer 24
assert_scanned '"\\u{ 1 2}"', :tSTRING, "\u0001\u0002", [0, 10]
setup_lexer 24
assert_scanned '"\\u{1 2}"', :tSTRING, "\u0001\u0002", [0, 10]
end
def test_integer_hex
assert_scanned "0x2a", :tINTEGER, 42, [0, 4]
end
def test_integer_hex_bad_none
refute_scanned "0x "
end
def test_integer_hex_bad_underscores
refute_scanned "0xab__cd"
end
def test_integer_oct
assert_scanned "052", :tINTEGER, 42, [0, 3]
end
def test_integer_oct_bad_range
refute_scanned "08"
end
def test_integer_oct_bad_underscores
refute_scanned "01__23"
end
def test_integer_oct_O
assert_scanned "0O52", :tINTEGER, 42, [0, 4]
end
def test_integer_oct_O_bad_range
refute_scanned "0O1238"
end
def test_integer_oct_O_bad_underscores
refute_scanned "0O1__23"
end
def test_integer_oct_O_not_bad_none
assert_scanned "0O ", :tINTEGER, 0, [0, 2]
end
def test_integer_oct_o
assert_scanned "0o52", :tINTEGER, 42, [0, 4]
end
def test_integer_oct_o_bad_range
refute_scanned "0o1283"
end
def test_integer_oct_o_bad_underscores
refute_scanned "0o1__23"
end
def test_integer_oct_o_not_bad_none
assert_scanned "0o ", :tINTEGER, 0, [0, 2]
end
def test_integer_trailing
assert_scanned("1.to_s",
:tINTEGER, 1, [0, 1],
:tDOT, '.', [1, 2],
:tIDENTIFIER, 'to_s', [2, 6])
end
def test_integer_underscore
assert_scanned "4_2", :tINTEGER, 42, [0, 3]
end
def test_integer_underscore_bad
refute_scanned "4__2"
end
def test_integer_zero
assert_scanned "0", :tINTEGER, 0, [0, 1]
end
def test_ivar
assert_scanned "@blah", :tIVAR, "@blah", [0, 5]
end
def test_ivar_bad
refute_scanned "@1"
end
def test_ivar_bad_0_length
refute_scanned "1+@\n", :tINTEGER, 1, [0, 1], :tPLUS, "+", [1, 2]
end
def test_keyword_expr
@lex.state = :expr_endarg
assert_scanned "if", :kIF_MOD, "if", [0, 2]
assert_equal :expr_beg, @lex.state
end
def test_lt
assert_scanned "<", :tLT, "<", [0, 1]
end
def test_lt2
assert_scanned("a <\< b",
:tIDENTIFIER, "a", [0, 1],
:tLSHFT, "<\<", [2, 4],
:tIDENTIFIER, "b", [5, 6])
end
def test_lt2_equals
assert_scanned("a <\<= b",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, "<\<", [2, 5],
:tIDENTIFIER, "b", [6, 7])
end
def test_lt_equals
assert_scanned "<=", :tLEQ, "<=", [0, 2]
end
def test_minus
assert_scanned("1 - 2",
:tINTEGER, 1, [0, 1],
:tMINUS, "-", [2, 3],
:tINTEGER, 2, [4, 5])
end
def test_minus_equals
@lex.state = :expr_end
assert_scanned "-=", :tOP_ASGN, "-", [0, 2]
end
def test_minus_method
@lex.state = :expr_fname
assert_scanned "-", :tMINUS, "-", [0, 1]
end
def test_minus_unary_method
@lex.state = :expr_fname
assert_scanned "-@", :tUMINUS, "-@", [0, 2]
end
def test_minus_unary_number
assert_scanned("-42",
:tUNARY_NUM, "-", [0, 1],
:tINTEGER, 42, [1, 3])
end
def test_minus_unary_whitespace_number
assert_scanned("- 42",
:tUNARY_NUM, "-", [0, 1],
:tINTEGER, 42, [2, 4])
end
def test_nth_ref
assert_scanned('[$1, $2, $3]',
:tLBRACK, "[", [0, 1],
:tNTH_REF, 1, [1, 3], :tCOMMA, ",", [3, 4],
:tNTH_REF, 2, [5, 7], :tCOMMA, ",", [7, 8],
:tNTH_REF, 3, [9, 11],
:tRBRACK, "]", [11, 12])
end
def test_open_bracket
assert_scanned("(", :tLPAREN, "(", [0, 1])
end
def test_open_bracket_cmdarg
assert_scanned("m (", :tIDENTIFIER, "m", [0, 1],
:tLPAREN_ARG, "(", [2, 3])
end
def test_open_bracket_exprarg
assert_scanned("m(", :tIDENTIFIER, "m", [0, 1],
:tLPAREN2, "(", [1, 2])
end
def test_open_curly_bracket
assert_scanned("{",
:tLBRACE, "{", [0, 1])
end
def test_open_curly_bracket_arg
assert_scanned("m { 3 }",
:tIDENTIFIER, "m", [0, 1],
:tLCURLY, "{", [2, 3],
:tINTEGER, 3, [4, 5],
:tRCURLY, "}", [6, 7])
end
def test_open_curly_bracket_block
@lex.state = :expr_endarg # seen m(3)
assert_scanned("{ 4 }",
:tLBRACE_ARG, "{", [0, 1],
:tINTEGER, 4, [2, 3],
:tRCURLY, "}", [4, 5])
end
def test_open_square_bracket_arg
assert_scanned("m [ 3 ]",
:tIDENTIFIER, "m", [0, 1],
:tLBRACK, "[", [2, 3],
:tINTEGER, 3, [4, 5],
:tRBRACK, "]", [6, 7])
end
def test_open_square_bracket_ary
assert_scanned("[1, 2, 3]",
:tLBRACK, "[", [0, 1],
:tINTEGER, 1, [1, 2],
:tCOMMA, ",", [2, 3],
:tINTEGER, 2, [4, 5],
:tCOMMA, ",", [5, 6],
:tINTEGER, 3, [7, 8],
:tRBRACK, "]", [8, 9])
end
def test_open_square_bracket_meth
assert_scanned("m[3]",
:tIDENTIFIER, "m", [0, 1],
:tLBRACK2, "[", [1, 2],
:tINTEGER, 3, [2, 3],
:tRBRACK, "]", [3, 4])
end
def test_or
assert_scanned "|", :tPIPE, "|", [0, 1]
end
def test_or2
assert_scanned "||", :tOROP, "||", [0, 2]
end
def test_or2__after_27
setup_lexer(27)
assert_scanned("||",
:tPIPE, "|", [0, 1],
:tPIPE, "|", [1, 2])
end
def test_or2_equals
assert_scanned "||=", :tOP_ASGN, "||", [0, 3]
end
def test_or_equals
assert_scanned "|=", :tOP_ASGN, "|", [0, 2]
end
def test_percent
assert_scanned("a % 2",
:tIDENTIFIER, "a", [0, 1],
:tPERCENT, "%", [2, 3],
:tINTEGER, 2, [4, 5])
end
def test_percent_equals
assert_scanned("a %= 2",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, "%", [2, 4],
:tINTEGER, 2, [5, 6])
end
def test_plus
assert_scanned("1 + 1",
:tINTEGER, 1, [0, 1],
:tPLUS, "+", [2, 3],
:tINTEGER, 1, [4, 5])
end
def test_plus_equals
@lex.state = :expr_end
assert_scanned "+=", :tOP_ASGN, "+", [0, 2]
end
def test_plus_method
@lex.state = :expr_fname
assert_scanned "+", :tPLUS, "+", [0, 1]
end
def test_plus_unary_method
@lex.state = :expr_fname
assert_scanned "+@", :tUPLUS, "+@", [0, 2]
end
def test_plus_unary_number
assert_scanned("+42",
:tUNARY_NUM, "+", [0, 1],
:tINTEGER, 42, [1, 3])
end
def test_plus_unary_whitespace_number
assert_scanned("+ 42",
:tUNARY_NUM, "+", [0, 1],
:tINTEGER, 42, [2, 4])
end
def test_numbers
assert_scanned "0b10", :tINTEGER, 2, [0, 4]
assert_scanned "0B10", :tINTEGER, 2, [0, 4]
assert_scanned "0d10", :tINTEGER, 10, [0, 4]
assert_scanned "0D10", :tINTEGER, 10, [0, 4]
assert_scanned "0x10", :tINTEGER, 16, [0, 4]
assert_scanned "0X10", :tINTEGER, 16, [0, 4]
assert_scanned "0o10", :tINTEGER, 8, [0, 4]
assert_scanned "0O10", :tINTEGER, 8, [0, 4]
assert_scanned "0o", :tINTEGER, 0, [0, 2]
assert_scanned "0O", :tINTEGER, 0, [0, 2]
assert_scanned "0o", :tINTEGER, 0, [0, 2]
assert_scanned "0O", :tINTEGER, 0, [0, 2]
assert_scanned "0777_333", :tINTEGER, 261851, [0, 8]
assert_scanned "0", :tINTEGER, 0, [0, 1]
refute_scanned "0x"
refute_scanned "0X"
refute_scanned "0b"
refute_scanned "0B"
refute_scanned "0d"
refute_scanned "0D"
refute_scanned "08"
refute_scanned "09"
refute_scanned "0o8"
refute_scanned "0o9"
refute_scanned "0O8"
refute_scanned "0O9"
refute_scanned "1_e1"
refute_scanned "1_.1"
refute_scanned "1__1"
refute_scanned "1end"
refute_scanned "1.1end"
end
def test_question__18
setup_lexer 18
assert_scanned "?*", :tINTEGER, 42, [0, 2]
end
def test_question__19
setup_lexer 19
assert_scanned "?*", :tCHARACTER, "*", [0, 2]
end
def test_question_bad_eos
refute_scanned "?"
end
def test_question_bad_ws
assert_scanned "? ", :tEH, "?", [0, 1]
assert_scanned "?\n", :tEH, "?", [0, 1]
assert_scanned "?\t", :tEH, "?", [0, 1]
assert_scanned "?\v", :tEH, "?", [0, 1]
assert_scanned "?\r", :tEH, "?", [0, 1]
assert_scanned "?\f", :tEH, "?", [0, 1]
end
def test_question_ws_backslashed__18
setup_lexer 18
@lex.state = :expr_beg
assert_scanned "?\\ ", :tINTEGER, 32, [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\n", :tINTEGER, 10, [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\t", :tINTEGER, 9, [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\v", :tINTEGER, 11, [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\r", :tINTEGER, 13, [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\f", :tINTEGER, 12, [0, 3]
end
def test_question_ws_backslashed__19
setup_lexer 19
@lex.state = :expr_beg
assert_scanned "?\\ ", :tCHARACTER, " ", [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\n", :tCHARACTER, "\n", [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\t", :tCHARACTER, "\t", [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\v", :tCHARACTER, "\v", [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\r", :tCHARACTER, "\r", [0, 3]
@lex.state = :expr_beg
assert_scanned "?\\f", :tCHARACTER, "\f", [0, 3]
end
def test_rbracket
assert_scanned "]", :tRBRACK, "]", [0, 1]
end
def test_rcurly
assert_scanned "}", :tRCURLY, "}", [0, 1]
end
def test_regexp
assert_scanned("/regexp/",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regexp", [1, 7],
:tSTRING_END, "/", [7, 8],
:tREGEXP_OPT, "", [8, 8])
end
def test_regexp_ambiguous
assert_scanned("method /regexp/",
:tIDENTIFIER, "method", [0, 6],
:tREGEXP_BEG, "/", [7, 8],
:tSTRING_CONTENT, "regexp", [8, 14],
:tSTRING_END, "/", [14, 15],
:tREGEXP_OPT, "", [15, 15])
end
def test_regexp_bad
refute_scanned("/.*/xyz",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, ".*", [1, 3],
:tSTRING_END, "/", [3, 4])
end
def test_regexp_escape_C
assert_scanned('/regex\\C-x/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\C-x", [1, 10],
:tSTRING_END, "/", [10, 11],
:tREGEXP_OPT, "", [11, 11])
end
def test_regexp_escape_C_M
assert_scanned('/regex\\C-\\M-x/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\C-\\M-x", [1, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_C_M_craaaazy
assert_scanned("/regex\\C-\\\n\\M-x/",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\C-\\M-x", [1, 15],
:tSTRING_END, "/", [15, 16],
:tREGEXP_OPT, "", [16, 16])
end
def test_regexp_escape_C_bad_dash
refute_scanned '/regex\\Cx/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_C_bad_dash_eos
refute_scanned '/regex\\C-/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_C_bad_dash_eos2
refute_scanned '/regex\\C-', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_C_bad_eos
refute_scanned '/regex\\C/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_C_bad_eos2
refute_scanned '/regex\\c', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_M
assert_scanned('/regex\\M-x/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\M-x", [1, 10],
:tSTRING_END, "/", [10, 11],
:tREGEXP_OPT, "", [11, 11])
end
def test_regexp_escape_M_C
assert_scanned('/regex\\M-\\C-x/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\M-\\C-x", [1, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_M_bad_dash
refute_scanned '/regex\\Mx/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_M_bad_dash_eos
refute_scanned '/regex\\M-/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_M_bad_dash_eos2
refute_scanned '/regex\\M-', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_M_bad_eos
refute_scanned '/regex\\M/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_backslash_slash
assert_scanned('/\\//',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, '/', [1, 3],
:tSTRING_END, "/", [3, 4],
:tREGEXP_OPT, "", [4, 4])
end
def test_regexp_escape_backslash_terminator
assert_scanned('%r%blah\\%blah%',
:tREGEXP_BEG, "%r%", [0, 3],
:tSTRING_CONTENT, "blah%blah", [3, 13],
:tSTRING_END, "%", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_backslash_terminator_meta1
assert_scanned('%r{blah\\}blah}',
:tREGEXP_BEG, "%r{", [0, 3],
:tSTRING_CONTENT, "blah\\}blah", [3, 13],
:tSTRING_END, "}", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_backslash_terminator_meta2
assert_scanned('%r/blah\\/blah/',
:tREGEXP_BEG, "%r/", [0, 3],
:tSTRING_CONTENT, "blah/blah", [3, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_backslash_terminator_meta3
assert_scanned('%r/blah\\%blah/',
:tREGEXP_BEG, "%r/", [0, 3],
:tSTRING_CONTENT, "blah\\%blah", [3, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_bad_eos
refute_scanned '/regex\\', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_bs
assert_scanned('/regex\\\\regex/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\\\regex", [1, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_c
assert_scanned('/regex\\cxxx/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\cxxx", [1, 11],
:tSTRING_END, "/", [11, 12],
:tREGEXP_OPT, "", [12, 12])
end
def test_regexp_escape_c_backslash
assert_scanned('/regex\\c\\n/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\c\\n", [1, 10],
:tSTRING_END, "/", [10, 11],
:tREGEXP_OPT, "", [11, 11])
end
def test_regexp_escape_chars
assert_scanned('/re\\tge\\nxp/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "re\\tge\\nxp", [1, 11],
:tSTRING_END, "/", [11, 12],
:tREGEXP_OPT, "", [12, 12])
end
def test_regexp_escape_double_backslash
assert_scanned('/[\\/\\\\]$/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT,'[/\\\\]$', [1, 8],
:tSTRING_END, "/", [8, 9],
:tREGEXP_OPT, "", [9, 9])
end
def test_regexp_escape_hex
assert_scanned('/regex\\x61xp/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\x61xp", [1, 12],
:tSTRING_END, "/", [12, 13],
:tREGEXP_OPT, "", [13, 13])
end
def test_regexp_escape_hex_bad
refute_scanned '/regex\\xzxp/', :tREGEXP_BEG, "/", [0, 1]
end
def test_regexp_escape_hex_one
assert_scanned('/^[\\xd\\xa]{2}/on',
:tREGEXP_BEG, '/', [0, 1],
:tSTRING_CONTENT, '^[\\xd\\xa]{2}', [1, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, 'on', [14, 16])
end
def test_regexp_escape_oct1
assert_scanned('/regex\\0xp/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\0xp", [1, 10],
:tSTRING_END, "/", [10, 11],
:tREGEXP_OPT, "", [11, 11])
end
def test_regexp_escape_oct2
assert_scanned('/regex\\07xp/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\07xp", [1, 11],
:tSTRING_END, "/", [11, 12],
:tREGEXP_OPT, "", [12, 12])
end
def test_regexp_escape_oct3
assert_scanned('/regex\\10142/',
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regex\\10142", [1, 12],
:tSTRING_END, "/", [12, 13],
:tREGEXP_OPT, "", [13, 13])
end
def test_regexp_escape_return
assert_scanned("/regex\\\nregex/",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "regexregex", [1, 13],
:tSTRING_END, "/", [13, 14],
:tREGEXP_OPT, "", [14, 14])
end
def test_regexp_escape_delimiter_meta
assert_scanned("%r(\\))",
:tREGEXP_BEG, "%r(", [0, 3],
:tSTRING_CONTENT, "\\)", [3, 5],
:tSTRING_END, ")", [5, 6],
:tREGEXP_OPT, "", [6, 6])
end
def test_regexp_escape_delimiter_nonmeta
assert_scanned("%r'\\''",
:tREGEXP_BEG, "%r'", [0, 3],
:tSTRING_CONTENT, "'", [3, 5],
:tSTRING_END, "'", [5, 6],
:tREGEXP_OPT, "", [6, 6])
end
def test_regexp_escape_other_meta
assert_scanned("/\\.\\$\\*\\+\\.\\?\\|/",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, "\\.\\$\\*\\+\\.\\?\\|", [1, 15],
:tSTRING_END, "/", [15, 16],
:tREGEXP_OPT, "", [16, 16])
end
def test_regexp_nm
assert_scanned("/.*/nm",
:tREGEXP_BEG, "/", [0, 1],
:tSTRING_CONTENT, ".*", [1, 3],
:tSTRING_END, "/", [3, 4],
:tREGEXP_OPT, "nm", [4, 6])
end
def test_rparen
assert_scanned ")", :tRPAREN, ")", [0, 1]
end
def test_rshft
assert_scanned("a >> 2",
:tIDENTIFIER, "a", [0, 1],
:tRSHFT, ">>", [2, 4],
:tINTEGER, 2, [5, 6])
end
def test_rshft_equals
assert_scanned("a >>= 2",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, ">>", [2, 5],
:tINTEGER, 2, [6, 7])
end
def test_star
assert_scanned("a * ",
:tIDENTIFIER, "a", [0, 1],
:tSTAR2, "*", [2, 3])
assert_equal :expr_value, @lex.state
end
def test_star2
assert_scanned("a ** ",
:tIDENTIFIER, "a", [0, 1],
:tPOW, "**", [2, 4])
assert_equal :expr_value, @lex.state
end
def test_star2_equals
assert_scanned("a **= ",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, "**", [2, 5])
assert_equal :expr_beg, @lex.state
end
def test_star2_beg
assert_scanned("** ",
:tDSTAR, "**", [0, 2])
assert_equal :expr_beg, @lex.state
end
def test_star_arg
@lex.state = :expr_arg
assert_scanned(" *a",
:tSTAR, "*", [1, 2],
:tIDENTIFIER, "a", [2, 3])
assert_equal :expr_arg, @lex.state
end
def test_star_arg_beg
@lex.state = :expr_beg
assert_scanned("*a",
:tSTAR, "*", [0, 1],
:tIDENTIFIER, "a", [1, 2])
assert_equal :expr_arg, @lex.state
end
def test_star_arg_beg_fname
@lex.state = :expr_fname
assert_scanned("*a",
:tSTAR2, "*", [0, 1],
:tIDENTIFIER, "a", [1, 2])
assert_equal :expr_arg, @lex.state
end
def test_star_equals
assert_scanned("a *= ",
:tIDENTIFIER, "a", [0, 1],
:tOP_ASGN, "*", [2, 4])
assert_equal :expr_beg, @lex.state
end
def test_string_bad_eos
refute_scanned('%',
:tSTRING_BEG, '%', [0, 1])
end
def test_string_bad_eos_quote
refute_scanned('%{nest',
:tSTRING_BEG, '%}', [0, 2])
end
def test_string_double
assert_scanned('"string"',
:tSTRING, "string", [0, 8])
end
def test_string_double_escape_C
assert_scanned('"\\C-a"',
:tSTRING, "\001", [0, 6])
end
def test_string_double_escape_C_backslash
assert_scanned('"\\C-\\\\"',
:tSTRING, "\034", [0, 7])
end
def test_string_double_escape_C_escape
assert_scanned('"\\C-\\M-a"',
:tSTRING, "\201", [0, 9])
end
def test_string_double_escape_C_question
assert_scanned('"\\C-?"',
:tSTRING, "\177", [0, 6])
end
def test_string_double_escape_M
assert_scanned('"\\M-a"',
:tSTRING, "\341", [0, 6])
end
def test_string_double_escape_M_backslash
assert_scanned('"\\M-\\\\"',
:tSTRING, "\334", [0, 7])
end
def test_string_double_escape_M_escape
assert_scanned('"\\M-\\C-a"',
:tSTRING, "\201", [0, 9])
end
def test_string_double_escape_bs1
assert_scanned('"a\\a\\a"',
:tSTRING, "a\a\a", [0, 7])
end
def test_string_double_escape_bs2
assert_scanned('"a\\\\a"',
:tSTRING, "a\\a", [0, 6])
end
def test_string_double_escape_c
assert_scanned('"\\ca"',
:tSTRING, "\001", [0, 5])
end
def test_string_double_escape_c_escape
assert_scanned('"\\c\\M-a"',
:tSTRING, "\201", [0, 8])
end
def test_string_double_escape_c_question
assert_scanned('"\\c?"',
:tSTRING, "\177", [0, 5])
end
def test_string_double_escape_chars
assert_scanned('"s\\tri\\ng"',
:tSTRING, "s\tri\ng", [0, 10])
end
def test_string_double_escape_hex
assert_scanned('"n = \\x61\\x62\\x63"',
:tSTRING, "n = abc", [0, 18])
end
def test_string_double_escape_octal
assert_scanned('"n = \\101\\102\\103"',
:tSTRING, "n = ABC", [0, 18])
end
def test_string_double_escape_octal_wrap
assert_scanned('"\\753"',
:tSTRING, "\xEB", [0, 6])
end
def test_string_double_interp
assert_scanned("\"blah #x a \#@a b \#$b c \#{3} # \"",
:tSTRING_BEG, "\"", [0, 1],
:tSTRING_CONTENT, "blah #x a ", [1, 11],
:tSTRING_DVAR, nil, [11, 12],
:tIVAR, "@a", [12, 14],
:tSTRING_CONTENT, " b ", [14, 17],
:tSTRING_DVAR, nil, [17, 18],
:tGVAR, "$b", [18, 20],
:tSTRING_CONTENT, " c ", [20, 23],
:tSTRING_DBEG, '#{', [23, 25],
:tINTEGER, 3, [25, 26],
:tRCURLY, "}", [26, 27],
:tSTRING_CONTENT, " # ", [27, 30],
:tSTRING_END, "\"", [30, 31])
end
def test_string_double_interp_label
assert_scanned('"#{foo:bar}"',
:tSTRING_BEG, '"', [0, 1],
:tSTRING_DBEG, '#{', [1, 3],
:tIDENTIFIER, 'foo', [3, 6],
:tSYMBOL, 'bar', [6, 10],
:tRCURLY, '}', [10, 11],
:tSTRING_END, '"', [11, 12])
end
def test_string_double_nested_curlies
assert_scanned('%{nest{one{two}one}nest}',
:tSTRING_BEG, '%{', [0, 2],
:tSTRING_CONTENT, "nest{one{two}one}nest", [2, 23],
:tSTRING_END, '}', [23, 24])
end
def test_string_double_no_interp
assert_scanned("\"# blah\"", # pound first
:tSTRING, "# blah", [0, 8])
assert_scanned("\"blah # blah\"", # pound not first
:tSTRING, "blah # blah", [0, 13])
end
def test_string_escape_x_single
assert_scanned('"\\x0"',
:tSTRING, "\000", [0, 5])
end
def test_string_pct_Q
assert_scanned("%Q[s1 s2]",
:tSTRING_BEG, '%Q[', [0, 3],
:tSTRING_CONTENT, "s1 s2", [3, 8],
:tSTRING_END, ']', [8, 9])
end
def test_string_pct_W
assert_scanned("%W[s1 s2\ns3]",
:tWORDS_BEG, "%W[", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 9],
:tSTRING_CONTENT, "s3", [9, 11],
:tSPACE, nil, [11, 11],
:tSTRING_END, ']', [11, 12])
end
def test_string_pct_W_bs_nl
assert_scanned("%W[s1 \\\ns2]",
:tWORDS_BEG, "%W[", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "\ns2", [6, 10],
:tSPACE, nil, [10, 10],
:tSTRING_END, ']', [10, 11])
end
def test_string_pct_W_interp
assert_scanned('%W[#{1}#{2} #@a]',
:tWORDS_BEG, '%W[', [0, 3],
:tSTRING_DBEG, '#{', [3, 5],
:tINTEGER, 1, [5, 6],
:tRCURLY, '}', [6, 7],
:tSTRING_DBEG, '#{', [7, 9],
:tINTEGER, 2, [9, 10],
:tRCURLY, '}', [10, 11],
:tSPACE, nil, [11, 12],
:tSTRING_DVAR, nil, [12, 13],
:tIVAR, '@a', [13, 15],
:tSPACE, nil, [15, 15],
:tSTRING_END, ']', [15, 16])
end
def test_string_pct_I
assert_scanned("%I(s1 s2)",
:tSYMBOLS_BEG, "%I(", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 8],
:tSTRING_END, ')', [8, 9])
end
def test_string_pct_angle
assert_scanned("%",
:tSTRING_BEG, '%<', [0, 2],
:tSTRING_CONTENT, "blah", [2, 6],
:tSTRING_END, '>', [6, 7])
end
def test_string_pct_pct
assert_scanned("%%blah%",
:tSTRING_BEG, '%%', [0, 2],
:tSTRING_CONTENT, "blah", [2, 6],
:tSTRING_END, '%', [6, 7])
end
def test_string_pct_w
assert_scanned("%w[s1 s2 ]",
:tQWORDS_BEG, "%w[", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 9],
:tSTRING_END, "]", [9, 10])
end
def test_string_pct_w_incomplete
refute_scanned("%w[s1 ",
:tQWORDS_BEG, "%w[", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6])
end
def test_string_pct_w_bs_nl
assert_scanned("%w[s1 \\\ns2]",
:tQWORDS_BEG, "%w[", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "\ns2", [6, 10],
:tSPACE, nil, [10, 10],
:tSTRING_END, ']', [10, 11])
end
def test_string_pct_w_bs_sp
assert_scanned("%w[s\\ 1 s\\ 2]",
:tQWORDS_BEG, "%w[", [0, 3],
:tSTRING_CONTENT, "s 1", [3, 7],
:tSPACE, nil, [7, 8],
:tSTRING_CONTENT, "s 2", [8, 12],
:tSPACE, nil, [12, 12],
:tSTRING_END, ']', [12, 13])
end
def test_string_pct_w_tab
assert_scanned("%w[abc\tdef]",
:tQWORDS_BEG, "%w[", [0, 3],
:tSTRING_CONTENT, "abc", [3, 6],
:tSPACE, nil, [6, 7],
:tSTRING_CONTENT, "def", [7, 10],
:tSPACE, nil, [10, 10],
:tSTRING_END, ']', [10, 11])
end
def test_string_pct_i
assert_scanned("%i(s1 s2)",
:tQSYMBOLS_BEG, "%i(", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 8],
:tSTRING_END, ')', [8, 9])
end
def test_string_pct_backslash
assert_scanned("%\\a\\",
:tSTRING_BEG, "%\\", [0, 2],
:tSTRING_CONTENT, "a", [2, 3],
:tSTRING_END, "\\", [3, 4])
end
def test_string_pct_w_backslash
assert_scanned("%w\\s1 s2 \\",
:tQWORDS_BEG, "%w\\", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 9],
:tSTRING_END, "\\", [9, 10])
end
def test_string_pct_w_backslash_nl
assert_scanned("%w\\s1 s2 \\\n",
:tQWORDS_BEG, "%w\\", [0, 3],
:tSTRING_CONTENT, "s1", [3, 5],
:tSPACE, nil, [5, 6],
:tSTRING_CONTENT, "s2", [6, 8],
:tSPACE, nil, [8, 9],
:tSTRING_END, "\\", [9, 10],
:tNL, nil, [10, 11])
end
def test_string_pct_w_backslash_interp_nl
assert_scanned("%W\\blah #x a \#@a b \#$b c \#{3} # \\",
:tWORDS_BEG, "%W\\", [0, 3],
:tSTRING_CONTENT, "blah", [3, 7],
:tSPACE, nil, [7, 8],
:tSTRING_CONTENT, "#x", [8, 10],
:tSPACE, nil, [10, 11],
:tSTRING_CONTENT, "a", [11, 12],
:tSPACE, nil, [12, 13],
:tSTRING_DVAR, nil, [13, 14],
:tIVAR, "@a", [14, 16],
:tSPACE, nil, [16, 17],
:tSTRING_CONTENT, "b", [17, 18],
:tSPACE, nil, [18, 19],
:tSTRING_DVAR, nil, [19, 20],
:tGVAR, "$b", [20, 22],
:tSPACE, nil, [22, 23],
:tSTRING_CONTENT, "c", [23, 24],
:tSPACE, nil, [24, 25],
:tSTRING_DBEG, '#{', [25, 27],
:tINTEGER, 3, [27, 28],
:tRCURLY, "}", [28, 29],
:tSPACE, nil, [29, 30],
:tSTRING_CONTENT, "#", [30, 31],
:tSPACE, nil, [31, 32],
:tSTRING_END, "\\", [32, 33])
end
def test_string_pct_backslash_with_bad_escape
# No escapes are allowed in a backslash-delimited string
refute_scanned("%\\a\\n\\",
:tSTRING_BEG, "%\\", [0, 2],
:tSTRING_CONTENT, "a", [2, 3],
:tSTRING_END, "\\", [3, 4],
:tIDENTIFIER, "n", [4, 5])
end
def test_string_pct_intertwined_with_heredoc
assert_scanned("<<-foo + %\\a\nbar\nfoo\nb\\",
:tSTRING_BEG, "<<\"", [0, 6],
:tSTRING_CONTENT, "bar\n", [13, 17],
:tSTRING_END, "foo", [17, 20],
:tPLUS, "+", [7, 8],
:tSTRING_BEG, "%\\", [9, 11],
:tSTRING_CONTENT, "a\n", [11, 13],
:tSTRING_CONTENT, "b", [21, 22],
:tSTRING_END, "\\", [22, 23])
end
def test_string_pct_q_backslash
assert_scanned("%q\\a\\",
:tSTRING_BEG, "%q\\", [0, 3],
:tSTRING_CONTENT, "a", [3, 4],
:tSTRING_END, "\\", [4, 5])
end
def test_string_pct_Q_backslash
assert_scanned("%Q\\a\\",
:tSTRING_BEG, "%Q\\", [0, 3],
:tSTRING_CONTENT, "a", [3, 4],
:tSTRING_END, "\\", [4, 5])
end
def test_string_single
assert_scanned("'string'",
:tSTRING, "string", [0, 8])
end
def test_string_single_escape_chars
assert_scanned("'s\\tri\\ng'",
:tSTRING, "s\\tri\\ng", [0, 10])
end
def test_string_single_nl
assert_scanned("'blah\\\nblah'",
:tSTRING_BEG, "'", [0, 1],
:tSTRING_CONTENT, "blah\\\n", [1, 7],
:tSTRING_CONTENT, "blah", [7, 11],
:tSTRING_END, "'", [11, 12])
end
def test_symbol
assert_scanned(":symbol",
:tSYMBOL, "symbol", [0, 7])
end
def test_symbol_double
assert_scanned(":\"symbol\"",
:tSYMBEG, ":\"", [0, 2],
:tSTRING_CONTENT, "symbol", [2, 8],
:tSTRING_END, "\"", [8, 9])
end
def test_symbol_single
assert_scanned(":'symbol'",
:tSYMBEG, ":'", [0, 2],
:tSTRING_CONTENT, "symbol", [2, 8],
:tSTRING_END, "'", [8, 9])
end
def test_ternary
assert_scanned("a ? b : c",
:tIDENTIFIER, "a", [0, 1],
:tEH, "?", [2, 3],
:tIDENTIFIER, "b", [4, 5],
:tCOLON, ":", [6, 7],
:tIDENTIFIER, "c", [8, 9])
assert_scanned("a ?b : c",
:tIDENTIFIER, "a", [0, 1],
:tINTEGER, 98, [2, 4],
:tCOLON, ":", [5, 6],
:tIDENTIFIER, "c", [7, 8])
assert_scanned("a ?bb : c", # GAH! MATZ!!!
:tIDENTIFIER, "a", [0, 1],
:tEH, "?", [2, 3],
:tIDENTIFIER, "bb", [3, 5],
:tCOLON, ":", [6, 7],
:tIDENTIFIER, "c", [8, 9])
assert_scanned("42 ?", # 42 forces expr_end
:tINTEGER, 42, [0, 2],
:tEH, "?", [3, 4])
end
def test_tilde
assert_scanned "~", :tTILDE, "~", [0, 1]
end
def test_tilde_unary
@lex.state = :expr_fname
assert_scanned "~@", :tTILDE, "~@", [0, 2]
end
def test_uminus
assert_scanned("-blah",
:tUMINUS, "-", [0, 1],
:tIDENTIFIER, "blah", [1, 5])
end
def test_underscore
assert_scanned("_var", :tIDENTIFIER, "_var", [0, 4])
end
def test_underscore_end
assert_scanned("__END__\n")
assert_scanned("__END__")
assert_scanned("__END__ foo",
:tIDENTIFIER, '__END__', [0, 7],
:tIDENTIFIER, 'foo', [8, 11])
assert_scanned("__END__\rfoo",
:tIDENTIFIER, '__END__', [0, 7],
:tIDENTIFIER, 'foo', [8, 11])
end
def test_uplus
assert_scanned("+blah",
:tUPLUS, "+", [0, 1],
:tIDENTIFIER, "blah", [1, 5])
end
def test_if_unless_mod
assert_scanned("return if true unless false",
:kRETURN, "return", [0, 6],
:kIF_MOD, "if", [7, 9],
:kTRUE, "true", [10, 14],
:kUNLESS_MOD, "unless", [15, 21],
:kFALSE, "false", [22, 27])
end
def test_if_stmt
assert_scanned("if true\n return end",
:kIF, "if", [0, 2],
:kTRUE, "true", [3, 7],
:tNL, nil, [7, 8],
:kRETURN, "return", [9, 15],
:kEND, "end", [16, 19])
end
def test_sclass_label
setup_lexer 20
assert_scanned("class << a:b",
:kCLASS, 'class', [0, 5],
:tLSHFT, '<<', [6, 8],
:tIDENTIFIER, 'a', [9, 10],
:tSYMBOL, 'b', [10, 12])
end
def test_fname_pct_s__22
setup_lexer 22
@lex.state = :expr_fname
assert_scanned("%s(a)",
:tPERCENT, '%', [0, 1],
:tIDENTIFIER, 's', [1, 2],
:tLPAREN2, '(', [2, 3],
:tIDENTIFIER, 'a', [3, 4],
:tRPAREN, ')', [4, 5])
end
def test_fname_pct_s__23
setup_lexer 23
@lex.state = :expr_fname
assert_scanned("%s(a)",
:tSYMBEG, '%s(', [0, 3],
:tSTRING_CONTENT, 'a', [3, 4],
:tSTRING_END, ')', [4, 5])
end
def test_static_env
env = Parser::StaticEnvironment.new
env.declare "a"
@lex.static_env = env
assert_scanned("a [42]",
:tIDENTIFIER, "a", [0, 1],
:tLBRACK2, "[", [2, 3],
:tINTEGER, 42, [3, 5],
:tRBRACK, "]", [5, 6])
end
def test_int_suffix
[18, 19, 20].each do |version|
setup_lexer version
assert_scanned("42r",
:tINTEGER, 42, [0, 2],
:tIDENTIFIER, 'r', [2, 3])
assert_scanned("42if",
:tINTEGER, 42, [0, 2],
:kIF_MOD, 'if', [2, 4])
end
setup_lexer 21
assert_scanned("42r", :tRATIONAL, Rational(42), [0, 3])
assert_scanned("42i", :tIMAGINARY, Complex(0, 42), [0, 3])
assert_scanned("42ri", :tIMAGINARY, Complex(0, Rational(42)), [0, 4])
end
def test_float_suffix
[18, 19, 20].each do |version|
setup_lexer version
assert_scanned("42.1r",
:tFLOAT, 42.1, [0, 4],
:tIDENTIFIER, 'r', [4, 5])
assert_scanned("42.1if",
:tFLOAT, 42.1, [0, 4],
:kIF_MOD, 'if', [4, 6])
assert_scanned("1e1r",
:tFLOAT, 1e1, [0, 3],
:tIDENTIFIER, 'r', [3, 4])
end
begin
# Feature-check.
Rational("10")
setup_lexer 21
assert_scanned("42.1r", :tRATIONAL, Rational(421, 10), [0, 5])
assert_scanned("42.1i", :tIMAGINARY, Complex(0, 42.1), [0, 5])
assert_scanned("42.1ri", :tIMAGINARY, Complex(0, Rational(421, 10)), [0, 6])
assert_scanned("42.1ir",
:tIMAGINARY, Complex(0, 42.1), [0, 5],
:tIDENTIFIER, 'r', [5, 6])
assert_scanned("1e1i", :tIMAGINARY, Complex(0, 1e1), [0, 4])
assert_scanned("1e1r",
:tFLOAT, 1e1, [0, 3],
:tIDENTIFIER, 'r', [3, 4])
assert_scanned("1e1ri",
:tFLOAT, 1e1, [0, 3],
:tIDENTIFIER, 'ri', [3, 5])
assert_scanned("1e1ir",
:tIMAGINARY, Complex(0, 1e1), [0, 4],
:tIDENTIFIER, 'r', [4, 5])
rescue NoMethodError
# Ruby not modern enough
end
end
def test_eof
assert_scanned("self",
:kSELF, "self", [0, 4])
assert_equal([false, ["$eof", Parser::Source::Range.new(@lex.source_buffer, 4, 4)]],
@lex.advance)
end
#
# Test for 'fluent interface'
#
def test_fluent_dot
assert_scanned("x\n.y",
:tIDENTIFIER, 'x', [0, 1],
:tDOT, '.', [2, 3],
:tIDENTIFIER, 'y', [3, 4])
assert_scanned("x\n .y",
:tIDENTIFIER, 'x', [0, 1],
:tDOT, '.', [4, 5],
:tIDENTIFIER, 'y', [5, 6])
assert_scanned("x # comment\n .y",
:tIDENTIFIER, 'x', [0, 1],
:tDOT, '.', [14, 15],
:tIDENTIFIER, 'y', [15, 16])
end
def test_fluent_and_dot
assert_scanned("x\n&.y",
:tIDENTIFIER, 'x', [0, 1],
:tANDDOT, '&.', [2, 4],
:tIDENTIFIER, 'y', [4, 5])
end
#
# Tests for whitespace.
#
def test_whitespace_fname
@lex.state = :expr_fname
assert_scanned('class',
:kCLASS, 'class', [0, 5])
@lex.state = :expr_fname
assert_scanned(' class',
:kCLASS, 'class', [1, 6])
@lex.state = :expr_fname
assert_scanned("\nclass",
:kCLASS, 'class', [1, 6])
@lex.state = :expr_fname
assert_scanned("\\\nclass",
:kCLASS, 'class', [2, 7])
@lex.state = :expr_fname
assert_scanned("#foo\nclass",
:kCLASS, 'class', [5, 10])
end
def test_whitespace_endfn
setup_lexer(21)
@lex.state = :expr_endfn
assert_scanned('foo:',
:tLABEL, 'foo', [0, 4])
@lex.state = :expr_endfn
assert_scanned(' foo:',
:tLABEL, 'foo', [1, 5])
@lex.state = :expr_endfn
assert_scanned("\nfoo:",
:tNL, nil, [0, 1],
:tIDENTIFIER, 'foo', [1, 4],
:tCOLON, ':', [4, 5])
@lex.state = :expr_endfn
assert_scanned("\nfoo: ",
:tNL, nil, [0, 1],
:tIDENTIFIER, 'foo', [1, 4],
:tCOLON, ':', [4, 5])
@lex.state = :expr_endfn
assert_scanned("\\\nfoo:",
:tLABEL, 'foo', [2, 6])
@lex.state = :expr_endfn
assert_scanned("#foo\nfoo:",
:tNL, nil, [4, 5],
:tIDENTIFIER, 'foo', [5, 8],
:tCOLON, ':', [8, 9])
@lex.state = :expr_endfn
assert_scanned("#foo\nfoo: ",
:tNL, nil, [4, 5],
:tIDENTIFIER, 'foo', [5, 8],
:tCOLON, ':', [8, 9])
end
def test_whitespace_dot
@lex.state = :expr_dot
assert_scanned('class',
:tIDENTIFIER, 'class', [0, 5])
@lex.state = :expr_dot
assert_scanned(' class',
:tIDENTIFIER, 'class', [1, 6])
@lex.state = :expr_dot
assert_scanned("\nclass",
:tIDENTIFIER, 'class', [1, 6])
@lex.state = :expr_dot
assert_scanned("\\\nclass",
:tIDENTIFIER, 'class', [2, 7])
@lex.state = :expr_dot
assert_scanned("#foo\nclass",
:tIDENTIFIER, 'class', [5, 10])
end
def test_whitespace_arg
@lex.state = :expr_arg
assert_scanned('+',
:tPLUS, '+', [0, 1])
@lex.state = :expr_arg
assert_scanned(' +',
:tUPLUS, '+', [1, 2])
@lex.state = :expr_arg
assert_scanned("\n+",
:tNL, nil, [0, 1],
:tUPLUS, '+', [1, 2])
@lex.state = :expr_arg
assert_scanned("\\\n+",
:tUPLUS, '+', [2, 3])
@lex.state = :expr_arg
assert_scanned("\\\n +",
:tUPLUS, '+', [3, 4])
@lex.state = :expr_arg
assert_scanned("#foo\n+",
:tNL, nil, [4, 5],
:tUPLUS, '+', [5, 6])
end
def test_whitespace_endarg
@lex.state = :expr_endarg
assert_scanned('{',
:tLBRACE_ARG, '{', [0, 1])
@lex.state = :expr_endarg
assert_scanned(' {',
:tLBRACE_ARG, '{', [1, 2])
@lex.state = :expr_endarg
assert_scanned("\n{",
:tNL, nil, [0, 1],
:tLBRACE, '{', [1, 2])
@lex.state = :expr_endarg
assert_scanned("\\\n{",
:tLBRACE_ARG, '{', [2, 3])
@lex.state = :expr_endarg
assert_scanned("#foo\n{",
:tNL, nil, [4, 5],
:tLBRACE, '{', [5, 6])
end
def test_whitespace_mid
@lex.state = :expr_mid
assert_scanned('+',
:tUPLUS, '+', [0, 1])
@lex.state = :expr_mid
assert_scanned(' +',
:tUPLUS, '+', [1, 2])
@lex.state = :expr_mid
assert_scanned("\n+",
:tNL, nil, [0, 1],
:tUPLUS, '+', [1, 2])
@lex.state = :expr_mid
assert_scanned("\\\n+",
:tUPLUS, '+', [2, 3])
@lex.state = :expr_mid
assert_scanned("#foo\n+",
:tNL, nil, [4, 5],
:tUPLUS, '+', [5, 6])
end
def test_whitespace_beg
@lex.state = :expr_beg
assert_scanned('+',
:tUPLUS, '+', [0, 1])
@lex.state = :expr_beg
assert_scanned(' +',
:tUPLUS, '+', [1, 2])
@lex.state = :expr_beg
assert_scanned("\n+",
:tUPLUS, '+', [1, 2])
@lex.state = :expr_beg
assert_scanned("\\\n+",
:tUPLUS, '+', [2, 3])
@lex.state = :expr_beg
assert_scanned("#foo\n+",
:tUPLUS, '+', [5, 6])
end
def test_whitespace_value
setup_lexer(20)
@lex.state = :expr_value
assert_scanned('a:b',
:tIDENTIFIER, 'a', [0, 1],
:tSYMBOL, 'b', [1, 3])
@lex.state = :expr_value
assert_scanned(' a:b',
:tIDENTIFIER, 'a', [1, 2],
:tSYMBOL, 'b', [2, 4])
@lex.state = :expr_value
assert_scanned("\na:b",
:tIDENTIFIER, 'a', [1, 2],
:tSYMBOL, 'b', [2, 4])
@lex.state = :expr_value
assert_scanned("\\\na:b",
:tIDENTIFIER, 'a', [2, 3],
:tSYMBOL, 'b', [3, 5])
@lex.state = :expr_value
assert_scanned("#foo\na:b",
:tIDENTIFIER, 'a', [5, 6],
:tSYMBOL, 'b', [6, 8])
end
def test_whitespace_end
@lex.state = :expr_end
assert_scanned('+ 1',
:tPLUS, '+', [0, 1],
:tINTEGER, 1, [2, 3])
@lex.state = :expr_end
assert_scanned(' + 1',
:tPLUS, '+', [1, 2],
:tINTEGER, 1, [3, 4])
@lex.state = :expr_end
assert_scanned("\n+ 1",
:tNL, nil, [0, 1],
:tUNARY_NUM, '+', [1, 2],
:tINTEGER, 1, [3, 4])
@lex.state = :expr_end
assert_scanned("\\\n+ 1",
:tPLUS, '+', [2, 3],
:tINTEGER, 1, [4, 5])
@lex.state = :expr_end
assert_scanned("#foo\n+ 1",
:tNL, nil, [4, 5],
:tUNARY_NUM, '+', [5, 6],
:tINTEGER, 1, [7, 8])
end
def test_whitespace_cr
setup_lexer(20)
assert_scanned("<",
:kRESCUE, 'rescue', [0, 6],
:tASSOC, '=>', [6, 8])
end
def test_bug_expr_arg_percent
@lex.state = :expr_arg
assert_scanned("%[",
:tPERCENT, "%", [0, 1],
:tLBRACK, "[", [1, 2])
@lex.state = :expr_arg
assert_scanned("%=1",
:tOP_ASGN, "%", [0, 2],
:tINTEGER, 1, [2, 3])
@lex.state = :expr_arg
assert_scanned(" %[1]",
:tSTRING_BEG, "%[", [1, 3],
:tSTRING_CONTENT, '1', [3, 4],
:tSTRING_END, ']', [4, 5])
@lex.state = :expr_arg
assert_scanned(" %=1=",
:tOP_ASGN, "%", [1, 3],
:tINTEGER, 1, [3, 4],
:tEQL, "=", [4, 5])
@lex.state = :expr_arg
assert_scanned(" %\n",
:tPERCENT, '%', [1, 2])
end
def test_bug_expr_arg_lt_lt
@lex.state = :expr_arg
assert_scanned("<