Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 188 lines (164 sloc) 4.54 kb
# This file is interpreted by miniruby.
# Do not use features that miniruby does not provide,
# including what's in prelude.rb.
require 'erb'
class Prelude
SRCDIR = File.dirname(__FILE__)
$:.unshift(SRCDIR)
C_ESC = {
"\\" => "\\\\",
'"' => '\"',
"\n" => '\n',
}
0x00.upto(0x1f) {|ch| C_ESC[[ch].pack("C")] ||= "\\%03o" % ch }
0x7f.upto(0xff) {|ch| C_ESC[[ch].pack("C")] = "\\%03o" % ch }
C_ESC_PAT = Regexp.union(*C_ESC.keys)
def c_esc(str)
'"' + str.gsub(C_ESC_PAT) { C_ESC[$&] } + '"'
end
def prelude_base(filename)
filename[/\A#{Regexp.quote(SRCDIR)}\/(.*?)(\.rb)?\z/om, 1]
end
def prelude_name(filename)
"<internal:" + prelude_base(filename) + ">"
end
def initialize(preludes)
@mkconf = nil
@have_sublib = false
@need_ruby_prefix = false
@preludes = {}
@mains = preludes.map {|filename| translate(filename)[0]}
end
def translate(filename, sub = false)
idx = @preludes[filename]
return idx if idx
lines = []
@preludes[filename] = result = [@preludes.size, filename, lines, sub]
File.readlines(filename).each do |line|
line.gsub!(/RbConfig::CONFIG\["(\w+)"\]/) {
key = $1
unless @mkconf
require './rbconfig'
@mkconf = RbConfig::MAKEFILE_CONFIG.merge('prefix'=>'#{TMP_RUBY_PREFIX}')
end
if RbConfig::MAKEFILE_CONFIG.has_key? key
val = RbConfig.expand("$(#{key})", @mkconf)
@need_ruby_prefix ||= /\A\#\{TMP_RUBY_PREFIX\}/ =~ val
c_esc(val)
else
"nil"
end
}
line.sub!(/require\s*\(?\s*(["'])(.*?)\1\)?/) do
orig, path = $&, $2
path = File.join(SRCDIR, path)
if File.exist?(path)
@have_sublib = true
"TMP_RUBY_PREFIX.require(#{translate(path, true)[0]})"
else
orig
end
end
lines << c_esc(line)
end
result
end
def emit(outfile)
init_name = outfile[/\w+(?=_prelude.c\b)/] || 'prelude'
erb = ERB.new(<<'EOS', nil, '%')
/* -*-c-*-
THIS FILE WAS AUTOGENERATED BY compile_prelude.rb. DO NOT EDIT.
soruces: <%= @preludes.map {|n,*| prelude_base(n)}.join(', ') %>
*/
#include "ruby.h"
VALUE rb_eval_prelude _((VALUE, const char *));
% preludes = @preludes.values.sort
% preludes.each {|i, prelude, lines, sub|
static const char prelude_name<%=i%>[] = <%=c_esc(prelude_name(*prelude))%>;
static const char prelude_code<%=i%>[] =
% lines.each {|line|
<%=line%>
% }
;
% }
#define PRELUDE_COUNT <%=@have_sublib ? preludes.size : 0%>
% if @have_sublib or @need_ruby_prefix
struct prelude_env {
volatile VALUE prefix_path;
#if PRELUDE_COUNT > 0
char loaded[PRELUDE_COUNT];
#endif
};
static VALUE
prelude_prefix_path(VALUE self)
{
struct prelude_env *ptr = DATA_PTR(self);
return ptr->prefix_path;
}
% end
% if @have_sublib
static VALUE
prelude_require(VALUE self, VALUE nth)
{
struct prelude_env *ptr = DATA_PTR(self);
VALUE code;
const char *name;
int n = FIX2INT(nth);
if (n > PRELUDE_COUNT) return Qfalse;
if (ptr->loaded[n]) return Qfalse;
ptr->loaded[n] = 1;
switch (n) {
% @preludes.each_value do |i, prelude, lines, sub|
% if sub
case <%=i%>:
code = rb_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1);
name = prelude_name<%=i%>;
break;
% end
% end
default:
return Qfalse;
}
rb_eval_prelude(code, name);
return Qtrue;
}
% end
void Init_<%=init_name%> _((void));
void
Init_<%=init_name%>()
{
% if @have_sublib or @need_ruby_prefix
struct prelude_env memo;
ID name = rb_intern("TMP_RUBY_PREFIX");
VALUE prelude = Data_Wrap_Struct(rb_cData, 0, 0, &memo);
memo.prefix_path = rb_const_remove(rb_cObject, name);
rb_const_set(rb_cObject, name, prelude);
rb_define_singleton_method(prelude, "to_s", prelude_prefix_path, 0);
% end
% if @have_sublib
memset(memo.loaded, 0, sizeof(memo.loaded));
rb_define_singleton_method(prelude, "require", prelude_require, 1);
% end
% preludes.each do |i, prelude, lines, sub|
% next if sub
rb_eval_prelude(rb_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1), prelude_name<%=i%>);
% end
% if @have_sublib or @need_ruby_prefix
rb_gc_force_recycle(prelude);
% end
#if 0
% preludes.length.times {|i|
puts(prelude_code<%=i%>);
% }
#endif
}
EOS
tmp = erb.result(binding)
open(outfile, 'w'){|f|
f << tmp
}
end
end
preludes = ARGV.dup
outfile = preludes.pop
Prelude.new(preludes).emit(outfile)
Jump to Line
Something went wrong with that request. Please try again.