parser 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
#
|