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
data/lib/ibex/runtime.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "runtime/version"
|
|
4
|
+
require_relative "runtime/table_format"
|
|
5
|
+
require_relative "tables/compact"
|
|
6
|
+
require_relative "tables/compact_actions"
|
|
7
|
+
require_relative "tables/compact_productions"
|
|
8
|
+
require_relative "runtime/event_sanitizer"
|
|
9
|
+
require_relative "runtime/event"
|
|
10
|
+
require_relative "runtime/observation"
|
|
11
|
+
require_relative "runtime/cst"
|
|
12
|
+
require_relative "runtime/ast_data"
|
|
13
|
+
require_relative "runtime/resource_limits"
|
|
14
|
+
require_relative "runtime/repair"
|
|
15
|
+
require_relative "runtime/repair_priority_queue"
|
|
16
|
+
require_relative "runtime/repair_search"
|
|
17
|
+
require_relative "runtime/parser_sync_recovery"
|
|
18
|
+
require_relative "runtime/parser"
|
|
19
|
+
require_relative "runtime/lexer_input"
|
|
20
|
+
require_relative "runtime/generated_lexer"
|
|
21
|
+
require_relative "runtime/jsonl_tracer"
|
|
22
|
+
require_relative "runtime/event_jsonl_tracer"
|
|
23
|
+
|
|
24
|
+
module Ibex
|
|
25
|
+
module Runtime
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module Ibex
|
|
5
|
+
module Tables
|
|
6
|
+
# Encodes nonnegative integer arrays into compact generated-source
|
|
7
|
+
# literals. Zero represents nil; positive values are offset by one.
|
|
8
|
+
module PackedIntegers
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# @rbs (Array[Integer?] values) -> String
|
|
12
|
+
def encode(values)
|
|
13
|
+
encoded = values.map do |value|
|
|
14
|
+
raise ArgumentError, "packed integer must be nonnegative or nil" if value&.negative?
|
|
15
|
+
|
|
16
|
+
value ? value + 1 : 0
|
|
17
|
+
end.pack("w*")
|
|
18
|
+
[encoded].pack("m0")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @rbs (String source) -> Array[Integer?]
|
|
22
|
+
def decode(source)
|
|
23
|
+
binary = source.unpack1("m0")
|
|
24
|
+
raise ArgumentError, "packed integer source is invalid" unless binary.is_a?(String)
|
|
25
|
+
|
|
26
|
+
values = binary.unpack("w*") #: Array[Integer]
|
|
27
|
+
values.map { |value| value.zero? ? nil : value - 1 }
|
|
28
|
+
rescue ArgumentError
|
|
29
|
+
raise ArgumentError, "packed integer source is invalid"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @rbs (String source) -> Array[Integer]
|
|
33
|
+
def decode_required(source)
|
|
34
|
+
decode(source).map do |value|
|
|
35
|
+
raise ArgumentError, "packed integer source contains nil" unless value
|
|
36
|
+
|
|
37
|
+
value
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Zigzag-encode signed values after reserving zero for nil.
|
|
42
|
+
# @rbs (Array[Integer?] values) -> String
|
|
43
|
+
def encode_signed(values)
|
|
44
|
+
encode(
|
|
45
|
+
values.map do |value|
|
|
46
|
+
next unless value
|
|
47
|
+
|
|
48
|
+
value.negative? ? (-value * 2) - 1 : value * 2
|
|
49
|
+
end
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @rbs (String source) -> Array[Integer?]
|
|
54
|
+
def decode_signed(source)
|
|
55
|
+
decode(source).map do |value|
|
|
56
|
+
next unless value
|
|
57
|
+
|
|
58
|
+
value.even? ? value / 2 : -((value + 1) / 2)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Sparse table represented by per-row offsets and ownership checks.
|
|
64
|
+
class Compact
|
|
65
|
+
DENSE_CELL_LIMIT = 1_000_000 #: Integer
|
|
66
|
+
|
|
67
|
+
attr_reader :offsets #: Array[Integer]
|
|
68
|
+
attr_reader :values #: Array[untyped]
|
|
69
|
+
attr_reader :checks #: Array[Integer?]
|
|
70
|
+
attr_reader :row_count #: Integer
|
|
71
|
+
attr_reader :dense_values #: Array[untyped]?
|
|
72
|
+
attr_reader :dense_width #: Integer?
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
# @rbs (Array[Hash[Integer, untyped]] rows, ?dense: bool) -> Compact
|
|
76
|
+
def build(rows, dense: true)
|
|
77
|
+
offsets = Array.new(rows.length, 0)
|
|
78
|
+
values = [] #: Array[untyped]
|
|
79
|
+
checks = [] #: Array[Integer?]
|
|
80
|
+
next_offsets = {} #: Hash[Array[Integer], Integer]
|
|
81
|
+
rows.each_index.sort_by { |row| [-rows[row].length, row] }.each do |row|
|
|
82
|
+
offset = find_offset(rows[row].keys, checks, next_offsets)
|
|
83
|
+
offsets[row] = offset
|
|
84
|
+
rows[row].each do |column, value|
|
|
85
|
+
index = offset + column
|
|
86
|
+
values[index] = value
|
|
87
|
+
checks[index] = row
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
dense_width = rows.flat_map(&:keys).max.to_i + 1 if dense
|
|
91
|
+
dense_width = nil if dense_width && (rows.length * dense_width) > DENSE_CELL_LIMIT
|
|
92
|
+
new(
|
|
93
|
+
offsets: offsets, values: values, checks: checks, row_count: rows.length,
|
|
94
|
+
dense_width: dense_width
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @rbs (String offsets, String values, String checks, row_count: Integer,
|
|
99
|
+
# ?dense_width: Integer?) -> Compact
|
|
100
|
+
def packed(offsets, values, checks, row_count:, dense_width: nil)
|
|
101
|
+
new(
|
|
102
|
+
offsets: PackedIntegers.decode_required(offsets),
|
|
103
|
+
values: PackedIntegers.decode(values),
|
|
104
|
+
checks: PackedIntegers.decode(checks),
|
|
105
|
+
row_count: row_count,
|
|
106
|
+
dense_width: dense_width
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
# @rbs (Array[Integer] columns, Array[Integer?] checks, Hash[Array[Integer], Integer] next_offsets) -> Integer
|
|
113
|
+
def find_offset(columns, checks, next_offsets)
|
|
114
|
+
return 0 if columns.empty?
|
|
115
|
+
|
|
116
|
+
signature = columns.sort
|
|
117
|
+
offset = next_offsets.fetch(signature, 0)
|
|
118
|
+
offset += 1 while columns.any? { |column| checks[offset + column] }
|
|
119
|
+
next_offsets[signature] = offset + 1
|
|
120
|
+
offset
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @rbs (offsets: Array[Integer], values: Array[untyped], checks: Array[Integer?],
|
|
125
|
+
# row_count: Integer, ?dense_width: Integer?) -> void
|
|
126
|
+
def initialize(offsets:, values:, checks:, row_count:, dense_width: nil)
|
|
127
|
+
@offsets = offsets.freeze
|
|
128
|
+
@values = values.freeze
|
|
129
|
+
@checks = checks.freeze
|
|
130
|
+
@row_count = row_count
|
|
131
|
+
@dense_width = dense_width
|
|
132
|
+
@dense_values = dense_layout(dense_width)
|
|
133
|
+
freeze
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Keep predicate dispatch out of this lookup because every parser action
|
|
137
|
+
# and goto crosses it.
|
|
138
|
+
# rubocop:disable Style/NumericPredicate
|
|
139
|
+
# @rbs (Integer row, Integer column) -> untyped
|
|
140
|
+
def lookup(row, column)
|
|
141
|
+
return nil if row < 0 || row >= @row_count || column < 0
|
|
142
|
+
|
|
143
|
+
index = @offsets[row] + column
|
|
144
|
+
return nil if index < 0 || index >= @checks.length
|
|
145
|
+
|
|
146
|
+
@checks[index] == row ? @values[index] : nil
|
|
147
|
+
end
|
|
148
|
+
# rubocop:enable Style/NumericPredicate
|
|
149
|
+
|
|
150
|
+
# @rbs (Integer row) -> Hash[Integer, untyped]
|
|
151
|
+
def row(row)
|
|
152
|
+
return {} unless row.between?(0, @row_count - 1)
|
|
153
|
+
|
|
154
|
+
result = {} #: Hash[Integer, untyped]
|
|
155
|
+
@checks.each_index do |index|
|
|
156
|
+
next unless @checks[index] == row
|
|
157
|
+
|
|
158
|
+
result[index - @offsets[row]] = @values[index]
|
|
159
|
+
end
|
|
160
|
+
result
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
# @rbs (Integer? dense_width) -> Array[untyped]?
|
|
166
|
+
def dense_layout(dense_width)
|
|
167
|
+
return nil unless dense_width
|
|
168
|
+
raise ArgumentError, "compact dense width must be positive" unless dense_width.positive?
|
|
169
|
+
return nil if (@row_count * dense_width) > DENSE_CELL_LIMIT
|
|
170
|
+
|
|
171
|
+
dense = Array.new(@row_count * dense_width) #: Array[untyped]
|
|
172
|
+
@checks.each_index do |index|
|
|
173
|
+
row = @checks[index]
|
|
174
|
+
next unless row
|
|
175
|
+
|
|
176
|
+
column = index - @offsets.fetch(row)
|
|
177
|
+
raise ArgumentError, "compact column exceeds the dense row width" unless
|
|
178
|
+
column.between?(0, dense_width - 1)
|
|
179
|
+
|
|
180
|
+
dense[(row * dense_width) + column] = @values[index]
|
|
181
|
+
end
|
|
182
|
+
dense.freeze
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require_relative "compact" unless defined?(Ibex::Tables::Compact)
|
|
5
|
+
|
|
6
|
+
module Ibex
|
|
7
|
+
module Tables
|
|
8
|
+
# Compact action table with an integer-coded hot representation and a
|
|
9
|
+
# compatible decoded lookup surface for the generic runtime.
|
|
10
|
+
class CompactActions < Compact
|
|
11
|
+
ACCEPT_CODE = 0 #: Integer
|
|
12
|
+
ERROR_CODE = -1 #: Integer
|
|
13
|
+
SHIFT_BASE = 1 #: Integer
|
|
14
|
+
REDUCE_BASE = -2 #: Integer
|
|
15
|
+
LEGACY_ERROR_CODE = 1 #: Integer
|
|
16
|
+
LEGACY_SHIFT_BASE = 2 #: Integer
|
|
17
|
+
LEGACY_REDUCE_BASE = 3 #: Integer
|
|
18
|
+
private_constant :LEGACY_ERROR_CODE, :LEGACY_SHIFT_BASE, :LEGACY_REDUCE_BASE
|
|
19
|
+
|
|
20
|
+
attr_reader :codes #: Array[Integer?]
|
|
21
|
+
attr_reader :dense_codes #: Array[Integer?]?
|
|
22
|
+
attr_reader :column_count #: Integer?
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
# @rbs (Array[Hash[Integer, untyped]] rows) -> CompactActions
|
|
26
|
+
def build(rows)
|
|
27
|
+
packed_rows = rows.map do |row|
|
|
28
|
+
row.transform_values { |action| pack(action) }
|
|
29
|
+
end
|
|
30
|
+
layout = Compact.build(packed_rows, dense: false)
|
|
31
|
+
column_count = rows.flat_map(&:keys).max.to_i + 1
|
|
32
|
+
column_count = nil if (rows.length * column_count) > Compact::DENSE_CELL_LIMIT
|
|
33
|
+
new(
|
|
34
|
+
offsets: layout.offsets,
|
|
35
|
+
codes: layout.values,
|
|
36
|
+
checks: layout.checks,
|
|
37
|
+
row_count: layout.row_count,
|
|
38
|
+
encoding: :signed,
|
|
39
|
+
column_count: column_count
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @rbs (String offsets, String codes, String checks, row_count: Integer,
|
|
44
|
+
# ?encoding: Symbol, ?column_count: Integer?) -> CompactActions
|
|
45
|
+
def packed(offsets, codes, checks, row_count:, encoding: :legacy, column_count: nil)
|
|
46
|
+
new(
|
|
47
|
+
offsets: PackedIntegers.decode_required(offsets),
|
|
48
|
+
codes: encoding == :signed ? PackedIntegers.decode_signed(codes) : PackedIntegers.decode(codes),
|
|
49
|
+
checks: PackedIntegers.decode(checks),
|
|
50
|
+
row_count: row_count,
|
|
51
|
+
encoding: encoding,
|
|
52
|
+
column_count: column_count
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @rbs (untyped action) -> Integer?
|
|
57
|
+
def pack(action)
|
|
58
|
+
return unless action
|
|
59
|
+
|
|
60
|
+
case action.fetch(0)
|
|
61
|
+
when :accept then ACCEPT_CODE
|
|
62
|
+
when :error then ERROR_CODE
|
|
63
|
+
when :shift then SHIFT_BASE + action.fetch(1)
|
|
64
|
+
when :reduce then REDUCE_BASE - action.fetch(1)
|
|
65
|
+
else raise ArgumentError, "unknown compact parser action #{action.inspect}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @rbs (Integer? code) -> untyped
|
|
70
|
+
def unpack(code)
|
|
71
|
+
return unless code
|
|
72
|
+
return [:accept].freeze if code == ACCEPT_CODE
|
|
73
|
+
return [:error].freeze if code == ERROR_CODE
|
|
74
|
+
return [:shift, code - SHIFT_BASE].freeze if code.positive?
|
|
75
|
+
|
|
76
|
+
[:reduce, REDUCE_BASE - code].freeze
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Convert codes emitted before signed compact actions without changing
|
|
80
|
+
# their generated table literals.
|
|
81
|
+
# @rbs (Integer? code) -> Integer?
|
|
82
|
+
def legacy_to_signed(code)
|
|
83
|
+
return unless code
|
|
84
|
+
return ACCEPT_CODE if code == ACCEPT_CODE
|
|
85
|
+
return ERROR_CODE if code == LEGACY_ERROR_CODE
|
|
86
|
+
return SHIFT_BASE + ((code - LEGACY_SHIFT_BASE) / 2) if code.even?
|
|
87
|
+
|
|
88
|
+
REDUCE_BASE - ((code - LEGACY_REDUCE_BASE) / 2)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (offsets: Array[Integer], codes: Array[Integer?], checks: Array[Integer?],
|
|
93
|
+
# row_count: Integer, ?encoding: Symbol, ?column_count: Integer?) -> void
|
|
94
|
+
def initialize(offsets:, codes:, checks:, row_count:, encoding: :legacy, column_count: nil)
|
|
95
|
+
codes = codes.map { |code| self.class.legacy_to_signed(code) } if encoding == :legacy
|
|
96
|
+
unless %i[legacy signed].include?(encoding)
|
|
97
|
+
raise ArgumentError, "unknown compact action encoding #{encoding.inspect}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
@codes = codes.freeze
|
|
101
|
+
@column_count = column_count
|
|
102
|
+
@dense_codes = dense_action_layout(offsets, codes, checks, row_count, column_count)
|
|
103
|
+
decoded_cache = {} #: Hash[Integer, untyped]
|
|
104
|
+
decoded = codes.map do |code|
|
|
105
|
+
code.nil? ? nil : decoded_cache[code] ||= self.class.unpack(code)
|
|
106
|
+
end
|
|
107
|
+
super(offsets: offsets, values: decoded, checks: checks, row_count: row_count)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
# @rbs (Array[Integer] offsets, Array[Integer?] codes, Array[Integer?] checks,
|
|
113
|
+
# Integer row_count, Integer? column_count) -> Array[Integer?]?
|
|
114
|
+
def dense_action_layout(offsets, codes, checks, row_count, column_count)
|
|
115
|
+
return nil unless column_count
|
|
116
|
+
raise ArgumentError, "compact action column count must be positive" unless column_count.positive?
|
|
117
|
+
|
|
118
|
+
return nil if (row_count * column_count) > Compact::DENSE_CELL_LIMIT
|
|
119
|
+
|
|
120
|
+
dense = Array.new(row_count * column_count) #: Array[Integer?]
|
|
121
|
+
checks.each_index do |index|
|
|
122
|
+
row = checks[index]
|
|
123
|
+
next unless row
|
|
124
|
+
|
|
125
|
+
column = index - offsets.fetch(row)
|
|
126
|
+
raise ArgumentError, "compact action column exceeds the dense row width" unless
|
|
127
|
+
column.between?(0, column_count - 1)
|
|
128
|
+
|
|
129
|
+
dense[(row * column_count) + column] = codes[index]
|
|
130
|
+
end
|
|
131
|
+
dense.freeze
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module Ibex
|
|
5
|
+
module Tables
|
|
6
|
+
# Production metadata with parallel primitive arrays for the direct parser
|
|
7
|
+
# and a compatible Array-of-Hash surface for generic runtime consumers.
|
|
8
|
+
class CompactProductions < Array #[Hash[Symbol, untyped]]
|
|
9
|
+
VALUES_ACTION = 1 #: Integer
|
|
10
|
+
BORROWED_VALUES_ACTION = 2 #: Integer
|
|
11
|
+
LOCATION_ACTION = 4 #: Integer
|
|
12
|
+
COMPOSITION_ACTION = 8 #: Integer
|
|
13
|
+
POSITIONAL_ACTION = 16 #: Integer
|
|
14
|
+
VALID_FLAGS = VALUES_ACTION | BORROWED_VALUES_ACTION | LOCATION_ACTION |
|
|
15
|
+
COMPOSITION_ACTION | POSITIONAL_ACTION #: Integer
|
|
16
|
+
CORE_FIELDS = %i[
|
|
17
|
+
lhs length action values_action borrowed_values_action location_action composition_action
|
|
18
|
+
].freeze #: Array[Symbol]
|
|
19
|
+
private_constant :VALID_FLAGS, :CORE_FIELDS
|
|
20
|
+
|
|
21
|
+
attr_reader :lhs_ids #: Array[Integer]
|
|
22
|
+
attr_reader :lengths #: Array[Integer]
|
|
23
|
+
attr_reader :actions #: Array[Symbol?]
|
|
24
|
+
attr_reader :flags #: Array[Integer]
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
# @rbs (Array[Hash[Symbol, untyped]] productions) -> CompactProductions
|
|
28
|
+
def build(productions)
|
|
29
|
+
lhs_ids = [] #: Array[Integer]
|
|
30
|
+
lengths = [] #: Array[Integer]
|
|
31
|
+
actions = [] #: Array[Symbol?]
|
|
32
|
+
flags = [] #: Array[Integer]
|
|
33
|
+
metadata = {} #: Hash[Integer, Hash[Symbol, untyped]]
|
|
34
|
+
productions.each_with_index do |production, index|
|
|
35
|
+
lhs_ids << production.fetch(:lhs)
|
|
36
|
+
lengths << production.fetch(:length)
|
|
37
|
+
actions << production[:action]
|
|
38
|
+
flags << flags_for(production)
|
|
39
|
+
extra = production.except(
|
|
40
|
+
:lhs, :length, :action, :values_action, :borrowed_values_action, :location_action, :composition_action
|
|
41
|
+
)
|
|
42
|
+
metadata[index] = extra unless extra.empty?
|
|
43
|
+
end
|
|
44
|
+
new(lhs_ids: lhs_ids, lengths: lengths, actions: actions, flags: flags, metadata: metadata)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @rbs (String lhs_ids, String lengths, String flags,
|
|
48
|
+
# ?metadata: Hash[Integer, Hash[Symbol, untyped]]) -> CompactProductions
|
|
49
|
+
def packed(lhs_ids, lengths, flags, metadata: {})
|
|
50
|
+
decoded_flags = PackedIntegers.decode_required(flags)
|
|
51
|
+
actions = decoded_flags.each_index.map do |index|
|
|
52
|
+
:"_ibex_action_#{index}" unless decoded_flags[index].zero?
|
|
53
|
+
end
|
|
54
|
+
new(
|
|
55
|
+
lhs_ids: PackedIntegers.decode_required(lhs_ids),
|
|
56
|
+
lengths: PackedIntegers.decode_required(lengths),
|
|
57
|
+
actions: actions,
|
|
58
|
+
flags: decoded_flags,
|
|
59
|
+
metadata: metadata
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# @rbs (Hash[Symbol, untyped] production) -> Integer
|
|
66
|
+
def flags_for(production)
|
|
67
|
+
value = 0
|
|
68
|
+
value |= VALUES_ACTION if production[:values_action] == true
|
|
69
|
+
value |= BORROWED_VALUES_ACTION if production[:borrowed_values_action] == true
|
|
70
|
+
value |= LOCATION_ACTION if production[:location_action] == true
|
|
71
|
+
value |= COMPOSITION_ACTION if production[:composition_action] == true
|
|
72
|
+
value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @rbs (lhs_ids: Array[Integer], lengths: Array[Integer], actions: Array[Symbol?],
|
|
77
|
+
# flags: Array[Integer], ?metadata: Hash[Integer, Hash[Symbol, untyped]]) -> void
|
|
78
|
+
def initialize(lhs_ids:, lengths:, actions:, flags:, metadata: {})
|
|
79
|
+
size = lhs_ids.length
|
|
80
|
+
unless lengths.length == size && actions.length == size && flags.length == size
|
|
81
|
+
raise ArgumentError, "compact production arrays must have the same length"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
@lhs_ids = lhs_ids.map { |value| nonnegative_integer!(value, "lhs") }.freeze
|
|
85
|
+
@lengths = lengths.map { |value| nonnegative_integer!(value, "length") }.freeze
|
|
86
|
+
@actions = actions.map { |value| action!(value) }.freeze
|
|
87
|
+
@flags = flags.map { |value| flags!(value) }.freeze
|
|
88
|
+
validate_markers!
|
|
89
|
+
validate_metadata!(metadata, size)
|
|
90
|
+
super(Array.new(size) { |index| decode(index, metadata[index]) })
|
|
91
|
+
freeze
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @rbs () -> bool
|
|
95
|
+
def direct_values?
|
|
96
|
+
@direct_values
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
# @rbs (untyped value, String name) -> Integer
|
|
102
|
+
def nonnegative_integer!(value, name)
|
|
103
|
+
return value if value.is_a?(Integer) && !value.negative?
|
|
104
|
+
|
|
105
|
+
raise ArgumentError, "compact production #{name} must be a nonnegative Integer"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @rbs (untyped value) -> Symbol?
|
|
109
|
+
def action!(value)
|
|
110
|
+
return value if value.nil? || value.is_a?(Symbol)
|
|
111
|
+
|
|
112
|
+
raise ArgumentError, "compact production action must be a Symbol or nil"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @rbs (untyped value) -> Integer
|
|
116
|
+
def flags!(value)
|
|
117
|
+
return value if value.is_a?(Integer) && !value.negative? && value.nobits?(~VALID_FLAGS)
|
|
118
|
+
|
|
119
|
+
raise ArgumentError, "compact production flags are invalid"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @rbs () -> void
|
|
123
|
+
def validate_markers!
|
|
124
|
+
@flags.each_with_index do |value, index|
|
|
125
|
+
borrowed = value.anybits?(BORROWED_VALUES_ACTION)
|
|
126
|
+
values = value.anybits?(VALUES_ACTION)
|
|
127
|
+
positional = value.anybits?(POSITIONAL_ACTION)
|
|
128
|
+
raise ArgumentError, "borrowed production #{index} must be a values action" if borrowed && !values
|
|
129
|
+
if positional && value.anybits?(VALUES_ACTION | LOCATION_ACTION | COMPOSITION_ACTION)
|
|
130
|
+
raise ArgumentError, "positional production #{index} cannot combine action ABI flags"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
@direct_values = @actions.each_index.all? do |index|
|
|
134
|
+
@actions[index].nil? || @flags[index].anybits?(VALUES_ACTION | POSITIONAL_ACTION)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @rbs (Hash[Integer, Hash[Symbol, untyped]] metadata, Integer size) -> void
|
|
139
|
+
def validate_metadata!(metadata, size)
|
|
140
|
+
metadata.each do |index, entry|
|
|
141
|
+
unless index.is_a?(Integer) && index.between?(0, size - 1) && entry.is_a?(Hash)
|
|
142
|
+
raise ArgumentError, "compact production metadata is invalid"
|
|
143
|
+
end
|
|
144
|
+
if entry.keys.any? { |key| CORE_FIELDS.include?(key) }
|
|
145
|
+
raise ArgumentError, "compact production metadata cannot replace core fields"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @rbs (Integer index, Hash[Symbol, untyped]? metadata) -> Hash[Symbol, untyped]
|
|
151
|
+
def decode(index, metadata)
|
|
152
|
+
entry = {} #: Hash[Symbol, untyped]
|
|
153
|
+
entry[:lhs] = @lhs_ids[index]
|
|
154
|
+
entry[:length] = @lengths[index]
|
|
155
|
+
entry[:action] = @actions[index]
|
|
156
|
+
value = @flags[index]
|
|
157
|
+
entry[:values_action] = true if value.anybits?(VALUES_ACTION)
|
|
158
|
+
entry[:borrowed_values_action] = true if value.anybits?(BORROWED_VALUES_ACTION)
|
|
159
|
+
entry[:location_action] = true if value.anybits?(LOCATION_ACTION)
|
|
160
|
+
entry[:composition_action] = true if value.anybits?(COMPOSITION_ACTION)
|
|
161
|
+
entry[:positional_action] = true if value.anybits?(POSITIONAL_ACTION)
|
|
162
|
+
entry.merge!(metadata) if metadata
|
|
163
|
+
entry.freeze
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/ast_data.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
# Builds Data classes on Ruby 3.2+ and an immutable Struct-compatible
|
|
6
|
+
# fallback on older supported Rubies.
|
|
7
|
+
module ASTData
|
|
8
|
+
# @rbs (*Symbol members) -> singleton(Object)
|
|
9
|
+
def self?.define: (*Symbol members) -> singleton(Object)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/cst/annotation.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
module CST
|
|
6
|
+
# Opaque identity used to track a syntax occurrence across path-copying edits.
|
|
7
|
+
class SyntaxAnnotation
|
|
8
|
+
# @rbs () -> void
|
|
9
|
+
def initialize: () -> void
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/cst/cursor.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
module CST
|
|
6
|
+
# Allocation-light cursor over Green elements and absolute offsets.
|
|
7
|
+
# rubocop:disable Naming/PredicateMethod -- cursor movement names follow the public tree-cursor convention.
|
|
8
|
+
class Cursor
|
|
9
|
+
type green = GreenNode | GreenToken
|
|
10
|
+
|
|
11
|
+
type frame = [ GreenNode, Integer, Integer ]
|
|
12
|
+
|
|
13
|
+
attr_reader green: green
|
|
14
|
+
|
|
15
|
+
attr_reader offset: Integer
|
|
16
|
+
|
|
17
|
+
# @rbs (SyntaxNode node) -> void
|
|
18
|
+
def initialize: (SyntaxNode node) -> void
|
|
19
|
+
|
|
20
|
+
# @rbs () -> bool
|
|
21
|
+
def goto_first_child: () -> bool
|
|
22
|
+
|
|
23
|
+
# @rbs () -> bool
|
|
24
|
+
def goto_next_sibling: () -> bool
|
|
25
|
+
|
|
26
|
+
# @rbs () -> bool
|
|
27
|
+
def goto_parent: () -> bool
|
|
28
|
+
|
|
29
|
+
# @rbs () -> Integer
|
|
30
|
+
def kind: () -> Integer
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/cst/diff.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
module CST
|
|
6
|
+
# Computes byte edits while skipping physically shared Green subtrees.
|
|
7
|
+
module Diff
|
|
8
|
+
# @rbs (SyntaxNode old_root, SyntaxNode new_root) -> Array[TextEdit]
|
|
9
|
+
def self?.text_edits: (SyntaxNode old_root, SyntaxNode new_root) -> Array[TextEdit]
|
|
10
|
+
|
|
11
|
+
# @rbs (GreenNode | GreenToken old_green, GreenNode | GreenToken new_green,
|
|
12
|
+
# Integer offset, Array[TextEdit] edits) -> void
|
|
13
|
+
def self?.compare: (GreenNode | GreenToken old_green, GreenNode | GreenToken new_green, Integer offset, Array[TextEdit] edits) -> void
|
|
14
|
+
|
|
15
|
+
# @rbs (GreenNode | GreenToken left, GreenNode | GreenToken right) -> bool
|
|
16
|
+
def self?.compatible_nodes?: (GreenNode | GreenToken left, GreenNode | GreenToken right) -> bool
|
|
17
|
+
|
|
18
|
+
# @rbs (String old_text, String new_text, Integer offset, Array[TextEdit] edits) -> void
|
|
19
|
+
def self?.append_trimmed_edit: (String old_text, String new_text, Integer offset, Array[TextEdit] edits) -> void
|
|
20
|
+
|
|
21
|
+
# @rbs (String left, String right) -> Integer
|
|
22
|
+
def self?.common_prefix: (String left, String right) -> Integer
|
|
23
|
+
|
|
24
|
+
# @rbs (String left, String right, Integer prefix) -> Integer
|
|
25
|
+
def self?.common_suffix: (String left, String right, Integer prefix) -> Integer
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/cst/editing.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
module CST
|
|
6
|
+
# Shared path-copying operations for Red syntax elements.
|
|
7
|
+
module Editing
|
|
8
|
+
type element = SyntaxNode | SyntaxToken
|
|
9
|
+
|
|
10
|
+
type green = GreenNode | GreenToken
|
|
11
|
+
|
|
12
|
+
# @rbs (element target, green | element replacement) -> SyntaxNode
|
|
13
|
+
def self?.replace: (element target, green | element replacement) -> SyntaxNode
|
|
14
|
+
|
|
15
|
+
# @rbs (SyntaxNode previous, GreenNode green) -> SyntaxNode
|
|
16
|
+
def self?.red_root: (SyntaxNode previous, GreenNode green) -> SyntaxNode
|
|
17
|
+
|
|
18
|
+
# @rbs (green | element value) -> green
|
|
19
|
+
def self?.green_element: (green | element value) -> green
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Generated from lib/ibex/runtime/cst/editor.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Runtime
|
|
5
|
+
module CST
|
|
6
|
+
class EditConflictError < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Applies multiple occurrence-addressed replacements in one path-copying pass.
|
|
10
|
+
class SyntaxEditor
|
|
11
|
+
type element = SyntaxNode | SyntaxToken
|
|
12
|
+
|
|
13
|
+
type green = GreenNode | GreenToken
|
|
14
|
+
|
|
15
|
+
type edit = [ element, green ]
|
|
16
|
+
|
|
17
|
+
@root: SyntaxNode
|
|
18
|
+
|
|
19
|
+
@edits: Array[edit]
|
|
20
|
+
|
|
21
|
+
# @rbs (SyntaxNode root) -> void
|
|
22
|
+
def initialize: (SyntaxNode root) -> void
|
|
23
|
+
|
|
24
|
+
# @rbs (element target, green | element replacement) -> self
|
|
25
|
+
def replace: (element target, green | element replacement) -> self
|
|
26
|
+
|
|
27
|
+
# @rbs () -> SyntaxNode
|
|
28
|
+
def apply: () -> SyntaxNode
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @rbs (element element) -> green
|
|
33
|
+
def apply_element: (element element) -> green
|
|
34
|
+
|
|
35
|
+
# @rbs (element possible_ancestor, element element) -> bool
|
|
36
|
+
def ancestor?: (element possible_ancestor, element element) -> bool
|
|
37
|
+
|
|
38
|
+
# @rbs (element left, element right) -> bool
|
|
39
|
+
def same_occurrence?: (element left, element right) -> bool
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|