Change soft-fail to use the config, rather than env
[rbx.git] / lib / compiler / compiler.rb
blob18643669b498083516a8c234627d250621a16cf5
1 require 'compiler/system_hints'
3 ##
4 # Turns text into CompiledMethods
6 class Compiler
8   Config = Hash.new
10   ##
11   # Compiler error subclass.
13   class Error < RuntimeError
14   end
16   def self.compile_file(path, flags=nil)
17     flags.each { |f| Config[f] = true } if flags
18     sexp = File.to_sexp(path, true)
20     comp = new(Generator)
21     node = comp.into_script(sexp)
22     return node.to_description(:__script__).to_cmethod
23   end
25   def self.compile_string(string, context=nil, filename="(eval)", line=1)
26     sexp = string.to_sexp(filename, line, true)
28     if context
29       comp = new(Generator, context)
30       node = comp.convert_sexp([:eval_expression, sexp])
31     else
32       comp = new(Generator)
33       node = comp.into_script(sexp)
34     end
36     cm = node.to_description(:__eval_script__).to_cmethod
37     cm.file = filename.to_sym if filename and !filename.empty?
38     return cm
39   end
41   TimeEpoch = 1141027200 # rubinius' birthday
43   @version_number = nil
45   def self.version_number
46     unless @version_number
47       begin
48         # handled for .rba files in init.rb
49         dir = $LOAD_PATH.detect { |path| File.file? "#{path}/compiler/compiler.rb" }
50         max = Dir["#{dir}/compiler/*.rb"].map { |f| File.mtime(f).to_i }.max
51         @version_number = max - TimeEpoch
52       rescue Exception
53         @version_number = 0
54       end
56       if $DEBUG_LOADING
57         STDERR.puts "[Compiler version: #{@version_number}]"
58       end
59     end
60     return @version_number
61   end
63   def self.version_number=(ver)
64     if ver
65       @version_number = ver - TimeEpoch
66     else
67       @version_number = 0
68     end
70     if $DEBUG_LOADING
71       STDERR.puts "[Compiler version: #{@version_number} (forced)]"
72     end
73   end
75   def initialize(gen_class, context=nil)
76     @variables = {}
77     @generator_class = gen_class
78     @plugins = Hash.new { |h,k| h[k]= [] }
80     @file = "(unknown)"
81     @line = 0
82     @context = context
84     @kernel = Config['rbx-kernel']
85     load_plugins
86   end
88   def kernel?
89     @kernel
90   end
92   def custom_scopes?
93     @context
94   end
96   def create_scopes
97     ctx = @context
98     if ctx.kind_of? BlockContext
99       all_scopes = []
100       block_scopes = []
102       while ctx.kind_of? BlockContext
103         scope = LocalScope.new(nil)
104         scope.from_eval = true
105         block_scopes.unshift scope
106         all_scopes << scope
108         if !ctx.env.from_eval? and names = ctx.method.local_names
109           i = 0
110           names.each do |name|
111             scope[name].created_in_block! i
112             i += 1
113           end
114         end
116         ctx = ctx.env.home_block
117       end
119       scope = LocalScope.new(nil)
120       scope.from_eval = true
121       all_scopes << scope
123       if names = ctx.method.local_names
124         i = 0
125         names.each do |name|
126           scope[name].slot = i
127           i += 1
128         end
129       end
131       return [scope, block_scopes, all_scopes, @context]
132     else
133       scope = LocalScope.new(nil)
134       scope.from_eval = true
135       i = 0
136       if names = ctx.method.local_names
137         names.each do |name|
138           scope[name].slot = i
139           i += 1
140         end
141       end
143       return [scope, [], [scope], @context]
144     end
145   end
147   attr_reader :plugins
148   attr_accessor :generator_class
150   def set_position(file, line)
151     @file, @line = file, line
152   end
154   def current_file
155     @file
156   end
158   def current_line
159     @line
160   end
162   def load_plugins
163     # The default plugins
164     activate_default :block_given
165     activate_default :primitive
166     activate_default :assembly
167     activate_default :fastmath
168     activate_default :current_method
169     activate :safemath if Config['rbx-safe-math']
170     activate :const_epxr if Config['rbx-kernel']
171     activate_default :inline if Config['rbx-inline-times']
172     activate_default :fastsystem
173     activate_default :fastgeneric
174     activate_default :auto_primitive
175     activate_default :conditional_compilation
176   end
178   def activate_default(name)
179     activate(name) unless Config["no-#{name}"]
180   end
182   def activate(name)
183     cls = Plugins.find_plugin(name)
184     raise Error, "Unknown plugin '#{name}'" unless cls
185     @plugins[cls.kind] << cls.new(self)
186   end
188   def inspect
189     "#<#{self.class}>"
190   end
192   def convert_sexp(sexp)
193     return nil if sexp.nil?
195     klass = Node::Mapping[sexp.first]
197     raise Error, "Unable to resolve #{sexp.first}" unless klass
199     return klass.create(self, sexp)
200   end
202   def into_script(sexp)
203     begin
204       convert_sexp([:script, sexp])
205     rescue Object => e
206       puts "Compilation error detected: #{e.message}"
207       puts "   near #{@file}:#{@line}"
208       puts
209       puts e.awesome_backtrace.show
210     end
211   end
213   def get(tag)
214     @variables[tag]
215   end
217   def set(tag, val=true)
218     if tag.kind_of? Hash
219       cur = @variables.dup
220       @variables.merge! tag
221       begin
222         yield
223       ensure
224         @variables = cur
225       end
226     else
227       cur = @variables[tag]
228       @variables[tag] = val
229       begin
230         yield
231       ensure
232         @variables[tag] = cur
233       end
234     end
235   end
237   ##
238   # Raised when turning the AST into bytecode fails in some way.
240   class GenerationError < Error; end
242   def show_errors(gen)
243     begin
244       yield
245     rescue GenerationError => e
246       raise e
247     rescue Object => e
248       puts "Bytecode generation error: "
249       puts "   #{e.message} (#{e.class})"
250       puts "   near #{gen.file}:#{gen.line}"
251       puts ""
252       puts e.awesome_backtrace.show
254       raise GenerationError, "unable to generate bytecode"
255     end
256   end
260 require 'compiler/nodes'
261 require 'compiler/local'
262 require 'compiler/bytecode'
263 require 'compiler/generator'
264 require 'compiler/plugins'