summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/prism/translation/parser.rb57
-rw-r--r--lib/prism/translation/parser/compiler.rb9
2 files changed, 49 insertions, 17 deletions
diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb
index 7cc18ac5de..589b33b6fe 100644
--- a/lib/prism/translation/parser.rb
+++ b/lib/prism/translation/parser.rb
@@ -9,6 +9,20 @@ module Prism
# the parser gem, and overrides the parse* methods to parse with prism and
# then translate.
class Parser < ::Parser::Base
+ # The parser gem has a list of diagnostics with a hard-coded set of error
+ # messages. We create our own diagnostic class in order to set our own
+ # error messages.
+ class Diagnostic < ::Parser::Diagnostic
+ # The message generated by prism.
+ attr_reader :message
+
+ # Initialize a new diagnostic with the given message and location.
+ def initialize(message, location)
+ @message = message
+ super(:error, :prism_error, {}, location, [])
+ end
+ end
+
Racc_debug_parser = false # :nodoc:
def version # :nodoc:
@@ -28,10 +42,9 @@ module Prism
@source_buffer = source_buffer
source = source_buffer.source
- build_ast(
- Prism.parse(source, filepath: source_buffer.name).value,
- build_offset_cache(source)
- )
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name))
+
+ build_ast(result.value, build_offset_cache(source))
ensure
@source_buffer = nil
end
@@ -42,7 +55,7 @@ module Prism
source = source_buffer.source
offset_cache = build_offset_cache(source)
- result = Prism.parse(source, filepath: source_buffer.name)
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name))
[
build_ast(result.value, offset_cache),
@@ -59,7 +72,8 @@ module Prism
source = source_buffer.source
offset_cache = build_offset_cache(source)
- result = Prism.parse_lex(source, filepath: source_buffer.name)
+ result = unwrap(Prism.parse_lex(source, filepath: source_buffer.name))
+
program, tokens = result.value
[
@@ -79,6 +93,18 @@ module Prism
private
+ # If there was a error generated during the parse, then raise an
+ # appropriate syntax error. Otherwise return the result.
+ def unwrap(result)
+ return result if result.success?
+
+ error = result.errors.first
+ offset_cache = build_offset_cache(source_buffer.source)
+
+ diagnostic = Diagnostic.new(error.message, build_range(error.location, offset_cache))
+ raise ::Parser::SyntaxError, diagnostic
+ end
+
# Prism deals with offsets in bytes, while the parser gem deals with
# offsets in characters. We need to handle this conversion in order to
# build the parser gem AST.
@@ -109,15 +135,7 @@ module Prism
# Build the parser gem comments from the prism comments.
def build_comments(comments, offset_cache)
comments.map do |comment|
- location = comment.location
-
- ::Parser::Source::Comment.new(
- ::Parser::Source::Range.new(
- source_buffer,
- offset_cache[location.start_offset],
- offset_cache[location.end_offset]
- )
- )
+ ::Parser::Source::Comment.new(build_range(comment.location, offset_cache))
end
end
@@ -126,6 +144,15 @@ module Prism
Lexer.new(source_buffer, tokens.map(&:first), offset_cache).to_a
end
+ # Build a range from a prism location.
+ def build_range(location, offset_cache)
+ ::Parser::Source::Range.new(
+ source_buffer,
+ offset_cache[location.start_offset],
+ offset_cache[location.end_offset]
+ )
+ end
+
require_relative "parser/compiler"
require_relative "parser/lexer"
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index d03de9efc5..ccd02c2181 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -83,11 +83,16 @@ module Prism
elements = [*node.requireds]
elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
elements.concat(node.posts)
+ visited = visit_all(elements)
+
+ if node.rest.is_a?(ImplicitRestNode)
+ visited[-1] = builder.match_with_trailing_comma(visited[-1], token(node.rest.location))
+ end
if node.constant
- builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(nil, visit_all(elements), nil), token(node.closing_loc))
+ builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(nil, visited, nil), token(node.closing_loc))
else
- builder.array_pattern(token(node.opening_loc), visit_all(elements), token(node.closing_loc))
+ builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc))
end
end