зеркало из https://github.com/github/ruby.git
196 строки
5.0 KiB
Cheetah
196 строки
5.0 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(_relative)?\s*\(?\s*(["'])(.*?)(?:\.rb)?\2\)?/) do
|
|
orig, rel, path = $&, $2, $3
|
|
if rel
|
|
path = File.join(File.dirname(filename), path)
|
|
nil while path.gsub!(%r'(\A|/)(?!\.\.?/)[^/]+/\.\.(?:/|\z)', '')
|
|
end
|
|
path = translate("#{path}.rb", 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(', ') %>
|
|
*/
|
|
%unless @preludes.empty?
|
|
#include "ruby/ruby.h"
|
|
#include "internal.h"
|
|
#include "vm_core.h"
|
|
#include "iseq.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%><%=%>
|
|
% }
|
|
;
|
|
% }
|
|
|
|
% if @have_sublib
|
|
#define PRELUDE_COUNT <%=preludes.size%>
|
|
|
|
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, int line)
|
|
{
|
|
static const rb_compile_option_t optimization = {
|
|
TRUE, /* int inline_const_cache; */
|
|
TRUE, /* int peephole_optimization; */
|
|
TRUE, /* int tailcall_optimization */
|
|
TRUE, /* int specialized_instruction; */
|
|
TRUE, /* int operands_unification; */
|
|
TRUE, /* int instructions_unification; */
|
|
TRUE, /* int stack_caching; */
|
|
FALSE, /* int trace_instruction */
|
|
TRUE,
|
|
FALSE,
|
|
};
|
|
|
|
NODE *node = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
|
|
if (!node) rb_exc_raise(rb_errinfo());
|
|
rb_iseq_eval(rb_iseq_new_with_opt(node, name, name, Qnil, INT2FIX(line),
|
|
NULL, ISEQ_TYPE_TOP, &optimization));
|
|
}
|
|
% 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, 1);
|
|
return Qtrue;
|
|
}
|
|
|
|
% end
|
|
%end
|
|
void
|
|
Init_<%=@init_name%><%=%>(void)
|
|
{
|
|
%unless @preludes.empty?
|
|
% 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
|
|
}
|
|
<%end -%>
|