parser 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/.gitignore +1 -0
- data/README.md +1 -1
- data/Rakefile +12 -2
- data/bin/benchmark +3 -3
- data/lib/parser/builders/default.rb +46 -3
- data/lib/parser/current.rb +34 -0
- data/lib/parser/lexer.rb +2760 -2667
- data/lib/parser/lexer.rl +38 -14
- data/lib/parser/ruby18.rb +1956 -1957
- data/lib/parser/ruby19.rb +1962 -1969
- data/lib/parser/ruby19.y +2 -0
- data/lib/parser/ruby20.rb +2412 -2407
- data/lib/parser/ruby20.y +16 -2
- data/lib/parser/ruby21.rb +7310 -0
- data/lib/parser/ruby21.y +2352 -0
- data/lib/parser/source/buffer.rb +52 -2
- data/lib/parser.rb +16 -5
- data/parser.gemspec +2 -1
- data/test/helper.rb +1 -1
- data/test/parse_helper.rb +12 -4
- data/test/test_current.rb +17 -0
- data/test/test_encoding.rb +31 -0
- data/test/test_lexer.rb +5 -7
- data/test/test_parse_helper.rb +9 -4
- data/test/test_parser.rb +172 -10
- metadata +93 -125
- data/TODO.md +0 -9
data/lib/parser/source/buffer.rb
CHANGED
@@ -1,9 +1,53 @@
|
|
1
|
+
# encoding:ascii-8bit
|
2
|
+
|
1
3
|
module Parser
|
2
4
|
module Source
|
3
5
|
|
4
6
|
class Buffer
|
5
7
|
attr_reader :name, :first_line
|
6
8
|
|
9
|
+
def self.recognize_encoding(string)
|
10
|
+
if string.empty?
|
11
|
+
return Encoding::UTF_8
|
12
|
+
end
|
13
|
+
|
14
|
+
# TODO: Make this more efficient.
|
15
|
+
first_line, second_line = string.lines.first(2)
|
16
|
+
first_line.force_encoding(Encoding::ASCII_8BIT)
|
17
|
+
|
18
|
+
if first_line =~ /\A\xef\xbb\xbf/ # BOM
|
19
|
+
return Encoding::UTF_8
|
20
|
+
elsif first_line[0, 2] == '#!'
|
21
|
+
encoding_line = second_line
|
22
|
+
else
|
23
|
+
encoding_line = first_line
|
24
|
+
end
|
25
|
+
|
26
|
+
encoding_line.force_encoding(Encoding::ASCII_8BIT)
|
27
|
+
|
28
|
+
if encoding_line =~ /coding[:=]?\s*([a-z0-9_-]+)/
|
29
|
+
Encoding.find($1)
|
30
|
+
else
|
31
|
+
string.encoding
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Lexer expects UTF-8 input. This method processes the input
|
36
|
+
# in an arbitrary valid Ruby encoding and returns an UTF-8 encoded
|
37
|
+
# string.
|
38
|
+
#
|
39
|
+
def self.reencode_string(string)
|
40
|
+
encoding = recognize_encoding(string)
|
41
|
+
|
42
|
+
unless encoding.ascii_compatible?
|
43
|
+
raise RuntimeError, "Encoding #{encoding} is not ASCII-compatible"
|
44
|
+
end
|
45
|
+
|
46
|
+
string.
|
47
|
+
force_encoding(encoding).
|
48
|
+
encode(Encoding::UTF_8)
|
49
|
+
end
|
50
|
+
|
7
51
|
def initialize(name, first_line = 1)
|
8
52
|
@name = name
|
9
53
|
@first_line = first_line
|
@@ -11,7 +55,9 @@ module Parser
|
|
11
55
|
end
|
12
56
|
|
13
57
|
def read
|
14
|
-
|
58
|
+
File.open(@name, 'rb') do |io|
|
59
|
+
self.source = io.read
|
60
|
+
end
|
15
61
|
|
16
62
|
self
|
17
63
|
end
|
@@ -25,7 +71,11 @@ module Parser
|
|
25
71
|
end
|
26
72
|
|
27
73
|
def source=(source)
|
28
|
-
|
74
|
+
if source.respond_to? :encoding
|
75
|
+
source = self.class.reencode_string(source)
|
76
|
+
end
|
77
|
+
|
78
|
+
@source = source.freeze
|
29
79
|
|
30
80
|
freeze
|
31
81
|
end
|
data/lib/parser.rb
CHANGED
@@ -50,8 +50,6 @@ module Parser
|
|
50
50
|
:regexp_options => "unknown regexp options: %{options}",
|
51
51
|
:cvar_name => "`%{name}' is not allowed as a class variable name",
|
52
52
|
:ivar_name => "`%{name}' is not allowed as an instance variable name",
|
53
|
-
:ambiguous_literal => "ambiguous first argument; parenthesize arguments or add whitespace to the right",
|
54
|
-
:ambiguous_prefix => "`%{prefix}' interpreted as argument prefix",
|
55
53
|
:trailing_underscore => "trailing `_' in number",
|
56
54
|
:empty_numeric => "numeric literal without digits",
|
57
55
|
:invalid_octal => "invalid octal digit",
|
@@ -60,10 +58,13 @@ module Parser
|
|
60
58
|
:unexpected => "unexpected %{character}",
|
61
59
|
:embedded_document => "embedded document meats end of file (and they embark on a romantic journey)",
|
62
60
|
|
61
|
+
# Lexer warnings
|
62
|
+
:ambiguous_literal => "ambiguous first argument; parenthesize arguments or add whitespace to the right",
|
63
|
+
:ambiguous_prefix => "`%{prefix}' interpreted as argument prefix",
|
64
|
+
|
63
65
|
# Parser errors
|
64
66
|
:nth_ref_alias => "cannot define an alias for a back-reference variable",
|
65
67
|
:begin_in_method => "BEGIN in method",
|
66
|
-
:end_in_method => "END in method; use at_exit",
|
67
68
|
:backref_assignment => "cannot assign to a back-reference variable",
|
68
69
|
:invalid_assignment => "cannot assign to a keyword",
|
69
70
|
:module_name_const => "class or module name must be a constant literal",
|
@@ -72,16 +73,26 @@ module Parser
|
|
72
73
|
:argument_ivar => "formal argument cannot be an instance variable",
|
73
74
|
:argument_gvar => "formal argument cannot be a global variable",
|
74
75
|
:argument_cvar => "formal argument cannot be a class variable",
|
76
|
+
:duplicate_argument => "duplicate argument name",
|
75
77
|
:empty_symbol => "empty symbol literal",
|
76
78
|
:odd_hash => "odd number of entries for a hash",
|
77
79
|
:singleton_literal => "cannot define a singleton method for a literal",
|
78
80
|
:dynamic_const => "dynamic constant assignment",
|
79
81
|
:module_in_def => "module definition in method body",
|
80
82
|
:class_in_def => "class definition in method body",
|
81
|
-
:space_before_lparen => "don't put space before argument parentheses",
|
82
83
|
:unexpected_percent_str => "%{type}: unknown type of percent-literal",
|
83
|
-
:useless_else => "else without rescue is useless",
|
84
84
|
:block_and_blockarg => "both block argument and literal block are passed",
|
85
85
|
:masgn_as_condition => "multiple assignment in conditional context",
|
86
|
+
|
87
|
+
# Parser warnings
|
88
|
+
:end_in_method => "END in method; use at_exit",
|
89
|
+
:space_before_lparen => "don't put space before argument parentheses",
|
90
|
+
:useless_else => "else without rescue is useless",
|
86
91
|
}.freeze
|
92
|
+
|
93
|
+
def self.check_for_encoding_support
|
94
|
+
unless defined?(Encoding)
|
95
|
+
raise RuntimeError, "Parsing 1.9 and later versions of Ruby is not supported on 1.8 due to the lack of Encoding support"
|
96
|
+
end
|
97
|
+
end
|
87
98
|
end
|
data/parser.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'parser'
|
5
|
-
spec.version = '1.0
|
5
|
+
spec.version = '1.1.0'
|
6
6
|
spec.authors = ['Peter Zotov']
|
7
7
|
spec.email = ['whitequark@whitequark.org']
|
8
8
|
spec.description = %q{A Ruby parser written in pure Ruby.}
|
@@ -15,6 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
lib/parser/ruby18.rb
|
16
16
|
lib/parser/ruby19.rb
|
17
17
|
lib/parser/ruby20.rb
|
18
|
+
lib/parser/ruby21.rb
|
18
19
|
)
|
19
20
|
spec.executables = %w()
|
20
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
data/test/helper.rb
CHANGED
@@ -7,7 +7,7 @@ if SimpleCov.usable?
|
|
7
7
|
if defined?(TracePoint)
|
8
8
|
require_relative 'racc_coverage_helper'
|
9
9
|
|
10
|
-
RaccCoverage.start(%w(ruby18.y ruby19.y ruby20.y),
|
10
|
+
RaccCoverage.start(%w(ruby18.y ruby19.y ruby20.y ruby21.y),
|
11
11
|
File.expand_path('../../lib/parser', __FILE__))
|
12
12
|
|
13
13
|
# Report results faster.
|
data/test/parse_helper.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
require 'parser/all'
|
2
|
-
|
3
1
|
module ParseHelper
|
4
2
|
include AST::Sexp
|
5
3
|
|
6
|
-
|
4
|
+
if RUBY_VERSION == '1.8.7'
|
5
|
+
require 'parser/ruby18'
|
6
|
+
|
7
|
+
ALL_VERSIONS = %w(1.8)
|
8
|
+
else
|
9
|
+
require 'parser/all'
|
10
|
+
require 'parser/ruby21'
|
11
|
+
|
12
|
+
ALL_VERSIONS = %w(1.8 1.9 2.0 2.1)
|
13
|
+
end
|
7
14
|
|
8
15
|
def setup
|
9
16
|
@diagnostics = []
|
@@ -16,6 +23,7 @@ module ParseHelper
|
|
16
23
|
when '1.8'; parser = Parser::Ruby18.new
|
17
24
|
when '1.9'; parser = Parser::Ruby19.new
|
18
25
|
when '2.0'; parser = Parser::Ruby20.new
|
26
|
+
when '2.1'; parser = Parser::Ruby21.new
|
19
27
|
else raise "Unrecognized Ruby version #{version}"
|
20
28
|
end
|
21
29
|
|
@@ -27,7 +35,7 @@ module ParseHelper
|
|
27
35
|
end
|
28
36
|
|
29
37
|
def with_versions(code, versions)
|
30
|
-
versions.each do |version|
|
38
|
+
(versions & ALL_VERSIONS).each do |version|
|
31
39
|
@diagnostics.clear
|
32
40
|
|
33
41
|
parser = parser_for_ruby_version(version)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
class TestCurrent < MiniTest::Unit::TestCase
|
5
|
+
def test_current
|
6
|
+
case RUBY_VERSION
|
7
|
+
when '1.8.7'
|
8
|
+
assert_equal Parser::Ruby18, Parser::CurrentRuby
|
9
|
+
when '1.9.2', '1.9.3'
|
10
|
+
assert_equal Parser::Ruby19, Parser::CurrentRuby
|
11
|
+
when '2.0.0'
|
12
|
+
assert_equal Parser::Ruby20, Parser::CurrentRuby
|
13
|
+
else
|
14
|
+
flunk "Update test_parser_current for #{RUBY_VERSION}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class TestEncoding < MiniTest::Unit::TestCase
|
6
|
+
def recognize(string)
|
7
|
+
Parser::Source::Buffer.recognize_encoding(string)
|
8
|
+
end
|
9
|
+
|
10
|
+
if defined?(Encoding)
|
11
|
+
def test_default
|
12
|
+
assert_equal Encoding::BINARY, recognize("foobar")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_bom
|
16
|
+
assert_equal Encoding::UTF_8, recognize("\xef\xbb\xbffoobar")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_magic_comment
|
20
|
+
assert_equal Encoding::KOI8_R, recognize("# coding:koi8-r\nfoobar")
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_shebang
|
24
|
+
assert_equal Encoding::KOI8_R, recognize("#!/bin/foo\n# coding:koi8-r\nfoobar")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_empty
|
28
|
+
assert_equal Encoding::UTF_8, recognize("")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/test/test_lexer.rb
CHANGED
@@ -50,10 +50,10 @@ class TestLexer < MiniTest::Unit::TestCase
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def util_lex_fname(name, type
|
53
|
+
def util_lex_fname(name, type)
|
54
54
|
util_lex_token("def #{name} ", :kDEF, 'def', type, name)
|
55
55
|
|
56
|
-
assert_equal
|
56
|
+
assert_equal :expr_endfn, @lex.state
|
57
57
|
end
|
58
58
|
|
59
59
|
def util_lex_token(input, *args)
|
@@ -149,14 +149,12 @@ class TestLexer < MiniTest::Unit::TestCase
|
|
149
149
|
:tIDENTIFIER, "m",
|
150
150
|
:tUMINUS_NUM, "-",
|
151
151
|
:tINTEGER, 3)
|
152
|
-
# TODO: verify warning
|
153
152
|
end
|
154
153
|
|
155
154
|
def test_ambiguous_uplus
|
156
155
|
util_lex_token("m +3",
|
157
156
|
:tIDENTIFIER, "m",
|
158
157
|
:tINTEGER, 3)
|
159
|
-
# TODO: verify warning
|
160
158
|
end
|
161
159
|
|
162
160
|
def test_and
|
@@ -319,7 +317,7 @@ class TestLexer < MiniTest::Unit::TestCase
|
|
319
317
|
def test_backtick_method
|
320
318
|
@lex.state = :expr_fname
|
321
319
|
util_lex_token("`", :tBACK_REF2, "`")
|
322
|
-
assert_equal :
|
320
|
+
assert_equal :expr_endfn, @lex.state
|
323
321
|
end
|
324
322
|
|
325
323
|
def test_bad_char
|
@@ -822,7 +820,7 @@ class TestLexer < MiniTest::Unit::TestCase
|
|
822
820
|
end
|
823
821
|
|
824
822
|
def test_identifier_def
|
825
|
-
util_lex_fname "identifier", :tIDENTIFIER
|
823
|
+
util_lex_fname "identifier", :tIDENTIFIER
|
826
824
|
end
|
827
825
|
|
828
826
|
def test_identifier_eh
|
@@ -854,7 +852,7 @@ class TestLexer < MiniTest::Unit::TestCase
|
|
854
852
|
end
|
855
853
|
|
856
854
|
def test_identifier_equals_def
|
857
|
-
util_lex_fname "identifier=", :tIDENTIFIER
|
855
|
+
util_lex_fname "identifier=", :tIDENTIFIER
|
858
856
|
end
|
859
857
|
|
860
858
|
def test_identifier_equals_def2
|
data/test/test_parse_helper.rb
CHANGED
@@ -8,11 +8,16 @@ class TestParseHelper < MiniTest::Unit::TestCase
|
|
8
8
|
assert_instance_of Parser::Ruby18,
|
9
9
|
parser_for_ruby_version('1.8')
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
unless RUBY_VERSION == '1.8.7'
|
12
|
+
assert_instance_of Parser::Ruby19,
|
13
|
+
parser_for_ruby_version('1.9')
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
assert_instance_of Parser::Ruby20,
|
16
|
+
parser_for_ruby_version('2.0')
|
17
|
+
|
18
|
+
assert_instance_of Parser::Ruby21,
|
19
|
+
parser_for_ruby_version('2.1')
|
20
|
+
end
|
16
21
|
end
|
17
22
|
|
18
23
|
def parse_maps(what)
|
data/test/test_parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
1
3
|
require 'helper'
|
2
4
|
require 'parse_helper'
|
3
5
|
|
@@ -1042,6 +1044,54 @@ class TestParser < MiniTest::Unit::TestCase
|
|
1042
1044
|
%q{~~~ location})
|
1043
1045
|
end
|
1044
1046
|
|
1047
|
+
def test_const_op_asgn
|
1048
|
+
assert_parses(
|
1049
|
+
s(:op_asgn,
|
1050
|
+
s(:cdecl, nil, :A), :+,
|
1051
|
+
s(:int, 1)),
|
1052
|
+
%q{A += 1})
|
1053
|
+
|
1054
|
+
assert_parses(
|
1055
|
+
s(:op_asgn,
|
1056
|
+
s(:cdecl, s(:cbase), :A), :+,
|
1057
|
+
s(:int, 1)),
|
1058
|
+
%q{::A += 1},
|
1059
|
+
%q{},
|
1060
|
+
ALL_VERSIONS - %w(1.8 1.9))
|
1061
|
+
|
1062
|
+
assert_parses(
|
1063
|
+
s(:op_asgn,
|
1064
|
+
s(:cdecl, s(:const, nil, :B), :A), :+,
|
1065
|
+
s(:int, 1)),
|
1066
|
+
%q{B::A += 1},
|
1067
|
+
%q{},
|
1068
|
+
ALL_VERSIONS - %w(1.8 1.9))
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
def test_const_op_asgn_invalid
|
1072
|
+
assert_diagnoses(
|
1073
|
+
[:error, :dynamic_const],
|
1074
|
+
%q{Foo::Bar += 1},
|
1075
|
+
%q{ ~~~ location},
|
1076
|
+
%w(1.8 1.9))
|
1077
|
+
|
1078
|
+
assert_diagnoses(
|
1079
|
+
[:error, :dynamic_const],
|
1080
|
+
%q{::Bar += 1},
|
1081
|
+
%q{ ~~~ location},
|
1082
|
+
%w(1.8 1.9))
|
1083
|
+
|
1084
|
+
assert_diagnoses(
|
1085
|
+
[:error, :dynamic_const],
|
1086
|
+
%q{def foo; Foo::Bar += 1; end},
|
1087
|
+
%q{ ~~~ location})
|
1088
|
+
|
1089
|
+
assert_diagnoses(
|
1090
|
+
[:error, :dynamic_const],
|
1091
|
+
%q{def foo; ::Bar += 1; end},
|
1092
|
+
%q{ ~~~ location})
|
1093
|
+
end
|
1094
|
+
|
1045
1095
|
# Method binary operator-assignment
|
1046
1096
|
|
1047
1097
|
def test_op_asgn
|
@@ -1133,16 +1183,6 @@ class TestParser < MiniTest::Unit::TestCase
|
|
1133
1183
|
[:error, :backref_assignment],
|
1134
1184
|
%q{$+ |= m foo},
|
1135
1185
|
%q{~~ location})
|
1136
|
-
|
1137
|
-
assert_diagnoses(
|
1138
|
-
[:error, :dynamic_const],
|
1139
|
-
%q{Foo::Bar += 1; end},
|
1140
|
-
%q{ ~~~ location})
|
1141
|
-
|
1142
|
-
assert_diagnoses(
|
1143
|
-
[:error, :dynamic_const],
|
1144
|
-
%q{::Bar += 1; end},
|
1145
|
-
%q{ ~~~ location})
|
1146
1186
|
end
|
1147
1187
|
|
1148
1188
|
# Variable logical operator-assignment
|
@@ -1716,6 +1756,14 @@ class TestParser < MiniTest::Unit::TestCase
|
|
1716
1756
|
ALL_VERSIONS - %w(1.8 1.9))
|
1717
1757
|
end
|
1718
1758
|
|
1759
|
+
def test_kwarg_no_paren
|
1760
|
+
assert_parses_args(
|
1761
|
+
s(:args,
|
1762
|
+
s(:kwarg, :foo)),
|
1763
|
+
%Q{foo:\n},
|
1764
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0))
|
1765
|
+
end
|
1766
|
+
|
1719
1767
|
def assert_parses_margs(ast, code, versions=ALL_VERSIONS - %w(1.8))
|
1720
1768
|
assert_parses_args(
|
1721
1769
|
s(:args, ast),
|
@@ -2085,6 +2133,105 @@ class TestParser < MiniTest::Unit::TestCase
|
|
2085
2133
|
%q{ ~~~~~ location})
|
2086
2134
|
end
|
2087
2135
|
|
2136
|
+
def test_arg_duplicate
|
2137
|
+
assert_diagnoses(
|
2138
|
+
[:error, :duplicate_argument],
|
2139
|
+
%q{def foo(aa, aa); end},
|
2140
|
+
%q{ ^^ location
|
2141
|
+
| ~~ highlights (0)})
|
2142
|
+
|
2143
|
+
assert_diagnoses(
|
2144
|
+
[:error, :duplicate_argument],
|
2145
|
+
%q{def foo(aa, aa=1); end},
|
2146
|
+
%q{ ^^ location
|
2147
|
+
| ~~ highlights (0)})
|
2148
|
+
|
2149
|
+
assert_diagnoses(
|
2150
|
+
[:error, :duplicate_argument],
|
2151
|
+
%q{def foo(aa, *aa); end},
|
2152
|
+
%q{ ^^ location
|
2153
|
+
| ~~ highlights (0)})
|
2154
|
+
|
2155
|
+
assert_diagnoses(
|
2156
|
+
[:error, :duplicate_argument],
|
2157
|
+
%q{def foo(aa, &aa); end},
|
2158
|
+
%q{ ^^ location
|
2159
|
+
| ~~ highlights (0)})
|
2160
|
+
|
2161
|
+
assert_diagnoses(
|
2162
|
+
[:error, :duplicate_argument],
|
2163
|
+
%q{def foo(aa, (bb, aa)); end},
|
2164
|
+
%q{ ^^ location
|
2165
|
+
| ~~ highlights (0)},
|
2166
|
+
ALL_VERSIONS - %w(1.8))
|
2167
|
+
|
2168
|
+
assert_diagnoses(
|
2169
|
+
[:error, :duplicate_argument],
|
2170
|
+
%q{def foo(aa, *r, aa); end},
|
2171
|
+
%q{ ^^ location
|
2172
|
+
| ~~ highlights (0)},
|
2173
|
+
ALL_VERSIONS - %w(1.8))
|
2174
|
+
|
2175
|
+
|
2176
|
+
assert_diagnoses(
|
2177
|
+
[:error, :duplicate_argument],
|
2178
|
+
%q{lambda do |aa; aa| end},
|
2179
|
+
%q{ ^^ location
|
2180
|
+
| ~~ highlights (0)},
|
2181
|
+
ALL_VERSIONS - %w(1.8))
|
2182
|
+
|
2183
|
+
assert_diagnoses(
|
2184
|
+
[:error, :duplicate_argument],
|
2185
|
+
%q{def foo(aa, aa: 1); end},
|
2186
|
+
%q{ ^^ location
|
2187
|
+
| ~~ highlights (0)},
|
2188
|
+
ALL_VERSIONS - %w(1.8 1.9))
|
2189
|
+
|
2190
|
+
assert_diagnoses(
|
2191
|
+
[:error, :duplicate_argument],
|
2192
|
+
%q{def foo(aa, **aa); end},
|
2193
|
+
%q{ ^^ location
|
2194
|
+
| ~~ highlights (0)},
|
2195
|
+
ALL_VERSIONS - %w(1.8 1.9))
|
2196
|
+
|
2197
|
+
assert_diagnoses(
|
2198
|
+
[:error, :duplicate_argument],
|
2199
|
+
%q{def foo(aa, aa:); end},
|
2200
|
+
%q{ ^^ location
|
2201
|
+
| ~~ highlights (0)},
|
2202
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0))
|
2203
|
+
end
|
2204
|
+
|
2205
|
+
def test_arg_duplicate_ignored
|
2206
|
+
assert_diagnoses(
|
2207
|
+
[:error, :duplicate_argument],
|
2208
|
+
%q{def foo(_, _); end},
|
2209
|
+
%q{},
|
2210
|
+
%w(1.8))
|
2211
|
+
|
2212
|
+
assert_parses(
|
2213
|
+
s(:def, :foo,
|
2214
|
+
s(:args, s(:arg, :_), s(:arg, :_)),
|
2215
|
+
s(:nil)),
|
2216
|
+
%q{def foo(_, _); end},
|
2217
|
+
%q{},
|
2218
|
+
ALL_VERSIONS - %w(1.8))
|
2219
|
+
|
2220
|
+
assert_diagnoses(
|
2221
|
+
[:error, :duplicate_argument],
|
2222
|
+
%q{def foo(_a, _a); end},
|
2223
|
+
%q{},
|
2224
|
+
%w(1.8 1.9))
|
2225
|
+
|
2226
|
+
assert_parses(
|
2227
|
+
s(:def, :foo,
|
2228
|
+
s(:args, s(:arg, :_a), s(:arg, :_a)),
|
2229
|
+
s(:nil)),
|
2230
|
+
%q{def foo(_a, _a); end},
|
2231
|
+
%q{},
|
2232
|
+
ALL_VERSIONS - %w(1.8 1.9))
|
2233
|
+
end
|
2234
|
+
|
2088
2235
|
def test_kwarg_invalid
|
2089
2236
|
assert_diagnoses(
|
2090
2237
|
[:error, :argument_const],
|
@@ -3922,6 +4069,21 @@ class TestParser < MiniTest::Unit::TestCase
|
|
3922
4069
|
ALL_VERSIONS - %w(1.8 1.9))
|
3923
4070
|
end
|
3924
4071
|
|
4072
|
+
if defined?(Encoding)
|
4073
|
+
def test_magic_encoding_comment
|
4074
|
+
assert_parses(
|
4075
|
+
s(:begin,
|
4076
|
+
s(:lvasgn, :"проверка", s(:int, 42)),
|
4077
|
+
s(:send, nil, :puts, s(:lvar, :"проверка"))),
|
4078
|
+
%Q{# coding:koi8-r
|
4079
|
+
\xd0\xd2\xcf\xd7\xc5\xd2\xcb\xc1 = 42
|
4080
|
+
puts \xd0\xd2\xcf\xd7\xc5\xd2\xcb\xc1}.
|
4081
|
+
force_encoding(Encoding::BINARY),
|
4082
|
+
%q{},
|
4083
|
+
%w(1.9 2.0 2.1))
|
4084
|
+
end
|
4085
|
+
end
|
4086
|
+
|
3925
4087
|
#
|
3926
4088
|
# Error recovery
|
3927
4089
|
#
|