lib/safemode/parser.rb in safemode-1.3.8 vs lib/safemode/parser.rb in safemode-1.4.0
- old
+ new
@@ -24,23 +24,26 @@
def parser=(parser)
@@parser = parser
end
end
- def jail(str, parentheses = false)
- str = parentheses ? "(#{str})." : "#{str}." if str
+ def jail(str, parentheses = false, safe_call: false)
+ str = if str
+ dot = safe_call ? "&." : "."
+ parentheses ? "(#{str})#{dot}" : "#{str}#{dot}"
+ end
"#{str}to_jail"
end
# split up #process_call. see below ...
- def process_call(exp)
- exp.shift # remove ":call" symbol
- receiver = jail process_call_receiver(exp)
- name = exp.shift
- args = process_call_args(exp)
+ def process_call(exp, safe_call = false)
+ _, recv, name, *args = exp
- process_call_code(receiver, name, args)
+ receiver = jail(process_call_receiver(recv), safe_call: safe_call)
+ arguments = process_call_args(name, args)
+
+ process_call_code(receiver, name, arguments, safe_call)
end
def process_fcall(exp)
# using haml we probably never arrive here because :lasgn'ed :fcalls
# somehow seem to change to :calls somewhere during processing
@@ -138,47 +141,70 @@
end
# split up Ruby2Ruby#process_call monster method so we can hook into it
# in a more readable manner
- def process_call_receiver(exp)
- receiver_node_type = exp.first.nil? ? nil : exp.first.first
- receiver = process exp.shift
- receiver = "(#{receiver})" if
- Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
+ def process_call_receiver(recv)
+ receiver_node_type = recv && recv.sexp_type
+ receiver = process recv
+ receiver = "(#{receiver})" if ASSIGN_NODES.include? receiver_node_type
receiver
end
- def process_call_args(exp)
- args = []
- while not exp.empty? do
- args_exp = exp.shift
- if args_exp && args_exp.first == :array # FIX
- processed = "#{process(args_exp)[1..-2]}"
- else
- processed = process args_exp
- end
- args << processed unless (processed.nil? or processed.empty?)
+ def process_call_args(name, args)
+ in_context :arglist do
+ max = args.size - 1
+ args = args.map.with_index { |arg, i|
+ arg_type = arg.sexp_type
+ is_empty_hash = arg == s(:hash)
+ arg = process arg
+
+ next if arg.empty?
+
+ strip_hash = (arg_type == :hash and
+ not BINARY.include? name and
+ not is_empty_hash and
+ (i == max or args[i + 1].sexp_type == :splat))
+ wrap_arg = Ruby2Ruby::ASSIGN_NODES.include? arg_type
+
+ arg = arg[2..-3] if strip_hash
+ arg = "(#{arg})" if wrap_arg
+
+ arg
+ }.compact
end
- args.empty? ? nil : args.join(", ")
end
- def process_call_code(receiver, name, args)
+ def process_call_code(receiver, name, args, safe_call)
case name
- when :<=>, :==, "!=".to_sym, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :** then
- "(#{receiver} #{name} #{args})"
+ when *BINARY then
+ if safe_call
+ "#{receiver}&.#{name}(#{args.join(", ")})"
+ elsif args.length > 1
+ "#{receiver}.#{name}(#{args.join(", ")})"
+ else
+ "(#{receiver} #{name} #{args.join(", ")})"
+ end
when :[] then
- "#{receiver}[#{args}]"
+ receiver ||= "self"
+ "#{receiver}[#{args.join(", ")}]"
+ when :[]= then
+ receiver ||= "self"
+ rhs = args.pop
+ "#{receiver}[#{args.join(", ")}] = #{rhs}"
+ when :"!" then
+ "(not #{receiver})"
when :"-@" then
"-#{receiver}"
when :"+@" then
"+#{receiver}"
else
- unless receiver.nil? then
- "#{receiver}.#{name}#{args ? "(#{args})" : args}"
- else
- "#{name}#{args ? "(#{args})" : args}"
- end
+ args = nil if args.empty?
+ args = "(#{args.join(", ")})" if args
+ receiver = "#{receiver}." if receiver and not safe_call
+ receiver = "#{receiver}&." if receiver and safe_call
+
+ "#{receiver}#{name}#{args}"
end
end
# Ruby2Ruby process_if rewrites if and unless statements in a way that
# makes the result unusable for evaluation in, e.g. ERB which appends a