b4dade13d0a03dcaff651fe7b6e8d2db434158a4 — Tim Morgan 1 year, 8 months ago 4d798bd
Extract file loading from Compiler
4 files changed, 40 insertions(+), 18 deletions(-)

M compiler.rb
M compiler/libraries.rb
A loader.rb
M spec/program_spec.rb
M compiler.rb => compiler.rb +1 -16
@@ 9,20 9,16 @@ require 'pp'
 require 'pry'
 
 class Compiler
-  ROOT_PATH = VM::ROOT_PATH
-  LOAD_PATH = [File.join(ROOT_PATH, 'lib')].freeze
-
   include Compiler::Libraries
   include Compiler::Lib::Scheme::Base
   include Compiler::Lib::Scheme::ProcessContext
   include Compiler::Lib::Scheme::Write
 
-  def initialize(ast = nil, filename:, arguments: {}, load_path: LOAD_PATH, program:)
+  def initialize(ast = nil, filename:, arguments: {}, program:)
     @program = program
     @variables = {}
     @filename = filename
     @arguments = arguments
-    @load_path = load_path
     @syntax = {}              # macro transformers
     @locals = {}              # top-level locals (globals)
     @libs = {}                # loaded libraries


@@ 284,15 280,4 @@ class Compiler
   def source
     @program.source
   end
-
-  def parse_file(filename, relative_to: nil)
-    path = if filename.start_with?('.') && relative_to
-             File.join(File.dirname(relative_to), filename)
-           else
-             @load_path.map { |p| File.join(p, filename) }.detect { |p| File.exist?(p) }
-           end
-    raise "File #{filename} not found in load path #{@load_path.join(';')}" unless path
-    code = File.read(path)
-    @program.parse(code, filename: filename)
-  end
 end

M compiler/libraries.rb => compiler/libraries.rb +8 -1
@@ 1,4 1,5 @@
 require_relative '../vm'
+require_relative '../loader'
 
 class Compiler
   module Libraries


@@ 16,11 17,17 @@ class Compiler
       paths.map do |path|
         raise "include expects a string, but got #{path.inspect}" unless path =~ /\A"(.+)?"\z/
         filename = $1
-        sexps = parse_file(filename, relative_to: relative_to)
+        sexps = load_and_parse_file(filename, relative_to: relative_to)
         compile_sexps(sexps, options: options)
       end
     end
 
+    def load_and_parse_file(filename, relative_to:)
+      loader = Loader.new(filename, relative_to: relative_to)
+      loader.load
+      @program.parse(loader.code, filename: loader.path)
+    end
+
     def do_import((*sets), relative_to, options)
       sets.map do |set|
         import_set(set, relative_to, options)

A loader.rb => loader.rb +30 -0
@@ 0,0 1,30 @@
+require 'pathname'
+require_relative './vm'
+
+class Loader
+  ROOT_PATH = VM::ROOT_PATH
+  LOAD_PATH = [File.join(ROOT_PATH, 'lib')].freeze
+
+  def initialize(filename, relative_to: nil)
+    @filename = filename
+    @relative_to = relative_to
+  end
+
+  attr_reader :filename, :relative_to, :path, :code
+
+  def load
+    @path = find_path
+    raise "File #{filename} not found in load path #{LOAD_PATH.join(';')}" unless @path
+    @code = File.read(@path)
+  end
+
+  private
+
+  def find_path
+    if filename.start_with?('.') && relative_to
+      File.expand_path(File.join(File.dirname(relative_to), filename))
+    else
+      LOAD_PATH.map { |p| File.expand_path(File.join(p, filename)) }.detect { |p| File.exist?(p) }
+    end
+  end
+end

M spec/program_spec.rb => spec/program_spec.rb +1 -1
@@ 265,7 265,7 @@ describe Program do
         stdout.rewind
         expect(stdout.read).to eq(
           "Error: foo is not defined\n\n" \
-            "./fixtures/bad-macro.scm#5\n\n" \
+            "#{File.expand_path('../fixtures/bad-macro.scm', __FILE__)}#5\n\n" \
             "    (syntax-rules ()\n" \
             "      ((bad-macro) (foo))))\n" \
             "                    ^ foo is not defined\n"