module Rensei::Unparser::Base
Public Instance Methods
# File lib/rensei/unparser.rb, line 42 def unparse(node, opt = {}) case node when RubyVM::AbstractSyntaxTree::Node, Hash, Array method_name = "NODE_#{node.type}" respond_to?(method_name, true) ? send(method_name, node, opt.dup) : node else node end end
Private Instance Methods
method alias statement format: alias [nd_1st] [nd_2nd] example: alias bar foo
# File lib/rensei/unparser.rb, line 1031 def NODE_ALIAS(node, opt = {}) node.children.then { |nd_1st, nd_2nd| "alias #{unparse(nd_1st, opt)} #{unparse(nd_2nd, opt)}" } end
&& operator format: [nd_1st] && [nd_2nd] example: foo && bar
# File lib/rensei/unparser.rb, line 348 def NODE_AND(node, opt = {}) node.children.then { |args| "(#{args.map { |node| unparse(node, opt) }.join(" && ")})" } end
method parameters format: def method_name(.., [nd_opt=some], *[nd_rest], [nd_pid], .., &[nd_body]) example: def foo(a, b, opt1=1, opt2=2, *rest, y, z, &blk); end
# File lib/rensei/unparser.rb, line 1263 def NODE_ARGS(node, opt_ = {}) ( _, # pre_num _, # pre_init opt, _, # first_post _, # post_num _, # post_init _, # rest _, # kw _, # kwrest _, # block ) = node.children "#{unparse(opt, opt_)}#{unparse(kw, opt_)}" end
splat argument following arguments format: ..(*[nd_head], [nd_body..]) example: foo(*ary, post_arg1, post_arg2)
# File lib/rensei/unparser.rb, line 936 def NODE_ARGSCAT(node, opt = {}) node.children.then { |head, body| case head.type when :ARRAY, :LIST opt_flags = { expand_ARRAY: true, expand_ARGSCAT: true, expand_ARGSPUSH: false } when :ARGSCAT opt_flags = { expand_ARRAY: true, expand_ARGSCAT: true, expand_ARGSPUSH: false } when :ARGSPUSH opt_flags = { expand_ARRAY: false, expand_ARGSCAT: false, expand_ARGSPUSH: true } else opt_flags = {} end star = "*" unless %i(ARRAY LIST).include? body.type if opt.delete(:expand_ARGSCAT) "#{unparse(head, opt.merge(opt_flags))}, #{star}#{unparse(body, opt.merge(expand_ARRAY: true))}" else "[#{unparse(head, opt.merge(opt_flags))}, #{star}#{unparse(body, opt.merge(expand_ARRAY: true))}]" end } end
splat argument following one argument format: ..(*[nd_head], [nd_body]) example: foo(*ary, post_arg)
# File lib/rensei/unparser.rb, line 961 def NODE_ARGSPUSH(node, opt = {}) node.children.then { |head, body| case head.type when :ARRAY, :LIST opt_flags = { expand_ARRAY: true, expand_ARGSCAT: true, expand_ARGSPUSH: false } when :ARGSCAT opt_flags = { expand_ARRAY: false, expand_ARGSCAT: true, expand_ARGSPUSH: false } when :ARGSPUSH opt_flags = { expand_ARRAY: false, expand_ARGSCAT: false, expand_ARGSPUSH: true } else opt_flags = {} end if opt.delete(:expand_ARGSPUSH) "#{unparse(head, opt.merge(opt_flags))}, #{unparse(body , opt)}" else "[#{unparse(head, opt.merge(opt_flags))}, #{unparse(body , opt)}]" end } end
# File lib/rensei/unparser.rb, line 1394 def NODE_ARGS_AUX(node, opt = {}) "" end
list constructor format: [ [nd_head], [nd_next].. ] (length: [nd_alen]) example: [1, 2, 3]
# File lib/rensei/unparser.rb, line 671 def NODE_ARRAY(node, opt = {}) node.children.then { |*args, _nil| if opt[:expand_ARRAY] "#{args.map(&_unparse(opt.except(:expand_ARRAY))).join(", ")}" else "[#{args.map(&_unparse(opt)).join(", ")}]" end } end
attr assignment format: [nd_recv]. = [nd_args] example: struct.field = foo
# File lib/rensei/unparser.rb, line 1204 def NODE_ATTRASGN(node, opt = {}) node.children.then { |recv, mid, args| if opt.delete(:ignore_equal_NODE_ATTRASGN) "#{unparse(recv, opt)}.#{mid.to_s.delete_suffix("=")}" elsif mid == :[]= *args_, right, _ = args.children "#{unparse(recv, opt)}[#{args_.map(&_unparse(opt.merge(expand_ARRAY: true))).join(", ")}] = #{unparse(right, opt.merge(expand_ARRAY: true))}" else "#{unparse(recv, opt)}.#{mid}(#{unparse(args, opt.merge(expand_ARRAY: true))})" end } end
back special variable reference format: $[nd_nth] example: $&, $`, $', $+
# File lib/rensei/unparser.rb, line 808 def NODE_BACK_REF(node, opt = {}) node.children.then { |vid,| vid.to_s } end
begin statement format: begin; [nd_body]; end example: begin; 1; end
# File lib/rensei/unparser.rb, line 277 def NODE_BEGIN(node, opt = {}) node.children.then { |body| if opt.delete(:pattern_match_BEGIN) "^(#{body.map(&_unparse(opt)).join("; ")})" elsif opt.delete(:without_BEGIN) "#{body.map(&_unparse(opt)).join("; ")}" elsif opt.delete(:within_BEGIN) "begin #{body.map(&_unparse(opt)).join("; ")} end" elsif body == [nil] "" else <<~EOS.chomp begin #{body.map(&_unparse(opt)).join("; ")} end EOS end } end
statement sequence format: [nd_head]; …; [nd_next] example: foo; bar
# File lib/rensei/unparser.rb, line 61 def NODE_BLOCK(node, opt = {}) node.children.then { |head, *nexts| if without_BEGIN = opt.fetch(:without_BEGIN, false) begin_ = proc { |str, _| str } else begin_ = proc { |str, semicolon| if semicolon "begin; #{str}; end" else "begin #{str}; end" end } end opt.merge!(within_BEGIN: !without_BEGIN) opt.delete(:without_BEGIN) if head.type == :BEGIN && head.children == [nil] begin_.(nexts.map(&_unparse(opt)).join("; "), true) elsif head.type == :BEGIN "BEGIN { #{unparse(head, opt)} }; #{nexts.drop(1).map(&_unparse(opt)).join("; ")}" else if nexts.empty? "#{unparse(head, opt)};" else begin_.([head, *nexts].map(&_unparse(opt)).join("; "), false) end end } end
arguments with block argument format: ..([nd_head], &[nd_body]) example: foo(x, &blk)
# File lib/rensei/unparser.rb, line 994 def NODE_BLOCK_PASS(node, opt = {}) node.children.then { |head, body| "#{head&.then { |it| "#{unparse(it, opt)}, " }}&#{unparse(body, opt)}" } end
break statement format: break [nd_stts] example: break 1
# File lib/rensei/unparser.rb, line 236 def NODE_BREAK(node, opt = {}) node.children.then { |stts,| "break #{unparse(stts, opt)}" } end
method invocation format: [nd_recv].([nd_args]) example: obj.foo(1)
# File lib/rensei/unparser.rb, line 584 def NODE_CALL(node, opt = {}) node.children.then { |receiver, mid, args| opt_flags = _expand_in_XXXCALL(args) "#{unparse(receiver, opt)}.#{unparse(mid, opt)}(#{unparse(args, opt.merge(_expand_in_XXXCALL(args)))})" } end
case statement format: case [nd_head]; [nd_body]; end example: case x; when 1; foo; when 2; bar; else baz; end
# File lib/rensei/unparser.rb, line 119 def NODE_CASE(node, opt) node.children.then { |head, body, else_| <<~EOS.chomp case #{unparse(head, opt)} #{unparse(body, opt)}#{else_ ? "\nelse\n#{unparse(else_, opt)}" : ""} end EOS } end
case statement with no head format: case; [nd_body]; end example: case; when 1; foo; when 2; bar; else baz; end
# File lib/rensei/unparser.rb, line 132 def NODE_CASE2(node, opt = {}) node.children.then { |_, body, else_| <<~EOS.chomp case #{unparse(body, opt)}#{else_ ? "\nelse\n#{unparse(else_, opt)}" : ""} end EOS } end
constant declaration format: [nd_else]::(constant) = [nd_value] example: X = foo
# File lib/rensei/unparser.rb, line 516 def NODE_CDECL(node, opt = {}) node.children.then { |else_, vid, value| rvalue = Symbol === vid ? value : (value || vid) if rvalue "(#{unparse(else_, opt)} = #{unparse(rvalue, opt)})" else "#{unparse(else_, opt)}" end } end
class definition format: class [nd_cpath] < [nd_super]; [nd_body]; end example: class C2 < C; ..; end
# File lib/rensei/unparser.rb, line 1058 def NODE_CLASS(node, opt = {}) node.children.then { |cpath, super_, body| <<~EOS.chomp class #{unparse(cpath, opt)}#{super_&.then { |it| " < #{unparse(it, opt)}" } } #{unparse(body, opt.merge(without_BEGIN: true))} end EOS } end
scoped constant reference format: [nd_head]:: example: M::C
# File lib/rensei/unparser.rb, line 1097 def NODE_COLON2(node, opt = {}) node.children.then { |head, mid| "#{unparse(head, opt)&.then { |it| "#{unparse(head, opt)}::" }}#{mid}" } end
top-level constant reference format: ::[nd_mid] example: ::object
# File lib/rensei/unparser.rb, line 1106 def NODE_COLON3(node, opt = {}) node.children.then { |mid,| "::#{mid}" } end
constant reference format: [nd_vid](constant) example: X
# File lib/rensei/unparser.rb, line 772 def NODE_CONST(node, opt = {}) node.children.then { |vid,| "#{vid}" } end
class variable reference format: [nd_vid](cvar) example: @@x
# File lib/rensei/unparser.rb, line 781 def NODE_CVAR(node, opt = {}) node.children.then { |vid,| vid.to_s } end
class variable assignment format: [nd_vid](cvar) = [nd_value] example: @@x = foo nd_vid, “class variable”
# File lib/rensei/unparser.rb, line 488 def NODE_CVASGN(node, opt = {}) node.children.then { |vid, value| if value "(#{vid} = #{unparse(value, opt)})" else # Support: `hoge(@@a = 1) { @@a, b = c }` "#{vid}" end } end
dynamic variable assignment (out of current scope) format: [nd_vid](dvar) = [nd_value] example: x = nil; 1.times { x = foo }
# File lib/rensei/unparser.rb, line 438 def NODE_DASGN(node, opt = {}) node.children.then { |vid, value| if value "(#{vid} = #{unparse(value, opt)})" else # Support: `hoge(a = 1) { a, b = c }` "#{vid}" end } end
dynamic variable assignment (in current scope) format: [nd_vid](current dvar) = [nd_value] example: 1.times { x = foo }
# File lib/rensei/unparser.rb, line 452 def NODE_DASGN_CURR(node, opt = {}) node.children.then { |vid, value| if value == :NODE_SPECIAL_REQUIRED_KEYWORD "#{vid}:" elsif opt.delete(:KW_ARG) "#{vid}:#{value&.then { |it| " #{unparse(it, opt)}" }}" elsif value.nil? "#{vid}" elsif opt.delete(:expand_DASGN_CURR) "#{vid} = #{unparse(value, opt)}" elsif value.type == :ERRINFO "=> #{vid}" else "(#{vid} = #{unparse(value, opt)})" end } end
defined? expression format: defined?() example: defined?(foo)
# File lib/rensei/unparser.rb, line 1186 def NODE_DEFINED(node, opt = {}) node.children.then { |head,| "defined?(#{unparse(head, opt)})" } end
method definition format: def [nd_mid] [nd_defn]; end example: def foo; bar; end
# File lib/rensei/unparser.rb, line 1003 def NODE_DEFN(node, opt = {}) node.children.then { |mid, defn| info = unparse_NODE_SCOPE(defn, opt) <<~EOS.chomp def #{mid}(#{info[:args]}) #{info[:body]} end EOS } end
singleton method definition format: def [nd_recv]. [nd_defn]; end example: def obj.foo; bar; end
# File lib/rensei/unparser.rb, line 1017 def NODE_DEFS(node, opt = {}) node.children.then { |recv, mid, defn| info = unparse_NODE_SCOPE(defn, opt) <<~EOS.chomp def #{unparse(recv, opt)}.#{mid}(#{info[:args]}) #{info[:body]} end EOS } end
range constructor (incl.) format: [nd_beg].. example: 1..5
# File lib/rensei/unparser.rb, line 1115 def NODE_DOT2(node, opt = {}) node.children.then { |beg, end_| "(#{unparse(beg, opt)}..#{unparse(end_, opt)})" } end
range constructor (excl.) format: [nd_beg]… example: 1…5
# File lib/rensei/unparser.rb, line 1124 def NODE_DOT3(node, opt = {}) node.children.then { |beg, end_| "(#{unparse(beg, opt)}...#{unparse(end_, opt)})" } end
regexp literal with interpolation format: [nd_lit] example: /foo#{ bar }baz/
# File lib/rensei/unparser.rb, line 904 def NODE_DREGX(node, opt = {}) node.children.then { |prefix, lit, suffix| suffix_ = suffix&.children&.compact&.map { |it| unparse(it, opt).then do |it| it.undump rescue it end }&.join "/#{prefix}#{unparse(lit, opt)}#{suffix_}/" } end
string literal with interpolation format: [nd_lit] example: "foo#{ bar }baz"
# File lib/rensei/unparser.rb, line 878 def NODE_DSTR(node, opt = {}) "\"#{without_DSTR_quote(node, opt)}\"" end
symbol literal with interpolation format: [nd_lit] example: :"foo#{ bar }baz"
# File lib/rensei/unparser.rb, line 920 def NODE_DSYM(node, opt = {}) ":#{NODE_DSTR(node, opt)}" end
dynamic variable reference format: [nd_vid](dvar) example: 1.times { x = 1; x }
# File lib/rensei/unparser.rb, line 754 def NODE_DVAR(node, opt = {}) node.children.then { |vid, dvar| vid.to_s } end
xstring literal with interpolation format: [nd_lit] example: `foo#{ bar }baz`
# File lib/rensei/unparser.rb, line 897 def NODE_DXSTR(node, opt = {}) "`#{without_DSTR_quote(node, opt)}`" end
ensure clause format: begin; [nd_head]; ensure; [nd_ensr]; end example: begin; foo; ensure; bar; end
# File lib/rensei/unparser.rb, line 333 def NODE_ENSURE(node, opt = {}) node.children.then { |head, ensr| <<~EOS.chomp begin #{unparse(head, opt)} ensure #{unparse(ensr, opt)} end EOS } end
virtual reference to $! format: rescue => id example: rescue => id
# File lib/rensei/unparser.rb, line 1179 def NODE_ERRINFO(node, opt = {}) "rescue" end
interpolation expression format: "..#{ [nd_lit] }.." example: "foo#{ bar }baz"
# File lib/rensei/unparser.rb, line 927 def NODE_EVSTR(node, opt = {}) node.children.then { |lit,| "\#{#{unparse(lit, opt)}}" } end
false format: false example: false
# File lib/rensei/unparser.rb, line 1172 def NODE_FALSE(*) "false" end
function call format: [nd_mid]() example: foo(1)
# File lib/rensei/unparser.rb, line 623 def NODE_FCALL(node, opt = {}) node.children.then { |mid, args| opt_flags = _expand_in_XXXCALL(args) # Support `self[key]` if mid == :[] "self[#{unparse(args, opt.merge(opt_flags))}]" else "#{unparse(mid, opt)}(#{unparse(args, opt.merge(opt_flags))})" end } end
flip-flop condition (incl.) format: [nd_beg].. example: if (x==1)..(x==5); foo; end
# File lib/rensei/unparser.rb, line 1133 def NODE_FLIP2(node, opt = {}) node.children.then { |beg, end_| "(#{unparse(beg, opt)})..(#{unparse(end_, opt)})" } end
flip-flop condition (excl.) format: [nd_beg]… example: if (x==1)…(x==5); foo; end
# File lib/rensei/unparser.rb, line 1142 def NODE_FLIP3(node, opt = {}) node.children.then { |beg, end_| "(#{unparse(beg, opt)})...(#{unparse(end_, opt)})" } end
for statement format: for * in [nd_iter] do [nd_body] end example: for i in 1..3 do foo end
# File lib/rensei/unparser.rb, line 215 def NODE_FOR(node, opt = {}) node.children.then { |iter, body, var| scope = unparse_NODE_SCOPE(body, opt) <<~EOS.chomp for #{unparse(scope[:args], opt) || "*"} in #{unparse(iter, opt)} do #{scope[:body]} end EOS } end
vars of for statement with masgn format: for [nd_var] in … do … end example: for x, y in 1..3 do foo end
# File lib/rensei/unparser.rb, line 229 def NODE_FOR_MASGN(node, opt = {}) # Support from NODE_MASGN end
global variable assignment format: [nd_entry](gvar) = [nd_value] example: $x = foo
# File lib/rensei/unparser.rb, line 502 def NODE_GASGN(node, opt = {}) node.children.then { |vid, value| if value "(#{vid} = #{unparse(value, opt)})" else # Support: `hoge($a = 1) { $a, b = c }` "#{vid}" end } end
global variable reference format: [nd_entry](gvar) example: $x
# File lib/rensei/unparser.rb, line 790 def NODE_GVAR(node, opt = {}) node.children.then { |vid,| vid.to_s } end
keyword arguments format: nd_head example: a: 1, b: 2 or hash constructor format: { [nd_head] } example: { 1 => 2, 3 => 4 }
# File lib/rensei/unparser.rb, line 702 def NODE_HASH(node, opt = {}) node.children.then { |head,| if head.nil? "{}" # Support `foo(**kwd)` elsif head.children.first.nil? "**#{unparse(head.children[1], opt)}" else result = (head).children[0..-2].each_slice(2).map { |key, value| if key.nil? "**#{unparse(value, opt)}" elsif key.type == :LIT && Symbol === key.children.first "#{key.children.first}: #{unparse(value, opt)}" else "#{unparse(key, opt)} => #{unparse(value, opt)}" end }.join(", ") if opt[:expand_HASH] "#{result}" else "{ #{result} }" end end } end
instance variable assignment format: [nd_vid](ivar) = [nd_value] example: @x = foo
# File lib/rensei/unparser.rb, line 473 def NODE_IASGN(node, opt = {}) node.children.then { |vid, value| if value "(#{vid} = #{unparse(value, opt)})" else # Support: `hoge(@a = 1) { @a, b = c }` "#{vid}" end } end
if statement format: if [nd_cond] then [nd_body] else [nd_else] end example: if x == 1 then foo else bar end
# File lib/rensei/unparser.rb, line 93 def NODE_IF(node, opt = {}) node.children.then { |cond, body, else_| <<~EOS.chomp (if #{unparse(cond, opt)} #{unparse(body, opt)}#{else_ ? "\nelse\n #{unparse(else_, opt)}" : ""} end) EOS } end
method call with block format: [nd_iter] { [nd_body] } example: 3.times { foo }
# File lib/rensei/unparser.rb, line 206 def NODE_ITER(node, opt = {}) node.children.then { |iter, body| "#{unparse(iter, opt)} { #{unparse(body, opt)} }" } end
instance variable reference format: [nd_vid](ivar) example: @x
# File lib/rensei/unparser.rb, line 763 def NODE_IVAR(node, opt = {}) node.children.then { |vid,| vid.to_s } end
keyword arguments format: def method_name(, [nd_next..]) example: def foo(a:1, b:2); end
# File lib/rensei/unparser.rb, line 1242 def NODE_KW_ARG(node, opt = {}) node.children[0..-1].map(&_unparse(opt.merge(KW_ARG: true))).compact.join(", ") end
lambda expression format: -> [nd_body] example: -> { foo }
# File lib/rensei/unparser.rb, line 1220 def NODE_LAMBDA(node, opt = {}) node.children.then { |scope,| result = unparse_NODE_SCOPE(scope, opt) "-> (#{result[:args]}) { #{result[:body]} }" } end
focal variable assignment lormat: [nd_vid](lvar) = [nd_value] example: x = foo
# File lib/rensei/unparser.rb, line 416 def NODE_LASGN(node, opt = {}) node.children.then { |vid, value| _value = unparse(value, opt) if value == :NODE_SPECIAL_REQUIRED_KEYWORD "#{vid}:" elsif opt.delete(:KW_ARG) "#{vid}:#{value&.then { |it| " #{unparse(it, opt)}" }}" elsif value.nil? || (_value).empty? "#{vid}" elsif opt.delete(:expand_LASGN) "#{vid} = #{_value}" elsif value.type == :ERRINFO "=> #{vid}" else "(#{vid} = #{_value})" end } end
# File lib/rensei/unparser.rb, line 1398 def NODE_LAST(node, opt = {}) "" end
literal format: [nd_lit] example: 1, /foo/
# File lib/rensei/unparser.rb, line 844 def NODE_LIT(node, opt = {}) node.children.first.inspect end
local variable reference format: [nd_vid](lvar) example: x
# File lib/rensei/unparser.rb, line 741 def NODE_LVAR(node, opt = {}) # Support pattern match # in ^expr if opt[:pattern_match_LVAR] "^#{node.children.first}" else "#{node.children.first}" end end
multiple assignment format: [nd_head], [nd_args] = [nd_value] example: a, b = foo
# File lib/rensei/unparser.rb, line 372 def NODE_MASGN(node, opt = {}) node_masgn = opt[:_NODE_MASGN] node.children.then { |right, left, _NODE_SPECIAL_NO_NAME_REST = :dummy| # Support: for x, y in 1..3 do foo end _right = unparse(right, opt)&.then { |it| right.type == :FOR_MASGN || it.empty? ? "" : " = #{it}" } # Support: (a,) = value if _right&.empty? _left = unparse(left, opt.merge(expand_ARRAY: true, ignore_equal_NODE_ATTRASGN: true)) || "*" elsif left if node_masgn && left.children.count <= 2 _left = left.children.map(&_unparse(opt.merge(expand_ARRAY: true, ignore_equal_NODE_ATTRASGN: true))).first else _left = left.children.map(&_unparse(opt.merge(expand_ARRAY: true, ignore_equal_NODE_ATTRASGN: true))).join(", ") end end # Support: for * in 1..3 do foo end # * = foo # a, b, * = foo if _NODE_SPECIAL_NO_NAME_REST # Support `(a, *) = foo` by 2.6 if _NODE_SPECIAL_NO_NAME_REST == :dummy vname = "" elsif _NODE_SPECIAL_NO_NAME_REST != :NODE_SPECIAL_NO_NAME_REST vname = unparse(_NODE_SPECIAL_NO_NAME_REST, opt) end if node_masgn _left = left.nil? || _left.empty? ? "*#{vname}" : "#{_left}, *#{vname}" else _left = left.nil? || _left.empty? ? "*#{vname}" : "#{_left}*#{vname}" end end "(#{_left})#{_right}" } end
match expression (against $_ implicitly) format: [nd_lit] (in condition) example: if /foo/; foo; end
# File lib/rensei/unparser.rb, line 817 def NODE_MATCH(node, opt = {}) node.children.then { |lit,| lit.inspect } end
match expression (regexp first) format: [nd_recv] =~ [nd_value] example: /foo/ =~ 'foo'
# File lib/rensei/unparser.rb, line 826 def NODE_MATCH2(node, opt = {}) node.children.then { |recv, value| "#{unparse(recv, opt)} =~ #{unparse(value, opt)}" } end
match expression (regexp second) format: [nd_recv] =~ [nd_value] example: 'foo' =~ /foo/
# File lib/rensei/unparser.rb, line 835 def NODE_MATCH3(node, opt = {}) node.children.then { |recv, value| "#{unparse(value, opt)} =~ #{unparse(recv, opt)}" } end
module definition format: module [nd_cpath]; [nd_body]; end example: module M; ..; end
# File lib/rensei/unparser.rb, line 1071 def NODE_MODULE(node, opt = {}) node.children.then { |cpath, body| <<~EOS.chomp module #{unparse(cpath, opt)} #{unparse(body, opt.merge(without_BEGIN: true))} end EOS } end
next statement format: next [nd_stts] example: next 1
# File lib/rensei/unparser.rb, line 245 def NODE_NEXT(node, opt = {}) node.children.then { |stts,| "next #{unparse(stts, opt)}" } end
nil format: nil example: nil
# File lib/rensei/unparser.rb, line 1158 def NODE_NIL(*) "nil" end
nth special variable reference format: $[nd_nth] example: $1, $2, ..
# File lib/rensei/unparser.rb, line 799 def NODE_NTH_REF(node, opt = {}) node.children.then { |vid,| vid.to_s } end
once evaluation format: [nd_body] example: /foo#{ bar }baz/o
# File lib/rensei/unparser.rb, line 871 def NODE_ONCE(node, opt = {}) "#{NODE_DREGX(node.children.first, opt)}o" end
method invocation format: [nd_recv] [nd_mid] [nd_args] example: foo + bar
# File lib/rensei/unparser.rb, line 594 def NODE_OPCALL(node, opt = {}) node.children.then { |left, op, right| # Support !hoge if right == nil "(#{op.to_s.delete_suffix("@")}#{unparse(left, opt)})" else "(#{unparse(left, opt)} #{op} #{unparse(right, opt.merge(expand_ARRAY: true))})" end } end
optional arguments format: def method_name(, [nd_next..]) example: def foo(a, b=1, c); end
# File lib/rensei/unparser.rb, line 1230 def NODE_OPT_ARG(node, opt = {}) node.children.map(&_unparse(opt.merge(expand_DASGN_CURR: true, expand_LASGN: true))).compact.join(", ") end
array assignment with operator format: [nd_recv] [ [nd_args->nd_head] ] [nd_mid]= [nd_args->nd_body] example: ary += foo
# File lib/rensei/unparser.rb, line 530 def NODE_OP_ASGN1(node, opt = {}) node.children.then { |recv, op, head, mid| "(#{unparse(recv, opt)}[#{unparse(head, opt.merge(expand_ARRAY: true))}] #{op}= #{unparse(mid, opt.merge(expand_ARRAY: true))})" } end
attr assignment with operator format: [nd_recv]. [nd_next->nd_mid]= [nd_value]
where [attr]: [nd_next->nd_vid]
example: struct.field += foo
# File lib/rensei/unparser.rb, line 540 def NODE_OP_ASGN2(node, opt = {}) raise NoImplemented, "Non supported `struct.field += foo`." end
assignment with && operator format: [nd_head] &&= [nd_value] example: foo &&= bar
# File lib/rensei/unparser.rb, line 547 def NODE_OP_ASGN_AND(node, opt = {}) node.children.then { |head, op, value| # MEMO: implement `foo &&= bar` to `(foo = (foo && bar))` # but, AST is not equal # value_ = value.children.then { |left, right| # "(#{unparse(left, opt)} && #{unparse(right, opt)})" # } # "(#{unparse(head)} = #{value_})" value.children.then { |left, right| "(#{unparse(left, opt)} &&= #{unparse(right, opt)})" } } end
assignment with || operator format: [nd_head] ||= [nd_value] example: foo ||= bar
# File lib/rensei/unparser.rb, line 564 def NODE_OP_ASGN_OR(node, opt = {}) node.children.then { |head, op, value| value.children.then { |left, right| "(#{unparse(left, opt)} ||= #{unparse(right, opt)})" } } end
constant declaration with operator format: [nd_head](constant) [nd_aid]= [nd_value] example: A::B ||= 1
# File lib/rensei/unparser.rb, line 575 def NODE_OP_CDECL(node, opt = {}) node.children.then { |head, aid, value| "(#{unparse(head, opt)} #{aid}= #{unparse(value, opt)})" } end
|| operator format: [nd_1st] || [nd_2nd] example: foo || bar
# File lib/rensei/unparser.rb, line 357 def NODE_OR(node, opt = {}) node.children.then { |args| # Support pattern match # in String | Integer if opt[:pattern_match_OR] "#{args.map { |node| unparse(node, opt) }.join(" | ")}" else "(#{args.map { |node| unparse(node, opt) }.join(" || ")})" end } end
post arguments format: *[nd_1st], [nd_2nd..] = .. example: a, *rest, z = foo
# File lib/rensei/unparser.rb, line 1254 def NODE_POSTARG(node, opt = {}) node.children.then { |_1st, _2nd| "#{unparse(_1st, opt)}, #{unparse(_2nd, opt.merge(expand_ARRAY: true))}" } end
post-execution format: END { [nd_body] } example: END { foo }
# File lib/rensei/unparser.rb, line 1195 def NODE_POSTEXE(node, opt = {}) node.children.then { |body,| "END { #{unparse(body, opt)} }" } end
safe method invocation format: [nd_recv]&.([nd_args]) example: obj&.foo(1)
# File lib/rensei/unparser.rb, line 646 def NODE_QCALL(node, opt = {}) node.children.then { |receiver, mid, args| "#{unparse(receiver, opt)}&.#{unparse(mid, opt)}(#{unparse(args, opt.merge(_expand_in_XXXCALL(args)))})" } end
redo statement format: redo example: redo
# File lib/rensei/unparser.rb, line 263 def NODE_REDO(node, opt = {}) "redo" end
rescue clause (cont'd) format: rescue [nd_args]; [nd_body]; (rescue) [nd_head] example: begin; foo; rescue; bar; else; baz; end
# File lib/rensei/unparser.rb, line 314 def NODE_RESBODY(node, opt = {}) node.children.then { |args, body| args_ = args&.then { |it| unparse(it, opt.merge(expand_ARRAY: true)) } if body.type == :BLOCK if body.children.first&.children[1]&.type == :ERRINFO "rescue #{args_} #{unparse(body, opt.merge(without_BEGIN: true))}" else "rescue #{args_}; #{unparse(body, opt)}" end else # MEMO: Support by `begin; foo; rescue; bar; else; baz; end` "rescue #{args_}; #{unparse(body, opt)}" end } end
rescue clause format: begin; [nd_body]; (rescue) [nd_resq]; else [nd_else]; end example: begin; foo; rescue; bar; else; baz; end
# File lib/rensei/unparser.rb, line 300 def NODE_RESCUE(node, opt = {}) node.children.then { |body, resq, else_| <<~EOS.chomp begin #{unparse(body, opt)} #{unparse(resq, opt)}#{else_ ? "\nelse\n #{unparse(else_)}" : ""} end EOS } end
retry statement format: retry example: retry
# File lib/rensei/unparser.rb, line 270 def NODE_RETRY(node, opt = {}) "retry" end
return statement format: return [nd_stts] example: return 1
# File lib/rensei/unparser.rb, line 254 def NODE_RETURN(node, opt = {}) node.children.then { |stts,| "(return #{unparse(stts, opt)})" } end
singleton class definition format: class << [nd_recv]; [nd_body]; end example: class << obj; ..; end
# File lib/rensei/unparser.rb, line 1084 def NODE_SCLASS(node, opt = {}) node.children.then { |recv, body| <<~EOS.chomp class << #{unparse(recv, opt)} #{unparse(body, opt.merge(without_BEGIN: true))} end EOS } end
new scope format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body
# File lib/rensei/unparser.rb, line 1314 def NODE_SCOPE(node, opt = {}) result = unparse_NODE_SCOPE(node, opt) if result[:args].empty? "#{result[:body]}" elsif opt[:ITER] "|#{result[:args]}| #{result[:body]}" else "|#{result[:args]}| #{result[:body]}" end end
self format: self example: self
# File lib/rensei/unparser.rb, line 1151 def NODE_SELF(*) "self" end
splat argument format: *[nd_head] example: foo(*ary)
# File lib/rensei/unparser.rb, line 985 def NODE_SPLAT(node, opt = {}) node.children.then { |head,| "*#{unparse(head, opt.merge(expand_ARRAY: false))}" } end
string literal format: [nd_lit] example: 'foo'
# File lib/rensei/unparser.rb, line 851 def NODE_STR(node, opt = {}) if opt.delete(:ignore_quote_STR) node.children.first.to_s.escape else node.children.first.inspect end end
super invocation format: super [nd_args] example: super 1
# File lib/rensei/unparser.rb, line 655 def NODE_SUPER(node, opt = {}) node.children.then { |args, | "super(#{unparse(args, opt.merge(expand_ARRAY: true))})" } end
true format: true example: true
# File lib/rensei/unparser.rb, line 1165 def NODE_TRUE(*) "true" end
method undef statement format: undef [nd_undef] example: undef foo
# File lib/rensei/unparser.rb, line 1049 def NODE_UNDEF(node, opt = {}) node.children.then { |nd_undef,| "undef #{unparse(nd_undef, opt)}" } end
unless statement format: unless [nd_cond] then [nd_body] else [nd_else] end example: unless x == 1 then foo else bar end
# File lib/rensei/unparser.rb, line 106 def NODE_UNLESS(node, opt = {}) node.children.then { |cond, body, else_| <<~EOS.chomp (unless #{unparse(cond, opt)} #{unparse(body, opt)}#{else_ ? "\nelse\n #{unparse(else_, opt)}" : ""} end) EOS } end
until statement format: until [nd_cond]; [nd_body]; end example: until x == 1; foo; end
# File lib/rensei/unparser.rb, line 182 def NODE_UNTIL(node, opt = {}) node.children.then { |cond, body, state| # MEMO: state is not supported Ruby 2.6 state = true if state.nil? if state <<~EOS.chomp until #{unparse(cond, opt)} #{unparse(body, opt)} end EOS # state: begin-end-until else <<~EOS.chomp begin #{unparse(body, opt)} end until #{unparse(cond, opt)} EOS end } end
global variable alias statement format: alias [nd_alias](gvar) [nd_orig](gvar) example: alias $y $x
# File lib/rensei/unparser.rb, line 1040 def NODE_VALIAS(node, opt = {}) node.children.then { |nd_1st, nd_2nd| "alias #{nd_1st} #{nd_2nd}" } end
return arguments format: [ [nd_head], [nd_next].. ] (length: [nd_alen]) example: return 1, 2, 3
# File lib/rensei/unparser.rb, line 684 def NODE_VALUES(node, opt = {}) node.children[0..-2].map(&_unparse(opt)).join(", ") end
function call with no argument format: [nd_mid] example: foo
# File lib/rensei/unparser.rb, line 639 def NODE_VCALL(node, opt = {}) node.children.first.to_s end
when clause format: when [nd_head]; [nd_body]; (when or else) [nd_next] example: case x; when 1; foo; when 2; bar; else baz; end
# File lib/rensei/unparser.rb, line 145 def NODE_WHEN(node, opt = {}) node.children.then { |head, body, next_| <<~EOS.chomp when #{unparse(head, opt.merge(expand_ARRAY: true))} #{unparse(body, opt)} #{next_&.type == :WHEN || next_.nil? ? unparse(next_, opt) : "else\n #{unparse(next_, opt)}"} EOS } end
while statement format: while [nd_cond]; [nd_body]; end example: while x == 1; foo; end
# File lib/rensei/unparser.rb, line 158 def NODE_WHILE(node, opt = {}) node.children.then { |cond, body, state| # MEMO: state is not supported Ruby 2.6 state = true if state.nil? if state <<~EOS.chomp while #{unparse(cond, opt)} #{unparse(body, opt)} end EOS # state: begin-end-while else <<~EOS.chomp begin #{unparse(body, opt)} end while #{unparse(cond, opt)} EOS end } end
xstring literal format: [nd_lit] example: `foo`
# File lib/rensei/unparser.rb, line 862 def NODE_XSTR(node, opt = {}) node.children.then { |lit,| "`#{lit.to_s}`" } end
yield invocation format: yield [nd_head] example: yield 1
# File lib/rensei/unparser.rb, line 732 def NODE_YIELD(node, opt = {}) node.children.then { |head,| "yield(#{unparse(head, opt.merge(expand_ARRAY: true))})" } end
empty list constructor format: [] example: []
# File lib/rensei/unparser.rb, line 691 def NODE_ZARRAY(node, opt = {}) "[]" end
super invocation with no argument format: super example: super
# File lib/rensei/unparser.rb, line 664 def NODE_ZSUPER(node, opt = {}) "super" end
# File lib/rensei/unparser.rb, line 605 def _expand_in_XXXCALL(node) case node&.type when :ARRAY, :LIST opt_flags = { expand_ARRAY: true } when :ARGSCAT opt_flags = { expand_ARGSCAT: true } when :ARGSPUSH opt_flags = { expand_ARGSPUSH: true } when :BLOCK_PASS _expand_in_XXXCALL(node.children.first) else opt_flags = { expand_ARRAY: true } end end
# File lib/rensei/unparser.rb, line 54 def _unparse(opt = {}) proc { |node| unparse(node, opt.dup) } end
# File lib/rensei/unparser.rb, line 1278 def unparse_NODE_ARGS(node, opt = {}) %i( pre_num pre_init opt first_post post_num post_init rest kw kwrest block ).map.with_index { |key, i| [key, node.children[i]] }.to_h.then { |info| info.merge( unparsed_pre_init: info[:pre_init]&.then { |node| node.type == :BLOCK ? node.children.map(&_unparse(opt)) : [unparse(node, opt)] } || [], unparsed_post_init: info[:post_init]&.then { |node| node.type == :BLOCK ? node.children.map(&_unparse(opt)) : [unparse(node, opt)] } || [], unparsed_opt: info[:opt]&.then { |it| unparse_NODE_OPT_ARG(it, opt.merge(expand_DASGN_CURR: true, expand_LASGN: true)) } || [], unparsed_rest: unparse(info[:rest], opt)&.then { |it| if it == :NODE_SPECIAL_EXCESSIVE_COMMA [" "] else ["*#{it}"] end } || [], unparsed_kw: info[:kw]&.then { |it| unparse_NODE_KW_ARG(it, opt.merge(expand_DASGN_CURR: true, expand_LASGN: true, KW_ARG: true)) } || [], unparsed_kwrest: info[:kwrest]&.then { |it| "**#{unparse(it, opt)}" }, ) } end
# File lib/rensei/unparser.rb, line 1245 def unparse_NODE_KW_ARG(node, opt = {}) node.children.then { |head, children| [unparse(head, opt)] + (children ? unparse_NODE_KW_ARG(children, opt) : []) } end
# File lib/rensei/unparser.rb, line 1233 def unparse_NODE_OPT_ARG(node, opt = {}) node.children.then { |head, children| [unparse(head, opt)] + (children ? unparse_NODE_OPT_ARG(children, opt) : []) } end
# File lib/rensei/unparser.rb, line 1324 def unparse_NODE_SCOPE(node, opt = {}) node.children.then { |tbl, args, body| break { args: "", body: unparse(body, opt) } if args.nil? info = unparse_NODE_ARGS(args, opt.merge(_NODE_MASGN: true)) # Support proc { |**| } break { args: "**", body: unparse(body, opt) } if tbl == [nil] && info[:kwrest] tbl_ = tbl.dup pre_args = [] [info[:pre_num], info[:unparsed_pre_init]&.size || 0].max.times { tbl_.shift.then { |it| pre_args << (it ? it : info[:unparsed_pre_init].shift) } } # skip to opt args # e.g. a = 1, b = 2 tbl_ = tbl_.drop(info[:unparsed_opt].count) # skip to rest args # e.g. *a tbl_ = tbl_.drop(info[:unparsed_rest].count) star = nil tbl_.take_while(&:nil?).tap { |nils| if info[:unparsed_post_init].count < nils.count star = "*" tbl_ = tbl_.drop(1) end } post_args = [] [info[:post_num], info[:unparsed_post_init]&.size || 0].max.times { tbl_.shift.then { |it| post_args << (it ? it : info[:unparsed_post_init].shift) } } # skip to kw args # e.g. a:, b: c: 1 tbl_ = tbl_.drop(info[:unparsed_kw].count.tap { |count| break count + 1 if count != 0 }) if info[:unparsed_kwrest] == "**" && tbl_.fetch(0, 1) != nil kwrest = "" else kwrest = info[:unparsed_kwrest] end if opt.delete(:ignore_numbered_paramters) pre_args -= [:_1, :_2, :_3, :_4, :_5, :_6, :_7, :_8, :_9] end params = [ pre_args, info[:unparsed_opt].join(", "), info[:unparsed_rest].join(", "), star, post_args, info[:unparsed_post_init].join(", "), info[:unparsed_kw].join(", "), kwrest, info[:block]&.then { |str| "&#{str}" }, ].compact.reject(&:empty?).join(", ") { args: params, body: unparse(body, opt) } } end
# File lib/rensei/unparser.rb, line 881 def without_DSTR_quote(node, opt) node.children.then { |prefix, lit, suffix| suffix_ = suffix&.children&.compact&.map { |it| if it.type == :STR unparse(it, opt.merge(ignore_quote_STR: true)) else unparse(it, opt.merge(ignore_quote_STR: false)) end }&.join "#{prefix&.escape}#{unparse(lit, opt)}#{suffix_}" } end