ruby/template/prelude.c.tmpl

171 строка
4.2 KiB
Cheetah

<%
# This file is interpreted by $(BASERUBY) and miniruby.
# $(BASERUBY) is used for miniprelude.c.
# miniruby is used for prelude.c.
# Since $(BASERUBY) may be older than Ruby 1.9,
# Ruby 1.9 feature should not be used.
class Prelude
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.chomp(".rb")
end
def prelude_name(filename)
"<internal:" + prelude_base(filename) + ">"
end
def initialize(init_name, preludes, vpath)
@init_name = init_name
@have_sublib = false
@vpath = vpath
@preludes = {}
@mains = preludes.map {|filename| translate(filename)[0]}
@preludes.delete_if {|_, (_, _, lines, sub)| sub && lines.empty?}
end
def translate(filename, sub = false)
idx = @preludes[filename]
return idx if idx
lines = []
result = [@preludes.size, @vpath.strip(filename), lines, sub]
@vpath.foreach(filename) do |line|
@preludes[filename] ||= result
line.sub!(/(?:^|\s+)\#(?:$|\s.*)/, '')
line.sub!(/require\s*\(?\s*(["'])(.*?)\1\)?/) do
orig, path = $&, $2
path = translate(path, true) rescue nil
if path
@have_sublib = true
"TMP_RUBY_PREFIX.require(#{path[0]})"
else
orig
end
end
lines << c_esc(line)
end
result
end
end
Prelude.new(output && output[/\w+(?=_prelude.c\b)/] || 'prelude', ARGV, vpath).instance_eval do
-%>
/* -*-c-*-
THIS FILE WAS AUTOGENERATED BY template/prelude.c.tmpl. DO NOT EDIT.
sources: <%= @preludes.map {|n,*| prelude_base(n)}.join(', ') %>
*/
#include "ruby/ruby.h"
#include "internal.h"
#include "vm_core.h"
% 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
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
% unless preludes.empty?
static void
prelude_eval(VALUE code, VALUE name, VALUE line)
{
rb_iseq_eval(rb_iseq_compile_with_option(code, name, Qnil, line, 0, Qtrue));
}
% end
% if @have_sublib
static VALUE
prelude_require(VALUE self, VALUE nth)
{
struct prelude_env *ptr = DATA_PTR(self);
VALUE code, 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_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1);
name = rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1);
break;
% end
% end
default:
return Qfalse;
}
prelude_eval(code, name, INT2FIX(1));
return Qtrue;
}
% end
void
Init_<%=@init_name%>(void)
{
% if @have_sublib
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
prelude_eval(
rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1),
rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1),
INT2FIX(1));
% end
% if @have_sublib
rb_gc_force_recycle(prelude);
% end
#if 0
% preludes.length.times {|i|
puts(prelude_code<%=i%>);
% }
#endif
}
<%end -%>