turn ruby ast to ruby source code
/********************************************************************** | |
node2ruby.c - ruby node tree to ruby source code | |
Copyright (C) 2017 fate0 | |
**********************************************************************/ | |
#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)); | |
} |
if a == a then | |
# NODE_BLOCK | |
foo; bar | |
# NODE_IF | |
if x == 1 then foo else bar end | |
# NODE_CASE & NODE_WHEN | |
case x; when 1; foo; when 2; bar; else baz; end | |
# NODE_WHILE | |
while x == 1; foo; end | |
# NODE_UNTIL | |
until x == 1; foo; end | |
# NODE_ITER | |
3.times { foo } | |
# NODE_FOR | |
for i in 1..3 do foo end | |
# NODE_BREAK | |
break 1 | |
# NODE_NEXT | |
next 1 | |
# NODE_RETURN | |
return 1 | |
# NODE_REDO | |
redo | |
# NODE_RETRY | |
retry | |
# NODE_BEGIN | |
begin | |
1 | |
end | |
# NODE_RESCUE & NODE_RESBODY | |
begin; foo; rescue; bar; else; baz; end | |
# NODE_ENSURE | |
begin; foo; ensure; bar; end | |
# NODE_AND | |
foo && bar | |
# NODE_OR | |
foo || bar | |
# NODE_MASGN | |
a, b = foo | |
# NODE_LASGN | |
x = foo | |
# NODE_DASGN | |
x = nil; 1.times { x = foo } | |
# NODE_DASGN_CURR | |
1.times { x = foo } | |
# NODE_IASGN | |
@x = foo | |
# NODE_CVASGN | |
@@x = foo | |
# NODE_GASGN | |
$x = foo | |
# NODE_CDECL | |
X = foo | |
# NODE_OP_ASGN1 | |
ary[1] += foo | |
# NODE_OP_ASGN2 | |
struct.field += foo | |
# NODE_OP_ASGN_AND | |
foo ||= bar | |
# NODE_CALL | |
obj.foo(1) | |
# NODE_FCALL | |
foo(1) | |
# NODE_VCALL | |
foo | |
# NODE_SUPER | |
super 1 | |
# NODE_ZSUPER | |
super | |
# NODE_ARRAY | |
[1, 2, 3] | |
# NODE_VALUES | |
return 1, 2, 3 | |
# NODE_ZARRAY | |
[] | |
# NODE_HASH | |
{ 1 => 2, 3 => 4 } | |
# NODE_YIELD | |
yield 1 | |
# NODE_LVAR | |
x | |
# NODE_DVAR | |
1.times { x = 1; x } | |
# NODE_IVAR | |
@x | |
# NODE_CONST | |
X | |
# NODE_CVAR | |
@@x | |
# NODE_GVAR | |
$x | |
# NODE_NTH_REF | |
$1 | |
# NODE_BACK_REF | |
$& | |
# NODE_MATCH | |
if /foo/; foo; end | |
# NODE_MATCH2 | |
/foo/ =~ 'foo' | |
# NODE_MATCH3 | |
'foo' =~ /foo/ | |
# NODE_LIT | |
/foo/ | |
# NODE_STR | |
'foo' | |
# NODE_XSTR | |
`foo` | |
# NODE_DSTR | |
"foo#{ bar }baz" | |
# NODE_DXSTR | |
`foo#{ bar }baz` | |
# NODE_DREGX | |
/foo#{ bar }baz/ | |
# NODE_DREGX_ONCE | |
/foo#{ bar }baz/o | |
# NODE_DSYM & NODE_EVSTR | |
"foo#{ bar }baz" | |
# NODE_ARGSCAT | |
foo(*ary, post_arg1, post_arg2) | |
# NODE_ARGSPUSH | |
foo(*ary, post_arg) | |
# NODE_SPLAT | |
foo(*ary) | |
# NODE_BLOCK_PASS | |
foo(x, &blk) | |
# NODE_DEFN | |
def foo; bar; end | |
# NODE_DEFS | |
def obj.foo; bar; end | |
# NODE_ALIAS | |
alias bar foo | |
# NODE_VALIAS | |
alias $y $x | |
# NODE_UNDEF | |
undef foo | |
# NODE_CLASS | |
class C2 < C; foo; end | |
# NODE_MODULE | |
module M | |
foo | |
end | |
# NODE_SCLASS | |
class << obj; foo; end | |
# NODE_COLON2 | |
M::C | |
# NODE_COLON3 | |
::Object | |
# NODE_DOT2 | |
1..5 | |
# NODE_DOT3 | |
1...5 | |
# NODE_FLIP2 | |
if (x==1)..(x==5); foo; end | |
# NODE_FLIP3 | |
if (x==1)...(x==5); foo; end | |
# NODE_SELF | |
self | |
# NODE_NIL | |
nil | |
# NODE_TRUE | |
true | |
# NODE_FALSE | |
false | |
# NODE_ERRINFO | |
begin; foo; rescue Exception1, Exception2 => myexc; bar; else; baz; end | |
# NODE_DEFINED | |
defined?(foo) | |
# NODE_POSTEXE | |
END { foo } | |
# NODE_ATTRASGN | |
struct.field = foo | |
# NODE_LAMBDA | |
-> { foo } | |
# NODE_OPT_ARG | |
def foo(a, b=1, c); end | |
# NODE_KW_ARG | |
def foo(a:1, b:2); end | |
# NODE_POSTARG | |
a, *rest, z = foo | |
# NODE_ARGS | |
def foo(a, b, opt1=1, opt2=2, *rest, y, z, &blk); end | |
end | |
# NODE_PRELUDE | |
bar; BEGIN { foo } |
This comment has been minimized.
This comment has been minimized.
能否提供编译好的程序,node2ruby要怎么使用 |
This comment has been minimized.
This comment has been minimized.
What version of ruby is needed to compile this? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
请问为什么在windows下编译该文件无法还原,在centos下确实可行