Skip to content

Instantly share code, notes, and snippets.

@fate0
Last active June 6, 2024 01:30
Show Gist options
  • Save fate0/a1851bb39efe177bec20dbcd4445f6f3 to your computer and use it in GitHub Desktop.
Save fate0/a1851bb39efe177bec20dbcd4445f6f3 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
**********************************************************************/
#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 }
@meiskam
Copy link

meiskam commented Feb 7, 2018

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