~tim/scheme-vm

ref: c5110102ce2df2d78a0c87f293edf20f5a3984e7 scheme-vm/vm/pair.rb -rw-r--r-- 1.5 KiB
c5110102Tim Morgan Add more char functions 2 years ago
                                                                                
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
class VM
  class Pair
    include Enumerable

    attr_accessor :address
    attr_accessor :next_node

    def initialize(address, next_node, heap:)
      @address = address
      @next_node = next_node
      @heap = heap
    end

    def raw
      to_a
    end

    def to_s
      items = to_a.flat_map do |item|
        if item.is_a?(Integer) # address
          @heap[item].to_s
        else
          ['.', item.to_s]
        end
      end
      "(#{items.join(' ')})"
    end

    def each
      pair = self
      while pair.is_a?(Pair) && (next_address = pair.next_node)
        yield pair.address
        pair = @heap[next_address]
      end
      yield pair unless pair.is_a?(Pair) || pair.is_a?(EmptyList)
    end

    def car
      return Unspecified.instance if address.nil?
      @heap[address]
    end

    def cdr
      return Unspecified.instance if address.nil?
      @heap[next_node]
    end

    def size
      @size ||= to_a.size
    end

    def empty?
      false
    end

    def to_ruby
      to_a.tap do |ary|
        ary.each_with_index do |address, index|
          part = if address.nil?
                   Unspecified.instance
                 else
                   @heap[address]
                 end
          ary[index] = part.to_ruby
        end
      end
    end

    def inspect
      "#<VM::Pair size=#{size}, car=#{car.inspect}, list=#{to_ruby.inspect}>"
    end

    alias eq? equal?

    def ==(other)
      other.is_a?(Pair) && raw == other.raw
    end
  end
end