Skip to content

Instantly share code, notes, and snippets.

@LItterBoy-GB
Forked from fate0/node2ruby.c
Last active January 25, 2022 07:36
Show Gist options
  • Save LItterBoy-GB/ccccb79e22778304fbc576b8ebd86080 to your computer and use it in GitHub Desktop.
Save LItterBoy-GB/ccccb79e22778304fbc576b8ebd86080 to your computer and use it in GitHub Desktop.
turn ruby ast to ruby source code
/**********************************************************************
node2ruby.c - ruby node tree to ruby source code
Copyright (C) 2017 fate0
//在 iseq.c 中实现 rb_iseq_nex
VALUE
rb_iseq_nex(NODE *node, VALUE name, VALUE path, VALUE absolute_path,
VALUE parent, enum iseq_type type)
{
rb_io_write(rb_stdout, rb_parser_dump_tree(node, 0));
printf("\n\n");
return rb_iseq_new(node, name, path, absolute_path, parent, type);
}
//实现 vm.c 中实现 rb_iseq_evax
VALUE
rb_iseq_evax(VALUE iseqval)
{
rb_io_write(rb_stdout, rb_iseq_disasm(iseqval));
return 0;
}
**********************************************************************/
#include "ruby/ruby.h"
#include "vm_core.h"
#define A(str) \
do { \
if ((str)) { \
rb_str_cat2(result, (str)); \
} \
} while (0)
#define AR(str) \
do { \
if ((str)) { \
rb_str_concat(result, (str)); \
} \
} while (0)
#define AD(str) \
do { \
AR(indent_str); \
A(str); \
} while (0)
#define ARD(str) \
do { \
AR(indent_str); \
AR(str); \
} while (0)
#define AD_IF_N(str) \
do { \
if (indent && new_line) { \
AR(indent_str); \
} \
A(str); \
} while (0)
#define ARD_IF_N(str) \
do { \
if (indent && new_line) { \
AR(indent_str); \
} \
AR(str); \
} while (0)
#define F_ID(name, comment) find_id(node->name)
#define F_GENTRY(name, comment) find_id((node->name)->id)
#define F_INT(name, comment) find_int(node->name)
#define F_LONG(name, comment) find_long(node->name)
#define F_LIT(name, comment) find_lit(node->name)
#define F_NODE(name, comment, new_line) dump_node(node->name, node, indent, new_line)
#define F_NODE_ONEL(name, comment) dump_node(node->name, node, indent, 0)
#define F_NODE_NEWL(name, comment) dump_node(node->name, node, indent, 1)
#define F_NODE_NEWL_D(name, comment) dump_node(node->name, node, indent+1, 1)
#define F_ARGS(name) parse_args(node->name, indent)
static VALUE dump_node(NODE *node, NODE *p_node, int indent, int new_line);
static VALUE
find_id(ID id) {
VALUE result = rb_str_new_cstr("");
if (id == 0) {
return result;
} else {
VALUE str = rb_id2str(id);
if (str) {
return str;
} else {
return result;
}
}
}
static VALUE
find_int(int val) {
VALUE result = rb_str_new_cstr("");
rb_str_catf(result, "%d", (val));
return result;
}
static VALUE
find_long(long val) {
VALUE result = rb_str_new_cstr("");
rb_str_catf(result, "%ld", (val));
return result;
}
static VALUE
find_lit(VALUE lit) {
VALUE result = rb_str_new_cstr("");
AR(rb_inspect(lit));
return result;
}
static VALUE
parse_args(NODE *node, int indent) {
VALUE result = rb_str_new_cstr("");
int index = 0;
if (!node || !node->nd_args || (node && nd_type(node) != NODE_SCOPE)) {
return result;
}
NODE *node_arg = node->nd_args;
int has_prefix_arg = 0;
VALUE ary_tbl = rb_ary_new();
ID *tbl = node->nd_tbl;
int size = tbl ? (int) *tbl++ : 0;
if (size == 0) {
return result;
}
for (int i = 0; i < size; i++) {
rb_ary_push(ary_tbl, find_id(tbl[i]));
}
if (node_arg->nd_ainfo->pre_init) {
NODE *pre_init = node_arg->nd_ainfo->pre_init;
if (nd_type(pre_init) == NODE_LASGN ||
nd_type(pre_init) == NODE_DASGN ||
nd_type(pre_init) == NODE_DASGN_CURR) {
VALUE for_var = find_id(node_arg->nd_ainfo->pre_init->nd_vid);
return for_var;
} else {
pre_init->nd_next;
if (pre_init && pre_init->nd_next && pre_init->nd_next->nd_head) {
VALUE for_var = dump_node(pre_init->nd_next->nd_head, pre_init->nd_next, 0, 0);
return for_var;
}
}
} else if (node_arg->nd_ainfo->post_init) {
// unknown
}
if (node_arg->nd_ainfo->pre_args_num) {
has_prefix_arg = 1;
for (; index < node_arg->nd_ainfo->pre_args_num; index++) {
VALUE pre_arg = rb_funcall(ary_tbl, rb_intern("[]"), 1, INT2NUM(index));
AR(pre_arg);
if ((index + 1) != node_arg->nd_ainfo->pre_args_num) {
A(", ");
}
}
}
if (node_arg->nd_ainfo->opt_args) {
VALUE opt_args = F_NODE_ONEL(nd_args->nd_ainfo->opt_args, "");
if (has_prefix_arg) {
A(", ");
} else {
has_prefix_arg = 1;
}
AR(opt_args);
}
if (node_arg->nd_ainfo->rest_arg) {
VALUE rest_arg = F_ID(nd_args->nd_ainfo->rest_arg, "rest argument");
if (has_prefix_arg) {
A(", ");
} else {
has_prefix_arg = 1;
}
A("*");
AR(rest_arg);
}
if (node_arg->nd_ainfo->post_args_num) {
VALUE first_post_arg = F_ID(nd_args->nd_ainfo->first_post_arg, "first post argument");
VALUE first_post_arg_index = rb_funcall(ary_tbl, rb_intern("index"), 1, first_post_arg);
if (first_post_arg_index != Qnil) {
for (int i=0; i < node_arg->nd_ainfo->post_args_num; i++) {
VALUE post_arg = rb_funcall(ary_tbl, rb_intern("[]"), 1, INT2NUM(NUM2INT(first_post_arg_index)+i));
A(", ");
AR(post_arg);
}
}
}
if (node_arg->nd_ainfo->kw_args) {
VALUE kw_args = F_NODE_ONEL(nd_args->nd_ainfo->kw_args, "keyword arguments");
if (has_prefix_arg) {
A(", ");
} else {
has_prefix_arg = 1;
}
AR(kw_args);
}
if (node_arg->nd_ainfo->kw_rest_arg) {
VALUE kw_rest_arg = 0;
if (node_arg->nd_ainfo->kw_args && node_arg->nd_ainfo->kw_rest_arg->nd_cflag != 0) {
kw_rest_arg = F_ID(nd_args->nd_ainfo->kw_rest_arg->nd_cflag, "keyword rest argument");
} else {
kw_rest_arg = F_NODE_ONEL(nd_args->nd_ainfo->kw_rest_arg, "keyword rest argument");
}
if (kw_rest_arg && RSTRING_LEN(kw_rest_arg) > 0) {
if (has_prefix_arg) {
A(", ");
} else {
has_prefix_arg = 1;
}
A("**");
AR(kw_rest_arg);
}
}
if (node_arg->nd_ainfo->block_arg) {
if (has_prefix_arg) {
A(", ");
} else {
has_prefix_arg = 1;
}
A("&");
AR(F_ID(nd_args->nd_ainfo->block_arg, ""));
}
return result;
}
static VALUE
dump_node(NODE *node, NODE *p_node, int indent, int new_line) {
VALUE result = rb_str_new_cstr("");
if (!node) {
return result;
}
VALUE each_indent_str = rb_str_new_cstr(" ");
VALUE indent_str = rb_funcall(each_indent_str, rb_intern("*"), 1, INT2NUM(indent));
VALUE nd_string1;
VALUE nd_string2;
VALUE nd_string3;
VALUE nd_string4;
VALUE nd_string5;
switch (nd_type(node)) {
case NODE_BLOCK:
/*
nd_string1
nd_string2
*/
nd_string1 = F_NODE_NEWL(nd_head, "current statement");
nd_string2 = F_NODE_NEWL(nd_next, "next block");
AR(nd_string1);
if (RSTRING_LEN(nd_string2) != 0) {
if (RSTRING_LEN(nd_string1) != 0) {
A("\n");
}
AR(nd_string2);
}
break;
case NODE_IF:
/*
if nd_string1 then
nd_string2
else
nd_string3
end
*/
nd_string1 = F_NODE_ONEL(nd_cond, "condition expr");
nd_string2 = F_NODE_NEWL_D(nd_body, "then clause");
if (node->nd_else) {
nd_string3 = F_NODE_NEWL_D(nd_else, "else clause");
} else {
nd_string3 = rb_str_new2("");
}
if (RSTRING_LEN(nd_string2) == 0 && RSTRING_LEN(nd_string3) != 0) {
AD_IF_N("unless ");
AR(nd_string1);
A(" then\n");
AR(nd_string3);
A("\n");
AD("end\n");
} else {
AD_IF_N("if ");
AR(nd_string1);
A(" then\n");
AR(nd_string2);
if (node->nd_else) {
A("\n");
AD("else\n");
AR(nd_string3);
}
A("\n");
AD("end\n");
}
break;
case NODE_CASE:
/*
case nd_string1
when_clauses
end
*/
nd_string1 = F_NODE_ONEL(nd_head, "case expr");
nd_string2 = F_NODE_NEWL(nd_body, "when clauses");
AD_IF_N("case ");
AR(nd_string1);
A("\n");
AR(nd_string2);
AD("end\n");
break;
case NODE_WHEN:
/*
when nd_string1
nd_string2
next_when_clause
else
nd_string3
*/
nd_string1 = F_NODE_ONEL(nd_head, "when value");
nd_string2 = F_NODE_NEWL_D(nd_body, "when clause");
AD_IF_N("when ");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
if (node && node->nd_next && nd_type(node->nd_next) == NODE_WHEN) {
nd_string3 = F_NODE_NEWL(nd_next, "next when clause");
AR(nd_string3);
} else if (node && node->nd_next) {
nd_string3 = F_NODE_NEWL_D(nd_next, "else clause");
AD("else\n");
AR(nd_string3);
A("\n");
}
break;
case NODE_OPT_N:
rb_bug("should not enter this node: %s", ruby_node_name(nd_type(node)));
break;
case NODE_WHILE:
/*
while nd_string1
nd_string2
end
begin
nd_string2
end while nd_string1
*/
nd_string1 = F_NODE_ONEL(nd_cond, "condition");
nd_string2 = F_NODE_NEWL_D(nd_body, "body");
// (while-end)
if (node->nd_state == 1) {
AD_IF_N("while ");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
AD("end");
} else { //(begin-end-while)
AD_IF_N("begin\n");
AR(nd_string2);
A("\n");
AD("end while ");
AR(nd_string1);
}
break;
case NODE_UNTIL:
/*
until nd_string1
nd_string2
end
*/
nd_string1 = F_NODE_ONEL(nd_cond, "condition");
nd_string2 = F_NODE_NEWL_D(nd_body, "body");
AD_IF_N("until ");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
AD("end\n");
break;
case NODE_ITER:
/*
nd_string1 |nd_string3| do
nd_string2
end
*/
nd_string1 = F_NODE_ONEL(nd_iter, "iteration receiver");
nd_string2 = F_NODE_NEWL_D(nd_body, "body");
nd_string3 = parse_args(node->nd_body, indent);
ARD_IF_N(nd_string1);
A(" do ");
if (RSTRING_LEN(nd_string3) != 0) {
A("|");
AR(nd_string3);
A("|");
}
A("\n");
AR(nd_string2);
A("\n");
AD("end");
break;
case NODE_FOR:
/*
for nd_string3 in nd_string1 do
nd_string2
end
*/
nd_string1 = F_NODE_ONEL(nd_iter, "iteration receiver");
nd_string2 = F_NODE_NEWL_D(nd_body, "body");
nd_string3 = F_ARGS(nd_body);
AD_IF_N("for ");
AR(nd_string3);
A(" in ");
AR(nd_string1);
A(" do\n");
AR(nd_string2);
A("\n");
AD("end\n");
break;
case NODE_BREAK:
/*
break nd_string1
*/
nd_string1 = F_NODE_ONEL(nd_stts, "value");
AD_IF_N("break ");
AR(nd_string1);
break;
case NODE_NEXT:
/*
next nd_string1
*/
nd_string1 = F_NODE_ONEL(nd_stts, "value");
AD_IF_N("next ");
AR(nd_string1);
break;
case NODE_RETURN:
/*
return nd_string1
*/
nd_string1 = F_NODE_ONEL(nd_stts, "value");
AD_IF_N("return ");
AR(nd_string1);
break;
case NODE_REDO:
/*
redo
*/
AD_IF_N("redo");
break;
case NODE_RETRY:
/*
retry
*/
AD_IF_N("retry");
break;
case NODE_BEGIN:
/*
begin
nd_string1
end
*/
nd_string1 = F_NODE_NEWL_D(nd_body, "body");
if (RSTRING_LEN(nd_string1) !=0 ) {
AD_IF_N("begin\n");
AR(nd_string1);
AD("end");
}
break;
case NODE_RESCUE:
/*
begin
nd_string1
rescue_clause
else
nd_string3
end
*/
nd_string1 = F_NODE_NEWL_D(nd_head, "body");
nd_string2 = F_NODE_NEWL(nd_resq, "rescue clause list");
nd_string3 = F_NODE_NEWL_D(nd_else, "rescue else clause");
AD_IF_N("begin\n");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
AD("else\n");
AR(nd_string3);
A("\n");
AD("end\n");
break;
case NODE_RESBODY:
nd_string1 = F_NODE_ONEL(nd_args, "rescue exceptions");
nd_string3 = F_NODE_NEWL(nd_head, "next rescue clause");
AD_IF_N("rescue ");
AR(nd_string1);
if (node->nd_body && nd_type(node->nd_body) == NODE_BLOCK &&
node->nd_body->nd_head && (nd_type(node->nd_body->nd_head) == NODE_LASGN ||
nd_type(node->nd_body->nd_head) == NODE_DASGN ||
nd_type(node->nd_body->nd_head) == NODE_DASGN_CURR ||
nd_type(node->nd_body->nd_head) == NODE_IASGN) && node->nd_body->nd_head->nd_value) {
if (nd_type(node->nd_body->nd_head->nd_value) == NODE_ERRINFO) {
nd_string4 = F_ID(nd_body->nd_head->nd_vid, "variable");
}
A(" => ");
AR(nd_string4);
nd_string2 = F_NODE_NEWL_D(nd_body->nd_next, "rescue clause");
} else {
nd_string2 = F_NODE_NEWL_D(nd_body, "rescue clause");
}
A("\n");
AR(nd_string2);
AR(nd_string3);
break;
case NODE_ENSURE:
nd_string1 = F_NODE_NEWL_D(nd_head, "body");
nd_string2 = F_NODE_NEWL_D(nd_ensr, "ensure clause");
AD_IF_N("begin\n");
AR(nd_string1);
A("\n");
AD("ensure\n");
AR(nd_string2);
A("\n");
AD("end\n");
break;
case NODE_AND:
nd_string1 = F_NODE_ONEL(nd_1st, "left expr");
nd_string2 = F_NODE_ONEL(nd_2nd, "right expr");
ARD_IF_N(nd_string1);
A(" and ");
AR(nd_string2);
break;
case NODE_OR:
nd_string1 = F_NODE_ONEL(nd_1st, "left expr");
nd_string2 = F_NODE_ONEL(nd_2nd, "right expr");
ARD_IF_N(nd_string1);
A(" or ");
AR(nd_string2);
break;
case NODE_MASGN:
nd_string1 = F_NODE_ONEL(nd_value, "rhsn");
nd_string2 = F_NODE_ONEL(nd_head, "lhsn");
nd_string3 = F_NODE_ONEL(nd_args, "splatn");
if (RSTRING_LEN(nd_string2) != 0) {
ARD_IF_N(nd_string2);
}
if ((VALUE)node->nd_args != (VALUE)-1) {
nd_string3 = F_NODE_ONEL(nd_args, "splatn");
if (RSTRING_LEN(nd_string2) != 0 && RSTRING_LEN(nd_string3) != 0) {
A(", ");
}
}
else {
A(", ");
nd_string3 = rb_str_new2("*");
}
if (RSTRING_LEN(nd_string2) != 0) {
AR(nd_string3);
} else {
ARD_IF_N(nd_string3);
}
if (RSTRING_LEN(nd_string1) != 0) {
A(" = ");
AR(nd_string1);
}
break;
case NODE_LASGN:
case NODE_DASGN:
case NODE_DASGN_CURR:
case NODE_IASGN:
case NODE_CVASGN:
nd_string1 = F_ID(nd_vid, "variable");
nd_string2 = F_NODE_ONEL(nd_value, "rvalue");
ARD_IF_N(nd_string1);
if (RSTRING_LEN(nd_string2) != 0) {
A(" = ");
AR(nd_string2);
}
break;
case NODE_GASGN:
nd_string1 = F_GENTRY(nd_entry, "global variable");
nd_string2 = F_NODE_ONEL(nd_value, "rvalue");
ARD_IF_N(nd_string1);
A(" = ");
AR(nd_string2);
break;
case NODE_CDECL:
/*
X = foo
*/
nd_string1 = F_ID(nd_vid, "variable");
nd_string2 = F_NODE_ONEL(nd_else, "extension");
nd_string3 = F_NODE_ONEL(nd_value, "rvalue");
if (node->nd_vid) {
ARD_IF_N(nd_string1);
A(" = ");
AR(nd_string3);
} else {
A("WTF NODE_CDECL");
}
break;
case NODE_OP_ASGN1:
nd_string1 = F_NODE_ONEL(nd_recv, "receiver");
nd_string2 = F_ID(nd_mid, "operator");
nd_string3 = F_NODE_ONEL(nd_args->nd_body, "index");
nd_string4 = F_NODE_ONEL(nd_args->nd_head, "rvalue");
ARD_IF_N(nd_string1);
A("[");
AR(nd_string4);
A("] ");
if (node->nd_mid == 0) {
A("||");
} else if (node->nd_mid == 1) {
A("&&");
} else {
AR(nd_string2);
}
A("= ");
AR(nd_string3);
break;
case NODE_OP_ASGN2:
nd_string1 = F_NODE_ONEL(nd_recv, "receiver");
nd_string2 = F_ID(nd_next->nd_vid, "reader");
switch (node->nd_next->nd_mid) {
case 0:
nd_string4 = rb_str_new_cstr("||");
break;
case 1:
nd_string4 = rb_str_new_cstr("&&");
break;
default:
nd_string4 = F_ID(nd_next->nd_mid, "some");
}
nd_string5 = F_NODE_ONEL(nd_value, "rvalue");
ARD_IF_N(nd_string1);
A(".");
AR(nd_string2);
A(" ");
AR(nd_string4);
A("= ");
AR(nd_string5);
break;
case NODE_OP_ASGN_AND:
nd_string1 = F_NODE_ONEL(nd_head, "variable");
nd_string2 = F_NODE_ONEL(nd_value, "rvalue");
ARD_IF_N(nd_string1);
A(" &&= ");
AR(nd_string2);
break;
case NODE_OP_ASGN_OR:
nd_string1 = F_NODE_ONEL(nd_head, "variable");
nd_string2 = F_NODE_ONEL(nd_value, "rvalue");
ARD_IF_N(nd_string1);
A(" ||= ");
AR(nd_string2);
break;
case NODE_CALL:
nd_string1 = F_ID(nd_mid, "method id");
nd_string2 = F_NODE_ONEL(nd_recv, "receiver");
nd_string3 = F_NODE_ONEL(nd_args, "arguments");
// 如果函数名是 正常函数
if (rb_str_cmp(nd_string1, rb_str_new2("[]")) == 0) {
ARD_IF_N(nd_string2);
A("[");
AR(nd_string3);
A("]");
// 双目运算
} else if ((rb_str_cmp(nd_string1, rb_str_new2("+")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("-")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("*")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("/")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("%")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("<=>")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("==")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("!=")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("~=")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2(">>")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("<<")) == 0 ||
rb_str_cmp(nd_string1, rb_str_new2("===")) == 0 )) {
ARD_IF_N(nd_string2);
A(" ");
AR(nd_string1);
A(" ");
AR(nd_string3);
} else if (!node->nd_args && (
(rb_str_cmp(nd_string1, rb_str_new2("!")) == 0))) {
AD_IF_N("not ");
AR(nd_string2);
}else{
ARD_IF_N(nd_string2);
A(".");
AR(nd_string1);
if (RSTRING_LEN(nd_string3) > 0) {
A("(");
AR(nd_string3);
A(")");
}
}
break;
case NODE_FCALL:
nd_string1 = F_ID(nd_mid, "method id");
nd_string2 = F_NODE_ONEL(nd_args, "arguments");
ARD_IF_N(nd_string1);
A("(");
AR(nd_string2);
A(")");
break;
case NODE_VCALL:
nd_string1 = F_ID(nd_mid, "method id");
ARD_IF_N(nd_string1);
break;
case NODE_SUPER:
nd_string1 = F_NODE_ONEL(nd_args, "arguments");
AD_IF_N("super ");
AR(nd_string1);
break;
case NODE_ZSUPER:
AD_IF_N("super");
break;
case NODE_ARRAY:
// TODO, fix [1,2,3]
nd_string1 = F_NODE_ONEL(nd_head, "element");
nd_string2 = F_NODE_ONEL(nd_next, "next element");
ARD_IF_N(nd_string1);
if (RSTRING_LEN(nd_string2) != 0) {
A(", ");
AR(nd_string2);
}
break;
case NODE_VALUES:
nd_string1 = F_NODE_ONEL(nd_head, "element");
nd_string2 = F_NODE_ONEL(nd_next, "next element");
ARD_IF_N(nd_string1);
if (RSTRING_LEN(nd_string2) != 0) {
A(", ");
AR(nd_string2);
}
break;
case NODE_ZARRAY:
AD_IF_N("[]");
break;
case NODE_HASH:
nd_string1 = F_NODE_ONEL(nd_head, "contents");
AD_IF_N("{");
if (node->nd_head && nd_type(node->nd_head) == NODE_ARRAY) {
NODE *array_node = node->nd_head;
while (array_node) {
VALUE hash_key = dump_node(array_node->nd_head, array_node, indent, 0);
array_node = array_node->nd_next;
VALUE hash_value = dump_node(array_node->nd_head, array_node, indent, 0);
array_node = array_node->nd_next;
AR(hash_key);
A(" => ");
AR(hash_value);
if (array_node) {
A(", ");
}
}
}
A("}");
break;
case NODE_YIELD:
nd_string1 = F_NODE_ONEL(nd_head, "arguments");
AD_IF_N("yield ");
AR(nd_string1);
break;
case NODE_LVAR:
case NODE_DVAR:
case NODE_IVAR:
case NODE_CONST:
case NODE_CVAR:
nd_string1 = F_ID(nd_vid, "local variable");
ARD_IF_N(nd_string1);
break;
case NODE_GVAR:
nd_string1 = F_GENTRY(nd_entry, "global variable");
ARD_IF_N(nd_string1);
break;
case NODE_NTH_REF:
nd_string1 = F_LONG(nd_nth, "nothing");
AD_IF_N("$");
AR(nd_string1);
break;
case NODE_BACK_REF:
do {
char name[3];
name[0] = '$';
name[1] = (char) node->nd_nth;
name[2] = '\0';
AD_IF_N(name);
} while (0);
break;
case NODE_MATCH:
nd_string1 = F_LIT(nd_lit, "regexp");
ARD_IF_N(nd_string1);
break;
case NODE_MATCH2:
nd_string1 = F_NODE_ONEL(nd_recv, "regexp (receiver)");
nd_string2 = F_NODE_ONEL(nd_value, "string (argument)");
ARD_IF_N(nd_string1);
A(" =~ ");
AR(nd_string2);
break;
case NODE_MATCH3:
nd_string1 = F_NODE_ONEL(nd_recv, "string (receiver)");
nd_string2 = F_NODE_ONEL(nd_value, "regexp (argument)");
ARD_IF_N(nd_string2);
A(" =~ ");
AR(nd_string1);
break;
case NODE_LIT:
nd_string1 = F_LIT(nd_lit, "literal");
ARD_IF_N(nd_string1);
break;
case NODE_STR:
nd_string1 = F_LIT(nd_lit, "literal");
ARD_IF_N(nd_string1);
break;
case NODE_XSTR:
nd_string1 = F_LIT(nd_lit, "literal");
AD_IF_N("`");
AR(nd_string1);
A("`");
break;
case NODE_DSYM:
case NODE_DSTR:
nd_string5 = rb_str_new2("");
nd_string1 = (VALUE)node->nd_lit;
nd_string2 = F_NODE_ONEL(nd_next->nd_head, "preceding string");
rb_str_concat(nd_string5, nd_string1);
rb_str_concat(nd_string5, nd_string2);
if (node->nd_next->nd_next && nd_type(node->nd_next->nd_next) == NODE_ARRAY) {
NODE *array_node = node->nd_next->nd_next;
while (array_node) {
if (nd_type(array_node->nd_head) == NODE_STR) {
nd_string3 = (VALUE)array_node->nd_head->nd_lit;
} else {
nd_string3 = dump_node(array_node->nd_head, array_node, indent, 0);
}
rb_str_concat(nd_string5, nd_string3);
array_node = array_node->nd_next;
}
}
nd_string5 = rb_funcall(nd_string5, rb_intern("gsub"), 2, rb_str_new2("\""), rb_str_new2("\\\""));
AD_IF_N("\"");
AR(nd_string5);
A("\"");
break;
case NODE_DXSTR:
nd_string1 = F_LIT(nd_lit, "literal");
nd_string2 = F_NODE_ONEL(nd_next->nd_head, "preceding string");
nd_string3 = F_NODE_ONEL(nd_next->nd_next, "interpolation");
AD_IF_N("`");
AR(nd_string1);
AR(nd_string2);
AR(nd_string3);
A("`");
break;
case NODE_DREGX:
nd_string1 = F_LIT(nd_lit, "literal");
nd_string2 = F_NODE_ONEL(nd_next->nd_head, "preceding string");
nd_string3 = F_NODE_ONEL(nd_next->nd_next, "interpolation");
AD_IF_N("/");
AR(nd_string1);
AR(nd_string2);
AR(nd_string3);
A("/");
break;
case NODE_DREGX_ONCE:
nd_string1 = F_LIT(nd_lit, "literal");
nd_string2 = F_NODE_ONEL(nd_next->nd_head, "preceding string");
nd_string3 = F_NODE_ONEL(nd_next->nd_next, "interpolation");
AD_IF_N("/");
AR(nd_string1);
AR(nd_string2);
AR(nd_string3);
A("/o");
break;
case NODE_EVSTR:
nd_string1 = F_NODE_ONEL(nd_body, "body");
AD_IF_N("#{ ");
AR(nd_string1);
A(" }");
break;
case NODE_ARGSCAT:
nd_string1 = F_NODE_ONEL(nd_head, "preceding array");
nd_string2 = F_NODE_ONEL(nd_body, "following array");
ARD_IF_N(nd_string1);
A(", ");
AR(nd_string2);
break;
case NODE_ARGSPUSH:
nd_string1 = F_NODE_ONEL(nd_head, "preceding array");
nd_string2 = F_NODE_ONEL(nd_body, "following element");
AD_IF_N("*");
AR(nd_string1);
A(", ");
AR(nd_string1);
break;
case NODE_SPLAT:
nd_string1 = F_NODE_ONEL(nd_head, "splat'ed array");
AD_IF_N("*");
AR(nd_string1);
break;
case NODE_BLOCK_PASS:
nd_string1 = F_NODE_ONEL(nd_head, "other arguments");
nd_string2 = F_NODE_ONEL(nd_body, "block argument");
ARD_IF_N(nd_string1);
if (RSTRING_LEN(nd_string1) > 0) {
A(", ");
}
A("&");
AR(nd_string2);
break;
case NODE_DEFN:
nd_string1 = F_ID(nd_mid, "method name");
nd_string2 = F_NODE_NEWL_D(nd_defn, "method definition");
nd_string3 = F_ARGS(nd_defn);
AD_IF_N("def ");
AR(nd_string1);
if (RSTRING_LEN(nd_string3) != 0) {
A("(");
AR(nd_string3);
A(")");
}
A("\n");
if (RSTRING_LEN(nd_string2) > 0) {
AR(nd_string2);
A("\n");
}
AD("end\n");
break;
case NODE_DEFS:
nd_string1 = F_NODE_ONEL(nd_recv, "receiver");
nd_string2 = F_ID(nd_mid, "method name");
nd_string3 = F_NODE_NEWL_D(nd_defn, "method definition");
nd_string4 = F_ARGS(nd_defn);
AD_IF_N("def ");
AR(nd_string1);
A(".");
AR(nd_string2);
if (RSTRING_LEN(nd_string4) != 0) {
A("(");
AR(nd_string4);
A(")");
}
A("\n");
AR(nd_string3);
A("\n");
AD("end\n");
break;
case NODE_ALIAS:
nd_string1 = F_NODE_ONEL(u1.node, "new name");
nd_string2 = F_NODE_ONEL(u2.node, "old name");
AD_IF_N("alias ");
AR(nd_string1);
A(" ");
AR(nd_string2);
break;
case NODE_VALIAS:
nd_string1 = F_ID(u1.id, "new name");
nd_string2 = F_ID(u2.id, "old name");
AD_IF_N("alias ");
AR(nd_string1);
A(" ");
AR(nd_string2);
break;
case NODE_UNDEF:
nd_string1 = F_NODE_ONEL(u2.node, "old name");
AD_IF_N("undef ");
AR(nd_string1);
break;
case NODE_CLASS:
nd_string1 = F_NODE_ONEL(nd_cpath, "class path");
nd_string2 = F_NODE_ONEL(nd_super, "superclass");
nd_string3 = F_NODE_NEWL_D(nd_body, "class definition");
AD_IF_N("class ");
AR(nd_string1);
if (RSTRING_LEN(nd_string2) != 0) {
A(" < ");
AR(nd_string2);
}
A("\n");
AR(nd_string3);
A("\n");
AD("end\n");
break;
case NODE_MODULE:
nd_string1 = F_NODE_ONEL(nd_cpath, "module path");
nd_string2 = F_NODE_NEWL_D(nd_body, "module definition");
AD_IF_N("module ");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
AD("end");
A("\n");
break;
case NODE_SCLASS:
nd_string1 = F_NODE_ONEL(nd_recv, "receiver");
nd_string2 = F_NODE_NEWL_D(nd_body, "singleton class definition");
AD_IF_N("class << ");
AR(nd_string1);
A("\n");
AR(nd_string2);
A("\n");
AD("end\n");
break;
case NODE_COLON2:
nd_string1 = F_ID(nd_mid, "constant name");
nd_string2 = F_NODE_ONEL(nd_head, "receiver");
ARD_IF_N(nd_string2);
A("::");
AR(nd_string1);
break;
case NODE_COLON3:
nd_string1 = F_ID(nd_mid, "constant name");
AD_IF_N("::");
AR(nd_string1);
break;
case NODE_DOT2:
nd_string1 = F_NODE_ONEL(nd_beg, "begin");
nd_string2 = F_NODE_ONEL(nd_end, "end");
ARD_IF_N(nd_string1);
A("..");
AR(nd_string2);
break;
case NODE_DOT3:
nd_string1 = F_NODE_ONEL(nd_beg, "begin");
nd_string2 = F_NODE_ONEL(nd_end, "end");
ARD_IF_N(nd_string1);
A("...");
AR(nd_string2);
break;
case NODE_FLIP2:
nd_string1 = F_NODE_ONEL(nd_beg, "begin");
nd_string2 = F_NODE_ONEL(nd_end, "end");
ARD_IF_N(nd_string1);
A("..");
AR(nd_string2);
break;
case NODE_FLIP3:
nd_string1 = F_NODE_ONEL(nd_beg, "begin");
nd_string2 = F_NODE_ONEL(nd_end, "end");
ARD_IF_N(nd_string1);
A("...");
AR(nd_string2);
break;
case NODE_SELF:
AD_IF_N("self");
break;
case NODE_NIL:
AD_IF_N("nil");
break;
case NODE_TRUE:
AD_IF_N("true");
break;
case NODE_FALSE:
AD_IF_N("false");
break;
case NODE_ERRINFO:
rb_bug("should not enter this node: %s", ruby_node_name(nd_type(node)));
break;
case NODE_DEFINED:
nd_string1 = F_NODE_ONEL(nd_head, "expr");
AD_IF_N("defined?(");
AR(nd_string1);
A(")");
break;
case NODE_POSTEXE:
nd_string1 = F_NODE_NEWL_D(nd_body, "END clause");
AD_IF_N("END {\n");
AR(nd_string1);
A("\n");
AD("}\n");
break;
case NODE_ATTRASGN:
if (node->nd_recv == (NODE *) 1) {
nd_string1 = rb_str_new2("self");
} else {
nd_string1 = F_NODE_ONEL(nd_recv, "receiver");
}
nd_string2 = F_ID(nd_mid, "method name");
if (rb_str_cmp(nd_string2, rb_str_new2("[]=")) == 0 && nd_type(node->nd_args) == NODE_ARRAY) {
nd_string4 = F_NODE_ONEL(nd_args->nd_head, "array last key");
nd_string3 = F_NODE_ONEL(nd_args->nd_next, "value");
ARD_IF_N(nd_string1);
A("[");
AR(nd_string4);
A("]");
A(" = ");
AR(nd_string3);
} else {
nd_string3 = F_NODE_ONEL(nd_args, "arguments");
ARD_IF_N(nd_string1);
A(".");
AR(nd_string2);
A(" = ");
AR(nd_string3);
}
break;
case NODE_PRELUDE:
nd_string1 = F_NODE_NEWL_D(nd_head, "prelude");
nd_string2 = F_NODE_ONEL(nd_body, "body");
AD_IF_N("BEGIN {\n");
AR(nd_string1);
A("\n");
AD("}\n");
AR(nd_string2);
break;
case NODE_LAMBDA:
nd_string1 = F_NODE_NEWL_D(nd_body, "lambda clause");
AD_IF_N("-> {\n");
AR(nd_string1);
A("\n");
AD("}");
break;
case NODE_OPT_ARG:
nd_string1 = F_ID(nd_body->nd_vid, "body");
nd_string2 = F_NODE_ONEL(nd_body->nd_value, "body");
nd_string3 = F_NODE_ONEL(nd_next, "next");
ARD_IF_N(nd_string1);
A("=");
AR(nd_string2);
if (RSTRING_LEN(nd_string3) != 0) {
A(", ");
AR(nd_string3);
}
break;
case NODE_KW_ARG:
nd_string1 = F_ID(nd_body->nd_vid, "body");
nd_string2 = F_NODE_ONEL(nd_body->nd_value, "body");
nd_string3 = F_NODE_ONEL(nd_next, "next");
ARD_IF_N(nd_string1);
A(": ");
AR(nd_string2);
if (RSTRING_LEN(nd_string3) != 0) {
A(", ");
AR(nd_string3);
}
break;
case NODE_POSTARG:
if ((VALUE)node->nd_1st != (VALUE)-1) {
nd_string1 = F_NODE_ONEL(nd_1st, "rest argument");
}
else {
nd_string1 = rb_str_new2("");
}
nd_string2 = F_NODE_ONEL(nd_2nd, "post arguments");
AD_IF_N("*");
AR(nd_string1);
if (RSTRING_LEN(nd_string2)) {
A(", ");
AR(nd_string2);
}
break;
case NODE_ARGS:
rb_bug("should not enter this node: %s", ruby_node_name(nd_type(node)));
break;
case NODE_SCOPE:
nd_string1 = F_NODE_NEWL(nd_body, "body");
AR(nd_string1);
break;
default:
rb_bug("dump_node: unknown node: %s", ruby_node_name(nd_type(node)));
}
return result;
}
void
rb_node_tree_to_ruby(NODE *node) {
rb_io_write(rb_stdout, dump_node(node, NULL, 0, 1));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment