1 /* indent-tabs-mode: nil */
2 #include "ruby.h"
3 #include "ruby/encoding.h"
4 #include "ruby/util.h"
5 #include "internal.h"
6 #include "node.h"
7 #include "vm_core.h"
8 #include "iseq.h"
9
10 static VALUE rb_mAST;
11 static VALUE rb_cNode;
12
13 struct ASTNodeData {
14 rb_ast_t *ast;
15 NODE *node;
16 };
17
18 static void
node_gc_mark(void * ptr)19 node_gc_mark(void *ptr)
20 {
21 struct ASTNodeData *data = (struct ASTNodeData *)ptr;
22 rb_gc_mark((VALUE)data->ast);
23 }
24
25 static const rb_data_type_t rb_node_type = {
26 "AST/node",
27 {node_gc_mark, RUBY_TYPED_DEFAULT_FREE, 0,},
28 0, 0,
29 RUBY_TYPED_FREE_IMMEDIATELY,
30 };
31
32 static VALUE rb_ast_node_alloc(VALUE klass);
33
34 static void
setup_node(VALUE obj,rb_ast_t * ast,NODE * node)35 setup_node(VALUE obj, rb_ast_t *ast, NODE *node)
36 {
37 struct ASTNodeData *data;
38
39 TypedData_Get_Struct(obj, struct ASTNodeData, &rb_node_type, data);
40 data->ast = ast;
41 data->node = node;
42 }
43
44 static VALUE
ast_new_internal(rb_ast_t * ast,NODE * node)45 ast_new_internal(rb_ast_t *ast, NODE *node)
46 {
47 VALUE obj;
48
49 obj = rb_ast_node_alloc(rb_cNode);
50 setup_node(obj, ast, node);
51
52 return obj;
53 }
54
55 static VALUE rb_ast_parse_str(VALUE str);
56 static VALUE rb_ast_parse_file(VALUE path);
57 static VALUE rb_ast_parse_array(VALUE array);
58
59 static VALUE
ast_parse_new(void)60 ast_parse_new(void)
61 {
62 return rb_parser_set_context(rb_parser_new(), NULL, 0);
63 }
64
65 static VALUE
ast_parse_done(rb_ast_t * ast)66 ast_parse_done(rb_ast_t *ast)
67 {
68 if (!ast->body.root) {
69 rb_ast_dispose(ast);
70 rb_exc_raise(GET_EC()->errinfo);
71 }
72
73 return ast_new_internal(ast, (NODE *)ast->body.root);
74 }
75
76 /*
77 * call-seq:
78 * RubyVM::AbstractSyntaxTree.parse(string) -> RubyVM::AbstractSyntaxTree::Node
79 *
80 * Parses the given string into an abstract syntax tree,
81 * returning the root node of that tree.
82 *
83 * SyntaxError is raised if the given string is invalid syntax.
84 *
85 * RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
86 * # => #<RubyVM::AbstractSyntaxTree::Node(NODE_SCOPE(0) 1:0, 1:9): >
87 */
88 static VALUE
rb_ast_s_parse(VALUE module,VALUE str)89 rb_ast_s_parse(VALUE module, VALUE str)
90 {
91 return rb_ast_parse_str(str);
92 }
93
94 static VALUE
rb_ast_parse_str(VALUE str)95 rb_ast_parse_str(VALUE str)
96 {
97 rb_ast_t *ast = 0;
98
99 StringValue(str);
100 ast = rb_parser_compile_string_path(ast_parse_new(), Qnil, str, 1);
101 return ast_parse_done(ast);
102 }
103
104 /*
105 * call-seq:
106 * RubyVM::AbstractSyntaxTree.parse_file(pathname) -> RubyVM::AbstractSyntaxTree::Node
107 *
108 * Reads the file from <code>pathname</code>, then parses it like ::parse,
109 * returning the root node of the abstract syntax tree.
110 *
111 * SyntaxError is raised if <code>pathname</code>'s contents are not
112 * valid Ruby syntax.
113 *
114 * RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
115 * # => #<RubyVM::AbstractSyntaxTree::Node(NODE_SCOPE(0) 1:0, 31:3): >
116 */
117 static VALUE
rb_ast_s_parse_file(VALUE module,VALUE path)118 rb_ast_s_parse_file(VALUE module, VALUE path)
119 {
120 return rb_ast_parse_file(path);
121 }
122
123 static VALUE
rb_ast_parse_file(VALUE path)124 rb_ast_parse_file(VALUE path)
125 {
126 VALUE f;
127 rb_ast_t *ast = 0;
128 rb_encoding *enc = rb_utf8_encoding();
129
130 FilePathValue(path);
131 f = rb_file_open_str(path, "r");
132 rb_funcall(f, rb_intern("set_encoding"), 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
133 ast = rb_parser_compile_file_path(ast_parse_new(), Qnil, f, 1);
134 rb_io_close(f);
135 return ast_parse_done(ast);
136 }
137
138 static VALUE
lex_array(VALUE array,int index)139 lex_array(VALUE array, int index)
140 {
141 VALUE str = rb_ary_entry(array, index);
142 if (!NIL_P(str)) {
143 StringValue(str);
144 if (!rb_enc_asciicompat(rb_enc_get(str))) {
145 rb_raise(rb_eArgError, "invalid source encoding");
146 }
147 }
148 return str;
149 }
150
151 static VALUE
rb_ast_parse_array(VALUE array)152 rb_ast_parse_array(VALUE array)
153 {
154 rb_ast_t *ast = 0;
155
156 array = rb_check_array_type(array);
157 ast = rb_parser_compile_generic(ast_parse_new(), lex_array, Qnil, array, 1);
158 return ast_parse_done(ast);
159 }
160
161 static VALUE node_children(rb_ast_t*, NODE*);
162
163 static VALUE
node_find(VALUE self,const int node_id)164 node_find(VALUE self, const int node_id)
165 {
166 VALUE ary;
167 long i;
168 struct ASTNodeData *data;
169 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
170
171 if (nd_node_id(data->node) == node_id) return self;
172
173 ary = node_children(data->ast, data->node);
174
175 for (i = 0; i < RARRAY_LEN(ary); i++) {
176 VALUE child = RARRAY_AREF(ary, i);
177
178 if (CLASS_OF(child) == rb_cNode) {
179 VALUE result = node_find(child, node_id);
180 if (RTEST(result)) return result;
181 }
182 }
183
184 return Qnil;
185 }
186
187 extern VALUE rb_e_script;
188
189 static VALUE
script_lines(VALUE path)190 script_lines(VALUE path)
191 {
192 VALUE hash, lines;
193 ID script_lines;
194 CONST_ID(script_lines, "SCRIPT_LINES__");
195 if (!rb_const_defined_at(rb_cObject, script_lines)) return Qnil;
196 hash = rb_const_get_at(rb_cObject, script_lines);
197 if (!RB_TYPE_P(hash, T_HASH)) return Qnil;
198 lines = rb_hash_lookup(hash, path);
199 if (!RB_TYPE_P(lines, T_ARRAY)) return Qnil;
200 return lines;
201 }
202
203 /*
204 * call-seq:
205 * RubyVM::AbstractSyntaxTree.of(proc) -> RubyVM::AbstractSyntaxTree::Node
206 * RubyVM::AbstractSyntaxTree.of(method) -> RubyVM::AbstractSyntaxTree::Node
207 *
208 * Returns AST nodes of the given proc or method.
209 *
210 * RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
211 * # => #<RubyVM::AbstractSyntaxTree::Node(NODE_SCOPE(0) 1:35, 1:42): >
212 *
213 * def hello
214 * puts "hello, world"
215 * end
216 *
217 * RubyVM::AbstractSyntaxTree.of(method(:hello))
218 * # => #<RubyVM::AbstractSyntaxTree::Node(NODE_SCOPE(0) 1:0, 3:3): >
219 */
220 static VALUE
rb_ast_s_of(VALUE module,VALUE body)221 rb_ast_s_of(VALUE module, VALUE body)
222 {
223 VALUE path, node, lines;
224 int node_id;
225 const rb_iseq_t *iseq = NULL;
226
227 if (rb_obj_is_proc(body)) {
228 iseq = vm_proc_iseq(body);
229
230 if (!rb_obj_is_iseq((VALUE)iseq)) {
231 iseq = NULL;
232 }
233 }
234 else {
235 iseq = rb_method_iseq(body);
236 }
237
238 if (!iseq) return Qnil;
239
240 path = rb_iseq_path(iseq);
241 node_id = iseq->body->location.node_id;
242 if (!NIL_P(lines = script_lines(path))) {
243 node = rb_ast_parse_array(lines);
244 }
245 else if (RSTRING_LEN(path) == 2 && memcmp(RSTRING_PTR(path), "-e", 2) == 0) {
246 node = rb_ast_parse_str(rb_e_script);
247 }
248 else {
249 node = rb_ast_parse_file(path);
250 }
251
252 return node_find(node, node_id);
253 }
254
255 static VALUE
rb_ast_node_alloc(VALUE klass)256 rb_ast_node_alloc(VALUE klass)
257 {
258 struct ASTNodeData *data;
259 VALUE obj = TypedData_Make_Struct(klass, struct ASTNodeData, &rb_node_type, data);
260
261 return obj;
262 }
263
264 static const char*
node_type_to_str(const NODE * node)265 node_type_to_str(const NODE *node)
266 {
267 return (ruby_node_name(nd_type(node)) + rb_strlen_lit("NODE_"));
268 }
269
270 /*
271 * call-seq:
272 * node.type -> symbol
273 *
274 * Returns the type of this node as a symbol.
275 *
276 * root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
277 * root.type # => :SCOPE
278 * call = root.children[2]
279 * call.type # => :OPCALL
280 */
281 static VALUE
rb_ast_node_type(VALUE self)282 rb_ast_node_type(VALUE self)
283 {
284 struct ASTNodeData *data;
285 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
286
287 return rb_sym_intern_ascii_cstr(node_type_to_str(data->node));
288 }
289
290 #define NEW_CHILD(ast, node) node ? ast_new_internal(ast, node) : Qnil
291
292 static VALUE
rb_ary_new_from_node_args(rb_ast_t * ast,long n,...)293 rb_ary_new_from_node_args(rb_ast_t *ast, long n, ...)
294 {
295 va_list ar;
296 VALUE ary;
297 long i;
298
299 ary = rb_ary_new2(n);
300
301 va_start(ar, n);
302 for (i=0; i<n; i++) {
303 NODE *node;
304 node = va_arg(ar, NODE *);
305 rb_ary_push(ary, NEW_CHILD(ast, node));
306 }
307 va_end(ar);
308 return ary;
309 }
310
311 static VALUE
dump_block(rb_ast_t * ast,NODE * node)312 dump_block(rb_ast_t *ast, NODE *node)
313 {
314 VALUE ary = rb_ary_new();
315 do {
316 rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
317 } while (node->nd_next &&
318 nd_type(node->nd_next) == NODE_BLOCK &&
319 (node = node->nd_next, 1));
320 if (node->nd_next) {
321 rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
322 }
323
324 return ary;
325 }
326
327 static VALUE
dump_array(rb_ast_t * ast,NODE * node)328 dump_array(rb_ast_t *ast, NODE *node)
329 {
330 VALUE ary = rb_ary_new();
331 rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
332
333 while (node->nd_next && nd_type(node->nd_next) == NODE_ARRAY) {
334 node = node->nd_next;
335 rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
336 }
337 rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
338
339 return ary;
340 }
341
342 static VALUE
var_name(ID id)343 var_name(ID id)
344 {
345 if (!id) return Qnil;
346 if (!rb_id2str(id)) return Qnil;
347 return ID2SYM(id);
348 }
349
350 static VALUE
node_children(rb_ast_t * ast,NODE * node)351 node_children(rb_ast_t *ast, NODE *node)
352 {
353 char name[DECIMAL_SIZE_OF_BITS(sizeof(long) * CHAR_BIT) + 2]; /* including '$' */
354
355 enum node_type type = nd_type(node);
356 switch (type) {
357 case NODE_BLOCK:
358 return dump_block(ast, node);
359 case NODE_IF:
360 return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
361 case NODE_UNLESS:
362 return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
363 case NODE_CASE:
364 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
365 case NODE_CASE2:
366 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
367 case NODE_WHEN:
368 return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_body, node->nd_next);
369 case NODE_WHILE:
370 goto loop;
371 case NODE_UNTIL:
372 loop:
373 return rb_ary_new_from_node_args(ast, 2, node->nd_cond, node->nd_body);
374 case NODE_ITER:
375 case NODE_FOR:
376 return rb_ary_new_from_node_args(ast, 2, node->nd_iter, node->nd_body);
377 case NODE_FOR_MASGN:
378 return rb_ary_new_from_node_args(ast, 1, node->nd_var);
379 case NODE_BREAK:
380 goto jump;
381 case NODE_NEXT:
382 goto jump;
383 case NODE_RETURN:
384 jump:
385 return rb_ary_new_from_node_args(ast, 1, node->nd_stts);
386 case NODE_REDO:
387 return rb_ary_new_from_node_args(ast, 0);
388 case NODE_RETRY:
389 return rb_ary_new_from_node_args(ast, 0);
390 case NODE_BEGIN:
391 return rb_ary_new_from_node_args(ast, 1, node->nd_body);
392 case NODE_RESCUE:
393 return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_resq, node->nd_else);
394 case NODE_RESBODY:
395 return rb_ary_new_from_node_args(ast, 3, node->nd_args, node->nd_body, node->nd_head);
396 case NODE_ENSURE:
397 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_ensr);
398 case NODE_AND:
399 goto andor;
400 case NODE_OR:
401 andor:
402 {
403 VALUE ary = rb_ary_new();
404
405 while (1) {
406 rb_ary_push(ary, NEW_CHILD(ast, node->nd_1st));
407 if (!node->nd_2nd || nd_type(node->nd_2nd) != (int)type)
408 break;
409 node = node->nd_2nd;
410 }
411 rb_ary_push(ary, NEW_CHILD(ast, node->nd_2nd));
412 return ary;
413 }
414 case NODE_MASGN:
415 if (NODE_NAMED_REST_P(node->nd_args)) {
416 return rb_ary_new_from_node_args(ast, 3, node->nd_value, node->nd_head, node->nd_args);
417 }
418 return rb_ary_new_from_node_args(ast, 2, node->nd_value, node->nd_head);
419 case NODE_LASGN:
420 goto asgn;
421 case NODE_DASGN:
422 goto asgn;
423 case NODE_DASGN_CURR:
424 goto asgn;
425 case NODE_IASGN:
426 goto asgn;
427 case NODE_CVASGN:
428 asgn:
429 if (NODE_REQUIRED_KEYWORD_P(node)) {
430 return rb_ary_new_from_args(1, var_name(node->nd_vid));
431 }
432 return rb_ary_new_from_args(2, var_name(node->nd_vid), NEW_CHILD(ast, node->nd_value));
433 case NODE_GASGN:
434 goto asgn;
435 case NODE_CDECL:
436 if (node->nd_vid) {
437 return rb_ary_new_from_args(2, ID2SYM(node->nd_vid), NEW_CHILD(ast, node->nd_value));
438 }
439 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_else), ID2SYM(node->nd_else->nd_mid), NEW_CHILD(ast, node->nd_value));
440 case NODE_OP_ASGN1:
441 return rb_ary_new_from_args(4, NEW_CHILD(ast, node->nd_recv),
442 ID2SYM(node->nd_mid),
443 NEW_CHILD(ast, node->nd_args->nd_head),
444 NEW_CHILD(ast, node->nd_args->nd_body));
445 case NODE_OP_ASGN2:
446 return rb_ary_new_from_args(5, NEW_CHILD(ast, node->nd_recv),
447 node->nd_next->nd_aid ? Qtrue : Qfalse,
448 ID2SYM(node->nd_next->nd_vid),
449 ID2SYM(node->nd_next->nd_mid),
450 NEW_CHILD(ast, node->nd_value));
451 case NODE_OP_ASGN_AND:
452 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idANDOP),
453 NEW_CHILD(ast, node->nd_value));
454 case NODE_OP_ASGN_OR:
455 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idOROP),
456 NEW_CHILD(ast, node->nd_value));
457 case NODE_OP_CDECL:
458 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head),
459 ID2SYM(node->nd_aid),
460 NEW_CHILD(ast, node->nd_value));
461 case NODE_CALL:
462 case NODE_OPCALL:
463 case NODE_QCALL:
464 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv),
465 ID2SYM(node->nd_mid),
466 NEW_CHILD(ast, node->nd_args));
467 case NODE_FCALL:
468 return rb_ary_new_from_args(2, ID2SYM(node->nd_mid),
469 NEW_CHILD(ast, node->nd_args));
470 case NODE_VCALL:
471 return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
472 case NODE_SUPER:
473 return rb_ary_new_from_node_args(ast, 1, node->nd_args);
474 case NODE_ZSUPER:
475 return rb_ary_new_from_node_args(ast, 0);
476 case NODE_ARRAY:
477 goto ary;
478 case NODE_VALUES:
479 ary:
480 return dump_array(ast, node);
481 case NODE_ZARRAY:
482 return rb_ary_new_from_node_args(ast, 0);
483 case NODE_HASH:
484 return rb_ary_new_from_node_args(ast, 1, node->nd_head);
485 case NODE_YIELD:
486 return rb_ary_new_from_node_args(ast, 1, node->nd_head);
487 case NODE_LVAR:
488 case NODE_DVAR:
489 return rb_ary_new_from_args(1, var_name(node->nd_vid));
490 case NODE_IVAR:
491 case NODE_CONST:
492 case NODE_CVAR:
493 case NODE_GVAR:
494 return rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
495 case NODE_NTH_REF:
496 snprintf(name, sizeof(name), "$%ld", node->nd_nth);
497 return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
498 case NODE_BACK_REF:
499 name[0] = '$';
500 name[1] = (char)node->nd_nth;
501 name[2] = '\0';
502 return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
503 case NODE_MATCH:
504 goto lit;
505 case NODE_MATCH2:
506 if (node->nd_args) {
507 return rb_ary_new_from_node_args(ast, 3, node->nd_recv, node->nd_value, node->nd_args);
508 }
509 return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
510 case NODE_MATCH3:
511 return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
512 case NODE_LIT:
513 goto lit;
514 case NODE_STR:
515 goto lit;
516 case NODE_XSTR:
517 lit:
518 return rb_ary_new_from_args(1, node->nd_lit);
519 case NODE_ONCE:
520 return rb_ary_new_from_node_args(ast, 1, node->nd_body);
521 case NODE_DSTR:
522 goto dlit;
523 case NODE_DXSTR:
524 goto dlit;
525 case NODE_DREGX:
526 goto dlit;
527 case NODE_DSYM:
528 dlit:
529 return rb_ary_new_from_args(3, node->nd_lit,
530 NEW_CHILD(ast, node->nd_next->nd_head),
531 NEW_CHILD(ast, node->nd_next->nd_next));
532 case NODE_EVSTR:
533 return rb_ary_new_from_node_args(ast, 1, node->nd_body);
534 case NODE_ARGSCAT:
535 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
536 case NODE_ARGSPUSH:
537 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
538 case NODE_SPLAT:
539 return rb_ary_new_from_node_args(ast, 1, node->nd_head);
540 case NODE_BLOCK_PASS:
541 return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
542 case NODE_DEFN:
543 return rb_ary_new_from_args(2, ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
544 case NODE_DEFS:
545 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
546 case NODE_ALIAS:
547 return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
548 case NODE_VALIAS:
549 return rb_ary_new_from_args(2, ID2SYM(node->nd_alias), ID2SYM(node->nd_orig));
550 case NODE_UNDEF:
551 return rb_ary_new_from_node_args(ast, 1, node->nd_undef);
552 case NODE_CLASS:
553 return rb_ary_new_from_node_args(ast, 3, node->nd_cpath, node->nd_super, node->nd_body);
554 case NODE_MODULE:
555 return rb_ary_new_from_node_args(ast, 2, node->nd_cpath, node->nd_body);
556 case NODE_SCLASS:
557 return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_body);
558 case NODE_COLON2:
559 return rb_ary_new_from_args(2, NEW_CHILD(ast, node->nd_head), ID2SYM(node->nd_mid));
560 case NODE_COLON3:
561 return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
562 case NODE_DOT2:
563 goto dot;
564 case NODE_DOT3:
565 goto dot;
566 case NODE_FLIP2:
567 goto dot;
568 case NODE_FLIP3:
569 dot:
570 return rb_ary_new_from_node_args(ast, 2, node->nd_beg, node->nd_end);
571 case NODE_SELF:
572 return rb_ary_new_from_node_args(ast, 0);
573 case NODE_NIL:
574 return rb_ary_new_from_node_args(ast, 0);
575 case NODE_TRUE:
576 return rb_ary_new_from_node_args(ast, 0);
577 case NODE_FALSE:
578 return rb_ary_new_from_node_args(ast, 0);
579 case NODE_ERRINFO:
580 return rb_ary_new_from_node_args(ast, 0);
581 case NODE_DEFINED:
582 return rb_ary_new_from_node_args(ast, 1, node->nd_head);
583 case NODE_POSTEXE:
584 return rb_ary_new_from_node_args(ast, 1, node->nd_body);
585 case NODE_ATTRASGN:
586 return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_args));
587 case NODE_LAMBDA:
588 return rb_ary_new_from_node_args(ast, 1, node->nd_body);
589 case NODE_OPT_ARG:
590 return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
591 case NODE_KW_ARG:
592 return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
593 case NODE_POSTARG:
594 if (NODE_NAMED_REST_P(node->nd_1st)) {
595 return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
596 }
597 return rb_ary_new_from_node_args(ast, 1, node->nd_2nd);
598 case NODE_ARGS:
599 {
600 struct rb_args_info *ainfo = node->nd_ainfo;
601 return rb_ary_new_from_args(10,
602 INT2NUM(ainfo->pre_args_num),
603 NEW_CHILD(ast, ainfo->pre_init),
604 NEW_CHILD(ast, ainfo->opt_args),
605 var_name(ainfo->first_post_arg),
606 INT2NUM(ainfo->post_args_num),
607 NEW_CHILD(ast, ainfo->post_init),
608 var_name(ainfo->rest_arg),
609 NEW_CHILD(ast, ainfo->kw_args),
610 NEW_CHILD(ast, ainfo->kw_rest_arg),
611 var_name(ainfo->block_arg));
612 }
613 case NODE_SCOPE:
614 {
615 ID *tbl = node->nd_tbl;
616 int i, size = tbl ? (int)*tbl++ : 0;
617 VALUE locals = rb_ary_new_capa(size);
618 for (i = 0; i < size; i++) {
619 rb_ary_push(locals, var_name(tbl[i]));
620 }
621 return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, node->nd_args), NEW_CHILD(ast, node->nd_body));
622 }
623 case NODE_ARGS_AUX:
624 case NODE_LAST:
625 break;
626 }
627
628 rb_bug("node_children: unknown node: %s", ruby_node_name(type));
629 }
630
631 /*
632 * call-seq:
633 * node.children -> array
634 *
635 * Returns AST nodes under this one. Each kind of node
636 * has different children, depending on what kind of node it is.
637 *
638 * The returned array may contain other nodes or <code>nil</code>.
639 */
640 static VALUE
rb_ast_node_children(VALUE self)641 rb_ast_node_children(VALUE self)
642 {
643 struct ASTNodeData *data;
644 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
645
646 return node_children(data->ast, data->node);
647 }
648
649 /*
650 * call-seq:
651 * node.first_lineno -> integer
652 *
653 * The line number in the source code where this AST's text began.
654 */
655 static VALUE
rb_ast_node_first_lineno(VALUE self)656 rb_ast_node_first_lineno(VALUE self)
657 {
658 struct ASTNodeData *data;
659 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
660
661 return INT2NUM(nd_first_lineno(data->node));
662 }
663
664 /*
665 * call-seq:
666 * node.first_column -> integer
667 *
668 * The column number in the source code where this AST's text began.
669 */
670 static VALUE
rb_ast_node_first_column(VALUE self)671 rb_ast_node_first_column(VALUE self)
672 {
673 struct ASTNodeData *data;
674 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
675
676 return INT2NUM(nd_first_column(data->node));
677 }
678
679 /*
680 * call-seq:
681 * node.last_lineno -> integer
682 *
683 * The line number in the source code where this AST's text ended.
684 */
685 static VALUE
rb_ast_node_last_lineno(VALUE self)686 rb_ast_node_last_lineno(VALUE self)
687 {
688 struct ASTNodeData *data;
689 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
690
691 return INT2NUM(nd_last_lineno(data->node));
692 }
693
694 /*
695 * call-seq:
696 * node.last_column -> integer
697 *
698 * The column number in the source code where this AST's text ended.
699 */
700 static VALUE
rb_ast_node_last_column(VALUE self)701 rb_ast_node_last_column(VALUE self)
702 {
703 struct ASTNodeData *data;
704 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
705
706 return INT2NUM(nd_last_column(data->node));
707 }
708
709 /*
710 * call-seq:
711 * node.inspect -> string
712 *
713 * Returns debugging information about this node as a string.
714 */
715 static VALUE
rb_ast_node_inspect(VALUE self)716 rb_ast_node_inspect(VALUE self)
717 {
718 VALUE str;
719 VALUE cname;
720 struct ASTNodeData *data;
721 TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
722
723 cname = rb_class_path(rb_obj_class(self));
724 str = rb_str_new2("#<");
725
726 rb_str_append(str, cname);
727 rb_str_catf(str, ":%s@%d:%d-%d:%d>",
728 node_type_to_str(data->node),
729 nd_first_lineno(data->node), nd_first_column(data->node),
730 nd_last_lineno(data->node), nd_last_column(data->node));
731
732 return str;
733 }
734
735 void
Init_ast(void)736 Init_ast(void)
737 {
738 /*
739 * AbstractSyntaxTree provides methods to parse Ruby code into
740 * abstract syntax trees. The nodes in the tree
741 * are instances of RubyVM::AbstractSyntaxTree::Node.
742 */
743 rb_mAST = rb_define_module_under(rb_cRubyVM, "AbstractSyntaxTree");
744 /*
745 * RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
746 * RubyVM::AbstractSyntaxTree.
747 */
748 rb_cNode = rb_define_class_under(rb_mAST, "Node", rb_cObject);
749
750 rb_undef_alloc_func(rb_cNode);
751 rb_define_singleton_method(rb_mAST, "parse", rb_ast_s_parse, 1);
752 rb_define_singleton_method(rb_mAST, "parse_file", rb_ast_s_parse_file, 1);
753 rb_define_singleton_method(rb_mAST, "of", rb_ast_s_of, 1);
754 rb_define_method(rb_cNode, "type", rb_ast_node_type, 0);
755 rb_define_method(rb_cNode, "first_lineno", rb_ast_node_first_lineno, 0);
756 rb_define_method(rb_cNode, "first_column", rb_ast_node_first_column, 0);
757 rb_define_method(rb_cNode, "last_lineno", rb_ast_node_last_lineno, 0);
758 rb_define_method(rb_cNode, "last_column", rb_ast_node_last_column, 0);
759 rb_define_method(rb_cNode, "children", rb_ast_node_children, 0);
760 rb_define_method(rb_cNode, "inspect", rb_ast_node_inspect, 0);
761 }
762