8.challenges.1
FossilOrigin-Name: 4dd1670a4466cf079d61e11677e4aa8dd9b9ec096700e2ae565a4073ec4efc12
change yrmuzytxmnvlorzmspmotvuwtmzkmuyt
commit 437d8f99c55d5ea6c10be3d847e0e17ce88bff73
author alpha <alpha@kejadlen.dev>
date
parent vvsszmku
diff --git a/ruby/bin/lox b/ruby/bin/lox
index 4cbfcbb..8e03bf6 100755
--- a/ruby/bin/lox
+++ b/ruby/bin/lox
@@ -4,33 +4,17 @@ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
 
 require "lox"
 
-def run_prompt
+def run_prompt(runner)
   loop do
     print "> "
     line = gets
     break if line.nil? || line.empty?
-    begin
-      run(line)
-    rescue Lox::ParseError => e
-      STDERR.puts e.message
-    rescue Lox::RuntimeError => e
-      STDERR.puts e.message
-    end
+    runner.run(line)
   end
 end
 
-def run_file(io)
-  run(io.read)
-rescue Lox::ParseError => e
-  STDERR.puts e.message
-  exit 65
-rescue Lox::RuntimeError => e
-  STDERR.puts e.message, "[line #{e.token.line}]"
-  exit 70
-end
-
-def run(src)
-  Lox::Runner.new.run(src)
+def run_file(runner, io)
+  runner.run(io.read)
 end
 
 
@@ -38,8 +22,8 @@ if __FILE__ == $0
   puts "Usage: #$0 [script]" or exit 64 if ARGV.length > 1
 
   if ARGV.empty?
-    run_prompt
+    run_prompt(Lox::PromptRunner.new)
   else
-    run_file(ARGF)
+    Lox::FileRunner.new.run(ARGF.read)
   end
 end
diff --git a/ruby/lib/lox.rb b/ruby/lib/lox.rb
index 3cb4e82..9a7ce98 100644
--- a/ruby/lib/lox.rb
+++ b/ruby/lib/lox.rb
@@ -10,18 +10,48 @@ require_relative "lox/token"
 
 module Lox
   class Runner
+    def initialize(scanner: Scanner.new, interpreter: Interpreter.new)
+      @scanner, @interpreter = scanner, interpreter
+    end
+
+    def run(src) = interpret(parse(scan(src)))
+
+    def scan(src) = @scanner.scan(src)
+    def parse(tokens) = Parser.new(tokens).parse!
+    def interpret(stmts) = @interpreter.interpret(stmts)
+  end
+
+  class FileRunner < Runner
+    def run(src)
+      super
+    rescue Lox::ParseError => e
+      STDERR.puts e.message
+      exit 65
+    rescue Lox::RuntimeError => e
+      STDERR.puts e.message, "[line #{e.token.line}]"
+      exit 70
+    end
+  end
+
+  class PromptRunner < Runner
     def initialize
-      @scanner = Scanner.new
-      @parser = Parser.new
-      @interpreter = Interpreter.new
+      super(interpreter: Interpreter.new(Environment.new))
     end
 
     def run(src)
-      tokens = @scanner.scan(src)
-      expr = @parser.parse(tokens)
-      value = @interpreter.interpret(expr)
+      super
+    rescue Lox::ParseError => e
+      STDERR.puts e.message
+    rescue Lox::RuntimeError => e
+      STDERR.puts e.message
+    end
 
-      puts value
+    def parse(tokens)
+      stmts = Parser.new(tokens).parse!
+      if stmts.last.instance_of?(Stmt::Expr)
+        stmts << Stmt::Print.new(stmts.pop.expr)
+      end
+      stmts
     end
   end
 end
diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb
index 3725811..0066043 100644
--- a/ruby/lib/lox/interpreter.rb
+++ b/ruby/lib/lox/interpreter.rb
@@ -3,8 +3,8 @@ require_relative "environment"
 module Lox
   class Interpreter
 
-    def initialize
-      @env = Environment.new
+    def initialize(env=Environment.new)
+      @env = env
     end
 
     # The book does printing and error catching here, but