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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +337 -0
- data/lib/ibex/runtime/ast_data.rb +23 -0
- data/lib/ibex/runtime/cst/annotation.rb +16 -0
- data/lib/ibex/runtime/cst/cursor.rb +68 -0
- data/lib/ibex/runtime/cst/diff.rb +80 -0
- data/lib/ibex/runtime/cst/editing.rb +56 -0
- data/lib/ibex/runtime/cst/editor.rb +94 -0
- data/lib/ibex/runtime/cst/green/builder.rb +211 -0
- data/lib/ibex/runtime/cst/green/cache.rb +150 -0
- data/lib/ibex/runtime/cst/green/node.rb +78 -0
- data/lib/ibex/runtime/cst/green/token.rb +91 -0
- data/lib/ibex/runtime/cst/green/trivia.rb +36 -0
- data/lib/ibex/runtime/cst/incremental/blender.rb +233 -0
- data/lib/ibex/runtime/cst/incremental/lexed_syntax.rb +28 -0
- data/lib/ibex/runtime/cst/incremental/parse_memo.rb +95 -0
- data/lib/ibex/runtime/cst/incremental/relexer.rb +134 -0
- data/lib/ibex/runtime/cst/incremental/session.rb +229 -0
- data/lib/ibex/runtime/cst/incremental/token_memo.rb +66 -0
- data/lib/ibex/runtime/cst/kind.rb +133 -0
- data/lib/ibex/runtime/cst/parse_result.rb +41 -0
- data/lib/ibex/runtime/cst/rewriter.rb +75 -0
- data/lib/ibex/runtime/cst/serialize.rb +127 -0
- data/lib/ibex/runtime/cst/serialized_tree.rb +44 -0
- data/lib/ibex/runtime/cst/source_text.rb +112 -0
- data/lib/ibex/runtime/cst/syntax_node.rb +432 -0
- data/lib/ibex/runtime/cst/syntax_token.rb +160 -0
- data/lib/ibex/runtime/cst/text_edit.rb +77 -0
- data/lib/ibex/runtime/cst/typed_node.rb +87 -0
- data/lib/ibex/runtime/cst/validator.rb +428 -0
- data/lib/ibex/runtime/cst.rb +38 -0
- data/lib/ibex/runtime/event.rb +44 -0
- data/lib/ibex/runtime/event_jsonl_tracer.rb +37 -0
- data/lib/ibex/runtime/event_sanitizer.rb +273 -0
- data/lib/ibex/runtime/generated_lexer.rb +514 -0
- data/lib/ibex/runtime/jsonl_tracer.rb +75 -0
- data/lib/ibex/runtime/lexer_input.rb +107 -0
- data/lib/ibex/runtime/location_span.rb +114 -0
- data/lib/ibex/runtime/observation.rb +82 -0
- data/lib/ibex/runtime/parser.rb +3027 -0
- data/lib/ibex/runtime/parser_sync_recovery.rb +108 -0
- data/lib/ibex/runtime/repair.rb +126 -0
- data/lib/ibex/runtime/repair_priority_queue.rb +60 -0
- data/lib/ibex/runtime/repair_search.rb +318 -0
- data/lib/ibex/runtime/resource_limits.rb +64 -0
- data/lib/ibex/runtime/table_format.rb +11 -0
- data/lib/ibex/runtime/version.rb +7 -0
- data/lib/ibex/runtime.rb +27 -0
- data/lib/ibex/tables/compact.rb +186 -0
- data/lib/ibex/tables/compact_actions.rb +135 -0
- data/lib/ibex/tables/compact_productions.rb +167 -0
- data/sig/ibex/runtime/ast_data.rbs +12 -0
- data/sig/ibex/runtime/cst/annotation.rbs +13 -0
- data/sig/ibex/runtime/cst/cursor.rbs +34 -0
- data/sig/ibex/runtime/cst/diff.rbs +29 -0
- data/sig/ibex/runtime/cst/editing.rbs +23 -0
- data/sig/ibex/runtime/cst/editor.rbs +43 -0
- data/sig/ibex/runtime/cst/green/builder.rbs +84 -0
- data/sig/ibex/runtime/cst/green/cache.rbs +60 -0
- data/sig/ibex/runtime/cst/green/node.rbs +49 -0
- data/sig/ibex/runtime/cst/green/token.rbs +59 -0
- data/sig/ibex/runtime/cst/green/trivia.rbs +29 -0
- data/sig/ibex/runtime/cst/incremental/blender.rbs +114 -0
- data/sig/ibex/runtime/cst/incremental/lexed_syntax.rbs +20 -0
- data/sig/ibex/runtime/cst/incremental/parse_memo.rbs +59 -0
- data/sig/ibex/runtime/cst/incremental/relexer.rbs +54 -0
- data/sig/ibex/runtime/cst/incremental/session.rbs +89 -0
- data/sig/ibex/runtime/cst/incremental/token_memo.rbs +31 -0
- data/sig/ibex/runtime/cst/kind.rbs +93 -0
- data/sig/ibex/runtime/cst/parse_result.rbs +35 -0
- data/sig/ibex/runtime/cst/rewriter.rbs +31 -0
- data/sig/ibex/runtime/cst/serialize.rbs +39 -0
- data/sig/ibex/runtime/cst/serialized_tree.rbs +34 -0
- data/sig/ibex/runtime/cst/source_text.rbs +51 -0
- data/sig/ibex/runtime/cst/syntax_node.rbs +195 -0
- data/sig/ibex/runtime/cst/syntax_token.rbs +112 -0
- data/sig/ibex/runtime/cst/text_edit.rbs +33 -0
- data/sig/ibex/runtime/cst/typed_node.rbs +50 -0
- data/sig/ibex/runtime/cst/validator.rbs +108 -0
- data/sig/ibex/runtime/cst.rbs +9 -0
- data/sig/ibex/runtime/event.rbs +26 -0
- data/sig/ibex/runtime/event_jsonl_tracer.rbs +25 -0
- data/sig/ibex/runtime/event_sanitizer.rbs +92 -0
- data/sig/ibex/runtime/generated_lexer.rbs +169 -0
- data/sig/ibex/runtime/jsonl_tracer.rbs +42 -0
- data/sig/ibex/runtime/lexer_input.rbs +44 -0
- data/sig/ibex/runtime/location_span.rbs +64 -0
- data/sig/ibex/runtime/observation.rbs +35 -0
- data/sig/ibex/runtime/parser.rbs +926 -0
- data/sig/ibex/runtime/parser_sync_recovery.rbs +60 -0
- data/sig/ibex/runtime/repair.rbs +92 -0
- data/sig/ibex/runtime/repair_priority_queue.rbs +27 -0
- data/sig/ibex/runtime/repair_search.rbs +114 -0
- data/sig/ibex/runtime/resource_limits.rbs +39 -0
- data/sig/ibex/runtime/table_format.rbs +11 -0
- data/sig/ibex/runtime/version.rbs +7 -0
- data/sig/ibex/runtime.rbs +6 -0
- data/sig/ibex/tables/compact.rbs +70 -0
- data/sig/ibex/tables/compact_actions.rbs +57 -0
- data/sig/ibex/tables/compact_productions.rbs +68 -0
- 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
|