Class: Node
- Defined in:
- ext/nodewrap.c,
lib/nodepp.rb,
lib/as_code.rb,
lib/node_to_a.rb,
lib/as_expression.rb,
ext/nodewrap.c
Overview
Node is a wrapper for Ruby’s Nodes, which are not objects. Nodes can be obtained from many of the other methods in the nodewrap library (see Method#body and Proc#body, for example).
Direct Known Subclasses
ALIAS, ALLOCA, AND, ARGS, ARGSCAT, ARGSPUSH, ARRAY, ATTRASGN, ATTRSET, BACK_REF, BEGIN, BLOCK, BLOCK_ARG, BLOCK_PASS, BMETHOD, BREAK, CALL, CASE, CDECL, CFUNC, CLASS, COLON2, COLON3, CONST, CREF, CVAR, CVAR2, CVASGN, CVDECL, DASGN, DASGN_CURR, DEFINED, DEFN, DEFS, DMETHOD, DOT2, DOT3, DREGX, DREGX_ONCE, DSTR, DSYM, DVAR, DXSTR, ENSURE, EVSTR, FALSENODE, FBODY, FCALL, FLIP2, FLIP3, FOR, GASGN, GVAR, HASH, IASGN, IF, IFUNC, ITER, IVAR, LASGN, LIT, LVAR, MASGN, MATCH, MATCH2, MATCH3, MEMO, METHOD, MODULE, NEWLINE, NEXT, NILNODE, NOT, NTH_REF, OPT_N, OP_ASGN1, OP_ASGN2, OP_ASGN_AND, OP_ASGN_OR, OR, POSTEXE, REDO, RESBODY, RESCUE, RESTARGS, RETRY, RETURN, SCLASS, SCOPE, SELF, STR, SUPER, TRUENODE, UNDEF, UNTIL, VALIAS, VCALL, WHEN, WHILE, XSTR, YIELD, ZARRAY, ZSUPER, VM::InlineCache
Defined Under Namespace
Classes: ALIAS, ALLOCA, AND, ARGS, ARGSCAT, ARGSPUSH, ARRAY, ATTRASGN, ATTRSET, BACK_REF, BEGIN, BLOCK, BLOCK_ARG, BLOCK_PASS, BMETHOD, BREAK, CALL, CASE, CDECL, CFUNC, CLASS, COLON2, COLON3, CONST, CREF, CVAR, CVAR2, CVASGN, CVDECL, DASGN, DASGN_CURR, DEFINED, DEFN, DEFS, DMETHOD, DOT2, DOT3, DREGX, DREGX_ONCE, DSTR, DSYM, DVAR, DXSTR, ENSURE, EVSTR, FALSENODE, FBODY, FCALL, FLIP2, FLIP3, FOR, GASGN, GVAR, HASH, IASGN, IF, IFUNC, ITER, IVAR, LASGN, LIT, LVAR, MASGN, MATCH, MATCH2, MATCH3, MEMO, METHOD, MODULE, NEWLINE, NEXT, NILNODE, NOT, NTH_REF, OPT_N, OP_ASGN1, OP_ASGN2, OP_ASGN_AND, OP_ASGN_OR, OR, POSTEXE, REDO, RESBODY, RESCUE, RESTARGS, RETRY, RETURN, SCLASS, SCOPE, SELF, STR, SUPER, TRUENODE, UNDEF, UNTIL, VALIAS, VCALL, WHEN, WHILE, XSTR, YIELD, ZARRAY, ZSUPER
Class Method Summary collapse
-
._load(str) ⇒ Node
Load a dumped node.
-
.compile_string(str) ⇒ Node
Compile a string into a node.
- .define_code(klass, &block) ⇒ Object
- .define_expression(klass, &block) ⇒ Object
Instance Method Summary collapse
-
#[](member) ⇒ Object
Return the given member of a node.
-
#_dump ⇒ String
Dump a node.
-
#address ⇒ Numeric
Returns a node’s address.
- #as_code(indent = 0, *args) ⇒ Object
-
#as_expression(*args) ⇒ Object
Return an string describing this node as a single expression.
-
#as_paren_expression(*args) ⇒ Object
Return a string as with as_expression, but surround it with parens if it is a composite expression, so that it can be used to form more complex expressions.
-
#bytecode_compile ⇒ VM::InstructionSequence
Compile a parsed node tree into a bytecode sequence.
-
#eval(Object) ⇒ Object
Evaluate a node with the given object as self and returns the result.
-
#flags ⇒ Numeric
Returns a node’s flags.
-
#inspect ⇒ String
Returns a string representation of the node’s data.
-
#members ⇒ Array of String
Return an array of strings containing the names of a node’s members.
-
#nd_file ⇒ String?
Returns the file the node is associated with.
-
#nd_line ⇒ Numeric
Returns the line number the node is associated with.
-
#nd_type ⇒ NodeType
Returns a NodeType structure representing the type of the node.
-
#pretty_print(pp) ⇒ Object
Pretty-print node using Node#tree onto s, which can be a String or IO.
-
#tree(s = '', prefix = '') ⇒ Object
Return a string containing an ascii-art tree of the node’s structure.
Class Method Details
._load(str) ⇒ Node
Load a dumped node.
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 |
# File 'ext/nodewrap.c', line 1370
static VALUE node_load(VALUE klass, VALUE str)
{
VALUE arr, node_hash, node_id, id_hash;
NODE * n;
VALUE data;
if( ruby_safe_level >= 4
|| (ruby_safe_level >= 1 && OBJ_TAINTED(str)))
{
/* no playing with knives in the sandbox */
rb_raise(rb_eSecurityError, "Insecure: can't load node");
}
arr = marshal_load(str);
node_hash = rb_ary_pop(arr);
node_id = rb_ary_pop(arr);
id_hash = rb_hash_new();
data = rb_hash_aref(node_hash, node_id);
n = load_node_from_hash(data, node_id, node_hash, id_hash);
/* TODO: Need a free function in this case */
return wrap_node(n);
}
|
.compile_string(str) ⇒ Node
Compile a string into a node.
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 |
# File 'ext/nodewrap.c', line 1286
static VALUE node_compile_string(int argc, VALUE * argv, VALUE self)
{
NODE * node;
VALUE str = Qnil, file = Qnil, line = Qnil;
rb_scan_args(argc, argv, "12", &str, &file, &line);
file = NIL_P(file) ? rb_str_new2("(compiled)") : file;
line = NIL_P(line) ? INT2NUM(1) : line;
node = rb_compile_string(STR2CSTR(file), str, NUM2INT(line));
if(ruby_nerrs > 0)
{
#ifdef RUBY_HAS_YARV
ruby_nerrs = 0;
rb_exc_raise(GET_THREAD()->errinfo);
#else
compile_error(0);
#endif
}
return wrap_node(node);
}
|
.define_code(klass, &block) ⇒ Object
50 51 52 53 54 |
# File 'lib/as_code.rb', line 50 def define_code(klass, &block) if const_defined?(klass) then const_get(klass).instance_eval { define_method(:as_code_impl, &block) } end end |
.define_expression(klass, &block) ⇒ Object
60 61 62 63 64 |
# File 'lib/as_expression.rb', line 60 def define_expression(klass, &block) if const_defined?(klass) then const_get(klass).instance_eval { define_method(:as_expression_impl, &block) } end end |
Instance Method Details
#[](member) ⇒ Object
Return the given member of a node.
384 385 386 387 388 389 390 |
# File 'ext/nodewrap.c', line 384
static VALUE node_bracket(VALUE node, VALUE member)
{
ID id = SYMBOL_P(member)
? SYM2ID(member)
: rb_intern(STR2CSTR(member));
return rb_funcall(node, id, 0);
}
|
#_dump ⇒ String
Dump a node.
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 |
# File 'ext/nodewrap.c', line 1344
static VALUE node_dump(VALUE self, VALUE limit)
{
NODE * n;
VALUE node_hash, arr;
if(ruby_safe_level >= 4)
{
/* no access to potentially sensitive data from the sandbox */
rb_raise(rb_eSecurityError, "Insecure: can't dump node");
}
Data_Get_Struct(self, NODE, n);
node_hash = node_to_hash(n);
arr = rb_ary_new();
rb_ary_push(arr, node_id(n));
rb_ary_push(arr, node_hash);
VALUE s = marshal_dump(arr, limit);
return s;
}
|
#address ⇒ Numeric
Returns a node’s address.
283 284 285 286 287 288 |
# File 'ext/nodewrap.c', line 283
static VALUE node_address(VALUE self)
{
NODE * n;
Data_Get_Struct(self, NODE, n);
return ULONG2NUM((unsigned long)(n));
}
|
#as_code(indent = 0, *args) ⇒ Object
33 34 35 |
# File 'lib/as_code.rb', line 33 def as_code(indent=0, *args) return as_code_impl(self, indent, *args) end |
#as_expression(*args) ⇒ Object
Return an string describing this node as a single expression. By default, this just returns the name of the node’s type, but some node types override this method to produce more meaningful output.
37 38 39 |
# File 'lib/as_expression.rb', line 37 def as_expression(*args) return as_expression_impl(self, *args) end |
#as_paren_expression(*args) ⇒ Object
Return a string as with as_expression, but surround it with parens if it is a composite expression, so that it can be used to form more complex expressions.
44 45 46 47 48 49 50 |
# File 'lib/as_expression.rb', line 44 def as_paren_expression(*args) expr = self.as_expression(*args) if not OMIT_PARENS[self.class] then expr = "(#{expr})" end return expr end |
#bytecode_compile ⇒ VM::InstructionSequence
Compile a parsed node tree into a bytecode sequence.
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 |
# File 'ext/nodewrap.c', line 1318
static VALUE node_bytecode_compile(int argc, VALUE * argv, VALUE self)
{
NODE * node = unwrap_node(self);
VALUE opt = Qnil;
rb_compile_option_t option;
rb_scan_args(argc, argv, "01", &opt);
make_compile_option(&option, opt);
return rb_iseq_new_with_opt(
node,
rb_str_new2("<main>"),
rb_str_new2(node->nd_file),
Qfalse,
ISEQ_TYPE_TOP,
&option);
}
|
#eval(Object) ⇒ Object
Evaluate a node with the given object as self and returns the result.
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 |
# File 'ext/nodewrap.c', line 1120
static VALUE node_eval(VALUE node, VALUE self)
{
NODE * n = unwrap_node(node);
if(ruby_safe_level >= 2)
{
/* evaluating a node can cause a crash */
rb_raise(rb_eSecurityError, "Insecure: can't add method");
}
#ifdef RUBY_HAS_YARV
return yarvcore_eval_parsed(n, rb_str_new2("(eval)"));
#else
{
/* Ruby doesn't give us access to rb_eval, so we have to fake it. */
struct BLOCK * b;
VALUE proc;
proc = create_proc(rb_cProc, Qnil, n, 0);
Data_Get_Struct(proc, struct BLOCK, b);
b->self = self;
return rb_funcall(proc, rb_intern("call"), 0);
}
#endif
}
|
#flags ⇒ Numeric
Returns a node’s flags.
296 297 298 299 300 301 |
# File 'ext/nodewrap.c', line 296
static VALUE node_flags(VALUE self)
{
NODE * n;
Data_Get_Struct(self, NODE, n);
return INT2NUM(n->flags);
}
|
#inspect ⇒ String
Returns a string representation of the node’s data.
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'ext/nodewrap.c', line 436
static VALUE node_inspect(VALUE node)
{
#if RUBY_VERSION_CODE < 190
if(rb_inspecting_p(node))
{
VALUE str = rb_str_new2("#<");
rb_str_cat2(str, rb_class2name(CLASS_OF(node)));
rb_str_cat2(str, ":...>");
return str;
}
else
{
return rb_protect_inspect(node_inspect_protect, node, 0);
}
#else
return rb_exec_recursive(node_inspect_protect, node, 0);
#endif
}
|
#members ⇒ Array of String
Return an array of strings containing the names of a node’s members.
373 374 375 376 |
# File 'ext/nodewrap.c', line 373
static VALUE node_members(VALUE node)
{
return node_s_members(rb_class_of(node));
}
|
#nd_file ⇒ String?
Returns the file the node is associated with
309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'ext/nodewrap.c', line 309
static VALUE node_nd_file(VALUE self)
{
NODE * n;
Data_Get_Struct(self, NODE, n);
if(n->nd_file)
{
return rb_str_new2(n->nd_file);
}
else
{
return Qnil;
}
}
|
#nd_line ⇒ Numeric
Returns the line number the node is associated with.
329 330 331 332 333 334 |
# File 'ext/nodewrap.c', line 329
static VALUE node_nd_line(VALUE self)
{
NODE * n;
Data_Get_Struct(self, NODE, n);
return LONG2NUM(nd_line(n));
}
|
#nd_type ⇒ NodeType
Returns a NodeType structure representing the type of the node.
342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'ext/nodewrap.c', line 342
static VALUE node_nd_type(VALUE self)
{
NODE * n;
const Node_Type_Descrip * descrip;
Data_Get_Struct(self, NODE, n);
rb_check_type((VALUE)(self), T_DATA);
descrip = node_type_descrip(nd_type(n));
return rb_struct_new(
rb_cNodeType,
rb_str_new2(descrip->name),
INT2NUM(descrip->nt));
}
|
#pretty_print(pp) ⇒ Object
Pretty-print node using Node#tree onto s, which can be a String or IO.
57 58 59 |
# File 'lib/nodepp.rb', line 57 def pretty_print(pp) pp.text(tree()) end |
#tree(s = '', prefix = '') ⇒ Object
Return a string containing an ascii-art tree of the node’s structure.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/nodepp.rb', line 23 def tree(s = '', prefix = '') s << "NODE_#{self.nd_type.to_s} at #{self.nd_file}:#{self.nd_line}\n" self.members.each_with_index do |member, idx| last = (idx == self.members.size-1) s << "#{prefix}#{(last ? '+-' : '|-')}#{member} = " value = self[member] if Node === value then value.tree(s, prefix + (last ? ' ' : '| ')) elsif Object.const_defined?(:VM) and VM.const_defined?(:InstructionSequence) and VM::InstructionSequence === value then s << "<ISeq:#{value.self.name}@#{value.self.filename}>\n" d = value.disasm lines = d.split("\n") lines.each_with_index do |line, idx| if line =~ /^== disasm: (.*?)=/ then line = $1; end if line =~ /(.*)\s+\(\s*\d+\)/ then line = $1; end next if line =~ /^\|-----/ last_line = (idx == lines.size-1) s << "#{prefix}#{last ? ' ' : '| '}#{(last_line ? '+-' : '|-')}#{line}\n" end # p value.local_table elsif member == 'noex' then s << Noex.stringify(value) + "\n" else s << value.inspect + "\n" end end return s end |