summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/prism/ripper_compat.rb154
-rw-r--r--test/prism/ripper_compat_test.rb30
2 files changed, 156 insertions, 28 deletions
diff --git a/lib/prism/ripper_compat.rb b/lib/prism/ripper_compat.rb
index 44983f8596..5c3b56d01b 100644
--- a/lib/prism/ripper_compat.rb
+++ b/lib/prism/ripper_compat.rb
@@ -132,7 +132,12 @@ module Prism
end
# A non-operator method call with parentheses
- args = on_arg_paren(node.arguments.nil? ? nil : args_node_to_arguments(node.arguments))
+
+ args = if node.arguments.nil?
+ on_arg_paren(nil)
+ else
+ on_arg_paren(on_args_add_block(visit_elements(node.arguments.arguments), false))
+ end
bounds(node.message_loc)
ident_val = on_ident(node.message)
@@ -142,31 +147,92 @@ module Prism
if node.block
block_val = visit(node.block)
- return on_method_add_block(args_call_val, on_brace_block(nil, block_val))
+ return on_method_add_block(args_call_val, block_val)
else
return args_call_val
end
end
- # Visit a BlockNode
+ # Visit a LocalVariableAndWriteNode.
+ def visit_local_variable_and_write_node(node)
+ visit_binary_op_assign(node)
+ end
+
+ # Visit a LocalVariableOrWriteNode.
+ def visit_local_variable_or_write_node(node)
+ visit_binary_op_assign(node)
+ end
+
+ # Visit nodes for +=, *=, -=, etc., called LocalVariableOperatorWriteNodes.
+ def visit_local_variable_operator_write_node(node)
+ visit_binary_op_assign(node, operator: node.operator.to_s + "=")
+ end
+
+ # Visit a LocalVariableReadNode.
+ def visit_local_variable_read_node(node)
+ bounds(node.location)
+ ident_val = on_ident(node.slice)
+
+ on_var_ref(ident_val)
+ end
+
+ # Visit a BlockNode.
def visit_block_node(node)
- if node.body.nil?
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.body)
- end
+ params_val = node.parameters.nil? ? nil : visit(node.parameters)
+
+ body_val = node.body.nil? ? on_stmts_add(on_stmts_new, on_void_stmt) : visit(node.body)
+
+ on_brace_block(params_val, body_val)
+ end
+
+ # Visit a BlockParametersNode.
+ def visit_block_parameters_node(node)
+ on_block_var(visit(node.parameters), no_block_value)
+ end
+
+ # Visit a ParametersNode.
+ # This will require expanding as we support more kinds of parameters.
+ def visit_parameters_node(node)
+ #on_params(required, optional, nil, nil, nil, nil, nil)
+ on_params(node.requireds.map { |n| visit(n) }, nil, nil, nil, nil, nil, nil)
end
- # Visit an AndNode
+ # Visit a RequiredParameterNode.
+ def visit_required_parameter_node(node)
+ bounds(node.location)
+ on_ident(node.name.to_s)
+ end
+
+ # Visit a BreakNode.
+ def visit_break_node(node)
+ return on_break(on_args_new) if node.arguments.nil?
+
+ args_val = visit_elements(node.arguments.arguments)
+ on_break(on_args_add_block(args_val,false))
+ end
+
+ # Visit an AndNode.
def visit_and_node(node)
visit_binary_operator(node)
end
- # Visit an OrNode
+ # Visit an OrNode.
def visit_or_node(node)
visit_binary_operator(node)
end
+ # Visit a TrueNode.
+ def visit_true_node(node)
+ bounds(node.location)
+ on_var_ref(on_kw(node.slice))
+ end
+
+ # Visit a FalseNode.
+ def visit_false_node(node)
+ bounds(node.location)
+ on_var_ref(on_kw(node.slice))
+ end
+
# Visit a FloatNode node.
def visit_float_node(node)
visit_number(node) { |text| on_float(text) }
@@ -195,6 +261,19 @@ module Prism
on_paren(body)
end
+ # Visit a BeginNode node.
+ # This is not at all bulletproof against different structures of begin/rescue/else/ensure/end.
+ def visit_begin_node(node)
+ rescue_val = node.rescue_clause ? on_rescue(nil, nil, visit(node.rescue_clause), nil) : nil
+ ensure_val = node.ensure_clause ? on_ensure(visit(node.ensure_clause.statements)) : nil
+ on_begin(on_bodystmt(visit(node.statements), rescue_val, nil, ensure_val))
+ end
+
+ # Visit a RescueNode node.
+ def visit_rescue_node(node)
+ visit(node.statements)
+ end
+
# Visit a ProgramNode node.
def visit_program_node(node)
statements = visit(node.statements)
@@ -260,7 +339,7 @@ module Prism
raise NotImplementedError, "More than two arguments for operator"
end
elsif node.call_operator_loc.nil?
- # In Ripper a method call like "puts myvar" with no parenthesis is a "command".
+ # In Ripper a method call like "puts myvar" with no parentheses is a "command".
bounds(node.message_loc)
ident_val = on_ident(node.message)
@@ -268,11 +347,20 @@ module Prism
if node.block
block_val = visit(node.block)
# In these calls, even if node.arguments is nil, we still get an :args_new call.
- method_args_val = on_method_add_arg(on_fcall(ident_val), args_node_to_arguments(node.arguments))
- return on_method_add_block(method_args_val, on_brace_block(nil, block_val))
+ args = if node.arguments.nil?
+ on_args_new
+ else
+ on_args_add_block(visit_elements(node.arguments.arguments))
+ end
+ method_args_val = on_method_add_arg(on_fcall(ident_val), args)
+ return on_method_add_block(method_args_val, block_val)
else
- args = node.arguments.nil? ? nil : args_node_to_arguments(node.arguments)
- return on_command(ident_val, args)
+ if node.arguments.nil?
+ return on_command(ident_val, nil)
+ else
+ args = on_args_add_block(visit_elements(node.arguments.arguments), false)
+ return on_command(ident_val, args)
+ end
end
else
operator = node.call_operator_loc.slice
@@ -289,7 +377,7 @@ module Prism
if node.block
block_val = visit(node.block)
- return on_method_add_block(call_val, on_brace_block(nil, block_val))
+ return on_method_add_block(call_val, block_val)
else
return call_val
end
@@ -299,17 +387,6 @@ module Prism
end
end
- # Ripper generates an interesting format of argument list.
- # It seems to be very location-specific. We should get rid of
- # this method and make it clearer how it's done in each place.
- def args_node_to_arguments(args_node)
- return on_args_new if args_node.nil?
-
- args = visit_elements(args_node.arguments)
-
- on_args_add_block(args, false)
- end
-
# Visit a list of elements, like the elements of an array or arguments.
def visit_elements(elements)
bounds(elements.first.location)
@@ -318,6 +395,17 @@ module Prism
end
end
+ # Visit an operation-and-assign node, such as +=.
+ def visit_binary_op_assign(node, operator: node.operator)
+ bounds(node.name_loc)
+ ident_val = on_ident(node.name.to_s)
+
+ bounds(node.operator_loc)
+ op_val = on_op(operator)
+
+ on_opassign(on_var_field(ident_val), op_val, visit(node.value))
+ end
+
# Visit a node that represents a number. We need to explicitly handle the
# unary - operator.
def visit_number(node)
@@ -348,6 +436,18 @@ module Prism
end
end
+ if RUBY_ENGINE == "jruby"
+ # For JRuby, "no block" in an on_block_var is nil
+ def no_block_value
+ nil
+ end
+ else
+ # For CRuby et al, "no block" in an on_block_var is false
+ def no_block_value
+ false
+ end
+ end
+
# Visit a binary operator node like an AndNode or OrNode
def visit_binary_operator(node)
left_val = visit(node.left)
diff --git a/test/prism/ripper_compat_test.rb b/test/prism/ripper_compat_test.rb
index 1aaade046f..c8fc208dff 100644
--- a/test/prism/ripper_compat_test.rb
+++ b/test/prism/ripper_compat_test.rb
@@ -27,6 +27,7 @@ module Prism
def test_method_calls_with_variable_names
assert_equivalent("foo")
assert_equivalent("foo()")
+ assert_equivalent("foo -7")
assert_equivalent("foo(-7)")
assert_equivalent("foo(1, 2, 3)")
assert_equivalent("foo 1")
@@ -49,9 +50,16 @@ module Prism
assert_equivalent("foo(1) { bar }")
assert_equivalent("foo(bar)")
assert_equivalent("foo(bar(1))")
+ assert_equivalent("foo(bar(1)) { 7 }")
assert_equivalent("foo bar(1)")
- # assert_equivalent("foo(bar 1)") # This succeeds for me locally but fails on CI
+ end
+
+ def test_method_call_blocks
+ assert_equivalent("foo { |a| a }")
+
+ # assert_equivalent("foo(bar 1)")
# assert_equivalent("foo bar 1")
+ # assert_equivalent("foo(bar 1) { 7 }")
end
def test_method_calls_on_immediate_values
@@ -85,6 +93,23 @@ module Prism
assert_equivalent("[1ri, -1ri, +1ri, 1.5ri, -1.5ri, +1.5ri]")
end
+ def test_begin_rescue
+ assert_equivalent("begin a; rescue; c; ensure b; end")
+ end
+
+ def test_break
+ assert_equivalent("foo { break }")
+ assert_equivalent("foo { break 7 }")
+ assert_equivalent("foo { break [1, 2, 3] }")
+ end
+
+ def test_op_assign
+ assert_equivalent("a += b")
+ assert_equivalent("a -= b")
+ assert_equivalent("a *= b")
+ assert_equivalent("a /= b")
+ end
+
private
def assert_equivalent(source)
@@ -100,6 +125,9 @@ module Prism
#relatives = ENV["FOCUS"] ? [ENV["FOCUS"]] : Dir["**/*.txt", base: base]
relatives = [
"arithmetic.txt",
+ "booleans.txt",
+ "boolean_operators.txt",
+ # "break.txt", # No longer parseable by Ripper in CRuby 3.3.0+
"comments.txt",
"integer_operations.txt",
]