8.5.2
Also add typeprof for the LSP

FossilOrigin-Name: 5083d12e51edc11e5c25174af3fb0276b6a1952a28184b8f43079b6907e2caf5
change vvsszmkursztvkkxqxuyswsmxzrxmmqo
commit bac0f512c9725d5c05412c877f1d8da4335487be
author alpha <alpha@kejadlen.dev>
date
parent pyxztuuz
diff --git a/ruby/Gemfile b/ruby/Gemfile
index e76dde0..ccdc25d 100644
--- a/ruby/Gemfile
+++ b/ruby/Gemfile
@@ -7,3 +7,4 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
 gem "minitest"
 gem "pry"
 gem "rake"
+gem "typeprof"
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
index 9900ff7..416e677 100644
--- a/ruby/Gemfile.lock
+++ b/ruby/Gemfile.lock
@@ -8,6 +8,9 @@ GEM
       coderay (~> 1.1)
       method_source (~> 1.0)
     rake (13.0.6)
+    rbs (2.6.0)
+    typeprof (0.21.3)
+      rbs (>= 1.8.1)
 
 PLATFORMS
   arm64-darwin-21
@@ -16,6 +19,7 @@ DEPENDENCIES
   minitest
   pry
   rake
+  typeprof
 
 BUNDLED WITH
    2.3.18
diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb
index b79776b..a073805 100644
--- a/ruby/lib/lox/ast_printer.rb
+++ b/ruby/lib/lox/ast_printer.rb
@@ -22,6 +22,10 @@ module Lox
       parenthesize("assign #{expr.name.lexeme}", expr.value)
     end
 
+    def visit_block(expr)
+      parenthesize("block", *expr.stmts)
+    end
+
     private
 
     def parenthesize(name, *exprs)
diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb
index b712ffe..3725811 100644
--- a/ruby/lib/lox/interpreter.rb
+++ b/ruby/lib/lox/interpreter.rb
@@ -11,11 +11,28 @@ module Lox
     # we're going to do it in the runner instead.
     def interpret(stmts)
       stmts.each do |stmt|
-        evaluate(stmt)
+        execute(stmt)
       end
     end
 
-    def evaluate(stmt) = stmt.accept(self)
+    def evaluate(expr) = expr.accept(self)
+    def execute(stmt) = stmt.accept(self)
+
+    def visit_block(stmt)
+      execute_block(stmt.stmts, Environment.new(@env))
+      nil
+    end
+
+    def execute_block(stmts, env)
+      prev_env = @env
+      @env = env
+
+      stmts.each do |stmt|
+        execute(stmt)
+      end
+    ensure
+      @env = prev_env
+    end
 
     def visit_expr(expr)
       evaluate(expr.expr)
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index 197cdef..bfece21 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -38,6 +38,7 @@ module Lox
 
     def statement
       return print if match?(:PRINT)
+      return Stmt::Block.new(block) if match?(:LEFT_BRACE)
 
       expression_stmt
     end
@@ -54,6 +55,15 @@ module Lox
       Stmt::Expr.new(value)
     end
 
+    def block
+      statements = []
+      until check?(:RIGHT_BRACE) || eot?
+        statements << declaration
+      end
+      consume!(:RIGHT_BRACE, "Expect '}' after block.")
+      statements
+    end
+
     def assignment
       expr = equality
 
diff --git a/ruby/lib/lox/stmt.rb b/ruby/lib/lox/stmt.rb
index 9f5d6c2..ba05b17 100644
--- a/ruby/lib/lox/stmt.rb
+++ b/ruby/lib/lox/stmt.rb
@@ -2,6 +2,10 @@ require_relative "visitable"
 
 module Lox
   module Stmt
+    Block = Struct.new(:stmts) do
+      include Visitable
+    end
+
     Expr = Struct.new(:expr) do
       include Visitable
     end
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index fde7786..10605cf 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -116,6 +116,40 @@ class TestInterpreter < Lox::Test
     SRC
   end
 
+  def test_block
+    assert_interpreted <<~EXPECTED.chomp, <<~SRC
+      inner a
+      outer b
+      global c
+      outer a
+      outer b
+      global c
+      global a
+      global b
+      global c
+    EXPECTED
+      var a = "global a";
+      var b = "global b";
+      var c = "global c";
+      {
+        var a = "outer a";
+        var b = "outer b";
+        {
+          var a = "inner a";
+          print a;
+          print b;
+          print c;
+        }
+        print a;
+        print b;
+        print c;
+      }
+      print a;
+      print b;
+      print c;
+    SRC
+  end
+
   private
 
   def assert_interpreted(expected, src)
diff --git a/ruby/test/lox/test_parser.rb b/ruby/test/lox/test_parser.rb
index 67b80ae..e5ad65c 100644
--- a/ruby/test/lox/test_parser.rb
+++ b/ruby/test/lox/test_parser.rb
@@ -60,6 +60,15 @@ class TestParser < Lox::Test
     assert_parsed "(print (assign foo 42.0))", :declaration, "print foo = 42.0;"
   end
 
+  def test_block
+    assert_parsed "(block (var foo bar) (print (var foo)))", :statement, <<~SRC
+      {
+        var foo = "bar";
+        print foo;
+      }
+    SRC
+  end
+
   private
 
   def assert_parsed(expected, name, src)