Class: Packcr::Node::AlternateNode

Inherits:
Packcr::Node show all
Defined in:
lib/packcr/node/alternate_node.rb,
lib/packcr/generated/node/alternate_node.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Packcr::Node

#link_references, #reversible?, #seq, #sequence?, #setup, #setup_rule

Constructor Details

#initialize(*nodes) ⇒ AlternateNode

Returns a new instance of AlternateNode.



6
7
8
9
# File 'lib/packcr/node/alternate_node.rb', line 6

def initialize(*nodes)
  super()
  self.nodes = nodes
end

Instance Attribute Details

#nodesObject

Returns the value of attribute nodes.



4
5
6
# File 'lib/packcr/node/alternate_node.rb', line 4

def nodes
  @nodes
end

Instance Method Details

#alt(node) ⇒ Object



11
12
13
14
# File 'lib/packcr/node/alternate_node.rb', line 11

def alt(node)
  @nodes << node if node
  self
end

#debug_dump(indent = 0) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/packcr/node/alternate_node.rb', line 16

def debug_dump(indent = 0)
  $stdout.print "#{" " * indent}Alternate(max:#{max}, len:#{nodes.length}) {\n"
  nodes.each do |node|
    node.debug_dump(indent + 2)
  end
  $stdout.print "#{" " * indent}}\n"
end

#generate_code(gen, onfail, indent, bare, oncut: nil) ⇒ Object



30
31
32
# File 'lib/packcr/node/alternate_node.rb', line 30

def generate_code(gen, onfail, indent, bare, oncut: nil)
  gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
end

#get_code(gen, onfail, indent, bare, oncut) ⇒ Object



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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/packcr/generated/node/alternate_node.rb', line 4

def get_code(gen, onfail, indent, bare, oncut)
  case gen.lang
  when :c
    erbout = +""
    m = gen.next_label
    erbout << "{\n    const size_t p = ctx->position_offset;\n".freeze

    if gen.location
      erbout << "    const packcr_location_t p_loc = ctx->position_offset_loc;\n".freeze
    end
    erbout << "    const size_t n = chunk->thunks.len;\n".freeze

    nodes.each_with_index do |expr, i|
      c = i + 1 < nodes.length
      l = gen.next_label
      r = expr.reachability

      erbout << "#{gen.generate_code(expr, l, 4, false)}".freeze
      if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
        if c
          erbout << "    /* unreachable codes omitted */\n".freeze
        end
        break
      elsif r == Packcr::CODE_REACH__BOTH
        erbout << "    goto L#{format("%04d", m)};\n".freeze
      end
      erbout << "L#{format("%04d", l)}:;\n    ctx->position_offset = p;\n".freeze

      if gen.location
        erbout << "    ctx->position_offset_loc = p_loc;\n".freeze
      end
      erbout << "    packcr_thunk_array__revert(ctx->auxil, &chunk->thunks, n);\n".freeze

      next if c

      erbout << "    goto L#{format("%04d", onfail)};\n".freeze
    end
    erbout << "L#{format("%04d", m)}:;\n}\n".freeze

    erbout
  when :rb
    erbout = +""
    m = gen.next_label
    erbout << "catch(#{m}) do\n  pos#{gen.level} = @position_offset\n".freeze

    if gen.location
      erbout << "  p_loc#{gen.level} = @position_offset_loc\n".freeze
    end
    erbout << "  n#{gen.level} = answer.thunks.length\n".freeze

    nodes.each_with_index do |expr, i|
      c = i + 1 < nodes.length
      if expr.reversible?(gen)

        erbout << "#{gen.generate_code(expr, m, 2, false, reverse: true, oncut: onfail)}".freeze
      else
        l = gen.next_label
        erbout << "  catch(#{l}) do\n".freeze

        r = expr.reachability

        erbout << "#{gen.generate_code(expr, l, 4, false, oncut: onfail)}".freeze
        if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
          if c
            erbout << "    # unreachable codes omitted\n".freeze
          end
          erbout << "  end\n".freeze

          break
        elsif r == Packcr::CODE_REACH__BOTH
          erbout << "    throw(#{m})\n".freeze
        end
        erbout << "  end\n".freeze
      end
      erbout << "  @position_offset = pos#{gen.level}\n".freeze

      if gen.location
        erbout << "  @position_offset_loc = p_loc#{gen.level}\n".freeze
      end
      erbout << "  answer.thunks[n#{gen.level}..-1] = []\n".freeze

      next if c

      erbout << "  throw(#{onfail})\n".freeze
    end
    erbout << "end\n".freeze

    erbout
  when :rs
    erbout = +""
    m = gen.next_label
    erbout << "'L#{format("%04d", m)}: {\n    let p = self.input.position_offset;\n".freeze

    if gen.location
      erbout << "    TODO\n".freeze
    end
    nodes.each_with_index do |expr, i|
      erbout << "    {\n".freeze

      c = i + 1 < nodes.length
      if expr.reversible?(gen)

        erbout << "#{gen.generate_code(expr, m, 8, false, reverse: true, oncut: onfail)}".freeze
      else
        l = gen.next_label
        erbout << "        'L#{format("%04d", l)}: {\n".freeze

        r = expr.reachability

        erbout << "#{gen.generate_code(expr, l, 12, false, oncut: onfail)}".freeze
        if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
          if c
            erbout << "            // unreachable codes omitted\n".freeze
          end
          erbout << "        }\n".freeze

          break
        elsif r == Packcr::CODE_REACH__BOTH
          erbout << "            break 'L#{format("%04d", m)};\n".freeze
        end
        erbout << "        }\n".freeze
      end
      erbout << "    }\n    self.input.position_offset = p;\n".freeze

      if gen.location
        erbout << "    TODO\n".freeze
      end
      next if c

      erbout << "    break 'L#{format("%04d", onfail)};\n".freeze
    end
    erbout << "} // 'L#{format("%04d", m)}\n".freeze

    erbout
  else
    raise "unknown lang #{gen.lang}"
  end
end

#maxObject



24
25
26
27
28
# File 'lib/packcr/node/alternate_node.rb', line 24

def max
  m = 1
  m <<= 1 while m < @nodes.length
  m
end

#reachabilityObject



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/packcr/node/alternate_node.rb', line 34

def reachability
  r = Packcr::CODE_REACH__ALWAYS_FAIL
  nodes.each do |expr|
    case expr.reachability
    when Packcr::CODE_REACH__ALWAYS_SUCCEED
      return Packcr::CODE_REACH__ALWAYS_SUCCEED
    when Packcr::CODE_REACH__BOTH
      r = Packcr::CODE_REACH__BOTH
    end
  end
  r
end

#to_hObject



76
77
78
79
80
81
# File 'lib/packcr/node/alternate_node.rb', line 76

def to_h
  {
    type: :alternate,
    nodes: nodes&.map(&:to_h),
  }
end

#verify_captures(ctx, capts) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/packcr/node/alternate_node.rb', line 64

def verify_captures(ctx, capts)
  m = capts.length
  v = capts.dup
  nodes.each do |node|
    v = v[0, m]
    node.verify_captures(ctx, v)
    v[m...-1].each do |added_node|
      capts.push(added_node)
    end
  end
end

#verify_variables(vars) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/packcr/node/alternate_node.rb', line 47

def verify_variables(vars)
  m = vars.length
  v = vars.dup
  nodes.each do |node|
    v = v[0, m]
    node.verify_variables(v)
    v[m...-1].each do |added_node|
      found = vars[m...-1].any? do |added_var|
        added_node.index == added_var.index
      end
      if !found
        vars.push(added_node)
      end
    end
  end
end