summaryrefslogtreecommitdiff
path: root/template/prelude.c.tmpl
diff options
context:
space:
mode:
Diffstat (limited to 'template/prelude.c.tmpl')
-rw-r--r--template/prelude.c.tmpl186
1 files changed, 186 insertions, 0 deletions
diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl
new file mode 100644
index 0000000000..e1859fd436
--- /dev/null
+++ b/template/prelude.c.tmpl
@@ -0,0 +1,186 @@
+<%
+# 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
+ @mkconf = nil
+ @have_sublib = false
+ @need_ruby_prefix = 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, filename, lines, sub]
+ @vpath.foreach(filename) do |line|
+ @preludes[filename] ||= result
+ line.sub!(/(?:^|\s+)\#(?:$|\s.*)/, '')
+ 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 = 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 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
+
+% 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 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
+ 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 or @need_ruby_prefix
+ rb_gc_force_recycle(prelude);
+% end
+
+#if 0
+% preludes.length.times {|i|
+ puts(prelude_code<%=i%>);
+% }
+#endif
+}
+<%end -%>