Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit caeb4619d682d31d11d6dad83d36f0f3be916d31 @akiray03 akiray03 committed Apr 7, 2013
Showing with 449 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +38 −0 README.md
  3. +7 −0 mrbgem.rake
  4. +80 −0 mrblib/require.rb
  5. +49 −0 run_test.rb
  6. +160 −0 src/require.c
  7. +114 −0 test/test.rb
@@ -0,0 +1 @@
+/tmp
@@ -0,0 +1,38 @@
+mruby-require
+=============
+
+### To build:
+
+Depend mrbgems:
+
+ * mruby-io
+ * mruby-dir
+ * mruby-tempfile
+
+### To run the tests:
+
+ ruby run_test.rb
+
+
+## License
+
+Copyright (c) 2013 Internet Initiative Japan Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
@@ -0,0 +1,7 @@
+MRuby::Gem::Specification.new('mruby-require') do |spec|
+ spec.license = 'MIT'
+ spec.authors = 'Internet Initiative Japan Inc.'
+
+ spec.cc.include_paths << "#{build.root}/src"
+end
+
@@ -0,0 +1,80 @@
+class LoadError < ScriptError; end
+
+class LoadUtil
+ def load(path)
+ raise NotImplementedError.new "'require' method depends on File" unless Object.const_defined?(:File)
+ raise TypeError unless path.class == String
+
+ if File.exist?(path) && File.extname(path) == ".rb"
+ _load_rb_str File.open(path).read, path
+ elsif File.exist?(path) && File.extname(path) == ".mrb"
+ _load_mrb_file path
+ else
+ raise LoadError.new "File not found -- #{path}"
+ end
+ end
+
+ def require(path)
+ raise NotImplementedError.new "'require' method depends on File" unless Object.const_defined?(:File)
+ raise TypeError unless path.class == String
+
+
+ if (path[0] == '/' || path[0] == '.') && File.exist?(path)
+ realpath = File.realpath path
+ $__mruby_loading_files__ << realpath
+ load realpath
+ $" << realpath
+ $__mruby_loading_files__.delete realpath
+ else
+ filenames = [path]
+ if File.extname(path).size == 0
+ filenames << "#{path}.rb"
+ filenames << "#{path}.mrb"
+ end
+ filename = nil
+ dir = ($LOAD_PATH || []).find do |dir0|
+ filename = filenames.find do |fname|
+ File.exist?(File.join dir0, fname)
+ end
+ end
+
+ if dir && filename
+ __require__(File.join dir, filename)
+ else
+ __require__(path)
+ end
+ end
+ end
+
+ def __require__(realpath)
+ raise LoadError.new "File not found -- #{realpath}" unless File.exist? realpath
+ $" ||= []
+ $__mruby_loading_files__ ||= []
+
+ # already required
+ return false if ($" + $__mruby_loading_files__).include?(realpath)
+
+ $__mruby_loading_files__ << realpath
+ load realpath
+ $" << realpath
+ $__mruby_loading_files__.delete realpath
+
+ true
+ end
+end
+
+
+module Kernel
+ def load(path)
+ LoadUtil.new.load(path)
+ end
+
+ def require(path)
+ LoadUtil.new.require(path)
+ end
+
+end
+
+$LOAD_PATH ||= []
+$" ||= []
+$__mruby_loading_files__ ||= []
@@ -0,0 +1,49 @@
+#!/usr/bin/env ruby
+#
+# mrbgems test runner
+#
+
+DEPEND_GEMS = {
+ 'tmp/mruby-io' => 'https://github.com/iij/mruby-io.git',
+ 'tmp/mruby-dir' => 'https://github.com/iij/mruby-dir.git',
+ 'tmp/mruby-tempfile' => 'https://github.com/iij/mruby-tempfile.git',
+}
+gemname = File.basename(File.dirname(File.expand_path __FILE__))
+
+if __FILE__ == $0
+ repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
+
+ build_args = ARGV
+ build_args = ['all', 'test'] if build_args.nil? or build_args.empty?
+
+ Dir.mkdir 'tmp' unless File.exist?('tmp')
+ unless File.exist?(dir)
+ system "git clone #{repository} #{dir}"
+ end
+
+ DEPEND_GEMS.each do |path, url|
+ unless File.exist?(path)
+ system "git clone #{url} #{path}"
+ end
+ end
+
+ exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
+end
+
+MRuby::Build.new do |conf|
+ toolchain :gcc
+ conf.gems.clear
+
+ conf.gem "#{root}/mrbgems/mruby-sprintf"
+ conf.gem "#{root}/mrbgems/mruby-print"
+
+ Dir.glob("#{root}/mrbgems/mruby-*") do |x|
+ conf.gem x unless x =~ /\/mruby-(print|sprintf)$/
+ end
+
+ DEPEND_GEMS.each do |path, url|
+ conf.gem path
+ end
+
+ conf.gem File.expand_path(File.dirname(__FILE__))
+end
@@ -0,0 +1,160 @@
+#include "mruby.h"
+#include "mruby/compile.h"
+#include "mruby/dump.h"
+#include "mruby/string.h"
+#include "mruby/proc.h"
+
+#include "opcode.h"
+#include "error.h"
+
+#define E_LOAD_ERROR (mrb_class_obj_get(mrb, "LoadError"))
+
+mrb_value
+mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c);
+
+static void
+replace_stop_with_return(mrb_state *mrb, mrb_irep *irep)
+{
+ if (irep->iseq[irep->ilen - 1] == MKOP_A(OP_STOP, 0)) {
+ irep->iseq = mrb_realloc(mrb, irep->iseq, (irep->ilen + 1) * sizeof(mrb_code));
+ irep->iseq[irep->ilen - 1] = MKOP_A(OP_LOADNIL, 0);
+ irep->iseq[irep->ilen] = MKOP_AB(OP_RETURN, 0, OP_R_NORMAL);
+ irep->ilen++;
+ }
+}
+
+static int
+compile_rb2mrb(mrb_state *mrb0, const char *code, int code_len, const char *path, FILE* tmpfp)
+{
+ mrb_state *mrb = mrb_open();
+ mrbc_context *c;
+ mrb_value irep_size;
+ int ret = -1;
+ int irep_len = mrb->irep_len;
+ int debuginfo = 1;
+
+ c = mrbc_context_new(mrb);
+ c->no_exec = 1;
+ if (path != NULL) {
+ mrbc_filename(mrb, c, path);
+ }
+
+ irep_size = mrb_load_nstring_cxt(mrb, code, code_len, c);
+
+ mrb->irep += mrb_fixnum(irep_size);
+ mrb->irep_len -= irep_len;
+
+ ret = mrb_dump_irep_binary(mrb, 0, debuginfo, tmpfp);
+
+ mrb->irep -= mrb_fixnum(irep_size);
+ mrb->irep_len += irep_len;
+ mrbc_context_free(mrb, c);
+ mrb_close(mrb);
+
+ return ret;
+}
+
+static void
+eval_load_irep(mrb_state *mrb, int n)
+{
+ int ai;
+ struct RProc *proc;
+ mrb_irep *irep = mrb->irep[n];
+
+ replace_stop_with_return(mrb, irep);
+ proc = mrb_proc_new(mrb, irep);
+ proc->target_class = mrb->object_class;
+
+ ai = mrb_gc_arena_save(mrb);
+ mrb_yield_internal(mrb, mrb_obj_value(proc), 0, NULL, mrb_top_self(mrb), mrb->object_class);
+ mrb_gc_arena_restore(mrb, ai);
+}
+
+static mrb_value
+mrb_require_load_rb_str(mrb_state *mrb, mrb_value self)
+{
+ char *path_ptr = NULL;
+ FILE *tmpfp = NULL;
+ int ret;
+ mrb_value code, path = mrb_nil_value();
+
+ mrb_get_args(mrb, "S|S", &code, &path);
+ if (!mrb_string_p(path)) {
+ path = mrb_str_new_cstr(mrb, "-");
+ }
+ path_ptr = mrb_str_to_cstr(mrb, path);
+
+ tmpfp = tmpfile();
+ if (tmpfp == NULL) {
+ mrb_sys_fail(mrb, "can't create tmpfile() at mrb_require_load_rb_str");
+ }
+
+ ret = compile_rb2mrb(mrb, RSTRING_PTR(code), RSTRING_LEN(code), path_ptr, tmpfp);
+ if (ret != MRB_DUMP_OK) {
+ fclose(tmpfp);
+ mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path);
+ return mrb_nil_value();
+ }
+
+ rewind(tmpfp);
+ ret = mrb_read_irep_file(mrb, tmpfp);
+ fclose(tmpfp);
+
+ if (ret >= 0) {
+ eval_load_irep(mrb, ret);
+ } else if (mrb->exc) {
+ // fail to load
+ longjmp(*(jmp_buf*)mrb->jmp, 1);
+ } else {
+ mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path);
+ return mrb_nil_value();
+ }
+
+ return mrb_true_value();
+}
+
+static mrb_value
+mrb_require_load_mrb_file(mrb_state *mrb, mrb_value self)
+{
+ char *path_ptr = NULL;
+ FILE *fp = NULL;
+ int ret;
+ mrb_value path;
+
+ mrb_get_args(mrb, "S", &path);
+ path_ptr = mrb_str_to_cstr(mrb, path);
+
+ fp = fopen(path_ptr, "rb");
+ if (fp == NULL) {
+ mrb_raisef(mrb, E_LOAD_ERROR, "can't open file -- %S", path);
+ }
+
+ ret = mrb_read_irep_file(mrb, fp);
+
+ if (ret >= 0) {
+ eval_load_irep(mrb, ret);
+ } else if (mrb->exc) {
+ // fail to load
+ longjmp(*(jmp_buf*)mrb->jmp, 1);
+ } else {
+ mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path);
+ return mrb_nil_value();
+ }
+
+ return mrb_true_value();
+}
+
+void
+mrb_mruby_require_gem_init(mrb_state *mrb)
+{
+ struct RClass *krn;
+ krn = mrb->kernel_module;
+
+ mrb_define_method(mrb, krn, "_load_rb_str", mrb_require_load_rb_str, ARGS_ANY());
+ mrb_define_method(mrb, krn, "_load_mrb_file", mrb_require_load_mrb_file, ARGS_REQ(1));
+}
+
+void
+mrb_mruby_require_gem_final(mrb_state *mrb)
+{
+}
Oops, something went wrong.

0 comments on commit caeb461

Please sign in to comment.