diff --git a/ChangeLog b/ChangeLog index 64b7f0a0c4..7771da16c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Wed Mar 17 02:29:46 2010 Yusuke Endoh + + * compile.c, iseq.c, ruby.c, vm.c, vm_core.h, vm_eval.c: add absolute + path field into rb_iseq_t. The field contains a string representing + a path to corresponding source file. or nil when the iseq is created + from -e, stdin, eval, etc. This field is used for require_relative. + [ruby-dev:40004] + + * load.c (rb_f_require_relative): add C implementation of + require_relative. + + * prelude.rb (require_relative): get rid of Ruby implementation of + require_relative. + Wed Mar 17 01:24:01 2010 Yusuke Endoh * parse.y (rb_intern3): prohibit Symbol with an invalid encoding. diff --git a/compile.c b/compile.c index 1db4e9c6b8..a89bccbc2f 100644 --- a/compile.c +++ b/compile.c @@ -169,6 +169,9 @@ PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2); #define iseq_filename(iseq) \ (((rb_iseq_t*)DATA_PTR(iseq))->filename) +#define iseq_filepath(iseq) \ + (((rb_iseq_t*)DATA_PTR(iseq))->filepath) + #define NEW_ISEQVAL(node, name, type, line_no) \ new_child_iseq(iseq, node, name, 0, type, line_no) @@ -917,7 +920,7 @@ new_child_iseq(rb_iseq_t *iseq, NODE *node, VALUE ret; debugs("[new_child_iseq]> ---------------------------------------\n"); - ret = rb_iseq_new_with_opt(node, name, iseq_filename(iseq->self), INT2FIX(line_no), + ret = rb_iseq_new_with_opt(node, name, iseq_filename(iseq->self), iseq_filepath(iseq->self), INT2FIX(line_no), parent, type, iseq->compile_data->option); debugs("[new_child_iseq]< ---------------------------------------\n"); iseq_add_mark_object(iseq, ret); diff --git a/file.c b/file.c index 64fe824ec2..7d6d25e21a 100644 --- a/file.c +++ b/file.c @@ -3188,8 +3188,8 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopche } } -static VALUE -realpath_internal(VALUE basedir, VALUE path, int strict) +VALUE +rb_realpath_internal(VALUE basedir, VALUE path, int strict) { long prefixlen; VALUE resolved; @@ -3277,7 +3277,7 @@ rb_file_s_realpath(int argc, VALUE *argv, VALUE klass) { VALUE path, basedir; rb_scan_args(argc, argv, "11", &path, &basedir); - return realpath_internal(basedir, path, 1); + return rb_realpath_internal(basedir, path, 1); } /* @@ -3297,7 +3297,7 @@ rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass) { VALUE path, basedir; rb_scan_args(argc, argv, "11", &path, &basedir); - return realpath_internal(basedir, path, 0); + return rb_realpath_internal(basedir, path, 0); } static size_t @@ -3429,7 +3429,7 @@ rb_file_s_basename(int argc, VALUE *argv) * File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work" */ -static VALUE +VALUE rb_file_s_dirname(VALUE klass, VALUE fname) { const char *name, *root, *p; diff --git a/iseq.c b/iseq.c index 1600cb0f2d..d6644f220f 100644 --- a/iseq.c +++ b/iseq.c @@ -98,6 +98,7 @@ iseq_mark(void *ptr) RUBY_MARK_UNLESS_NULL(iseq->mark_ary); RUBY_MARK_UNLESS_NULL(iseq->name); RUBY_MARK_UNLESS_NULL(iseq->filename); + RUBY_MARK_UNLESS_NULL(iseq->filepath); RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack); RUBY_MARK_UNLESS_NULL(iseq->klass); RUBY_MARK_UNLESS_NULL(iseq->coverage); @@ -207,9 +208,11 @@ set_relation(rb_iseq_t *iseq, const VALUE parent) } } +VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict); + static VALUE prepare_iseq_build(rb_iseq_t *iseq, - VALUE name, VALUE filename, VALUE line_no, + VALUE name, VALUE filename, VALUE filepath, VALUE line_no, VALUE parent, VALUE type, VALUE block_opt, const rb_compile_option_t *option) { @@ -218,6 +221,7 @@ prepare_iseq_build(rb_iseq_t *iseq, iseq->name = name; iseq->filename = filename; + iseq->filepath = filepath == Qnil ? Qnil : rb_realpath_internal(Qnil, filepath, 1); iseq->line_no = line_no; iseq->defined_method_id = 0; iseq->mark_ary = rb_ary_tmp_new(3); @@ -361,31 +365,31 @@ make_compile_option_value(rb_compile_option_t *option) } VALUE -rb_iseq_new(NODE *node, VALUE name, VALUE filename, +rb_iseq_new(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent, VALUE type) { - return rb_iseq_new_with_opt(node, name, filename, INT2FIX(0), parent, type, + return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, type, &COMPILE_OPTION_DEFAULT); } VALUE -rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE parent) +rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent) { - return rb_iseq_new_with_opt(node, name, filename, INT2FIX(0), parent, ISEQ_TYPE_TOP, + return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT); } VALUE -rb_iseq_new_main(NODE *node, VALUE filename) +rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath) { rb_thread_t *th = GET_THREAD(); VALUE parent = th->base_block->iseq->self; - return rb_iseq_new_with_opt(node, rb_str_new2("
"), filename, INT2FIX(0), + return rb_iseq_new_with_opt(node, rb_str_new2("
"), filename, filepath, INT2FIX(0), parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT); } static VALUE -rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE line_no, +rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no, VALUE parent, VALUE type, VALUE bopt, const rb_compile_option_t *option) { @@ -395,28 +399,28 @@ rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE line GetISeqPtr(self, iseq); iseq->self = self; - prepare_iseq_build(iseq, name, filename, line_no, parent, type, bopt, option); + prepare_iseq_build(iseq, name, filename, filepath, line_no, parent, type, bopt, option); rb_iseq_compile_node(self, node); cleanup_iseq_build(iseq); return self; } VALUE -rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename, VALUE line_no, +rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no, VALUE parent, VALUE type, const rb_compile_option_t *option) { /* TODO: argument check */ - return rb_iseq_new_with_bopt_and_opt(node, name, filename, line_no, parent, type, + return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type, Qfalse, option); } VALUE -rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename, VALUE line_no, +rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no, VALUE parent, VALUE type, VALUE bopt) { /* TODO: argument check */ - return rb_iseq_new_with_bopt_and_opt(node, name, filename, line_no, parent, type, + return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type, bopt, &COMPILE_OPTION_DEFAULT); } @@ -430,7 +434,7 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt) VALUE iseqval = iseq_alloc(self); VALUE magic, version1, version2, format_type, misc; - VALUE name, filename, line_no; + VALUE name, filename, filepath, line_no; VALUE type, body, locals, args, exception; VALUE iseq_type; @@ -454,6 +458,7 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt) name = CHECK_STRING(rb_ary_entry(data, i++)); filename = CHECK_STRING(rb_ary_entry(data, i++)); + filepath = CHECK_STRING(rb_ary_entry(data, i++)); line_no = CHECK_INTEGER(rb_ary_entry(data, i++)); type = CHECK_SYMBOL(rb_ary_entry(data, i++)); @@ -496,7 +501,7 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt) } make_compile_option(&option, opt); - prepare_iseq_build(iseq, name, filename, line_no, + prepare_iseq_build(iseq, name, filename, filepath, line_no, parent, iseq_type, 0, &option); rb_iseq_build_from_ary(iseq, locals, args, exception, body); @@ -533,7 +538,7 @@ parse_string(VALUE str, const char *file, int line) } VALUE -rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt) +rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE filepath, VALUE line, VALUE opt) { rb_compile_option_t option; const char *fn = StringValueCStr(file); @@ -544,11 +549,11 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt) if (th->base_block && th->base_block->iseq) { return rb_iseq_new_with_opt(node, th->base_block->iseq->name, - file, line, th->base_block->iseq->self, + file, filepath, line, th->base_block->iseq->self, ISEQ_TYPE_EVAL, &option); } else { - return rb_iseq_new_with_opt(node, rb_str_new2(""), file, line, Qfalse, + return rb_iseq_new_with_opt(node, rb_str_new2(""), file, filepath, line, Qfalse, ISEQ_TYPE_TOP, &option); } } @@ -556,21 +561,21 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt) VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line) { - return rb_iseq_compile_with_option(src, file, line, Qnil); + return rb_iseq_compile_with_option(src, file, Qnil, line, Qnil); } static VALUE iseq_s_compile(int argc, VALUE *argv, VALUE self) { - VALUE src, file = Qnil, line = INT2FIX(1), opt = Qnil; + VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil; rb_secure(1); - rb_scan_args(argc, argv, "13", &src, &file, &line, &opt); + rb_scan_args(argc, argv, "13", &src, &file, &path, &line, &opt); if (NIL_P(file)) file = rb_str_new2(""); if (NIL_P(line)) line = INT2FIX(1); - return rb_iseq_compile_with_option(src, file, line, opt); + return rb_iseq_compile_with_option(src, file, path, line, opt); } static VALUE @@ -593,7 +598,7 @@ iseq_s_compile_file(int argc, VALUE *argv, VALUE self) parser = rb_parser_new(); node = rb_parser_compile_file(parser, fname, f, NUM2INT(line)); make_compile_option(&option, opt); - return rb_iseq_new_with_opt(node, rb_str_new2("
"), file, line, Qfalse, + return rb_iseq_new_with_opt(node, rb_str_new2("
"), file, file, line, Qfalse, ISEQ_TYPE_TOP, &option); } @@ -1311,7 +1316,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) /* * [:magic, :major_version, :minor_version, :format_type, :misc, - * :name, :filename, :line_no, :type, :locals, :args, + * :name, :filename, :filepath, :line_no, :type, :locals, :args, * :catch_table, :bytecode] */ rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat")); @@ -1321,6 +1326,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) rb_ary_push(val, misc); rb_ary_push(val, iseq->name); rb_ary_push(val, iseq->filename); + rb_ary_push(val, iseq->filepath); rb_ary_push(val, iseq->line_no); rb_ary_push(val, type); rb_ary_push(val, locals); diff --git a/load.c b/load.c index 95be55ff67..2c391a1b86 100644 --- a/load.c +++ b/load.c @@ -297,7 +297,7 @@ rb_load_internal(VALUE fname, int wrap) th->mild_compile_error++; node = (NODE *)rb_load_file(RSTRING_PTR(fname)); loaded = TRUE; - iseq = rb_iseq_new_top(node, rb_str_new2(""), fname, Qfalse); + iseq = rb_iseq_new_top(node, rb_str_new2(""), fname, fname, Qfalse); th->mild_compile_error--; rb_iseq_eval(iseq); } @@ -448,6 +448,19 @@ rb_f_require(VALUE obj, VALUE fname) return rb_require_safe(fname, rb_safe_level()); } +VALUE +rb_f_require_relative(VALUE obj, VALUE fname) +{ + VALUE rb_current_realfilepath(void); + VALUE rb_file_s_dirname(VALUE klass, VALUE fname); + VALUE base = rb_current_realfilepath(); + if (NIL_P(base)) { + rb_raise(rb_eLoadError, "cannot infer basepath"); + } + base = rb_file_s_dirname(rb_cFile, base); + return rb_require_safe(rb_file_expand_path(fname, base), rb_safe_level()); +} + static int search_required(VALUE fname, volatile VALUE *path, int safe_level) { @@ -743,6 +756,7 @@ Init_load() rb_define_global_function("load", rb_f_load, -1); rb_define_global_function("require", rb_f_require, 1); + rb_define_global_function("require_relative", rb_f_require_relative, 1); rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2); rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1); rb_define_global_function("autoload", rb_f_autoload, 2); diff --git a/prelude.rb b/prelude.rb index 679e831ca4..1d084dfd8f 100644 --- a/prelude.rb +++ b/prelude.rb @@ -22,17 +22,3 @@ class Thread } end end - -module Kernel - module_function - def require_relative(relative_feature) - c = caller.first - e = c.rindex(/:\d+:in /) - file = $` - if /\A\((.*)\)/ =~ file # eval, etc. - raise LoadError, "require_relative is called in #{$1}" - end - absolute_feature = File.join(File.dirname(File.realpath(file)), relative_feature) - require absolute_feature - end -end diff --git a/ruby.c b/ruby.c index bf0f83d67c..b97830f691 100644 --- a/ruby.c +++ b/ruby.c @@ -1454,7 +1454,9 @@ process_options(int argc, char **argv, struct cmdline_options *opt) } PREPARE_PARSE_MAIN({ - iseq = rb_iseq_new_main(tree, opt->script_name); + VALUE path = Qnil; + if (!opt->e_script && strcmp(opt->script, "-")) path = opt->script_name; + iseq = rb_iseq_new_main(tree, opt->script_name, path); }); if (opt->dump & DUMP_BIT(insns)) { diff --git a/vm.c b/vm.c index 96a04bfcba..678fcb8762 100644 --- a/vm.c +++ b/vm.c @@ -1441,7 +1441,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, { rb_thread_t *th = GET_THREAD(); const rb_control_frame_t *reg_cfp = th->cfp; - volatile VALUE iseqval = rb_iseq_new(0, filename, filename, 0, ISEQ_TYPE_TOP); + volatile VALUE iseqval = rb_iseq_new(0, filename, filename, filename, 0, ISEQ_TYPE_TOP); VALUE val; vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP, @@ -2052,7 +2052,7 @@ Init_VM(void) rb_vm_t *vm = ruby_current_vm; rb_thread_t *th = GET_THREAD(); VALUE filename = rb_str_new2("
"); - volatile VALUE iseqval = rb_iseq_new(0, filename, filename, 0, ISEQ_TYPE_TOP); + volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP); volatile VALUE th_self; rb_iseq_t *iseq; diff --git a/vm_core.h b/vm_core.h index 126f48ec80..7bf199b68a 100644 --- a/vm_core.h +++ b/vm_core.h @@ -155,6 +155,7 @@ struct rb_iseq_struct { VALUE type; /* instruction sequence type */ VALUE name; /* String: iseq name */ VALUE filename; /* file information where this sequence from */ + VALUE filepath; /* real file path or nil */ VALUE *iseq; /* iseq (insn number and openrads) */ VALUE *iseq_encoded; /* encoded iseq */ unsigned long iseq_size; @@ -464,11 +465,11 @@ typedef struct rb_thread_struct } rb_thread_t; /* iseq.c */ -VALUE rb_iseq_new(NODE*, VALUE, VALUE, VALUE, VALUE); -VALUE rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE parent); -VALUE rb_iseq_new_main(NODE *node, VALUE filename); -VALUE rb_iseq_new_with_bopt(NODE*, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE); -VALUE rb_iseq_new_with_opt(NODE*, VALUE, VALUE, VALUE, VALUE, VALUE, const rb_compile_option_t*); +VALUE rb_iseq_new(NODE*, VALUE, VALUE, VALUE, VALUE, VALUE); +VALUE rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent); +VALUE rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath); +VALUE rb_iseq_new_with_bopt(NODE*, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE); +VALUE rb_iseq_new_with_opt(NODE*, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, const rb_compile_option_t*); VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line); VALUE rb_iseq_disasm(VALUE self); int rb_iseq_disasm_insn(VALUE str, VALUE *iseqval, size_t pos, rb_iseq_t *iseq, VALUE child); diff --git a/vm_eval.c b/vm_eval.c index 2e011c7b7e..0ce4b8f45d 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1709,6 +1709,16 @@ rb_f_block_given_p(void) } } +VALUE +rb_current_realfilepath(void) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp = th->cfp; + cfp = vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)); + if (cfp != 0) return cfp->iseq->filepath; + return Qnil; +} + void Init_vm_eval(void) {