Class: Ibex::Runtime::CST::SyntaxNode

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/json5/generated_parser.rb

Overview

Lazy Red navigation facade for one Green node occurrence.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(green:, kinds:, parent: nil, index: 0, offset: 0, trivia_policy: :leading, source_text: nil) ⇒ SyntaxNode

Returns a new instance of SyntaxNode.

RBS:

  • (green: GreenNode, kinds: Kind, ?parent: SyntaxNode?, ?index: Integer, ?offset: Integer, ?trivia_policy: Symbol, ?source_text: SourceText?) -> void



1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
# File 'lib/json5/generated_parser.rb', line 1136

def initialize(green:, kinds:, parent: nil, index: 0, offset: 0, trivia_policy: :leading, source_text: nil)
  @green = green
  @kinds = kinds
  @parent = parent
  @index = index
  @offset = offset
  @trivia_policy = trivia_policy
  @source_text = source_text || SourceText.new(root_source)
  @children = Array.new(@green.children.length) #: Array[element?]
end

Instance Attribute Details

#greenObject (readonly)

Signature:

  • GreenNode



1126
1127
1128
# File 'lib/json5/generated_parser.rb', line 1126

def green
  @green
end

#indexObject (readonly)

Signature:

  • Integer



1128
1129
1130
# File 'lib/json5/generated_parser.rb', line 1128

def index
  @index
end

#kindsObject (readonly)

Signature:

  • Kind



1130
1131
1132
# File 'lib/json5/generated_parser.rb', line 1130

def kinds
  @kinds
end

#offsetObject (readonly)

Signature:

  • Integer



1129
1130
1131
# File 'lib/json5/generated_parser.rb', line 1129

def offset
  @offset
end

#parentObject (readonly)

Signature:

  • SyntaxNode?



1127
1128
1129
# File 'lib/json5/generated_parser.rb', line 1127

def parent
  @parent
end

#source_textObject (readonly)

Signature:

  • SourceText



1132
1133
1134
# File 'lib/json5/generated_parser.rb', line 1132

def source_text
  @source_text
end

#trivia_policyObject (readonly)

Signature:

  • Symbol



1131
1132
1133
# File 'lib/json5/generated_parser.rb', line 1131

def trivia_policy
  @trivia_policy
end

Instance Method Details

#==(other) ⇒ Object

RBS:

  • (Object? other) -> bool



1461
1462
1463
# File 'lib/json5/generated_parser.rb', line 1461

def ==(other)
  other.is_a?(SyntaxNode) && @green == other.green
end

#ancestorsObject

RBS:

  • () -> Enumerator[SyntaxNode, void]



1234
1235
1236
1237
1238
1239
1240
1241
1242
# File 'lib/json5/generated_parser.rb', line 1234

def ancestors
  Enumerator.new do |yielder|
    ancestor = @parent
    while ancestor
      yielder << ancestor
      ancestor = ancestor.parent
    end
  end
end

#annotate(annotation) ⇒ Object

RBS:

  • (SyntaxAnnotation annotation) -> SyntaxNode

Raises:

  • (TypeError)


1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
# File 'lib/json5/generated_parser.rb', line 1357

def annotate(annotation)
  raise TypeError, "annotation must be a SyntaxAnnotation" unless annotation.is_a?(SyntaxAnnotation)
  return root if @green.annotations.include?(annotation)

  replace_with(
    GreenNode.new(
      kind: @green.kind, children: @green.children,
      flags: @green.intrinsic_flags, annotations: @green.annotations + [annotation]
    )
  )
end

#annotated(annotation) ⇒ Object

RBS:

  • (SyntaxAnnotation annotation) -> Enumerator[SyntaxNode, void]



1370
1371
1372
1373
1374
1375
1376
1377
1378
# File 'lib/json5/generated_parser.rb', line 1370

def annotated(annotation)
  Enumerator.new do |yielder|
    visit = lambda do |node|
      yielder << node if node.green.annotations.include?(annotation)
      node.child_nodes.each { |child| visit.call(child) }
    end
    visit.call(self)
  end
end

#child_at(child_index) ⇒ Object

RBS:

  • (Integer child_index) -> element



1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
# File 'lib/json5/generated_parser.rb', line 1179

def child_at(child_index)
  cached = @children.fetch(child_index)
  return cached if cached

  green_child = @green.children.fetch(child_index)
  child_offset = offset_for(child_index)
  value = if green_child.is_a?(GreenNode)
            self.class.new(
              green: green_child, kinds: @kinds, parent: self, index: child_index,
              offset: child_offset, trivia_policy: @trivia_policy, source_text: @source_text
            )
          else
            SyntaxToken.new(green: green_child, parent: self, index: child_index, offset: child_offset)
          end
  @children[child_index] = value
end

#child_nodesObject

RBS:

  • () -> Array[SyntaxNode]



1197
1198
1199
1200
1201
# File 'lib/json5/generated_parser.rb', line 1197

def child_nodes
  nodes = [] #: Array[SyntaxNode]
  children.each { |child| nodes << child if child.is_a?(SyntaxNode) }
  nodes.freeze
end

#childrenObject

RBS:

  • () -> Array[element]



1163
1164
1165
# File 'lib/json5/generated_parser.rb', line 1163

def children
  @green.children.each_index.map { |child_index| child_at(child_index) }.freeze
end

#contains_error?Boolean

RBS:

  • () -> bool

Returns:

  • (Boolean)


1307
# File 'lib/json5/generated_parser.rb', line 1307

def contains_error? = @green.flags.anybits?(Flags::CONTAINS_ERROR)

#covering(range) ⇒ Object

Return the smallest syntax element whose full span covers a range.

RBS:

  • (Range[Integer] range) -> element?



1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
# File 'lib/json5/generated_parser.rb', line 1398

def covering(range)
  ensure_coordinates!
  start_offset, end_offset = normalize_range(range)
  return unless covers_offsets?(start_offset, end_offset)

  node = self
  loop do
    child = node.children.find do |candidate|
      candidate_start = candidate.offset
      candidate_end = candidate.offset + candidate.green.full_width
      candidate_start <= start_offset && candidate_end >= end_offset
    end
    return node unless child
    return child if child.is_a?(SyntaxToken)

    node = child
  end
end

#cursorObject

RBS:

  • () -> Cursor



1453
# File 'lib/json5/generated_parser.rb', line 1453

def cursor = Cursor.new(self)

#deconstructObject

RBS:

  • () -> Array[element]



1466
# File 'lib/json5/generated_parser.rb', line 1466

def deconstruct = children

#deconstruct_keys(_keys) ⇒ Object

RBS:

  • (Array[Symbol]?) -> Hash[Symbol, Object?]



1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
# File 'lib/json5/generated_parser.rb', line 1469

def deconstruct_keys(_keys)
  values = {
    kind: :node, symbol: symbol, production_id: production_id, children: children,
    location: location, trailing_trivia: trailing_trivia
  } #: Hash[Symbol, Object?]
  @kinds.fields(kind).each do |name, slot|
    index = slot.is_a?(Hash) ? slot.fetch(:index) : slot
    values[name.to_sym] = child_at(index)
  end
  values.freeze
end

#descendantsObject

RBS:

  • () -> Enumerator[element, void]



1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
# File 'lib/json5/generated_parser.rb', line 1245

def descendants
  Enumerator.new do |yielder|
    visit = lambda do |node|
      node.children.each do |child|
        yielder << child
        visit.call(child) if child.is_a?(SyntaxNode)
      end
    end
    visit.call(self)
  end
end

#each(&block) ⇒ Object

RBS:

  • def each: () -> Enumerator[element, self]
            | () { (element) -> void } -> self


1171
1172
1173
1174
1175
1176
# File 'lib/json5/generated_parser.rb', line 1171

def each(&block)
  return enum_for(:each) unless block

  children.each(&block)
  self
end

#each_error(&block) ⇒ Object

RBS:

  • () -> Enumerator[element, void]

  • () { (element) -> void } -> self



1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
# File 'lib/json5/generated_parser.rb', line 1427

def each_error(&block)
  errors = Enumerator.new do |yielder|
    descendants.each do |element|
      yielder << element if element.error? || element.missing?
    end
  end #: Enumerator[element, void]
  return errors unless block

  errors.each(&block)
  self
end

#error?Boolean

RBS:

  • () -> bool

Returns:

  • (Boolean)


1301
# File 'lib/json5/generated_parser.rb', line 1301

def error? = @kinds.error?(kind)

#find(kind:) ⇒ Object

RBS:

  • (kind: Integer | String | Symbol) -> Enumerator[element, void]



1418
1419
1420
1421
1422
1423
# File 'lib/json5/generated_parser.rb', line 1418

def find(kind:)
  expected = kind.is_a?(Integer) ? kind : @kinds.fetch(kind)
  Enumerator.new do |yielder|
    descendants.each { |element| yielder << element if element.kind == expected }
  end
end

#first_tokenObject

RBS:

  • () -> SyntaxToken?



1211
# File 'lib/json5/generated_parser.rb', line 1211

def first_token = tokens.first

#full_spanObject

RBS:

  • () -> Range[Integer]



1264
1265
1266
1267
# File 'lib/json5/generated_parser.rb', line 1264

def full_span
  ensure_coordinates!
  @offset...(@offset + @green.full_width)
end

#full_textObject Also known as: to_source

RBS:

  • () -> String



1279
# File 'lib/json5/generated_parser.rb', line 1279

def full_text = @green.to_source

#incomplete_input?Boolean

RBS:

  • () -> bool

Returns:

  • (Boolean)


1310
# File 'lib/json5/generated_parser.rb', line 1310

def incomplete_input? = @green.flags.anybits?(Flags::INCOMPLETE_INPUT)

#insert_child(child_index, child) ⇒ Object

RBS:

  • (Integer child_index, GreenNode | GreenToken | SyntaxNode | SyntaxToken child) -> SyntaxNode

Raises:

  • (IndexError)


1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
# File 'lib/json5/generated_parser.rb', line 1329

def insert_child(child_index, child)
  raise IndexError, "child index #{child_index} is outside 0..#{@green.children.length}" unless
    child_index.between?(0, @green.children.length)

  children = @green.children.dup
  children.insert(child_index, Editing.green_element(child))
  replace_with(
    GreenNode.new(
      kind: @green.kind, children: children,
      flags: @green.intrinsic_flags, annotations: @green.annotations
    )
  )
end

#kindObject

RBS:

  • () -> Integer



1148
# File 'lib/json5/generated_parser.rb', line 1148

def kind = @green.kind

#kind_nameObject

RBS:

  • () -> String



1151
# File 'lib/json5/generated_parser.rb', line 1151

def kind_name = @kinds.name(kind)

#last_tokenObject

RBS:

  • () -> SyntaxToken?



1214
# File 'lib/json5/generated_parser.rb', line 1214

def last_token = tokens.last

#locationObject

RBS:

  • () -> Ibex::Location



1276
# File 'lib/json5/generated_parser.rb', line 1276

def location = @source_text.location(span)

#missing?Boolean

RBS:

  • () -> bool

Returns:

  • (Boolean)


1304
# File 'lib/json5/generated_parser.rb', line 1304

def missing? = false

#next_siblingObject

RBS:

  • () -> element?



1217
1218
1219
1220
1221
1222
# File 'lib/json5/generated_parser.rb', line 1217

def next_sibling
  parent = @parent
  return unless parent

  parent.children[@index + 1]
end

#prev_siblingObject

RBS:

  • () -> element?



1225
1226
1227
1228
1229
1230
1231
# File 'lib/json5/generated_parser.rb', line 1225

def prev_sibling
  parent = @parent
  return unless parent
  return if @index.zero?

  parent.children[@index - 1]
end

#production_idObject

Green kinds replace occurrence-local production ids. Keep the legacy key and reader with the historical synthetic sentinel.

RBS:

  • () -> Integer



1160
# File 'lib/json5/generated_parser.rb', line 1160

def production_id = -1

#remove_child(child_index) ⇒ Object

RBS:

  • (Integer child_index) -> SyntaxNode



1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
# File 'lib/json5/generated_parser.rb', line 1344

def remove_child(child_index)
  children = @green.children.dup
  children.fetch(child_index)
  children.delete_at(child_index)
  replace_with(
    GreenNode.new(
      kind: @green.kind, children: children,
      flags: @green.intrinsic_flags, annotations: @green.annotations
    )
  )
end

#replace_with(replacement) ⇒ Object

RBS:

  • (GreenNode | GreenToken | SyntaxNode | SyntaxToken replacement) -> SyntaxNode



1313
# File 'lib/json5/generated_parser.rb', line 1313

def replace_with(replacement) = Editing.replace(self, replacement)

#rootObject

RBS:

  • () -> SyntaxNode



1258
1259
1260
1261
# File 'lib/json5/generated_parser.rb', line 1258

def root
  parent = @parent
  parent ? parent.root : self
end

#same_node?(other) ⇒ Boolean

RBS:

  • (SyntaxNode other) -> bool

Returns:

  • (Boolean)


1456
1457
1458
# File 'lib/json5/generated_parser.rb', line 1456

def same_node?(other)
  root.equal?(other.root) && @green.equal?(other.green) && @offset == other.offset
end

#spanObject

RBS:

  • () -> Range[Integer]



1270
1271
1272
1273
# File 'lib/json5/generated_parser.rb', line 1270

def span
  ensure_coordinates!
  (@offset + @green.leading_width)...(@offset + @green.full_width - @green.trailing_width)
end

#symbolObject

Compatibility name for the physical grammar symbol.

RBS:

  • () -> String



1155
# File 'lib/json5/generated_parser.rb', line 1155

def symbol = @kinds.name(@kinds.nonterminal_of(kind))

#textObject

RBS:

  • () -> String



1283
1284
1285
1286
1287
# File 'lib/json5/generated_parser.rb', line 1283

def text
  start_offset = @green.leading_width
  width = @green.full_width - @green.leading_width - @green.trailing_width
  full_text.byteslice(start_offset, width) || "".b
end

#to_hObject

RBS:

  • () -> Hash[Symbol, Object?]



1482
# File 'lib/json5/generated_parser.rb', line 1482

def to_h = deconstruct_keys(nil)

#token_at(source_offset) ⇒ Object

Find the full-span-owning token for a byte offset.

RBS:

  • (Integer source_offset) -> SyntaxToken?



1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
# File 'lib/json5/generated_parser.rb', line 1382

def token_at(source_offset)
  ensure_coordinates!
  return unless source_offset >= @offset && source_offset < @offset + @green.full_width

  node = self
  loop do
    child = node.child_covering_offset(source_offset)
    return unless child
    return child if child.is_a?(SyntaxToken)

    node = child
  end
end

#tokensObject

RBS:

  • () -> Array[SyntaxToken]



1204
1205
1206
1207
1208
# File 'lib/json5/generated_parser.rb', line 1204

def tokens
  values = [] #: Array[SyntaxToken]
  descendants.each { |element| values << element if element.is_a?(SyntaxToken) }
  values.freeze
end

#trailing_triviaObject

Compatibility view of file-tail trivia. The Red/Green layout owns it on EOF rather than on the start node.

RBS:

  • () -> Array[GreenTrivia]



1292
1293
1294
1295
1296
1297
1298
# File 'lib/json5/generated_parser.rb', line 1292

def trailing_trivia
  eof = compatibility_eof
  return (eof.green.leading + eof.green.trailing).freeze if eof

  token = last_token
  token ? token.green.trailing : []
end

#walk(&block) ⇒ Object

RBS:

  • () { (Symbol, element) -> void } -> self

Raises:

  • (ArgumentError)


1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
# File 'lib/json5/generated_parser.rb', line 1440

def walk(&block)
  raise ArgumentError, "walk requires a block" unless block

  visit = lambda do |element|
    block.call(:enter, element)
    element.children.each { |child| visit.call(child) } if element.is_a?(SyntaxNode)
    block.call(:leave, element)
  end
  visit.call(self)
  self
end

#with_child(child_index, child) ⇒ Object

RBS:

  • (Integer child_index, GreenNode | GreenToken | SyntaxNode | SyntaxToken child) -> SyntaxNode



1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
# File 'lib/json5/generated_parser.rb', line 1316

def with_child(child_index, child)
  children = @green.children.dup
  children.fetch(child_index)
  children[child_index] = Editing.green_element(child)
  replace_with(
    GreenNode.new(
      kind: @green.kind, children: children,
      flags: @green.intrinsic_flags, annotations: @green.annotations
    )
  )
end