module Atomy::CodeLoader

Constants

LOADED_MODULES
Lock

Public Instance Methods

evaluate_sequences(gen, n, mod) click to toggle source
# File lib/atomy/codeloader.rb, line 203
def evaluate_sequences(gen, n, mod)
  if n.is_a?(Atomy::Grammar::AST::Sequence)
    res = nil

    n.nodes.each.with_index do |sub, i|
      gen.pop unless i == 0
      res = evaluate_sequences(gen, sub, mod)
    end

    res
  else
    res = mod.evaluate(n, mod.compile_context)
    mod.compile(gen, n)
    res
  end
end
find_atomy_source(path, search_in = $LOAD_PATH) click to toggle source
# File lib/atomy/codeloader.rb, line 232
def find_atomy_source(path, search_in = $LOAD_PATH)
  path += source_extension unless path.end_with?(source_extension)
  find_source(path)
end
find_source(path, search_in = $LOAD_PATH) click to toggle source
# File lib/atomy/codeloader.rb, line 220
def find_source(path, search_in = $LOAD_PATH)
  if qualified?(path)
    expanded = File.expand_path(path)
    return expanded if File.file?(expanded)

    expanded = "#{expanded}#{source_extension}"
    return expanded if File.file?(expanded)
  else
    search_path(path, search_in)
  end
end
load(path) click to toggle source
# File lib/atomy/codeloader.rb, line 91
def load(path)
  file = find_source(path)
  unless file
    raise LoadError, "atomy source not found: #{path}"
  end

  synchronized_load(file, true)
end
load_atomy(file, check_up_to_date) click to toggle source
# File lib/atomy/codeloader.rb, line 150
def load_atomy(file, check_up_to_date)
  if loaded?(file, check_up_to_date)
    LOADED_MODULES[file][:module]
  else
    _, mod = run_script(file)
    register_feature(file, mod)
    mod
  end
end
load_map() click to toggle source
# File lib/atomy/codeloader.rb, line 17
def load_map
  @load_map ||= {}
end
register_feature(file, mod) click to toggle source
# File lib/atomy/codeloader.rb, line 141
def register_feature(file, mod)
  LOADED_MODULES[file] = {
    module: mod,
    time: Time.now
  }

  $LOADED_FEATURES << file
end
require(path) click to toggle source
Calls superclass method
# File lib/atomy/codeloader.rb, line 83
def require(path)
  file = find_source(path)

  return super unless file

  synchronized_load(file, false)
end
run_script(path) click to toggle source
# File lib/atomy/codeloader.rb, line 160
def run_script(path)
  file = find_source(path)

  raise LoadError, "no such file to load -- #{path}" unless file

  mod = Atomy::Module.new { use(Atomy::Bootstrap) }
  mod.file = file.to_sym

  compiled_file_name = CodeTools::Compiler.compiled_name(file)
  if compiled_file_up_to_date(compiled_file_name, file)
    code_loader = Rubinius::CodeLoader.new(compiled_file_name)
    code = code_loader.load_compiled_file(compiled_file_name, 0, 0)

    Rubinius.attach_method(
      :__script__,
      code,
      mod.compile_context.lexical_scope,
      mod)

    res = mod.__script__

    return [res, mod]
  end

  node = Atomy::Parser.parse_file(file)

  res = nil
  code =
    Atomy::Compiler.package(mod.file) do |gen|
      res = evaluate_sequences(gen, node, mod)
    end

  if ENV["DEBUG"]
    printer = CodeTools::Compiler::MethodPrinter.new
    printer.bytecode = true
    printer.print_method(code)
  end

  write_compiled_file(compiled_file_name, mod, code) if compiled_file_name

  [res, mod]
end
synchronized_load(file, check_up_to_date) click to toggle source
# File lib/atomy/codeloader.rb, line 100
def synchronized_load(file, check_up_to_date)
  wait = false
  req = nil

  reqs = load_map

  Rubinius.synchronize(Lock) do
    if req = reqs[file]
      return req.module if req.current_thread?
      wait = true
    else
      req = RequireRequest.new(reqs, file)
      reqs[file] = req
      req.take!
    end
  end

  if wait
    if req.wait
      # While waiting the code was loaded by another thread.
      # We need to release the lock so other threads can continue too.
      req.unlock
      return req.module
    end

    # The other thread doing the lock raised an exception
    # through the require, so we try and load it again here.
  end

  begin
    mod = load_atomy(file, check_up_to_date)
  else
    req.module = mod
    req.passed!
  ensure
    req.remove!
  end

  mod
end

Private Instance Methods

compiled_file_up_to_date(compiled_file, source_file) click to toggle source
# File lib/atomy/codeloader.rb, line 257
def compiled_file_up_to_date(compiled_file, source_file)
  return false unless compiled_file
  return false unless File.exists?(compiled_file)

  compiled_mtime = File.mtime(compiled_file)
  return false if File.mtime(source_file) > compiled_mtime

  module_list_file_name = compiled_file + ".modules"
  if File.exists?(module_list_file_name)
    File.open(module_list_file_name, "r") do |io|
      io.each_line do |line|
        mod_file = line.rstrip
        return false if File.mtime(mod_file) > compiled_mtime
      end
    end
  end

  true
end
kernel_path() click to toggle source
# File lib/atomy/codeloader.rb, line 305
def kernel_path
  @kernel_path ||= File.expand_path("../../../kernel", __FILE__)
end
loaded?(file, check_up_to_date) click to toggle source
# File lib/atomy/codeloader.rb, line 239
def loaded?(file, check_up_to_date)
  loaded = LOADED_MODULES[file]
  return false unless loaded

  if check_up_to_date
    return false if File.mtime(file) > loaded[:time]

    compiled_file = CodeTools::Compiler.compiled_name(file)
    return false unless compiled_file_up_to_date(compiled_file, file)
  end

  true
end
qualified?(path) click to toggle source

something that doesn’t look like it should be grabbed from the load path

# File lib/atomy/codeloader.rb, line 311
def qualified?(path)
  path =~ /^([~\/]|\.\.?\/)/
end
search_path(path, load_paths) click to toggle source
# File lib/atomy/codeloader.rb, line 291
def search_path(path, load_paths)
  load_paths.each do |load_path|
    if found = find_source("#{load_path}/#{path}")
      return found
    end
  end

  if found = find_source("#{kernel_path}/#{path}")
    return found
  end

  nil
end
source_extension() click to toggle source
# File lib/atomy/codeloader.rb, line 253
def source_extension
  ".ay"
end
write_compiled_file(compiled_file_name, mod, code) click to toggle source
# File lib/atomy/codeloader.rb, line 277
def write_compiled_file(compiled_file_name, mod, code)
  FileUtils.mkdir_p(File.expand_path("../", compiled_file_name))
  CodeTools::CompiledFile.dump(code, compiled_file_name, Rubinius::Signature, 0)

  module_list_file_name = compiled_file_name + ".modules"
  File.open(module_list_file_name, "w") do |io|
    mod.singleton_class.included_modules.each do |used_module|
      next if used_module == mod
      next unless used_module.is_a?(Atomy::Module) && used_module.file
      io.puts(used_module.file.to_s)
    end
  end
end