File: pn.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (236 lines) | stat: -rw-r--r-- 4,162 bytes parent folder | download | duplicates (3)
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
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
module Puppet::Pops
module PN
  KEY_PATTERN = /^[A-Za-z_-][0-9A-Za-z_-]*$/

  def pnError(message)
    raise ArgumentError, message
  end

  def as_call(name)
    Call.new(name, self)
  end

  def as_parameters
    [self]
  end

  def ==(o)
    eql?(o)
  end

  def to_s
    s = ''
    format(nil, s)
    s
  end

  def with_name(name)
    Entry.new(name, self)
  end

  def double_quote(str, bld)
    bld << '"'
    str.each_codepoint do |codepoint|
      case codepoint
      when 0x09
        bld << '\\t'
      when 0x0a
        bld << '\\n'
      when 0x0d
        bld << '\\r'
      when 0x22
        bld << '\\"'
      when 0x5c
        bld << '\\\\'
      else
        if codepoint < 0x20
          bld << sprintf('\\o%3.3o', codepoint)
        elsif codepoint <= 0x7f
          bld << codepoint
        else
          bld << [codepoint].pack('U')
        end
      end
    end
    bld << '"'
  end

  def format_elements(elements, indent, b)
    elements.each_with_index do |e, i|
      if indent
        b << "\n" << indent.current
      elsif i > 0
        b << ' '
      end
      e.format(indent, b)
    end
  end

  class Indent
    attr_reader :current
    def initialize(indent = '  ', current = '')
      @indent = indent
      @current = current
    end

    def increase
      Indent.new(@indent, @current + @indent)
    end
  end

  class Call
    include PN
    attr_reader :name, :elements

    def initialize(name, *elements)
      @name = name
      @elements = elements
    end

    def [](idx)
      @elements[idx]
    end

    def as_call(name)
      Call.new(name, *@elements)
    end

    def as_parameters
      List.new(@elements)
    end

    def eql?(o)
      o.is_a?(Call) && @name == o.name && @elements == o.elements
    end

    def format(indent, b)
      b << '(' << @name
      if @elements.size > 0
        b << ' ' unless indent
        format_elements(@elements, indent ? indent.increase : nil, b)
      end
      b << ')'
    end

    def to_data
      { '^' => [@name] + @elements.map { |e| e.to_data } }
    end
  end

  class Entry
    attr_reader :key, :value
    def initialize(key, value)
      @key = key
      @value = value
    end

    def eql?(o)
      o.is_a?(Entry) && @key == o.key && @value == o.value
    end

    alias == eql?
  end

  class List
    include PN
    attr_reader :elements

    def initialize(elements)
      @elements = elements
    end

    def [](idx)
      @elements[idx]
    end

    def as_call(name)
      Call.new(name, *@elements)
    end

    def as_parameters
      @elements
    end

    def eql?(o)
      o.is_a?(List) && @elements == o.elements
    end

    def format(indent, b)
      b << '['
      format_elements(@elements, indent ? indent.increase : nil, b) unless @elements.empty?
      b << ']'
    end

    def to_data
      @elements.map { |e| e.to_data }
    end
  end

  class Literal
    include PN
    attr_reader :value

    def initialize(value)
      @value = value
    end

    def format(indent, b)
      if @value.nil?
        b << 'nil'
      elsif value.is_a?(String)
        double_quote(value, b)
      else
        b << value.to_s
      end
    end

    def eql?(o)
      o.is_a?(Literal) && @value == o.value
    end

    def to_data
      @value
    end
  end

  class Map
    include PN
    attr_reader :entries

    def initialize(entries)
      entries.each { |e| pnError("key #{e.key} does not conform to pattern /#{KEY_PATTERN.source}/)") unless e.key =~ KEY_PATTERN }
      @entries = entries
    end

    def eql?(o)
      o.is_a?(Map) && @entries == o.entries
    end

    def format(indent, b)
      local_indent = indent ? indent.increase : nil
      b << '{'
      @entries.each_with_index do |e,i|
        if indent
          b << "\n" << local_indent.current
        elsif i > 0
          b << ' '
        end
        b << ':' << e.key
        b << ' '
        e.value.format(local_indent, b)
      end
      b << '}'
    end

    def to_data
      r = []
      @entries.each { |e| r << e.key << e.value.to_data }
      { '#' => r }
    end
  end
end
end

require_relative 'model/pn_transformer'
require_relative 'parser/pn_parser'