Last active
June 6, 2024 01:30
-
-
Save fate0/a1851bb39efe177bec20dbcd4445f6f3 to your computer and use it in GitHub Desktop.
turn ruby ast to ruby source code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************************************** | |
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)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What version of ruby is needed to compile this?
需要什么版本的红宝石来编译?