mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
5af983af4f
Clang 12 warns "suspicious concatenation of string literals in an array initialization", which is rather annoying than useful in this context.
273 lines
7.3 KiB
Cheetah
273 lines
7.3 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.
|
|
|
|
require_relative '../tool/ruby_vm/helpers/c_escape'
|
|
|
|
class Prelude
|
|
include RubyVM::CEscape
|
|
LINE_LIMIT = 509 # by C89
|
|
|
|
def prelude_base(filename)
|
|
filename.chomp(".rb")
|
|
end
|
|
def prelude_name(filename)
|
|
"<internal:" + prelude_base(filename) + ">"
|
|
end
|
|
|
|
def initialize(output, preludes, vpath)
|
|
@output = output
|
|
@have_sublib = false
|
|
@vpath = vpath
|
|
@prelude_count = 0
|
|
@builtin_count = 0
|
|
@preludes = {}
|
|
@mains = preludes.map do |filename|
|
|
if prelude = filename.end_with?("golf_prelude.rb")
|
|
@prelude_count += 1
|
|
else
|
|
@builtin_count += 1
|
|
end
|
|
translate(filename, (filename unless prelude))[0]
|
|
end
|
|
@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|
|
|
line.force_encoding("ASCII-8BIT") if line.respond_to?(:force_encoding)
|
|
@preludes[filename] ||= result
|
|
comment = ($1 || '' if line.sub!(/(?:^|\s+)\#(?:$|[#\s](.*))/, ''))
|
|
if line.size > LINE_LIMIT
|
|
raise "#{filename}:#{lines.size+1}: too long line"
|
|
end
|
|
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 << [line, comment]
|
|
end
|
|
result
|
|
end
|
|
end
|
|
Prelude.new(output, 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 "internal.h"
|
|
#include "internal/warnings.h"
|
|
#include "iseq.h"
|
|
#include "ruby/ruby.h"
|
|
#include "vm_core.h"
|
|
|
|
COMPILER_WARNING_PUSH
|
|
#if __has_warning("-Wstring-concatenation")
|
|
COMPILER_WARNING_IGNORED(-Wstring-concatenation)
|
|
#endif
|
|
% preludes = @preludes.values.sort
|
|
% preludes.each {|i, prelude, lines, sub|
|
|
|
|
% name = prelude_name(*prelude)
|
|
static const char prelude_name<%=i%><%=%>[] = <%=rstring2cstr(name)%>;
|
|
static const struct {
|
|
% size = beg = 0
|
|
% lines.each_with_index {|(line, comment), n|
|
|
% if size + line.size < Prelude::LINE_LIMIT
|
|
% size += line.size
|
|
% next
|
|
% end
|
|
char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=n%> */
|
|
% size = line.size
|
|
% beg = n
|
|
% }
|
|
% if size > 0
|
|
char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=lines.size+1%> */
|
|
% end
|
|
} prelude_code<%=i%><%=%> = {
|
|
% size = 0
|
|
#line 1 <%=rstring2cstr(prelude)%>
|
|
% lines.each_with_index {|(line, comment), n|
|
|
% if size + line.size >= Prelude::LINE_LIMIT
|
|
% size = 0
|
|
,
|
|
#line <%=n+1%> <%=rstring2cstr(prelude)%>
|
|
% end
|
|
% size += line.size
|
|
<%=rstring2cstr(line)%><%if comment%><%=commentify(comment)%><%end%>
|
|
% }
|
|
#line <%=_erbout.count("\n")+2%> "<%=@output%>"
|
|
};
|
|
% }
|
|
|
|
COMPILER_WARNING_POP
|
|
|
|
% 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?
|
|
#define PRELUDE_NAME(n) rb_usascii_str_new_static(prelude_name##n, sizeof(prelude_name##n)-1)
|
|
#define PRELUDE_CODE(n) rb_utf8_str_new_static(prelude_code##n.L0, sizeof(prelude_code##n))
|
|
|
|
static rb_ast_t *
|
|
prelude_ast(VALUE name, VALUE code, int line)
|
|
{
|
|
rb_ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
|
|
if (!ast->body.root) {
|
|
rb_ast_dispose(ast);
|
|
rb_exc_raise(rb_errinfo());
|
|
}
|
|
return ast;
|
|
}
|
|
|
|
% end
|
|
% if @builtin_count > 0
|
|
#define PRELUDE_AST(n, name_str) \
|
|
(((sizeof(prelude_name<%='##'%><%=%>n) - prefix_len - 2) == namelen) && \
|
|
(strncmp(prelude_name<%='##'%><%=%>n + prefix_len, feature_name, namelen) == 0) ? \
|
|
prelude_ast((name_str) = PRELUDE_NAME(n), PRELUDE_CODE(n), 1) : 0)
|
|
|
|
rb_ast_t *
|
|
rb_builtin_ast(const char *feature_name, VALUE *name_str)
|
|
{
|
|
const size_t prefix_len = rb_strlen_lit("<internal:");
|
|
size_t namelen = strlen(feature_name);
|
|
rb_ast_t *ast = 0;
|
|
|
|
% @preludes.each_value do |i, prelude, lines, sub|
|
|
% if sub and sub != true
|
|
if ((ast = PRELUDE_AST(<%=i%><%=%>, *name_str)) != 0) return ast;
|
|
% end
|
|
% end
|
|
return ast;
|
|
}
|
|
|
|
% end
|
|
% if @prelude_count > 0
|
|
COMPILER_WARNING_PUSH
|
|
#if GCC_VERSION_SINCE(4, 2, 0)
|
|
COMPILER_WARNING_ERROR(-Wmissing-field-initializers)
|
|
#endif
|
|
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; */
|
|
FALSE,/* int tailcall_optimization; */
|
|
TRUE, /* int specialized_instruction; */
|
|
TRUE, /* int operands_unification; */
|
|
TRUE, /* int instructions_unification; */
|
|
TRUE, /* int stack_caching; */
|
|
TRUE, /* int frozen_string_literal; */
|
|
FALSE, /* int debug_frozen_string_literal; */
|
|
FALSE, /* unsigned int coverage_enabled; */
|
|
0, /* int debug_level; */
|
|
};
|
|
|
|
rb_ast_t *ast = prelude_ast(name, code, line);
|
|
rb_iseq_eval(rb_iseq_new_with_opt(&ast->body, name, name, Qnil, INT2FIX(line),
|
|
NULL, ISEQ_TYPE_TOP, &optimization));
|
|
rb_ast_dispose(ast);
|
|
}
|
|
COMPILER_WARNING_POP
|
|
|
|
% 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 == true
|
|
case <%=i%><%=%>:
|
|
code = PRELUDE_CODE(<%=i%><%=%>);
|
|
name = PRELUDE_NAME(<%=i%><%=%>);
|
|
break;
|
|
% end
|
|
% end
|
|
default:
|
|
return Qfalse;
|
|
}
|
|
prelude_eval(code, name, 1);
|
|
return Qtrue;
|
|
}
|
|
|
|
% end
|
|
%end
|
|
% init_name = @output && @output[/\w+(?=_prelude.c\b)/] || 'prelude'
|
|
void
|
|
Init_<%=init_name%><%=%>(void)
|
|
{
|
|
%unless @prelude_count.zero?
|
|
% 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(PRELUDE_CODE(<%=i%><%=%>), PRELUDE_NAME(<%=i%><%=%>), 1);
|
|
% end
|
|
% if @have_sublib
|
|
rb_gc_force_recycle(prelude);
|
|
% end
|
|
|
|
#if 0
|
|
% preludes.length.times {|i|
|
|
printf("%.*s", (int)sizeof(prelude_code<%=i%><%=%>), prelude_code<%=i%><%=%>.L0);
|
|
% }
|
|
#endif
|
|
%end
|
|
}
|
|
<%end -%>
|