Class: JSON5::Input

Inherits:
Object
  • Object
show all
Defined in:
lib/json5/input.rb

Defined Under Namespace

Classes: Position

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, limits: Limits.default, filename: nil) ⇒ Input

Returns a new instance of Input.



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
# File 'lib/json5/input.rb', line 9

def initialize(source, limits: Limits.default, filename: nil)
  unless source.is_a?(String)
    raise TypeError, "source must be a String"
  end
  unless limits.is_a?(Limits)
    raise ArgumentError, "limits must be a JSON5::Limits"
  end
  @filename = filename
  unless [Encoding::UTF_8, Encoding::US_ASCII].include?(source.encoding)
    raise EncodingError.new(
      "source must be UTF-8 or US-ASCII",
      code: "invalid_encoding",
      filename: filename,
      byte_offset: 0,
      end_byte_offset: [source.bytesize, 1].min,
      line: 1,
      column: 1,
      excerpt: excerpt_for(source, 0)
    )
  end
  if limits.max_input_bytes && source.bytesize > limits.max_input_bytes
    line, column = position_for_limit(source, limits.max_input_bytes)
    raise LimitError.new(
      "input exceeds max_input_bytes",
      code: "maximum_input_size_exceeded",
      filename: filename,
      byte_offset: limits.max_input_bytes,
      end_byte_offset: limits.max_input_bytes + 1,
      line: line,
      column: column,
      excerpt: limit_excerpt_for(source, limits.max_input_bytes)
    )
  end
  unless source.valid_encoding?
    offset = first_invalid_utf8_offset(source)
    line, column = position_at(source, offset)
    raise EncodingError.new(
      "source is not valid UTF-8",
      code: "invalid_encoding",
      filename: filename,
      byte_offset: offset,
      end_byte_offset: [offset + 1, source.bytesize].min,
      line: line,
      column: column,
      excerpt: excerpt_for(source, offset)
    )
  end

  @source = source
  @limits = limits
  @index = 0
  @line = 1
  @column = 1
  @line_start_byte = 0
end

Instance Attribute Details

#columnObject (readonly)

Returns the value of attribute column.



7
8
9
# File 'lib/json5/input.rb', line 7

def column
  @column
end

#indexObject (readonly)

Returns the value of attribute index.



7
8
9
# File 'lib/json5/input.rb', line 7

def index
  @index
end

#lineObject (readonly)

Returns the value of attribute line.



7
8
9
# File 'lib/json5/input.rb', line 7

def line
  @line
end

#line_start_byteObject (readonly)

Returns the value of attribute line_start_byte.



7
8
9
# File 'lib/json5/input.rb', line 7

def line_start_byte
  @line_start_byte
end

#sourceObject (readonly)

Returns the value of attribute source.



7
8
9
# File 'lib/json5/input.rb', line 7

def source
  @source
end

Class Method Details

.position_for(source, byte_offset) ⇒ Object



81
82
83
84
85
86
87
88
89
90
# File 'lib/json5/input.rb', line 81

def self.position_for(source, byte_offset)
  return [nil, nil] unless source.is_a?(String)

  normalized = source.dup
  normalized.force_encoding(Encoding::UTF_8) unless normalized.encoding == Encoding::UTF_8
  input = allocate
  input.send(:position_at, normalized, [[byte_offset, 0].max, normalized.bytesize].min)
rescue ArgumentError, TypeError
  [nil, nil]
end

Instance Method Details

#byteslice(start_byte, end_byte = index) ⇒ Object



92
93
94
# File 'lib/json5/input.rb', line 92

def byteslice(start_byte, end_byte = index)
  source.byteslice(start_byte...end_byte)
end

#consume_ascii(expected = nil) ⇒ Object



108
109
110
111
112
113
114
# File 'lib/json5/input.rb', line 108

def consume_ascii(expected = nil)
  byte = peek_byte
  if expected && byte != expected
    raise ArgumentError, "expected byte #{expected}, got #{byte.inspect}"
  end
  consume_byte
end

#consume_ascii_bytes(count) ⇒ Object



120
121
122
123
# File 'lib/json5/input.rb', line 120

def consume_ascii_bytes(count)
  @index += count
  @column += count
end

#consume_byteObject



100
101
102
103
104
105
106
# File 'lib/json5/input.rb', line 100

def consume_byte
  byte = peek_byte
  return nil unless byte
  @index += 1
  @column += 1
  byte
end

#consume_bytes(count) ⇒ Object



116
117
118
# File 'lib/json5/input.rb', line 116

def consume_bytes(count)
  count.times { consume_byte }
end

#consume_codepointObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/json5/input.rb', line 132

def consume_codepoint
  codepoint, width = peek_codepoint
  return [nil, 0] unless codepoint
  if codepoint == 0x0d
    width += 1 if peek_byte(width) == 0x0a
    @index += width
    advance_line
  elsif line_terminator?(codepoint)
    @index += width
    advance_line
  else
    @index += width
    @column += 1
  end
  [codepoint, width]
end

#eof?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/json5/input.rb', line 65

def eof?
  index >= source.bytesize
end

#excerpt_at(byte_offset, radius: 40) ⇒ Object



153
154
155
156
157
# File 'lib/json5/input.rb', line 153

def excerpt_at(byte_offset, radius: 40)
  start_byte = [byte_offset - radius, 0].max
  finish_byte = [byte_offset + radius, source.bytesize].min
  source.byteslice(start_byte...finish_byte)&.scrub
end

#line_terminator?(codepoint) ⇒ Boolean

Returns:

  • (Boolean)


149
150
151
# File 'lib/json5/input.rb', line 149

def line_terminator?(codepoint)
  codepoint == 0x0a || codepoint == 0x0d || codepoint == 0x2028 || codepoint == 0x2029
end

#markObject



73
74
75
# File 'lib/json5/input.rb', line 73

def mark
  Position.new(index, line, column)
end

#peek_byte(offset = 0) ⇒ Object



69
70
71
# File 'lib/json5/input.rb', line 69

def peek_byte(offset = 0)
  source.getbyte(index + offset)
end

#peek_codepointObject



125
126
127
128
129
130
# File 'lib/json5/input.rb', line 125

def peek_codepoint
  return [nil, 0] if eof?
  byte = peek_byte
  return [byte, 1] if byte < 0x80
  decode_utf8(index)
end

#positionObject



77
78
79
# File 'lib/json5/input.rb', line 77

def position
  mark
end

#remainingObject



96
97
98
# File 'lib/json5/input.rb', line 96

def remaining
  source.bytesize - index
end