8.5.2
Also add typeprof for the LSP
FossilOrigin-Name: 5083d12e51edc11e5c25174af3fb0276b6a1952a28184b8f43079b6907e2caf5
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)