1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
require_relative "../test_helper"

require "lox/ast_printer"
require "lox/parser"
require "lox/resolver"
require "lox/scanner"

class TestResolver < Lox::Test

  def test_resolver
    assert_resolved [
      ["(var j)", 0],
      ["(var j)", 2],
      ["(var j)", 1],
      ["(assign j (+ (var j) 1.0))", 1],
      ["(var k)", 0],
      ["(var k)", 2],
      ["(var k)", 1],
      ["(assign k (+ (var k) 1.0))", 1],
    ], <<~SRC
      var i = 0;
      while (i < 3) {
        print i;
        i = i + 1;
      }

      for(var j=0; j<3; j=j+1) {
        print j;
      }

      {
        var k = 0;
        while (k < 3) {
          {
            print k;
          }
          k = k + 1;
        }
      }
    SRC
  end

  def test_same_var_name_in_scope
    assert_raises Lox::ResolverError do
      resolve(<<~SRC)
        fun bad() {
          var a = "first";
          var a = "second";
        }
      SRC
    end
  end

  def test_returning_from_top_level
    assert_raises Lox::ResolverError do
      resolve(<<~SRC)
        return;
      SRC
    end
  end

  private

  def assert_resolved(expected, src)
    resolves = resolve(src)

    ast_printer = Lox::AstPrinter.new
    assert_equal expected, resolves.map {|expr, depth|
      [ast_printer.print(expr), depth]
    }
  end

  def resolve(src)
    stmts = Lox::Parser.new(Lox::Scanner.new.scan(src)).parse!

    interpreter = Interpreter.new
    Lox::Resolver.new(interpreter).resolve(*stmts)

    interpreter.resolves
  end

  class Interpreter
    attr_reader :resolves

    def initialize
      @resolves = []
    end

    def resolve(expr, depth)
      resolves << [expr, depth]
    end
  end

end