Module: Postsvg::Visitors::PsVisitor::Container

Included in:
Postsvg::Visitors::PsVisitor
Defined in:
lib/postsvg/visitors/ps_visitor/container.rb

Overview

Operators that operate on any collection (string, array, dictionary). The visitor dispatches by is_a? on the operand at runtime.

Instance Method Summary collapse

Instance Method Details

#visit_anchorsearch(op, _ctx) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 118

def visit_anchorsearch(op, _ctx)
  haystack = string_value(op.target)
  needle = string_value(op.pattern)
  if haystack && needle && haystack.start_with?(needle)
    @stack << haystack[needle.length..]
    @stack << needle
    @stack << true
  else
    @stack << haystack
    @stack << false
  end
end

#visit_astore(op, _ctx) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 95

def visit_astore(op, _ctx)
  # astore pops N items and builds an array. The parser
  # already gave us the array via from_operands; just push
  # it back. The original semantics (`arr astore` arr is on
  # bottom, n items on top) are preserved.
  @stack << (op.array.is_a?(Array) ? op.array : [])
end

#visit_cvs(op, _ctx) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 149

def visit_cvs(op, _ctx)
  text =
    case op.value
    when Numeric then op.value.to_s
    when String then op.value
    when Model::Literals::StringLiteral then op.value.value
    when Model::Literals::Name then op.value.value
    else op.value.to_s
    end
  @stack << text
end

#visit_forall(op, _ctx) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 72

def visit_forall(op, _ctx)
  return unless op.body.is_a?(Model::Literals::Procedure)

  case op.collection
  when Array
    op.collection.each do |item|
      @stack << item
      op.body.body.each { |node| node.accept(self, nil) }
    end
  when Hash
    op.collection.each do |key, value|
      @stack << value
      @stack << key
      op.body.body.each { |node| node.accept(self, nil) }
    end
  when String
    op.collection.each_byte do |byte|
      @stack << byte
      op.body.body.each { |node| node.accept(self, nil) }
    end
  end
end

#visit_get(op, _ctx) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 26

def visit_get(op, _ctx)
  operand = op.operand
  key = op.key
  value =
    case operand
    when Hash
      operand[normalize_key(key)]
    when Array
      operand[key.to_i]
    when String
      operand.getbyte(key.to_i)
    when Model::Literals::Dictionary
      operand.entries[normalize_key(key)]
    when Model::Literals::ArrayLiteral
      operand.elements[key.to_i]
    when Model::Literals::StringLiteral
      operand.value.getbyte(key.to_i)
    end
  @stack << value
end

#visit_getinterval(op, _ctx) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 53

def visit_getinterval(op, _ctx)
  case op.operand
  when String
    @stack << op.operand[op.start, op.count]
  when Array
    @stack << op.operand[op.start, op.count]
  when Model::Literals::StringLiteral
    @stack << op.operand.value[op.start, op.count]
  when Model::Literals::ArrayLiteral
    @stack << op.operand.elements[op.start, op.count]
  else
    @stack << ""
  end
end

#visit_length(op, _ctx) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 10

def visit_length(op, _ctx)
  operand = op.operand
  value =
    case operand
    when String then operand.length
    when Array then operand.length
    when Hash then operand.length
    when Model::Literals::StringLiteral then operand.value.length
    when Model::Literals::ArrayLiteral then operand.elements.length
    when Model::Literals::Dictionary then operand.entries.length
    when Model::Literals::HexLiteral then operand.value.length / 2
    else 0
    end
  @stack << value
end

#visit_put(op, _ctx) ⇒ Object



47
48
49
50
51
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 47

def visit_put(op, _ctx)
  # PS put mutates in place. Our value objects are immutable.
  # Marked as a comment in the output so the gap is visible.
  @builder.comment("put: in-place mutation not supported")
end

#visit_putinterval(_op, _ctx) ⇒ Object



68
69
70
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 68

def visit_putinterval(_op, _ctx)
  @builder.comment("putinterval: in-place mutation not supported")
end

#visit_search(op, _ctx) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 103

def visit_search(op, _ctx)
  haystack = string_value(op.target)
  needle = string_value(op.pattern)
  if haystack && needle && (idx = haystack.index(needle))
    post = haystack[(idx + needle.length)..]
    @stack << post
    @stack << needle
    @stack << haystack[0, idx]
    @stack << true
  else
    @stack << haystack
    @stack << false
  end
end

#visit_string(op, _ctx) ⇒ Object



145
146
147
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 145

def visit_string(op, _ctx)
  @stack << ("\0" * op.count.to_i)
end

#visit_token(op, _ctx) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/postsvg/visitors/ps_visitor/container.rb', line 131

def visit_token(op, _ctx)
  text = string_value(op.target)
  return @stack << false unless text

  # PS token splits on whitespace and parses the next token.
  if (match = text.match(/\A\s*(-?\d+(?:\.\d+)?(?:[eE][-+]?\d+)?)/))
    @stack << match[1].to_f
    @stack << text[match[0].length..]
    @stack << true
  else
    @stack << false
  end
end