From 03372d840caf2f59fd537c76a4213282a7d84808 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Mon, 11 Apr 2022 14:59:40 -0400 Subject: [PATCH] Serialize to JSON through a visitor --- lib/syntax_tree.rb | 4 + lib/syntax_tree/json_visitor.rb | 1338 +++++++++++++++++++++++ lib/syntax_tree/node.rb | 1771 +++++++++---------------------- lib/syntax_tree/visitor.rb | 4 +- test/formatting_test.rb | 39 +- test/json_visitor_test.rb | 13 + test/test_helper.rb | 58 + 7 files changed, 1930 insertions(+), 1297 deletions(-) create mode 100644 lib/syntax_tree/json_visitor.rb create mode 100644 test/json_visitor_test.rb diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index 1dcfc348..dde21f18 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "json" require "pp" require "prettyprint" require "ripper" @@ -9,6 +10,9 @@ require_relative "syntax_tree/node" require_relative "syntax_tree/parser" require_relative "syntax_tree/version" +require_relative "syntax_tree/visitor" + +require_relative "syntax_tree/json_visitor" # If PrettyPrint::Align isn't defined, then we haven't gotten the updated # version of prettyprint. In that case we'll define our own. This is going to diff --git a/lib/syntax_tree/json_visitor.rb b/lib/syntax_tree/json_visitor.rb new file mode 100644 index 00000000..a557eab2 --- /dev/null +++ b/lib/syntax_tree/json_visitor.rb @@ -0,0 +1,1338 @@ +# frozen_string_literal: true + +module SyntaxTree + class JSONVisitor < Visitor + def visit_aref(node) + { + type: :aref, + collection: visit(node.collection), + index: visit(node.index), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_aref_field(node) + { + type: :aref_field, + collection: visit(node.collection), + index: visit(node.index), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_alias(node) + { + type: :alias, + left: visit(node.left), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_arg_block(node) + { + type: :arg_block, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_arg_paren(node) + { + type: :arg_paren, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_arg_star(node) + { + type: :arg_star, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_args(node) + { + type: :args, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_args_forward(node) + visit_token(:args_forward, node) + end + + def visit_array(node) + { + type: :array, + cnts: visit(node.contents), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_aryptn(node) + { + type: :aryptn, + constant: visit(node.constant), + reqs: visit_all(node.requireds), + rest: visit(node.rest), + posts: visit_all(node.posts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_assign(node) + { + type: :assign, + target: visit(node.target), + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_assoc(node) + { + type: :assoc, + key: visit(node.key), + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_assoc_splat(node) + { + type: :assoc_splat, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_BEGIN(node) + { + type: :BEGIN, + lbrace: visit(node.lbrace), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_backref(node) + visit_token(:backref, node) + end + + def visit_backtick(node) + visit_token(:backtick, node) + end + + def visit_bare_assoc_hash(node) + { + type: :bare_assoc_hash, + assocs: visit_all(node.assocs), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_begin(node) + { + type: :begin, + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_binary(node) + { + type: :binary, + left: visit(node.left), + op: node.operator, + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_block_arg(node) + { + type: :blockarg, + name: visit(node.name), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_block_var(node) + { + type: :block_var, + params: visit(node.params), + locals: visit_all(node.locals), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_bodystmt(node) + { + type: :bodystmt, + stmts: visit(node.statements), + rsc: visit(node.rescue_clause), + els: visit(node.else_clause), + ens: visit(node.ensure_clause), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_brace_block(node) + { + type: :brace_block, + lbrace: visit(node.lbrace), + block_var: visit(node.block_var), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_break(node) + { + type: :break, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_call(node) + { + type: :call, + receiver: visit(node.receiver), + op: visit_call_operator(node.operator), + message: node.message == :call ? :call : visit(node.message), + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_case(node) + { + type: :case, + value: visit(node.value), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_CHAR(node) + visit_token(:CHAR, node) + end + + def visit_class(node) + { + type: :class, + constant: visit(node.constant), + superclass: visit(node.superclass), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_comma(node) + visit_token(:comma, node) + end + + def visit_command(node) + { + type: :command, + message: visit(node.message), + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_command_call(node) + { + type: :command_call, + receiver: visit(node.receiver), + op: visit_call_operator(node.operator), + message: visit(node.message), + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_comment(node) + { + type: :comment, + value: node.value, + inline: node.inline, + loc: visit_location(node.location) + } + end + + def visit_const(node) + visit_token(:const, node) + end + + def visit_const_path_field(node) + { + type: :const_path_field, + parent: visit(node.parent), + constant: visit(node.constant), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_const_path_ref(node) + { + type: :const_path_ref, + parent: visit(node.parent), + constant: visit(node.constant), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_const_ref(node) + { + type: :const_ref, + constant: visit(node.constant), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_cvar(node) + visit_token(:cvar, node) + end + + def visit_def(node) + { + type: :def, + name: visit(node.name), + params: visit(node.params), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_def_endless(node) + { + type: :def_endless, + name: visit(node.name), + paren: visit(node.paren), + stmt: visit(node.statement), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_defined(node) + visit_token(:defined, node) + end + + def visit_defs(node) + { + type: :defs, + target: visit(node.target), + op: visit(node.operator), + name: visit(node.name), + params: visit(node.params), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_do_block(node) + { + type: :do_block, + keyword: visit(node.keyword), + block_var: visit(node.block_var), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_dot2(node) + { + type: :dot2, + left: visit(node.left), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_dot3(node) + { + type: :dot3, + left: visit(node.left), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_dyna_symbol(node) + { + type: :dyna_symbol, + parts: visit_all(node.parts), + quote: node.quote, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_END(node) + { + type: :END, + lbrace: visit(node.lbrace), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_else(node) + { + type: :else, + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_elsif(node) + { + type: :elsif, + pred: visit(node.predicate), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_embdoc(node) + { + type: :embdoc, + value: node.value, + loc: visit_location(node.location) + } + end + + def visit_embexpr_beg(node) + { + type: :embexpr_beg, + value: node.value, + loc: visit_location(node.location) + } + end + + def visit_embexpr_end(node) + { + type: :embexpr_end, + value: node.value, + loc: visit_location(node.location) + } + end + + def visit_embvar(node) + { + type: :embvar, + value: node.value, + loc: visit_location(node.location) + } + end + + def visit___end__(node) + visit_token(:__end__, node) + end + + def visit_ensure(node) + { + type: :ensure, + keyword: visit(node.keyword), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_excessed_comma(node) + visit_token(:excessed_comma, node) + end + + def visit_fcall(node) + { + type: :fcall, + value: visit(node.value), + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_field(node) + { + type: :field, + parent: visit(node.parent), + op: visit_call_operator(node.operator), + name: visit(node.name), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_float(node) + visit_token(:float, node) + end + + def visit_fndptn(node) + { + type: :fndptn, + constant: visit(node.constant), + left: visit(node.left), + values: visit_all(node.values), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_for(node) + { + type: :for, + index: visit(node.index), + collection: visit(node.collection), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_gvar(node) + visit_token(:gvar, node) + end + + def visit_hash(node) + { + type: :hash, + assocs: visit_all(node.assocs), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_heredoc(node) + { + type: :heredoc, + beging: visit(node.beginning), + ending: node.ending, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_heredoc_beg(node) + visit_token(:heredoc_beg, node) + end + + def visit_hshptn(node) + { + type: :hshptn, + constant: visit(node.constant), + keywords: node.keywords.map { |(name, value)| [visit(name), visit(value)] }, + kwrest: visit(node.keyword_rest), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_ident(node) + visit_token(:ident, node) + end + + def visit_if(node) + { + type: :if, + pred: visit(node.predicate), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_if_mod(node) + { + type: :if_mod, + stmt: visit(node.statement), + pred: visit(node.predicate), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_if_op(node) + { + type: :ifop, + pred: visit(node.predicate), + tthy: visit(node.truthy), + flsy: visit(node.falsy), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_imaginary(node) + visit_token(:imaginary, node) + end + + def visit_in(node) + { + type: :in, + pattern: visit(node.pattern), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_int(node) + visit_token(:int, node) + end + + def visit_ivar(node) + visit_token(:ivar, node) + end + + def visit_kw(node) + visit_token(:kw, node) + end + + def visit_kwrest_param(node) + { + type: :kwrest_param, + name: visit(node.name), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_label(node) + visit_token(:label, node) + end + + def visit_label_end(node) + visit_token(:label_end, node) + end + + def visit_lambda(node) + { + type: :lambda, + params: visit(node.params), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_lbrace(node) + visit_token(:lbrace, node) + end + + def visit_lbracket(node) + visit_token(:lbracket, node) + end + + def visit_lparen(node) + visit_token(:lparen, node) + end + + def visit_massign(node) + { + type: :massign, + target: visit(node.target), + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_method_add_block(node) + { + type: :method_add_block, + call: visit(node.call), + block: visit(node.block), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_mlhs(node) + { + type: :mlhs, + parts: visit_all(node.parts), + comma: node.comma, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_mlhs_paren(node) + { + type: :mlhs_paren, + cnts: visit(node.contents), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_module(node) + { + type: :module, + constant: visit(node.constant), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_mrhs(node) + { + type: :mrhs, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_next(node) + { + type: :next, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_not(node) + { + type: :not, + value: visit(node.statement), + paren: node.parentheses, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_op(node) + visit_token(:op, node) + end + + def visit_op_assign(node) + { + type: :opassign, + target: visit(node.target), + op: visit(node.operator), + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_params(node) + { + type: :params, + reqs: visit_all(node.requireds), + opts: node.optionals.map { |(name, value)| [visit(name), visit(value)] }, + rest: visit(node.rest), + posts: visit_all(node.posts), + keywords: node.keywords.map { |(name, value)| [visit(name), visit(value || nil)] }, + kwrest: node.keyword_rest == :nil ? "nil" : visit(node.keyword_rest), + block: visit(node.block), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_paren(node) + { + type: :paren, + lparen: visit(node.lparen), + cnts: visit(node.contents), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_period(node) + visit_token(:period, node) + end + + def visit_pinned_begin(node) + { + type: :pinned_begin, + stmt: visit(node.statement), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_pinned_var_ref(node) + { + type: :pinned_var_ref, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_program(node) + { + type: :program, + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_qsymbols(node) + { + type: :qsymbols, + elems: visit_all(node.elements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_qsymbols_beg(node) + visit_token(:qsymbols_beg, node) + end + + def visit_qwords(node) + { + type: :qwords, + elems: visit_all(node.elements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_qwords_beg(node) + visit_token(:qwords_beg, node) + end + + def visit_rassign(node) + { + type: :rassign, + value: visit(node.value), + op: visit(node.operator), + pattern: visit(node.pattern), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_rational(node) + visit_token(:rational, node) + end + + def visit_rbrace(node) + visit_token(:rbrace, node) + end + + def visit_rbracket(node) + visit_token(:rbracket, node) + end + + def visit_redo(node) + visit_token(:redo, node) + end + + def visit_regexp_beg(node) + visit_token(:regexp_beg, node) + end + + def visit_regexp_content(node) + { + type: :regexp_content, + beging: node.beginning, + parts: visit_all(node.parts), + loc: visit_location(node.location) + } + end + + def visit_regexp_end(node) + visit_token(:regexp_end, node) + end + + def visit_regexp_literal(node) + { + type: :regexp_literal, + beging: node.beginning, + ending: node.ending, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_rescue(node) + { + type: :rescue, + extn: visit(node.exception), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_rescue_ex(node) + { + type: :rescue_ex, + extns: visit(node.exceptions), + var: visit(node.variable), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_rescue_mod(node) + { + type: :rescue_mod, + stmt: visit(node.statement), + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_rest_param(node) + { + type: :rest_param, + name: visit(node.name), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_retry(node) + visit_token(:retry, node) + end + + def visit_return(node) + { + type: :return, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_return0(node) + visit_token(:return0, node) + end + + def visit_rparen(node) + visit_token(:rparen, node) + end + + def visit_sclass(node) + { + type: :sclass, + target: visit(node.target), + bodystmt: visit(node.bodystmt), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_statements(node) + { + type: :statements, + body: visit_all(node.body), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_string_concat(node) + { + type: :string_concat, + left: visit(node.left), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_string_content(node) + { + type: :string_content, + parts: visit_all(node.parts), + loc: visit_location(node.location) + } + end + + def visit_string_dvar(node) + { + type: :string_dvar, + var: visit(node.variable), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_string_embexpr(node) + { + type: :string_embexpr, + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_string_literal(node) + { + type: :string_literal, + parts: visit_all(node.parts), + quote: node.quote, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_super(node) + { + type: :super, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_symbeg(node) + visit_token(:symbeg, node) + end + + def visit_symbol_content(node) + { + type: :symbol_content, + value: visit(node.value), + loc: visit_location(node.location) + } + end + + def visit_symbol_literal(node) + { + type: :symbol_literal, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_symbols(node) + { + type: :symbols, + elems: visit_all(node.elements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_symbols_beg(node) + visit_token(:symbols_beg, node) + end + + def visit_tlambda(node) + visit_token(:tlambda, node) + end + + def visit_tlambeg(node) + visit_token(:tlambeg, node) + end + + def visit_tstring_beg(node) + visit_token(:tstring_beg, node) + end + + def visit_tstring_content(node) + visit_token(:tstring_content, node) + end + + def visit_tstring_end(node) + visit_token(:tstring_end, node) + end + + def visit_top_const_field(node) + { + type: :top_const_field, + constant: visit(node.constant), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_top_const_ref(node) + { + type: :top_const_ref, + constant: visit(node.constant), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_unary(node) + { + type: :unary, + op: node.operator, + value: visit(node.statement), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_undef(node) + { + type: :undef, + syms: visit_all(node.symbols), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_unless(node) + { + type: :unless, + pred: visit(node.predicate), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_unless_mod(node) + { + type: :unless_mod, + stmt: visit(node.statement), + pred: visit(node.predicate), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_until(node) + { + type: :until, + pred: visit(node.predicate), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_until_mod(node) + { + type: :until_mod, + stmt: visit(node.statement), + pred: visit(node.predicate), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_var_alias(node) + { + type: :var_alias, + left: visit(node.left), + right: visit(node.right), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_var_field(node) + { + type: :var_field, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_var_ref(node) + { + type: :var_ref, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_vcall(node) + { + type: :vcall, + value: visit(node.value), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_void_stmt(node) + { + type: :void_stmt, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_when(node) + { + type: :when, + args: visit(node.arguments), + stmts: visit(node.statements), + cons: visit(node.consequent), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_while(node) + { + type: :while, + pred: visit(node.predicate), + stmts: visit(node.statements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_while_mod(node) + { + type: :while_mod, + stmt: visit(node.statement), + pred: visit(node.predicate), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_word(node) + { + type: :word, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_words(node) + { + type: :words, + elems: visit_all(node.elements), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_words_beg(node) + visit_token(:words_beg, node) + end + + def visit_xstring(node) + { + type: :xstring, + parts: visit_all(node.parts), + loc: visit_location(node.location) + } + end + + def visit_xstring_literal(node) + { + type: :xstring_literal, + parts: visit_all(node.parts), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_yield(node) + { + type: :yield, + args: visit(node.arguments), + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + + def visit_yield0(node) + visit_token(:yield0, node) + end + + def visit_zsuper(node) + visit_token(:zsuper, node) + end + + # Explicitly undefine the default aliased method for each of the visitor + # methods so that if there is one that isn't implemented it will raise an + # error. + undef visit_child_nodes + + private + + def visit_call_operator(operator) + operator == :"::" ? :"::" : visit(operator) + end + + def visit_location(location) + [ + location.start_line, + location.start_char, + location.end_line, + location.end_char + ] + end + + def visit_token(type, node) + { + type: type, + value: node.value, + loc: visit_location(node.location), + cmts: visit_all(node.comments) + } + end + end +end diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 24cb49ea..9081d977 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "syntax_tree/visitor" - module SyntaxTree # Represents the location of a node in the tree from the source code. class Location @@ -33,10 +31,6 @@ def to(other) ) end - def to_json(*opts) - [start_line, start_char, end_line, end_char].to_json(*opts) - end - def self.token(line:, char:, size:) new( start_line: line, @@ -83,7 +77,8 @@ def pretty_print(q) end def to_json(*opts) - raise NotImplementedError + visitor = JSONVisitor.new + visitor.visit(self).to_json(*opts) end end @@ -155,16 +150,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :BEGIN, - lbrace: lbrace, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # CHAR irepresents a single codepoint in the script encoding. @@ -220,12 +205,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :CHAR, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # ENDBlock represents the use of the +END+ keyword, which hooks into the @@ -296,16 +275,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :END, - lbrace: lbrace, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # EndContent represents the use of __END__ syntax, which allows individual @@ -362,12 +331,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :__end__, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Alias represents the use of the +alias+ keyword with regular arguments (not @@ -466,16 +429,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :alias, - left: left, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ARef represents when you're pulling a value out of a collection at a @@ -557,16 +510,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :aref, - collection: collection, - index: index, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ARefField represents assigning values into collections at specific indices. @@ -642,16 +585,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :aref_field, - collection: collection, - index: index, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ArgParen represents wrapping arguments to a method inside a set of @@ -718,15 +651,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :arg_paren, - args: arguments, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Args represents a list of arguments being passed to a method call or array @@ -775,12 +699,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :args, parts: parts, loc: location, cmts: comments }.to_json( - *opts - ) - end end # ArgBlock represents using a block operator on an expression. @@ -831,12 +749,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :arg_block, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Star represents using a splat operator on an expression. @@ -885,12 +797,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :arg_star, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # ArgsForward represents forwarding all kinds of arguments onto another method @@ -951,15 +857,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :args_forward, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ArrayLiteral represents an array literal, which can optionally contain @@ -1117,12 +1014,6 @@ def pretty_print(q) end end - def to_json(*opts) - { type: :array, cnts: contents, loc: location, cmts: comments }.to_json( - *opts - ) - end - private def qwords? @@ -1308,18 +1199,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :aryptn, - constant: constant, - reqs: requireds, - rest: rest, - posts: posts, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Determins if the following value should be indented or not. @@ -1408,16 +1287,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :assign, - target: target, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def skip_indent? @@ -1487,16 +1356,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :assoc, - key: key, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def format_contents(q) @@ -1562,15 +1421,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :assoc_splat, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Backref represents a global variable referencing a matched value. It comes @@ -1619,12 +1469,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :backref, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Backtick represents the use of the ` operator. It's usually found being used @@ -1671,12 +1515,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :backtick, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # This module is responsible for formatting the assocs contained within a @@ -1793,15 +1631,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :bare_assoc_hash, - assocs: assocs, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Begin represents a begin..end chain. @@ -1861,15 +1690,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :begin, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # PinnedBegin represents a pinning a nested statement within pattern matching. @@ -1929,15 +1749,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :pinned_begin, - stmt: statement, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Binary represents any expression that involves two sub-expressions with an @@ -2031,17 +1842,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :binary, - left: left, - op: operator, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # This module will remove any breakables from the list of contents so that no @@ -2155,16 +1955,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :block_var, - params: params, - locals: locals, - loc: location, - cmts: comments - }.to_json(*opts) - end end # BlockArg represents declaring a block parameter on a method definition. @@ -2215,12 +2005,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :blockarg, name: name, loc: location, cmts: comments }.to_json( - *opts - ) - end end # bodystmt can't actually determine its bounds appropriately because it @@ -2372,18 +2156,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :bodystmt, - stmts: statements, - rsc: rescue_clause, - els: else_clause, - ens: ensure_clause, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Responsible for formatting either a BraceBlock or a DoBlock. @@ -2609,17 +2381,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :brace_block, - lbrace: lbrace, - block_var: block_var, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Formats either a Break or Next node. @@ -2722,12 +2483,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :break, args: arguments, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Wraps a call operator (which can be a string literal :: or an Op node or a @@ -2864,18 +2619,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :call, - receiver: receiver, - op: operator, - message: message, - args: arguments, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Case represents the beginning of a case chain. @@ -2965,16 +2708,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :case, - value: value, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # RAssign represents a single-line pattern match. @@ -3054,17 +2787,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :rassign, - value: value, - op: operator, - pattern: pattern, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Class represents defining a class using the +class+ keyword. @@ -3193,17 +2915,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :class, - constant: constant, - superclass: superclass, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Comma represents the use of the , operator. @@ -3211,13 +2922,32 @@ class Comma < Node # [String] the comma in the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_comma(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("comma") + + q.breakable + q.pp(value) + end end end @@ -3290,16 +3020,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :command, - message: message, - args: arguments, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def align?(node) @@ -3410,18 +3130,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :command_call, - receiver: receiver, - op: operator, - message: message, - args: arguments, - loc: location, - cmts: comments - }.to_json(*opts) - end - private # This is a somewhat naive method that is attempting to sum up the width of @@ -3560,15 +3268,6 @@ def pretty_print(q) q.pp(value) end end - - def to_json(*opts) - { - type: :comment, - value: value.force_encoding("UTF-8"), - inline: inline, - loc: location - }.to_json(*opts) - end end # Const represents a literal value that _looks_ like a constant. This could @@ -3626,12 +3325,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :const, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # ConstPathField represents the child node of some kind of assignment. It @@ -3695,16 +3388,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :const_path_field, - parent: parent, - constant: constant, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ConstPathRef represents referencing a constant by a path. @@ -3766,16 +3449,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :const_path_ref, - parent: parent, - constant: constant, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ConstRef represents the name of the constant being used in a class or module @@ -3825,15 +3498,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :const_ref, - constant: constant, - loc: location, - cmts: comments - }.to_json(*opts) - end end # CVar represents the use of a class variable. @@ -3881,12 +3545,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :cvar, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Def represents defining a regular method on the current self object. @@ -3970,17 +3628,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :def, - name: name, - params: params, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # DefEndless represents defining a single-line method since Ruby 3.0+. @@ -4099,17 +3746,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :def_endless, - name: name, - paren: paren, - stmt: statement, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Defined represents the use of the +defined?+ operator. It can be used with @@ -4164,12 +3800,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :defined, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Defs represents defining a singleton method on an object. @@ -4279,19 +3909,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :defs, - target: target, - op: operator, - name: name, - params: params, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # DoBlock represents passing a block to a method call using the +do+ and +end+ @@ -4360,18 +3977,7 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :do_block, - keyword: keyword, - block_var: block_var, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end - end + end # Responsible for formatting Dot2 and Dot3 nodes. class DotFormatter @@ -4463,16 +4069,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :dot2, - left: left, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Dot3 represents using the ... operator between two expressions. Usually this @@ -4539,16 +4135,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :dot3, - left: left, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Responsible for providing information about quotes to be used for strings @@ -4662,16 +4248,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :dyna_symbol, - parts: parts, - quote: quote, - loc: location, - cmts: comments - }.to_json(*opts) - end - private # Here we determine the quotes to use for a dynamic symbol. It's bound by a @@ -4777,12 +4353,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :else, stmts: statements, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Elsif represents another clause in an +if+ or +unless+ chain. @@ -4879,17 +4449,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :elsif, - pred: predicate, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # EmbDoc represents a multi-line comment. @@ -4947,10 +4506,6 @@ def pretty_print(q) q.pp(value) end end - - def to_json(*opts) - { type: :embdoc, value: value, loc: location }.to_json(*opts) - end end # EmbExprBeg represents the beginning token for using interpolation inside of @@ -4963,13 +4518,32 @@ class EmbExprBeg < Node # [String] the #{ used in the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_embexpr_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("embexpr_beg") + + q.breakable + q.pp(value) + end end end @@ -4983,13 +4557,32 @@ class EmbExprEnd < Node # [String] the } used in the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_embexpr_end(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("embexpr_end") + + q.breakable + q.pp(value) + end end end @@ -5005,13 +4598,32 @@ class EmbVar < Node # [String] the # used in the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_embvar(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("embvar") + + q.breakable + q.pp(value) + end end end @@ -5079,16 +4691,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :ensure, - keyword: keyword, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ExcessedComma represents a trailing comma in a list of block parameters. It @@ -5142,15 +4744,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :excessed_comma, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # FCall represents the piece of a method call that comes before any arguments @@ -5216,16 +4809,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :fcall, - value: value, - args: arguments, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Field is always the child of an assignment. It represents assigning to a @@ -5298,17 +4881,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :field, - parent: parent, - op: operator, - name: name, - loc: location, - cmts: comments - }.to_json(*opts) - end end # FloatLiteral represents a floating point number literal. @@ -5356,12 +4928,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :float, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # FndPtn represents matching against a pattern where you find a pattern in an @@ -5454,18 +5020,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :fndptn, - constant: constant, - left: left, - values: values, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # For represents using a +for+ loop. @@ -5550,17 +5104,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :for, - index: index, - collection: collection, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # GVar represents a global variable literal. @@ -5608,12 +5151,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :gvar, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # HashLiteral represents a hash literal. @@ -5676,12 +5213,6 @@ def pretty_print(q) end end - def to_json(*opts) - { type: :hash, assocs: assocs, loc: location, cmts: comments }.to_json( - *opts - ) - end - private def format_contents(q) @@ -5790,17 +5321,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :heredoc, - beging: beginning, - ending: ending, - parts: parts, - loc: location, - cmts: comments - }.to_json(*opts) - end end # HeredocBeg represents the beginning declaration of a heredoc. @@ -5851,15 +5371,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :heredoc_beg, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # HshPtn represents matching against a hash pattern using the Ruby 2.7+ @@ -6011,17 +5522,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :hshptn, - constant: constant, - keywords: keywords, - kwrest: keyword_rest, - loc: location, - cmts: comments - }.to_json(*opts) - end end # The list of nodes that represent patterns inside of pattern matching so that @@ -6074,15 +5574,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :ident, - value: value.force_encoding("UTF-8"), - loc: location, - cmts: comments - }.to_json(*opts) - end end # If the predicate of a conditional or loop contains an assignment (in which @@ -6237,17 +5728,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :if, - pred: predicate, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # IfOp represents a ternary clause. @@ -6328,17 +5808,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :ifop, - pred: predicate, - tthy: truthy, - flsy: falsy, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def format_break(q) @@ -6477,16 +5946,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :if_mod, - stmt: statement, - pred: predicate, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Imaginary represents an imaginary number literal. @@ -6534,12 +5993,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :imaginary, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # In represents using the +in+ keyword within the Ruby 2.7+ pattern matching @@ -6629,17 +6082,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :in, - pattern: pattern, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Int represents an integer number literal. @@ -6695,10 +6137,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :int, value: value, loc: location, cmts: comments }.to_json(*opts) - end end # IVar represents an instance variable literal. @@ -6746,12 +6184,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :ivar, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Kw represents the use of a keyword. It can be almost anywhere in the syntax @@ -6808,10 +6240,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :kw, value: value, loc: location, cmts: comments }.to_json(*opts) - end end # KwRestParam represents defining a parameter in a method definition that @@ -6861,15 +6289,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :kwrest_param, - name: name, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Label represents the use of an identifier to associate with an object. You @@ -6927,12 +6346,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :label, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # LabelEnd represents the end of a dynamic symbol. @@ -6946,13 +6359,32 @@ class LabelEnd < Node # [String] the end of the label attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_label_end(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("label_end") + + q.breakable + q.pp(value) + end end end @@ -7044,16 +6476,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :lambda, - params: params, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # LBrace represents the use of a left brace, i.e., {. @@ -7098,12 +6520,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :lbrace, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # LBracket represents the use of a left bracket, i.e., [. @@ -7148,12 +6564,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :lbracket, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # LParen represents the use of a left parenthesis, i.e., (. @@ -7198,12 +6608,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :lparen, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # MAssign is a parent node of any kind of multiple assignment. This includes @@ -7275,16 +6679,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :massign, - target: target, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # MethodAddBlock represents a method call with a block argument. @@ -7340,17 +6734,7 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :method_add_block, - call: call, - block: block, - loc: location, - cmts: comments - }.to_json(*opts) - end - end + end # MLHS represents a list of values being destructured on the left-hand side # of a multiple assignment. @@ -7406,16 +6790,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :mlhs, - parts: parts, - comma: comma, - loc: location, - cmts: comments - }.to_json(*opts) - end end # MLHSParen represents parentheses being used to destruct values in a multiple @@ -7477,15 +6851,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :mlhs_paren, - cnts: contents, - loc: location, - cmts: comments - }.to_json(*opts) - end end # ModuleDeclaration represents defining a module using the +module+ keyword. @@ -7571,16 +6936,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :module, - constant: constant, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # MRHS represents the values that are being assigned on the right-hand side of @@ -7629,12 +6984,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :mrhs, parts: parts, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Next represents using the +next+ keyword. @@ -7695,12 +7044,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :next, args: arguments, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Op represents an operator literal in the source. @@ -7749,10 +7092,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :op, value: value, loc: location, cmts: comments }.to_json(*opts) - end end # OpAssign represents assigning a value to a variable or constant using an @@ -7837,17 +7176,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :opassign, - target: target, - op: operator, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def skip_indent? @@ -8178,21 +7506,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :params, - reqs: requireds, - opts: optionals, - rest: rest, - posts: posts, - keywords: keywords, - kwrest: keyword_rest, - block: block, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Paren represents using balanced parentheses in a couple places in a Ruby @@ -8263,16 +7576,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :paren, - lparen: lparen, - cnts: contents, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Period represents the use of the +.+ operator. It is usually found in method @@ -8318,12 +7621,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :period, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Program represents the overall syntax tree. @@ -8373,16 +7670,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :program, - stmts: statements, - comments: comments, - loc: location, - cmts: comments - }.to_json(*opts) - end end # QSymbols represents a symbol literal array without interpolation. @@ -8454,15 +7741,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :qsymbols, - elems: elements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # QSymbolsBeg represents the beginning of a symbol literal array. @@ -8476,13 +7754,32 @@ class QSymbolsBeg < Node # [String] the beginning of the array literal attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_qsymbols_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("qsymbols_beg") + + q.breakable + q.pp(value) + end end end @@ -8555,12 +7852,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :qwords, elems: elements, loc: location, cmts: comments }.to_json( - *opts - ) - end end # QWordsBeg represents the beginning of a string literal array. @@ -8574,13 +7865,32 @@ class QWordsBeg < Node # [String] the beginning of the array literal attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_qwords_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("qwords_beg") + + q.breakable + q.pp(value) + end end end @@ -8629,12 +7939,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :rational, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # RBrace represents the use of a right brace, i.e., +++. @@ -8642,13 +7946,32 @@ class RBrace < Node # [String] the right brace attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_rbrace(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("rbrace") + + q.breakable + q.pp(value) + end end end @@ -8657,13 +7980,32 @@ class RBracket < Node # [String] the right bracket attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_rbracket(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("rbracket") + + q.breakable + q.pp(value) + end end end @@ -8712,12 +8054,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :redo, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # RegexpContent represents the body of a regular expression. @@ -8734,15 +8070,34 @@ class RegexpContent < Node # regular expression attr_reader :parts - def accept(visitor) - visitor.visit_regexp_content(self) - end - def initialize(beginning:, parts:, location:) @beginning = beginning @parts = parts @location = location end + + def accept(visitor) + visitor.visit_regexp_content(self) + end + + def child_nodes + parts + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { beginning: beginning, parts: parts, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("regexp_content") + + q.breakable + q.group(2, "(", ")") { q.seplist(parts) { |part| q.pp(part) } } + end + end end # RegexpBeg represents the start of a regular expression literal. @@ -8758,13 +8113,32 @@ class RegexpBeg < Node # [String] the beginning of the regular expression attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_regexp_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("regexp_beg") + + q.breakable + q.pp(value) + end end end @@ -8782,13 +8156,32 @@ class RegexpEnd < Node # [String] the end of the regular expression attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_regexp_end(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("regexp_end") + + q.breakable + q.pp(value) + end end end @@ -8889,17 +8282,6 @@ def pretty_print(q) end end - def to_json(*opts) - { - type: :regexp_literal, - beging: beginning, - ending: ending, - parts: parts, - loc: location, - cmts: comments - }.to_json(*opts) - end - private def include?(pattern) @@ -8991,16 +8373,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :rescue_ex, - extns: exceptions, - var: variable, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Rescue represents the use of the rescue keyword inside of a BodyStmt node. @@ -9123,17 +8495,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :rescue, - extn: exception, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # RescueMod represents the use of the modifier form of a +rescue+ clause. @@ -9205,16 +8566,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :rescue_mod, - stmt: statement, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # RestParam represents defining a parameter in a method definition that @@ -9264,12 +8615,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :rest_param, name: name, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Retry represents the use of the +retry+ keyword. @@ -9317,12 +8662,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :retry, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Return represents using the +return+ keyword with arguments. @@ -9370,12 +8709,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :return, args: arguments, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Return0 represents the bare +return+ keyword with no arguments. @@ -9423,12 +8756,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :return0, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # RParen represents the use of a right parenthesis, i.e., +)+. @@ -9436,13 +8763,32 @@ class RParen < Node # [String] the parenthesis attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_rparen(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("rparen") + + q.breakable + q.pp(value) + end end end @@ -9513,16 +8859,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :sclass, - target: target, - bodystmt: bodystmt, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Everything that has a block of code inside of it has a list of statements. @@ -9666,12 +9002,6 @@ def pretty_print(q) end end - def to_json(*opts) - { type: :statements, body: body, loc: location, cmts: comments }.to_json( - *opts - ) - end - private # As efficiently as possible, gather up all of the comments that have been @@ -9716,13 +9046,32 @@ class StringContent < Node # string attr_reader :parts + def initialize(parts:, location:) + @parts = parts + @location = location + end + def accept(visitor) visitor.visit_string_content(self) end - def initialize(parts:, location:) - @parts = parts - @location = location + def child_nodes + parts + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { parts: parts, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("string_content") + + q.breakable + q.group(2, "(", ")") { q.seplist(parts) { |part| q.pp(part) } } + end end end @@ -9787,16 +9136,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :string_concat, - left: left, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # StringDVar represents shorthand interpolation of a variable into a string. @@ -9848,15 +9187,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :string_dvar, - var: variable, - loc: location, - cmts: comments - }.to_json(*opts) - end end # StringEmbExpr represents interpolated content. It can be contained within a @@ -9923,15 +9253,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :string_embexpr, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # StringLiteral represents a string literal. @@ -10010,16 +9331,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :string_literal, - parts: parts, - quote: quote, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Super represents using the +super+ keyword with arguments. It can optionally @@ -10077,12 +9388,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :super, args: arguments, loc: location, cmts: comments }.to_json( - *opts - ) - end end # SymBeg represents the beginning of a symbol literal. @@ -10105,14 +9410,33 @@ class SymBeg < Node # [String] the beginning of the symbol attr_reader :value - def accept(visitor) - visitor.visit_sym_beg(self) - end - def initialize(value:, location:) @value = value @location = location end + + def accept(visitor) + visitor.visit_symbeg(self) + end + + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("symbeg") + + q.breakable + q.pp(value) + end + end end # SymbolContent represents symbol contents and is always the child of a @@ -10125,13 +9449,32 @@ class SymbolContent < Node # symbol attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_symbol_content(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("symbol_content") + + q.breakable + q.pp(value) + end end end @@ -10183,15 +9526,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :symbol_literal, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Symbols represents a symbol array literal with interpolation. @@ -10263,15 +9597,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :symbols, - elems: elements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # SymbolsBeg represents the start of a symbol array literal with @@ -10286,13 +9611,32 @@ class SymbolsBeg < Node # [String] the beginning of the symbol literal array attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_symbols_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("symbols_beg") + + q.breakable + q.pp(value) + end end end @@ -10305,13 +9649,32 @@ class TLambda < Node # [String] the beginning of the lambda literal attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_tlambda(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("tlambda") + + q.breakable + q.pp(value) + end end end @@ -10325,13 +9688,32 @@ class TLamBeg < Node # [String] the beginning of the body of the lambda literal attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_tlambeg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("tlambeg") + + q.breakable + q.pp(value) + end end end @@ -10383,15 +9765,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :top_const_field, - constant: constant, - loc: location, - cmts: comments - }.to_json(*opts) - end end # TopConstRef is very similar to TopConstField except that it is not involved @@ -10441,15 +9814,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :top_const_ref, - constant: constant, - loc: location, - cmts: comments - }.to_json(*opts) - end end # TStringBeg represents the beginning of a string literal. @@ -10466,13 +9830,32 @@ class TStringBeg < Node # [String] the beginning of the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_tstring_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("tstring_beg") + + q.breakable + q.pp(value) + end end end @@ -10529,15 +9912,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :tstring_content, - value: value.force_encoding("UTF-8"), - loc: location, - cmts: comments - }.to_json(*opts) - end end # TStringEnd represents the end of a string literal. @@ -10554,13 +9928,32 @@ class TStringEnd < Node # [String] the end of the string attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_tstring_end(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("tstring_end") + + q.breakable + q.pp(value) + end end end @@ -10620,16 +10013,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :not, - value: statement, - paren: parentheses, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Unary represents a unary method being called on an expression, as in +!+ or @@ -10691,16 +10074,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :unary, - op: operator, - value: statement, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Undef represents the use of the +undef+ keyword. @@ -10777,12 +10150,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :undef, syms: symbols, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Unless represents the first clause in an +unless+ chain. @@ -10859,17 +10226,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :unless, - pred: predicate, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # UnlessMod represents the modifier form of an +unless+ statement. @@ -10929,16 +10285,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :unless_mod, - stmt: statement, - pred: predicate, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Formats an Until, UntilMod, While, or WhileMod node. @@ -11059,16 +10405,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :until, - pred: predicate, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # UntilMod represents the modifier form of a +until+ loop. @@ -11148,16 +10484,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :until_mod, - stmt: statement, - pred: predicate, - loc: location, - cmts: comments - }.to_json(*opts) - end end # VarAlias represents when you're using the +alias+ keyword with global @@ -11218,16 +10544,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :var_alias, - left: left, - right: right, - loc: location, - cmts: comments - }.to_json(*opts) - end end # VarField represents a variable that is being assigned a value. As such, it @@ -11277,12 +10593,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :var_field, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # VarRef represents a variable reference. @@ -11334,12 +10644,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :var_ref, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # PinnedVarRef represents a pinned variable reference within a pattern @@ -11395,15 +10699,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :pinned_var_ref, - value: value, - loc: location, - cmts: comments - }.to_json(*opts) - end end # VCall represent any plain named object with Ruby that could be either a @@ -11452,12 +10747,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :vcall, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # VoidStmt represents an empty lexical block of code. @@ -11499,10 +10788,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :void_stmt, loc: location, cmts: comments }.to_json(*opts) - end end # When represents a +when+ clause in a +case+ chain. @@ -11614,17 +10899,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :when, - args: arguments, - stmts: statements, - cons: consequent, - loc: location, - cmts: comments - }.to_json(*opts) - end end # While represents a +while+ loop. @@ -11696,16 +10970,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :while, - pred: predicate, - stmts: statements, - loc: location, - cmts: comments - }.to_json(*opts) - end end # WhileMod represents the modifier form of a +while+ loop. @@ -11785,16 +11049,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :while_mod, - stmt: statement, - pred: predicate, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Word represents an element within a special array literal that accepts @@ -11850,12 +11104,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :word, parts: parts, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Words represents a string literal array with interpolation. @@ -11927,12 +11175,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :words, elems: elements, loc: location, cmts: comments }.to_json( - *opts - ) - end end # WordsBeg represents the beginning of a string literal array with @@ -11947,13 +11189,32 @@ class WordsBeg < Node # [String] the start of the word literal array attr_reader :value + def initialize(value:, location:) + @value = value + @location = location + end + def accept(visitor) visitor.visit_words_beg(self) end - def initialize(value:, location:) - @value = value - @location = location + def child_nodes + [] + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { value: value, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("words_beg") + + q.breakable + q.pp(value) + end end end @@ -11966,13 +11227,32 @@ class XString < Node # xstring attr_reader :parts + def initialize(parts:, location:) + @parts = parts + @location = location + end + def accept(visitor) visitor.visit_xstring(self) end - def initialize(parts:, location:) - @parts = parts - @location = location + def child_nodes + parts + end + + alias deconstruct child_nodes + + def deconstruct_keys(keys) + { parts: parts, location: location } + end + + def pretty_print(q) + q.group(2, "(", ")") do + q.text("xstring") + + q.breakable + q.group(2, "(", ")") { q.seplist(parts) { |part| q.pp(part) } } + end end end @@ -12024,15 +11304,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { - type: :xstring_literal, - parts: parts, - loc: location, - cmts: comments - }.to_json(*opts) - end end # Yield represents using the +yield+ keyword with arguments. @@ -12094,12 +11365,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :yield, args: arguments, loc: location, cmts: comments }.to_json( - *opts - ) - end end # Yield0 represents the bare +yield+ keyword with no arguments. @@ -12147,12 +11412,6 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :yield0, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end # ZSuper represents the bare +super+ keyword with no arguments. @@ -12200,11 +11459,5 @@ def pretty_print(q) q.pp(Comment::List.new(comments)) end end - - def to_json(*opts) - { type: :zsuper, value: value, loc: location, cmts: comments }.to_json( - *opts - ) - end end end diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 27561cdf..c14dbffa 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -58,7 +58,7 @@ def visit(node) end def visit_all(nodes) - nodes.each { |node| visit(node) } + nodes.map { |node| visit(node) } end def visit_child_nodes(node) @@ -444,7 +444,7 @@ def visit_child_nodes(node) alias visit_super visit_child_nodes # Visit a SymBeg node. - alias visit_sym_beg visit_child_nodes + alias visit_symbeg visit_child_nodes # Visit a SymbolContent node. alias visit_symbol_content visit_child_nodes diff --git a/test/formatting_test.rb b/test/formatting_test.rb index 4b649052..25059658 100644 --- a/test/formatting_test.rb +++ b/test/formatting_test.rb @@ -4,42 +4,9 @@ module SyntaxTree class FormattingTest < Minitest::Test - FIXTURES_3_0_0 = %w[ - command_def_endless - def_endless - fndptn - rassign - rassign_rocket - ] - - FIXTURES_3_1_0 = %w[ - pinned_begin - var_field_rassign - ] - - fixtures = Dir[File.join(__dir__, "fixtures", "*.rb")].map { |filepath| File.basename(filepath, ".rb") } - fixtures -= FIXTURES_3_1_0 if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.1.0") - fixtures -= FIXTURES_3_0_0 if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.0.0") - - delimiter = /%(?: # (.+?))?\n/ - fixtures.each do |fixture| - filepath = File.join(__dir__, "fixtures", "#{fixture}.rb") - - File.readlines(filepath).slice_before(delimiter).each_with_index do |source, index| - comment = source.shift.match(delimiter)[1] - original, expected = source.join.split("-\n") - - # If there's a comment starting with >= that starts after the % that - # delineates the test, then we're going to check if the version - # satisfies that constraint. - if comment&.start_with?(">=") - version = Gem::Version.new(comment.split[1]) - next if Gem::Version.new(RUBY_VERSION) < version - end - - define_method(:"test_formatting_#{fixture}_#{index}") do - assert_equal(expected || original, SyntaxTree.format(original)) - end + Fixtures.each_fixture do |fixture| + define_method(:"test_formatted_#{fixture.name}") do + assert_equal(fixture.formatted, SyntaxTree.format(fixture.source)) end end end diff --git a/test/json_visitor_test.rb b/test/json_visitor_test.rb new file mode 100644 index 00000000..917aca71 --- /dev/null +++ b/test/json_visitor_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +module SyntaxTree + class JSONVisitorTest < Minitest::Test + Fixtures.each_fixture do |fixture| + define_method(:"test_json_#{fixture.name}") do + refute_includes(SyntaxTree.format(fixture.source).to_json, "#<") + end + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 8512253c..09c4dd0a 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -9,3 +9,61 @@ require "json" require "pp" require "minitest/autorun" + +# There are a bunch of fixtures defined in test/fixtures. They exercise every +# possible combination of syntax that leads to variations in the types of nodes. +# They are used for testing various parts of Syntax Tree, including formatting, +# serialization, and parsing. This module provides a single each_fixture method +# that can be used to drive tests on each fixture. +module Fixtures + FIXTURES_3_0_0 = %w[ + command_def_endless + def_endless + fndptn + rassign + rassign_rocket + ] + + FIXTURES_3_1_0 = %w[ + pinned_begin + var_field_rassign + ] + + Fixture = Struct.new(:name, :source, :formatted, keyword_init: true) + + def self.each_fixture + ruby_version = Gem::Version.new(RUBY_VERSION) + + # First, get a list of the basenames of all of the fixture files. + fixtures = + Dir[File.expand_path("fixtures/*.rb", __dir__)].map do |filepath| + File.basename(filepath, ".rb") + end + + # Next, subtract out any fixtures that aren't supported by the current Ruby + # version. + fixtures -= FIXTURES_3_1_0 if ruby_version < Gem::Version.new("3.1.0") + fixtures -= FIXTURES_3_0_0 if ruby_version < Gem::Version.new("3.0.0") + + delimiter = /%(?: # (.+?))?\n/ + fixtures.each do |fixture| + filepath = File.expand_path("fixtures/#{fixture}.rb", __dir__) + + # For each fixture in the fixture file yield a Fixture object. + File.readlines(filepath).slice_before(delimiter).each_with_index do |source, index| + comment = source.shift.match(delimiter)[1] + source, formatted = source.join.split("-\n") + + # If there's a comment starting with >= that starts after the % that + # delineates the test, then we're going to check if the version + # satisfies that constraint. + if comment&.start_with?(">=") + next if ruby_version < Gem::Version.new(comment.split[1]) + end + + name = :"#{fixture}_#{index}" + yield Fixture.new(name: name, source: source, formatted: formatted || source) + end + end + end +end