diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index ae57242707..df1d66f44c 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -588,6 +588,7 @@ module Prism autoload :Newlines, "prism/parse_result/newlines" private_constant :Comments + private_constant :Errors private_constant :Newlines # The syntax tree that was parsed from the source code. diff --git a/lib/prism/parse_result/errors.rb b/lib/prism/parse_result/errors.rb index 1eaeebee6e..847a8442fe 100644 --- a/lib/prism/parse_result/errors.rb +++ b/lib/prism/parse_result/errors.rb @@ -32,19 +32,19 @@ module Prism io = StringIO.new source_lines.each.with_index(1) do |line, line_number| io.puts(line) - + (error_lines.delete(line_number) || []).each do |error| location = error.location - + case line_number when location.start_line io.print(" " * location.start_column + "^") - + if location.start_line == location.end_line if location.start_column != location.end_column io.print("~" * (location.end_column - location.start_column - 1)) end - + io.puts(" " + error.message) else io.puts("~" * (line.bytesize - location.start_column)) @@ -56,7 +56,7 @@ module Prism end end end - + io.puts io.string end diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index 750af194a8..08212318bc 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -104,6 +104,7 @@ Gem::Specification.new do |spec| "prism.gemspec", "rbi/prism.rbi", "rbi/prism/compiler.rbi", + "rbi/prism/dsl.rbi", "rbi/prism/inspect_visitor.rbi", "rbi/prism/node_ext.rbi", "rbi/prism/node.rbi", diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb index d004ffb25b..f0dac2a4f0 100644 --- a/prism/templates/lib/prism/dsl.rb.erb +++ b/prism/templates/lib/prism/dsl.rb.erb @@ -69,8 +69,15 @@ module Prism # Create a new <%= node.name %> node. def <%= node.human %>(<%= ["source: default_source", "node_id: 0", "location: default_location", "flags: 0", *node.fields.map { |field| case field - when Prism::Template::NodeField, Prism::Template::ConstantField - "#{field.name}: default_node(source, location)" + when Prism::Template::NodeField + if !field.kind? + "#{field.name}: default_node(source, location)" + else + kind = field.specific_kind || field.union_kind.first + "#{field.name}: #{kind.gsub(/(?<=.)[A-Z]/, "_\\0").downcase}(source: source)" + end + when Prism::Template::ConstantField + "#{field.name}: :\"\"" when Prism::Template::OptionalNodeField, Prism::Template::OptionalConstantField, Prism::Template::OptionalLocationField "#{field.name}: nil" when Prism::Template::NodeListField, Prism::Template::ConstantListField @@ -79,8 +86,10 @@ module Prism "#{field.name}: \"\"" when Prism::Template::LocationField "#{field.name}: location" - when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField, Prism::Template::DoubleField + when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField "#{field.name}: 0" + when Prism::Template::DoubleField + "#{field.name}: 0.0" else raise end @@ -96,7 +105,7 @@ module Prism <%- flag.values.each do |value| -%> when :<%= value.name.downcase %> then <%= flag.name %>::<%= value.name %> <%- end -%> - else raise ArgumentError, "invalid <%= flag.name %> flag: #{name.inspect}" + else Kernel.raise ArgumentError, "invalid <%= flag.name %> flag: #{name.inspect}" end end <%- end -%> @@ -118,7 +127,7 @@ module Prism # The default node that gets attached to nodes if no node is specified for a # required node field. def default_node(source, location) - MissingNode.new(source, location) + MissingNode.new(source, -1, location, 0) end end end diff --git a/prism/templates/template.rb b/prism/templates/template.rb index 8e6f1b16aa..130e15d075 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -93,6 +93,10 @@ module Prism # Some node fields can be specialized if they point to a specific kind of # node and not just a generic node. class NodeKindField < Field + def kind? + options.key?(:kind) + end + def c_type if specific_kind "pm_#{specific_kind.gsub(/(?<=.)[A-Z]/, "_\\0").downcase}" @@ -624,6 +628,7 @@ module Prism "src/prettyprint.c", "src/serialize.c", "src/token_type.c", + "rbi/prism/dsl.rbi", "rbi/prism/node.rbi", "rbi/prism/visitor.rbi", "sig/prism.rbs", diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 4c5f93cc9f..9a108ceca7 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -18,6 +18,12 @@ module Prism ] end + if RUBY_VERSION < "3.4" + filepaths -= [ + "it_with_ordinary_parameter.txt" + ] + end + filepaths.each do |filepath| define_method(:"test_#{File.basename(filepath, ".txt")}") do assert_errors(File.join(base, filepath)) @@ -77,7 +83,7 @@ module Prism private def assert_errors(filepath) - expected = File.read(filepath) + expected = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8) source = expected.lines.grep_v(/^\s*\^/).join.gsub(/\n*\z/, "") refute_valid_syntax(source) diff --git a/test/prism/result/warnings_test.rb b/test/prism/result/warnings_test.rb index 747440dd76..c147616a6a 100644 --- a/test/prism/result/warnings_test.rb +++ b/test/prism/result/warnings_test.rb @@ -76,33 +76,38 @@ module Prism end def test_literal_in_conditionals - source = <<~RUBY - if (a = 2); a; end - if ($a = 2); end - if (@a = 2); end - if (@@a = 2); end - if a; elsif b = 2; b end - unless (a = 2); a; end - unless ($a = 2); end - unless (@a = 2); end - unless (@@a = 2); end - while (a = 2); a; end - while ($a = 2); end - while (@a = 2); end - while (@@a = 2); end - until (a = 2); a; end - until ($a = 2); end - until (@a = 2); end - until (@@a = 2); end - foo if (a, b = 2); [a, b] - foo if a = 2 and a - (@foo = 1) ? a : b - !(a = 2) and a - not a = 2 and a - RUBY + sources = [ + "if (a = 2); a; end", + "if ($a = 2); end", + "if (@a = 2); end", + "if a; elsif b = 2; b end", + "unless (a = 2); a; end", + "unless ($a = 2); end", + "unless (@a = 2); end", + "while (a = 2); a; end", + "while ($a = 2); end", + "while (@a = 2); end", + "until (a = 2); a; end", + "until ($a = 2); end", + "until (@a = 2); end", + "foo if (a, b = 2); [a, b]", + "foo if a = 2 and a", + "(@foo = 1) ? a : b", + "!(a = 2) and a", + "not a = 2 and a" + ] - source.each_line(chomp: true) do |line| - assert_warning(line, "found '= literal' in conditional, should be ==") + if RUBY_VERSION >= "3.3" + sources.push( + "if (@@a = 2); end", + "unless (@@a = 2); end", + "while (@@a = 2); end", + "until (@@a = 2); end" + ) + end + + sources.each do |source| + assert_warning(source, "= literal' in conditional, should be ==") end end diff --git a/tool/bundler/rubocop_gems.rb b/tool/bundler/rubocop_gems.rb index 4d0b21060a..01159ea876 100644 --- a/tool/bundler/rubocop_gems.rb +++ b/tool/bundler/rubocop_gems.rb @@ -2,11 +2,12 @@ source "https://rubygems.org" -gem "rubocop", ">= 1.52.1", "< 2" +gemspec path: "../.." gem "minitest" gem "rake" gem "rake-compiler" gem "rspec" +gem "rubocop", ">= 1.52.1", "< 2" gem "test-unit" gem "rb_sys"