Hi,

At Fri, 22 Aug 2003 21:00:47 +0900,
Robert Feldt wrote:
> >> How are "dynamic" strings represented internally?
> >
> > NodeDump or ii would help you.
> >
> Have you been able to compile them with 1.8? I haven't.

Hmmm, the latest in PragProg site still seems 0.1.7 for 1.6.

This is my own patch to NodeDump 0.1.7.


diff -ru2pN nodeDump-0.1.7/MANIFEST nodeDump-0.1.7+/MANIFEST --- nodeDump-0.1.7/MANIFEST 1970-01-01 09:00:00.000000000 +0900 +++ nodeDump-0.1.7+/MANIFEST 2003-07-29 12:10:48.000000000 +0900 @@ -0,0 +7 @@ +MANIFEST +README +depend +extconf.rb +makenodenames.rb +nd_version.h +nodeDump.c diff -ru2pN nodeDump-0.1.7/depend nodeDump-0.1.7+/depend --- nodeDump-0.1.7/depend 1970-01-01 09:00:00.000000000 +0900 +++ nodeDump-0.1.7+/depend 2003-07-28 01:03:05.000000000 +0900 @@ -0,0 +1,4 @@ +node_names.h: $(hdrdir)/node.h + $(RUBY) $(srcdir)/makenodenames.rb $< $@ + +nodeDump.o: node_names.h diff -ru2pN nodeDump-0.1.7/extconf.rb nodeDump-0.1.7+/extconf.rb --- nodeDump-0.1.7/extconf.rb 2002-06-18 00:44:02.000000000 +0900 +++ nodeDump-0.1.7+/extconf.rb 2003-07-28 01:00:39.000000000 +0900 @@ -3,114 +3,6 @@ # for the typedef. # - - require 'mkmf' -require "rbconfig" - -# Return the full path to node.h - -def nameOfNode_h - cfg = Config::CONFIG - srcdir = cfg["srcdir"] - libdir = cfg["libdir"]+"/ruby/"+cfg["MAJOR"]+"."+cfg["MINOR"] - archdir = libdir+"/"+cfg["arch"] - - if File.exist? archdir + "/ruby.h" - hdrdir = archdir - else File.exist? srcdir + "/ruby.h" - hdrdir = srcdir - end - - hdrdir + "/node.h" -end - -# Given a list of node names, check that our nodeDump.c file -# handles them all - -# these are internal Ruby nodes that don't appear in a parse tree - -DUMMY_NODES = %w( NODE_MEMO NODE_LAST NODE_ALLOCA NODE_CNAME - NODE_CFUNC NODE_IFUNC NODE_RESBODY) - - -def checkWeHandle(nameList) - nodes = File.new(File.join(File.dirname($0), "nodeDump.c")).grep(/case\s+(NODE_\w+):/) { $1 } - inRubyNotDump = nameList - nodes - DUMMY_NODES - inDumpNotRuby = nodes - nameList - - if !inRubyNotDump.empty? - $stderr.print "\n\nNodes we don't handle:\n", inRubyNotDump.join(", "), "\n" - end - - if !inDumpNotRuby.empty? - $stderr.print "\n\nNodes we handle not in Ruby:\n", inDumpNotRuby.join(", "), "\n" - end - - # fail if there's anything in Ruby that we don't now about - return inRubyNotDump.empty? -end - - -# Create a node_names.h file containing enum -> name mappings - -def createNodeNames - - nameList = [] - - node = nameOfNode_h() - - File.open("node_names.h", "w") do |op| - - copying = false - - op.puts "const char *node_names[] = {" - - IO.foreach(node) do |line| - - if copying - if line =~ /\};/ - copying = false - else - if line =~ /^#/ - op.puts line - else - if line =~ /\s*(\w+)(,)?/ - op.puts "\t\"#$1\"#$2" - op.puts "\#define\t #{$1} #{$1}" - nameList << $1 - end - end - end - end - - copying = true if line =~ /enum node_type/ - end - - op.puts "};" - end - - checkWeHandle(nameList) -end - -if createNodeNames() - - have_func("rb_proc_new", "ruby.h") - - $CPPFLAGS << " -I." - create_makefile("NodeDump") - -else - - $stderr.puts <<_EOM_ - -================================================================= - -NodeDump can not be built on this system. This is probably due to -an incompatibility with Ruby versions. This version of NodeDump -only runs with Ruby 1.6 or later. - -================================================================= - -_EOM_ -end +have_func("rb_proc_new", "ruby.h") +create_makefile("NodeDump") diff -ru2pN nodeDump-0.1.7/makenodenames.rb nodeDump-0.1.7+/makenodenames.rb --- nodeDump-0.1.7/makenodenames.rb 1970-01-01 09:00:00.000000000 +0900 +++ nodeDump-0.1.7+/makenodenames.rb 2003-07-28 00:59:44.000000000 +0900 @@ -0,0 +1,71 @@ +#! /usr/bin/ruby + +class NodeList + DUMMY = %w( NODE_MEMO NODE_LAST NODE_ALLOCA NODE_CNAME + NODE_CFUNC NODE_IFUNC NODE_RESBODY) + + def initialize(node, src = File.join(File.dirname(__FILE__), "nodeDump.c")) + @in_dump = File.new(src).grep(/case\s+(NODE_\w+):/) {$1} + copying = false + @in_ruby = [] + @source = [] + IO.foreach(node) do |line| + if copying + case line + when /\};/ + break + when /^#/ + @source << line + when /\s*(\w+)(,)?/ + @source << "\t\"#$1\"#$2" + @source << "\#define\t #{$1} #{$1}" + @in_ruby << $1 + end + elsif line =~ /enum node_type/ + copying = true + end + end + end + + def handle? + inRubyNotDump = @in_ruby - @in_dump - DUMMY + inDumpNotRuby = @in_dump - @in_ruby + unless inRubyNotDump.empty? + $deferr.puts "\n\nNodes we don't handle:", inRubyNotDump.join(", ") + end + unless inDumpNotRuby.empty? + $deferr.puts "\n\nNodes we handle not in Ruby:", inDumpNotRuby.join(", ") + end + inRubyNotDump.empty? + end + + # Create a node_names.h file containing enum -> name mappings + def create(out) + out.puts "#ifndef NODE_NAMES_H" + out.puts "#define NODE_NAMES_H" + out.puts "const char *node_names[] = {" + out.puts @source + out.puts "};" + out.puts "#endif /* NODE_NAMES_H */" + end +end + +# (1..2) === ARGV.size or abort "usage: #$0 node.h [node_names.h]" + +nodes = NodeList.new(ARGV.shift) +nodes.handle? or abort <<_EOM_ + +================================================================= + +NodeDump can not be built on this system. This is probably due to +an incompatibility with Ruby versions. This version of NodeDump +only runs with Ruby 1.6 or later. + +================================================================= + +_EOM_ +if ARGV.empty? + nodes.create($defout) +else + File.open(ARGV.shift, "w") {|op| nodes.create(op)} +end diff -ru2pN nodeDump-0.1.7/nodeDump.c nodeDump-0.1.7+/nodeDump.c --- nodeDump-0.1.7/nodeDump.c 2002-07-11 22:37:39.000000000 +0900 +++ nodeDump-0.1.7+/nodeDump.c 2003-03-26 16:35:17.000000000 +0900 @@ -32,4 +32,6 @@ struct global_entry { }; +static void doDump(NODE *n, int level); + static void lp(int level, const char *fmt, ...) { va_list ap; @@ -57,4 +59,23 @@ static char * tail(char* s, char *e) } +static void +dump_cpath(const char *s, NODE *cpath, int level) +{ + ID id; + if (SPECIAL_CONST_P(cpath)) { + id = (ID)cpath; + cpath = 0; + } + else { + id = cpath->nd_mid; + if (cpath->nd_head) { + p(" %s %d (%s) in\n", s, id, rb_id2name(id)); + doDump(cpath->nd_head, level+2); + return; + } + } + p(" class %d (%s)\n", id, rb_id2name(id)); +} + static void dumpLiteral(long lit, int level) { @@ -90,5 +111,6 @@ static void dumpValue(VALUE v, int level } -static void doDump(NODE *n, int level) { +static void doDump(NODE *n, int level) +{ NODE *n1; @@ -103,5 +125,4 @@ static void doDump(NODE *n, int level) { lp(level, "%s: ", node_names[type]); - again: switch (type) { @@ -117,10 +138,9 @@ static void doDump(NODE *n, int level) { case NODE_OR: nl(); - doDump(n->nd_1st, level + 1); - if (n->nd_2nd && nd_type(n->nd_2nd)) { - n = n->nd_2nd; - goto again; - } - doDump(n->nd_2nd, level + 1); + ++level; + do { + doDump(n->nd_1st, level); + } while (n->nd_2nd && (type == nd_type(n = n->nd_2nd))); + doDump(n, level); break; @@ -196,4 +216,7 @@ static void doDump(NODE *n, int level) { case NODE_CALL: case NODE_FCALL: +#ifdef NODE_ATTRASGN + case NODE_ATTRASGN: +#endif if (type == NODE_FCALL) { p(" to function: %d (%s)\n", n->nd_mid, rb_id2name(n->nd_mid)); @@ -202,5 +225,10 @@ static void doDump(NODE *n, int level) { p(" to method: %d (%s)\n", n->nd_mid, rb_id2name(n->nd_mid)); lp(level, "Receiver:\n"); - doDump(n->nd_recv, level+1); + if (n->nd_recv == (NODE *)1) { + lp(level, "%s: ", node_names[NODE_SELF]); + } + else { + doDump(n->nd_recv, level+1); + } } @@ -254,6 +282,10 @@ static void doDump(NODE *n, int level) { case NODE_CLASS: +#ifdef nd_cpath + dump_cpath("class", n->nd_cpath, level); +#else id = n->nd_cname; p(" class %d (%s)\n", id, rb_id2name(id)); +#endif if (n->nd_super) { lp(level+1, "Superclass:\n"); @@ -352,4 +384,7 @@ static void doDump(NODE *n, int level) { case NODE_DREGX: case NODE_DREGX_ONCE: +#ifdef NODE_DSYM + case NODE_DSYM: +#endif dumpLiteral(n->nd_lit, level+1); n1 = n->nd_next; @@ -460,10 +495,15 @@ static void doDump(NODE *n, int level) { break; - case NODE_LIT: case NODE_EVSTR: + if (!n->nd_lit) { + nl(); + doDump(n->nd_body, level+1); + break; + } + case NODE_LIT: case NODE_XSTR: dumpLiteral(n->nd_lit, level+1); break; - + case NODE_LVAR: p(" LV %d (%s)\n", n->nd_cnt, rb_id2name(n->nd_vid)); @@ -499,6 +539,10 @@ static void doDump(NODE *n, int level) { case NODE_MODULE: +#ifdef nd_cpath + dump_cpath("module", n->nd_cpath, level); +#else id = n->nd_cname; p(" module %d (%s)\n", id, rb_id2name(id)); +#endif doDump(n->nd_body, level+1); break; @@ -609,11 +653,22 @@ static void doDump(NODE *n, int level) { break; +#ifdef NODE_RESTARGS case NODE_RESTARGS: +#endif #ifdef NODE_RESTARY case NODE_RESTARY: #endif +#ifdef NODE_RESTARY2 + case NODE_RESTARY2: +#endif #ifdef NODE_REXPAND case NODE_REXPAND: #endif +#ifdef NODE_SPLAT + case NODE_SPLAT: +#endif +#ifdef NODE_SVALUE + case NODE_SVALUE: +#endif nl(); doDump(n->nd_head, level+1); @@ -672,8 +727,14 @@ static void doDump(NODE *n, int level) { case NODE_WHILE: nl(); - lp(level+1, "Condition:\n"); - doDump(n->nd_cond, level+2); + if (n->nd_state) { + lp(level+1, "Condition:\n"); + doDump(n->nd_cond, level+2); + } lp(level+1, "Body:\n"); doDump(n->nd_body, level+2); + if (!n->nd_state) { + lp(level+1, "Condition:\n"); + doDump(n->nd_cond, level+2); + } break;
-- Nobu Nakada