parsetree19 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +155 -0
- data/NEWS +2 -0
- data/README.md +8 -0
- data/Rakefile +158 -0
- data/ext/add_to_parse_tree.inc +906 -0
- data/ext/extconf.rb +8 -0
- data/ext/parse_tree.c +149 -0
- data/include/method_mini.h +90 -0
- data/include/node.h +483 -0
- data/include/ruby19_externs.h +36 -0
- data/include/thread_pthread.h +24 -0
- data/include/vm_core_mini.h +369 -0
- data/test/unit/test_parse_tree_for_meth.rb +33 -0
- data/test/unit/test_parse_tree_for_str.rb +162 -0
- metadata +80 -0
data/ext/extconf.rb
ADDED
data/ext/parse_tree.c
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
/* What release we got? */
|
2
|
+
#define PARSETREE19_VERSION "0.2"
|
3
|
+
#include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
|
4
|
+
#include "../include/ruby19_externs.h"
|
5
|
+
|
6
|
+
/* Turn a Ruby node string, e.g. "NODE_FALSE" into a symbol that ParseTree
|
7
|
+
uses, e.g. :false. */
|
8
|
+
static VALUE
|
9
|
+
pt_node_name(const char *name)
|
10
|
+
{
|
11
|
+
if (0 == strncmp(name, "NODE_", strlen("NODE_"))) {
|
12
|
+
const char * name_sans_node = &name[strlen("NODE_")];
|
13
|
+
return
|
14
|
+
rb_funcall(
|
15
|
+
rb_funcall(rb_str_new2(name_sans_node), rb_intern("downcase"),
|
16
|
+
0),
|
17
|
+
rb_intern("to_sym"), 0);
|
18
|
+
} else {
|
19
|
+
rb_bug("pt_node_name: node %s name should start with NODE_", name);
|
20
|
+
return Qnil;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
static VALUE
|
25
|
+
wrap_into_node(const char * name, VALUE val)
|
26
|
+
{
|
27
|
+
VALUE n = rb_ary_new();
|
28
|
+
rb_ary_push(n, pt_node_name(name));
|
29
|
+
if (val) rb_ary_push(n, val);
|
30
|
+
return n;
|
31
|
+
}
|
32
|
+
|
33
|
+
#include "add_to_parse_tree.inc"
|
34
|
+
|
35
|
+
static VALUE
|
36
|
+
parse_tree_for_node(VALUE self, NODE *node, VALUE tree)
|
37
|
+
{
|
38
|
+
VALUE result = rb_ary_new();
|
39
|
+
|
40
|
+
if (Qfalse == tree)
|
41
|
+
result = rb_parser_dump_tree(node, 0);
|
42
|
+
else
|
43
|
+
result = add_to_parse_tree(self, result, node, NULL);
|
44
|
+
return (result);
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE
|
48
|
+
parse_tree_for_iseq_internal(VALUE self, rb_iseq_t *iseq, VALUE tree)
|
49
|
+
{
|
50
|
+
VALUE result = rb_ary_new();
|
51
|
+
|
52
|
+
if (iseq->tree_node) {
|
53
|
+
if (Qfalse == tree)
|
54
|
+
result = rb_parser_dump_tree(iseq->tree_node, 0);
|
55
|
+
else
|
56
|
+
result = add_to_parse_tree(self, result, iseq->tree_node, NULL);
|
57
|
+
return (result);
|
58
|
+
} else
|
59
|
+
return Qnil;
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE
|
63
|
+
parse_tree_for_iseq(VALUE self, VALUE iseqval, VALUE tree)
|
64
|
+
{
|
65
|
+
rb_iseq_t *iseq;
|
66
|
+
VALUE result = rb_ary_new();
|
67
|
+
|
68
|
+
GetISeqPtr(iseqval, iseq);
|
69
|
+
parse_tree_for_iseq_internal(self, iseq, tree);
|
70
|
+
}
|
71
|
+
|
72
|
+
/* Defined in Ruby 1.9 proc.c */
|
73
|
+
extern rb_iseq_t *rb_method_get_iseq(VALUE method);
|
74
|
+
|
75
|
+
static VALUE
|
76
|
+
parse_tree_for_method(VALUE self, VALUE method, VALUE tree)
|
77
|
+
{
|
78
|
+
rb_iseq_t *iseq = rb_method_get_iseq(method);
|
79
|
+
parse_tree_for_iseq_internal(self, iseq, tree);
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE
|
83
|
+
parse_tree_common(VALUE self, VALUE source, VALUE filename, VALUE line,
|
84
|
+
VALUE tree)
|
85
|
+
{
|
86
|
+
VALUE tmp;
|
87
|
+
VALUE result = rb_ary_new();
|
88
|
+
NODE *node = NULL;
|
89
|
+
|
90
|
+
#ifdef FIXED
|
91
|
+
rb_thread_t *th = GET_THREAD();
|
92
|
+
int critical;
|
93
|
+
#endif
|
94
|
+
|
95
|
+
tmp = rb_check_string_type(filename);
|
96
|
+
if (NIL_P(tmp)) {
|
97
|
+
filename = rb_str_new2("(string)");
|
98
|
+
}
|
99
|
+
|
100
|
+
if (NIL_P(line)) {
|
101
|
+
line = LONG2FIX(1);
|
102
|
+
}
|
103
|
+
|
104
|
+
#ifdef FIXED
|
105
|
+
ruby_nerrs = 0;
|
106
|
+
critical = rb_thread_critical;
|
107
|
+
rb_thread_critical = Qtrue;
|
108
|
+
th->parse_in_eval++;
|
109
|
+
#endif
|
110
|
+
|
111
|
+
StringValue(source);
|
112
|
+
node = rb_compile_string(StringValuePtr(filename), source, NUM2INT(line));
|
113
|
+
|
114
|
+
#ifdef FIXED
|
115
|
+
th->parse_in_eval--;
|
116
|
+
rb_thread_critical = critical;
|
117
|
+
if (ruby_nerrs > 0) {
|
118
|
+
ruby_nerrs = 0;
|
119
|
+
rb_exc_raise(th->errinfo);
|
120
|
+
}
|
121
|
+
#endif
|
122
|
+
|
123
|
+
return parse_tree_for_node(self, node, tree);
|
124
|
+
}
|
125
|
+
|
126
|
+
static VALUE
|
127
|
+
parse_tree_for_str(VALUE self, VALUE source, VALUE filename, VALUE line)
|
128
|
+
{
|
129
|
+
return parse_tree_common(self, source, filename, line, Qtrue);
|
130
|
+
}
|
131
|
+
|
132
|
+
static VALUE
|
133
|
+
parse_tree_dump(VALUE self, VALUE source, VALUE filename, VALUE line)
|
134
|
+
{
|
135
|
+
return parse_tree_common(self, source, filename, line, Qfalse);
|
136
|
+
}
|
137
|
+
|
138
|
+
void Init_parse_tree(void)
|
139
|
+
{
|
140
|
+
VALUE c = rb_define_class("ParseTree19", rb_cObject);
|
141
|
+
rb_define_method(c, "parse_tree_for_iseq",
|
142
|
+
(VALUE(*)(ANYARGS))parse_tree_for_iseq, 2);
|
143
|
+
rb_define_method(c, "parse_tree_for_method",
|
144
|
+
(VALUE(*)(ANYARGS))parse_tree_for_method, 2);
|
145
|
+
rb_define_method(c, "parse_tree_for_str",
|
146
|
+
(VALUE(*)(ANYARGS))parse_tree_for_str, 3);
|
147
|
+
rb_define_method(c, "parse_tree_dump",
|
148
|
+
(VALUE(*)(ANYARGS))parse_tree_dump, 3);
|
149
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
From Ruby 1.9's method.h.
|
3
|
+
|
4
|
+
Copyright (C) 2009 Koichi Sasada
|
5
|
+
|
6
|
+
**********************************************************************/
|
7
|
+
#ifndef METHOD_H
|
8
|
+
#define METHOD_H
|
9
|
+
|
10
|
+
typedef enum {
|
11
|
+
NOEX_PUBLIC = 0x00,
|
12
|
+
NOEX_NOSUPER = 0x01,
|
13
|
+
NOEX_PRIVATE = 0x02,
|
14
|
+
NOEX_PROTECTED = 0x04,
|
15
|
+
NOEX_MASK = 0x06,
|
16
|
+
NOEX_BASIC = 0x08,
|
17
|
+
NOEX_UNDEF = NOEX_NOSUPER,
|
18
|
+
NOEX_MODFUNC = 0x12,
|
19
|
+
NOEX_SUPER = 0x20,
|
20
|
+
NOEX_VCALL = 0x40,
|
21
|
+
NOEX_RESPONDS = 0x80
|
22
|
+
} rb_method_flag_t;
|
23
|
+
|
24
|
+
#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F)
|
25
|
+
#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC))
|
26
|
+
#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
|
27
|
+
|
28
|
+
/* method data type */
|
29
|
+
|
30
|
+
typedef enum {
|
31
|
+
VM_METHOD_TYPE_ISEQ,
|
32
|
+
VM_METHOD_TYPE_CFUNC,
|
33
|
+
VM_METHOD_TYPE_ATTRSET,
|
34
|
+
VM_METHOD_TYPE_IVAR,
|
35
|
+
VM_METHOD_TYPE_BMETHOD,
|
36
|
+
VM_METHOD_TYPE_ZSUPER,
|
37
|
+
VM_METHOD_TYPE_UNDEF,
|
38
|
+
VM_METHOD_TYPE_NOTIMPLEMENTED,
|
39
|
+
VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
|
40
|
+
VM_METHOD_TYPE_MISSING /* wrapper for method_missing(id) */
|
41
|
+
} rb_method_type_t;
|
42
|
+
|
43
|
+
typedef struct rb_method_cfunc_struct {
|
44
|
+
VALUE (*func)(ANYARGS);
|
45
|
+
int argc; /* This should probably be called "arity" since it is based
|
46
|
+
on the static prototype, not the supplied arguments
|
47
|
+
at runtime. */
|
48
|
+
int actual_argc; /* This probably should be called argc. It is the
|
49
|
+
argument count at runtime.*/
|
50
|
+
} rb_method_cfunc_t;
|
51
|
+
|
52
|
+
typedef struct rb_method_attr_struct {
|
53
|
+
ID id;
|
54
|
+
VALUE location;
|
55
|
+
} rb_method_attr_t;
|
56
|
+
|
57
|
+
/* typedef struct rb_iseq_struct rb_iseq_t; */
|
58
|
+
|
59
|
+
typedef struct rb_method_definition_struct {
|
60
|
+
rb_method_type_t type; /* method type */
|
61
|
+
ID original_id;
|
62
|
+
union {
|
63
|
+
rb_iseq_t *iseq; /* should be mark */
|
64
|
+
rb_method_cfunc_t cfunc;
|
65
|
+
rb_method_attr_t attr;
|
66
|
+
VALUE proc; /* should be mark */
|
67
|
+
enum method_optimized_type {
|
68
|
+
OPTIMIZED_METHOD_TYPE_SEND,
|
69
|
+
OPTIMIZED_METHOD_TYPE_CALL
|
70
|
+
} optimize_type;
|
71
|
+
} body;
|
72
|
+
int alias_count;
|
73
|
+
} rb_method_definition_t;
|
74
|
+
|
75
|
+
typedef struct rb_method_entry_struct {
|
76
|
+
rb_method_flag_t flag;
|
77
|
+
char mark;
|
78
|
+
rb_method_definition_t *def;
|
79
|
+
ID called_id;
|
80
|
+
VALUE klass; /* should be mark */
|
81
|
+
} rb_method_entry_t;
|
82
|
+
|
83
|
+
struct unlinked_method_entry_list_entry {
|
84
|
+
struct unlinked_method_entry_list_entry *next;
|
85
|
+
rb_method_entry_t *me;
|
86
|
+
};
|
87
|
+
|
88
|
+
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
|
89
|
+
|
90
|
+
#endif /* METHOD_H */
|