ibex-runtime 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +337 -0
  4. data/lib/ibex/runtime/ast_data.rb +23 -0
  5. data/lib/ibex/runtime/cst/annotation.rb +16 -0
  6. data/lib/ibex/runtime/cst/cursor.rb +68 -0
  7. data/lib/ibex/runtime/cst/diff.rb +80 -0
  8. data/lib/ibex/runtime/cst/editing.rb +56 -0
  9. data/lib/ibex/runtime/cst/editor.rb +94 -0
  10. data/lib/ibex/runtime/cst/green/builder.rb +211 -0
  11. data/lib/ibex/runtime/cst/green/cache.rb +150 -0
  12. data/lib/ibex/runtime/cst/green/node.rb +78 -0
  13. data/lib/ibex/runtime/cst/green/token.rb +91 -0
  14. data/lib/ibex/runtime/cst/green/trivia.rb +36 -0
  15. data/lib/ibex/runtime/cst/incremental/blender.rb +233 -0
  16. data/lib/ibex/runtime/cst/incremental/lexed_syntax.rb +28 -0
  17. data/lib/ibex/runtime/cst/incremental/parse_memo.rb +95 -0
  18. data/lib/ibex/runtime/cst/incremental/relexer.rb +134 -0
  19. data/lib/ibex/runtime/cst/incremental/session.rb +229 -0
  20. data/lib/ibex/runtime/cst/incremental/token_memo.rb +66 -0
  21. data/lib/ibex/runtime/cst/kind.rb +133 -0
  22. data/lib/ibex/runtime/cst/parse_result.rb +41 -0
  23. data/lib/ibex/runtime/cst/rewriter.rb +75 -0
  24. data/lib/ibex/runtime/cst/serialize.rb +127 -0
  25. data/lib/ibex/runtime/cst/serialized_tree.rb +44 -0
  26. data/lib/ibex/runtime/cst/source_text.rb +112 -0
  27. data/lib/ibex/runtime/cst/syntax_node.rb +432 -0
  28. data/lib/ibex/runtime/cst/syntax_token.rb +160 -0
  29. data/lib/ibex/runtime/cst/text_edit.rb +77 -0
  30. data/lib/ibex/runtime/cst/typed_node.rb +87 -0
  31. data/lib/ibex/runtime/cst/validator.rb +428 -0
  32. data/lib/ibex/runtime/cst.rb +38 -0
  33. data/lib/ibex/runtime/event.rb +44 -0
  34. data/lib/ibex/runtime/event_jsonl_tracer.rb +37 -0
  35. data/lib/ibex/runtime/event_sanitizer.rb +273 -0
  36. data/lib/ibex/runtime/generated_lexer.rb +514 -0
  37. data/lib/ibex/runtime/jsonl_tracer.rb +75 -0
  38. data/lib/ibex/runtime/lexer_input.rb +107 -0
  39. data/lib/ibex/runtime/location_span.rb +114 -0
  40. data/lib/ibex/runtime/observation.rb +82 -0
  41. data/lib/ibex/runtime/parser.rb +3027 -0
  42. data/lib/ibex/runtime/parser_sync_recovery.rb +108 -0
  43. data/lib/ibex/runtime/repair.rb +126 -0
  44. data/lib/ibex/runtime/repair_priority_queue.rb +60 -0
  45. data/lib/ibex/runtime/repair_search.rb +318 -0
  46. data/lib/ibex/runtime/resource_limits.rb +64 -0
  47. data/lib/ibex/runtime/table_format.rb +11 -0
  48. data/lib/ibex/runtime/version.rb +7 -0
  49. data/lib/ibex/runtime.rb +27 -0
  50. data/lib/ibex/tables/compact.rb +186 -0
  51. data/lib/ibex/tables/compact_actions.rb +135 -0
  52. data/lib/ibex/tables/compact_productions.rb +167 -0
  53. data/sig/ibex/runtime/ast_data.rbs +12 -0
  54. data/sig/ibex/runtime/cst/annotation.rbs +13 -0
  55. data/sig/ibex/runtime/cst/cursor.rbs +34 -0
  56. data/sig/ibex/runtime/cst/diff.rbs +29 -0
  57. data/sig/ibex/runtime/cst/editing.rbs +23 -0
  58. data/sig/ibex/runtime/cst/editor.rbs +43 -0
  59. data/sig/ibex/runtime/cst/green/builder.rbs +84 -0
  60. data/sig/ibex/runtime/cst/green/cache.rbs +60 -0
  61. data/sig/ibex/runtime/cst/green/node.rbs +49 -0
  62. data/sig/ibex/runtime/cst/green/token.rbs +59 -0
  63. data/sig/ibex/runtime/cst/green/trivia.rbs +29 -0
  64. data/sig/ibex/runtime/cst/incremental/blender.rbs +114 -0
  65. data/sig/ibex/runtime/cst/incremental/lexed_syntax.rbs +20 -0
  66. data/sig/ibex/runtime/cst/incremental/parse_memo.rbs +59 -0
  67. data/sig/ibex/runtime/cst/incremental/relexer.rbs +54 -0
  68. data/sig/ibex/runtime/cst/incremental/session.rbs +89 -0
  69. data/sig/ibex/runtime/cst/incremental/token_memo.rbs +31 -0
  70. data/sig/ibex/runtime/cst/kind.rbs +93 -0
  71. data/sig/ibex/runtime/cst/parse_result.rbs +35 -0
  72. data/sig/ibex/runtime/cst/rewriter.rbs +31 -0
  73. data/sig/ibex/runtime/cst/serialize.rbs +39 -0
  74. data/sig/ibex/runtime/cst/serialized_tree.rbs +34 -0
  75. data/sig/ibex/runtime/cst/source_text.rbs +51 -0
  76. data/sig/ibex/runtime/cst/syntax_node.rbs +195 -0
  77. data/sig/ibex/runtime/cst/syntax_token.rbs +112 -0
  78. data/sig/ibex/runtime/cst/text_edit.rbs +33 -0
  79. data/sig/ibex/runtime/cst/typed_node.rbs +50 -0
  80. data/sig/ibex/runtime/cst/validator.rbs +108 -0
  81. data/sig/ibex/runtime/cst.rbs +9 -0
  82. data/sig/ibex/runtime/event.rbs +26 -0
  83. data/sig/ibex/runtime/event_jsonl_tracer.rbs +25 -0
  84. data/sig/ibex/runtime/event_sanitizer.rbs +92 -0
  85. data/sig/ibex/runtime/generated_lexer.rbs +169 -0
  86. data/sig/ibex/runtime/jsonl_tracer.rbs +42 -0
  87. data/sig/ibex/runtime/lexer_input.rbs +44 -0
  88. data/sig/ibex/runtime/location_span.rbs +64 -0
  89. data/sig/ibex/runtime/observation.rbs +35 -0
  90. data/sig/ibex/runtime/parser.rbs +926 -0
  91. data/sig/ibex/runtime/parser_sync_recovery.rbs +60 -0
  92. data/sig/ibex/runtime/repair.rbs +92 -0
  93. data/sig/ibex/runtime/repair_priority_queue.rbs +27 -0
  94. data/sig/ibex/runtime/repair_search.rbs +114 -0
  95. data/sig/ibex/runtime/resource_limits.rbs +39 -0
  96. data/sig/ibex/runtime/table_format.rbs +11 -0
  97. data/sig/ibex/runtime/version.rbs +7 -0
  98. data/sig/ibex/runtime.rbs +6 -0
  99. data/sig/ibex/tables/compact.rbs +70 -0
  100. data/sig/ibex/tables/compact_actions.rbs +57 -0
  101. data/sig/ibex/tables/compact_productions.rbs +68 -0
  102. metadata +144 -0
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "green/token" unless defined?(Ibex::Runtime::CST::GreenToken)
5
+
6
+ module Ibex
7
+ module Runtime
8
+ module CST
9
+ # Raised when source-coordinate APIs are used on a trivia-dropped tree.
10
+ class TriviaDroppedError < StandardError; end
11
+
12
+ # Lightweight Red facade for one Green token occurrence.
13
+ class SyntaxToken
14
+ attr_reader :green #: GreenToken
15
+ attr_reader :parent #: SyntaxNode
16
+ attr_reader :index #: Integer
17
+ attr_reader :offset #: Integer
18
+
19
+ # @rbs (green: GreenToken, parent: SyntaxNode, index: Integer, offset: Integer) -> void
20
+ def initialize(green:, parent:, index:, offset:)
21
+ @green = green
22
+ @parent = parent
23
+ @index = index
24
+ @offset = offset
25
+ freeze
26
+ end
27
+
28
+ # @rbs () -> Integer
29
+ def kind = @green.kind
30
+
31
+ # @rbs () -> String
32
+ def kind_name = @parent.kinds.name(kind)
33
+
34
+ # @rbs () -> String
35
+ def symbol = kind_name
36
+
37
+ # @rbs () -> String
38
+ def text = @green.text
39
+
40
+ # Compatibility projection for the legacy token API. Semantic lexer
41
+ # values remain on the parser value path; syntax exposes source bytes.
42
+ # @rbs () -> String
43
+ def value = text
44
+
45
+ # @rbs () -> Array[GreenTrivia]
46
+ def leading_trivia = @green.leading
47
+
48
+ # @rbs () -> Array[untyped]
49
+ def children = []
50
+
51
+ # @rbs () -> String
52
+ def full_text = @green.to_source
53
+ alias to_source full_text
54
+
55
+ # @rbs () -> Range[Integer]
56
+ def full_span
57
+ ensure_coordinates!
58
+ @offset...(@offset + @green.full_width)
59
+ end
60
+
61
+ # @rbs () -> Range[Integer]
62
+ def span
63
+ ensure_coordinates!
64
+ (@offset + @green.leading_width)...(@offset + @green.full_width - @green.trailing_width)
65
+ end
66
+
67
+ # @rbs () -> Ibex::Location
68
+ def location = @parent.source_text.location(span)
69
+
70
+ # @rbs () -> bool
71
+ def error? = @parent.kinds.error?(kind)
72
+
73
+ # @rbs () -> bool
74
+ def missing? = @green.flags.anybits?(Flags::CONTAINS_MISSING)
75
+
76
+ # @rbs () -> bool
77
+ def contains_error? = @green.flags.anybits?(Flags::CONTAINS_ERROR)
78
+
79
+ # @rbs (GreenNode | GreenToken | SyntaxNode | SyntaxToken replacement) -> SyntaxNode
80
+ def replace_with(replacement) = Editing.replace(self, replacement)
81
+
82
+ # @rbs (String value) -> SyntaxNode
83
+ def with_text(value)
84
+ replace_with(
85
+ GreenToken.new(
86
+ kind: @green.kind, text: value, leading: @green.leading, trailing: @green.trailing,
87
+ flags: @green.flags, expected_kind: @green.expected_kind
88
+ )
89
+ )
90
+ end
91
+
92
+ # @rbs (Array[GreenTrivia] trivia) -> SyntaxNode
93
+ def with_leading(trivia)
94
+ replace_with(
95
+ GreenToken.new(
96
+ kind: @green.kind, text: @green.text, leading: trivia, trailing: @green.trailing,
97
+ flags: @green.flags, expected_kind: @green.expected_kind
98
+ )
99
+ )
100
+ end
101
+
102
+ # @rbs (Array[GreenTrivia] trivia) -> SyntaxNode
103
+ def with_trailing(trivia)
104
+ replace_with(
105
+ GreenToken.new(
106
+ kind: @green.kind, text: @green.text, leading: @green.leading, trailing: trivia,
107
+ flags: @green.flags, expected_kind: @green.expected_kind
108
+ )
109
+ )
110
+ end
111
+
112
+ # @rbs () -> (SyntaxNode | SyntaxToken)?
113
+ def next_sibling = @parent.children[@index + 1]
114
+
115
+ # @rbs () -> (SyntaxNode | SyntaxToken)?
116
+ def prev_sibling
117
+ return if @index.zero?
118
+
119
+ @parent.children[@index - 1]
120
+ end
121
+
122
+ # @rbs () -> SyntaxNode
123
+ def root = @parent.root
124
+
125
+ # @rbs (SyntaxToken other) -> bool
126
+ def same_node?(other)
127
+ root.equal?(other.root) && @green.equal?(other.green) && @offset == other.offset
128
+ end
129
+
130
+ # @rbs (untyped other) -> bool
131
+ def ==(other)
132
+ other.is_a?(SyntaxToken) && @green == other.green
133
+ end
134
+
135
+ # @rbs () -> Array[untyped]
136
+ def deconstruct = []
137
+
138
+ # @rbs (Array[Symbol]?) -> Hash[Symbol, untyped]
139
+ def deconstruct_keys(_keys)
140
+ {
141
+ kind: :token, symbol: symbol, value: value, location: location,
142
+ leading_trivia: leading_trivia
143
+ }.freeze
144
+ end
145
+
146
+ # @rbs () -> Hash[Symbol, untyped]
147
+ def to_h = deconstruct_keys(nil)
148
+
149
+ private
150
+
151
+ # @rbs () -> void
152
+ def ensure_coordinates!
153
+ return unless @parent.trivia_policy == :drop
154
+
155
+ raise TriviaDroppedError, "source coordinates are unavailable when CST trivia is dropped"
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Runtime
6
+ module CST
7
+ # One byte-oriented source replacement.
8
+ class TextEdit
9
+ class << self
10
+ # Sort and merge adjacent edits while rejecting intersecting source ranges.
11
+ # All edits remain expressed against the unedited source.
12
+ # @rbs (Array[TextEdit] edits) -> Array[TextEdit]
13
+ def normalize(edits)
14
+ raise ArgumentError, "edits must contain only TextEdit values" unless edits.all?(TextEdit)
15
+
16
+ merge_adjacent(
17
+ edits.each_with_index.sort_by do |edit, index|
18
+ [edit.start, edit.delete_length.zero? ? 0 : 1, index]
19
+ end.map(&:first)
20
+ ).freeze
21
+ end
22
+
23
+ private
24
+
25
+ # @rbs (Array[TextEdit] ordered) -> Array[TextEdit]
26
+ def merge_adjacent(ordered)
27
+ normalized = [] #: Array[TextEdit]
28
+ ordered.each do |edit|
29
+ previous = normalized.last
30
+ unless previous
31
+ normalized << edit
32
+ next
33
+ end
34
+
35
+ merge_with_previous(normalized, previous, edit)
36
+ end
37
+ normalized
38
+ end
39
+
40
+ # @rbs (Array[TextEdit] normalized, TextEdit previous, TextEdit edit) -> void
41
+ def merge_with_previous(normalized, previous, edit)
42
+ previous_end = previous.start + previous.delete_length
43
+ raise ArgumentError, "text edits overlap" if edit.start < previous_end
44
+
45
+ if edit.start == previous_end
46
+ normalized[-1] = TextEdit.new(
47
+ start: previous.start,
48
+ delete_length: previous.delete_length + edit.delete_length,
49
+ insert_text: previous.insert_text + edit.insert_text
50
+ )
51
+ else
52
+ normalized << edit
53
+ end
54
+ end
55
+ end
56
+
57
+ attr_reader :start #: Integer
58
+ attr_reader :delete_length #: Integer
59
+ attr_reader :insert_text #: String
60
+
61
+ # @rbs (start: Integer, delete_length: Integer, insert_text: String) -> void
62
+ def initialize(start:, delete_length:, insert_text:)
63
+ raise ArgumentError, "start must be non-negative" if start.negative?
64
+ raise ArgumentError, "delete_length must be non-negative" if delete_length.negative?
65
+
66
+ @start = start
67
+ @delete_length = delete_length
68
+ @insert_text = insert_text.b.freeze
69
+ freeze
70
+ end
71
+
72
+ # @rbs () -> Range[Integer]
73
+ def range = @start...(@start + @delete_length)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "syntax_node" unless defined?(Ibex::Runtime::CST::SyntaxNode)
5
+
6
+ module Ibex
7
+ module Runtime
8
+ module CST
9
+ # Grammar-generated typed view over one Red syntax node.
10
+ class TypedNode
11
+ # @rbs! type element = SyntaxNode | SyntaxToken
12
+
13
+ attr_reader :node #: SyntaxNode
14
+
15
+ # @rbs (SyntaxNode node) -> void
16
+ def initialize(node)
17
+ @node = node
18
+ freeze
19
+ end
20
+
21
+ # @rbs () -> Integer
22
+ def kind = @node.kind
23
+
24
+ # @rbs () -> String
25
+ def kind_name = @node.kind_name
26
+
27
+ # @rbs (Integer index) -> element
28
+ def child_at_slot(index) = @node.child_at(index)
29
+
30
+ # @rbs (Integer index) -> SyntaxNode
31
+ def node_at_slot(index)
32
+ child = child_at_slot(index)
33
+ return child if child.is_a?(SyntaxNode)
34
+
35
+ raise TypeError, "CST slot #{index} is not a syntax node"
36
+ end
37
+
38
+ # @rbs (Integer index) -> SyntaxToken
39
+ def token_at_slot(index)
40
+ child = child_at_slot(index)
41
+ return child if child.is_a?(SyntaxToken)
42
+
43
+ raise TypeError, "CST slot #{index} is not a syntax token"
44
+ end
45
+
46
+ # @rbs () -> Array[element]
47
+ def deconstruct = @node.deconstruct
48
+
49
+ # @rbs (Array[Symbol]?) -> Hash[Symbol, untyped]
50
+ def deconstruct_keys(keys) = @node.deconstruct_keys(keys)
51
+
52
+ # @rbs () -> String
53
+ def to_source = @node.to_source
54
+
55
+ protected
56
+
57
+ # Flatten a lowered repetition helper and enumerate elements or separators.
58
+ # @rbs (Integer index, separated: bool, ?separators: bool) -> Enumerator[element, void]
59
+ def list_items(index, separated:, separators: false)
60
+ root = node_at_slot(index)
61
+ flattened = [] #: Array[element]
62
+ flatten_list(root, root.kind, flattened)
63
+ return flattened.each unless separated
64
+
65
+ selected = [] #: Array[element]
66
+ flattened.each_with_index do |item, item_index|
67
+ selected << item if separators == item_index.odd?
68
+ end
69
+ selected.each
70
+ end
71
+
72
+ private
73
+
74
+ # @rbs (SyntaxNode current, Integer helper_kind, Array[element] result) -> void
75
+ def flatten_list(current, helper_kind, result)
76
+ current.children.each do |child|
77
+ if child.is_a?(SyntaxNode) && child.kind == helper_kind
78
+ flatten_list(child, helper_kind, result)
79
+ else
80
+ result << child
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end