Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add types to counterexamples #483

Merged
merged 19 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ target :lib do
signature "sig"

check "lib/lrama/grammar"

check "lib/lrama/counterexamples"
check "lib/lrama/lexer"
check "lib/lrama/report"
check "lib/lrama/state"
check "lib/lrama/states"
check "lib/lrama/bitmap.rb"
check "lib/lrama/counterexamples.rb"
check "lib/lrama/digraph.rb"
check "lib/lrama/grammar.rb"
check "lib/lrama/options.rb"
Expand Down
28 changes: 19 additions & 9 deletions lib/lrama/counterexamples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ def compute(conflict_state)
conflict_state.conflicts.flat_map do |conflict|
case conflict.type
when :shift_reduce
# @type var conflict: State::ShiftReduceConflict
shift_reduce_example(conflict_state, conflict)
when :reduce_reduce
# @type var conflict: State::ReduceReduceConflict
reduce_reduce_examples(conflict_state, conflict)
end
end.compact
Expand All @@ -48,7 +50,7 @@ def setup_transitions
@reverse_transitions = {}

@states.states.each do |src_state|
trans = {}
trans = {} #: Hash[Grammar::Symbol, State]

src_state.transitions.each do |shift, next_state|
trans[shift.next_sym] = next_state
Expand All @@ -66,6 +68,7 @@ def setup_transitions

@transitions[[src_state_item, sym]] = dest_state_item

# @type var key: [StateItem, Grammar::Symbol]
key = [dest_state_item, sym]
@reverse_transitions[key] ||= Set.new
@reverse_transitions[key] << src_state_item
Expand All @@ -82,7 +85,7 @@ def setup_productions

@states.states.each do |state|
# LHS => Set(Item)
h = {}
h = {} #: Hash[Grammar::Symbol, Set[States::Item]]

state.closure.each do |item|
sym = item.lhs
Expand All @@ -97,6 +100,7 @@ def setup_productions

sym = item.next_sym
state_item = StateItem.new(state, item)
# @type var key: [State, Grammar::Symbol]
key = [state, sym]

@productions[state_item] = h[sym]
Expand All @@ -109,6 +113,7 @@ def setup_productions

def shift_reduce_example(conflict_state, conflict)
conflict_symbol = conflict.symbols.first
# @type var shift_conflict_item: ::Lrama::States::Item
shift_conflict_item = conflict_state.items.find { |item| item.next_sym == conflict_symbol }
path2 = shortest_path(conflict_state, conflict.reduce.item, conflict_symbol)
path1 = find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item)
Expand Down Expand Up @@ -153,12 +158,14 @@ def find_shift_conflict_shortest_state_items(reduce_path, conflict_state, confli
prev_state_item = prev_path&.to

if target_state_item == state_item || target_state_item.item.start_item?
result.concat(reversed_reduce_path[_j..-1].map(&:to))
result.concat(
reversed_reduce_path[_j..-1] #: Array[StartPath|TransitionPath|ProductionPath]
.map(&:to))
break
end

if target_state_item.item.beginning_of_rule?
queue = []
queue = [] #: Array[Array[StateItem]]
queue << [target_state_item]

# Find reverse production
Expand All @@ -174,15 +181,17 @@ def find_shift_conflict_shortest_state_items(reduce_path, conflict_state, confli
end

if si.item.beginning_of_rule?
# @type var key: [State, Grammar::Symbol]
key = [si.state, si.item.lhs]
@reverse_productions[key].each do |item|
state_item = StateItem.new(si.state, item)
queue << (sis + [state_item])
end
else
# @type var key: [StateItem, Grammar::Symbol]
key = [si, si.item.previous_sym]
@reverse_transitions[key].each do |prev_target_state_item|
next if prev_target_state_item.state != prev_state_item.state
next if prev_target_state_item.state != prev_state_item&.state
sis.shift
result.concat(sis)
result << prev_target_state_item
Expand All @@ -195,9 +204,10 @@ def find_shift_conflict_shortest_state_items(reduce_path, conflict_state, confli
end
else
# Find reverse transition
# @type var key: [StateItem, Grammar::Symbol]
key = [target_state_item, target_state_item.item.previous_sym]
@reverse_transitions[key].each do |prev_target_state_item|
next if prev_target_state_item.state != prev_state_item.state
next if prev_target_state_item.state != prev_state_item&.state
result << prev_target_state_item
target_state_item = prev_target_state_item
i = j
Expand All @@ -224,9 +234,9 @@ def build_paths_from_state_items(state_items)

def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
# queue: is an array of [Triple, [Path]]
queue = []
visited = {}
start_state = @states.states.first
queue = [] #: Array[[Triple, Array[StartPath|TransitionPath|ProductionPath]]]
visited = {} #: Hash[Triple, true]
start_state = @states.states.first #: Lrama::State
raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1

start = Triple.new(start_state, start_state.kernels.first, Set.new([@states.eof_symbol]))
Expand Down
9 changes: 5 additions & 4 deletions lib/lrama/counterexamples/derivation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def to_s
alias :inspect :to_s

def render_strings_for_report
result = []
result = [] #: Array[String]
_render_for_report(self, 0, result, 0)
result.map(&:rstrip)
end
Expand Down Expand Up @@ -51,11 +51,12 @@ def _render_for_report(derivation, offset, strings, index)
end

if derivation.right&.left
length = _render_for_report(derivation.right.left, str.length, strings, index + 1)
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
left = derivation.right&.left #: Derivation
length = _render_for_report(left, str.length, strings, index + 1)
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore
str << " " * (length - str.length) if length > str.length
elsif item.next_next_sym
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore
end

return str.length
Expand Down
11 changes: 7 additions & 4 deletions lib/lrama/counterexamples/example.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ def derivations2
private

def _derivations(paths)
derivation = nil
derivation = nil #: Derivation
current = :production
lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
last_path = paths.last #: Path
lookahead_sym = last_path.to.item.end_of_rule? ? @conflict_symbol : nil

paths.reverse_each do |path|
item = path.to.item
Expand All @@ -57,12 +58,14 @@ def _derivations(paths)
when ProductionPath
derivation = Derivation.new(item, derivation)
current = :production
else
raise "Unexpected. #{path}"
end

if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
state_item = @counterexamples.transitions[[path.to, item.next_sym]]
derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
derivation.right = derivation2
derivation.right = derivation2 # steep:ignore
lookahead_sym = nil
end

Expand All @@ -89,7 +92,7 @@ def _derivations(paths)
end

def find_derivation_for_symbol(state_item, sym)
queue = []
queue = [] #: Array[Array[StateItem]]
queue << [state_item]

while (sis = queue.shift)
Expand Down
4 changes: 4 additions & 0 deletions lib/lrama/counterexamples/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def to_s
"#<Path(#{type})>"
end
alias :inspect :to_s

def type
raise NotImplementedError
end
end
end
end
6 changes: 3 additions & 3 deletions rbs_collection.lock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ gems:
source:
type: git
name: ruby/gem_rbs_collection
revision: f2fa96be08e0f7fe5237a45d2b69d9d7a5d0b416
revision: 71fb7ae83789ae150bdee1cd8a7cd3035b5d79e2
remote: https://github.com/ruby/gem_rbs_collection.git
repo_dir: gems
- name: erb
Expand All @@ -26,15 +26,15 @@ gems:
source:
type: git
name: ruby/gem_rbs_collection
revision: f2fa96be08e0f7fe5237a45d2b69d9d7a5d0b416
revision: 71fb7ae83789ae150bdee1cd8a7cd3035b5d79e2
remote: https://github.com/ruby/gem_rbs_collection.git
repo_dir: gems
- name: stackprof
version: '0.2'
source:
type: git
name: ruby/gem_rbs_collection
revision: f2fa96be08e0f7fe5237a45d2b69d9d7a5d0b416
revision: 71fb7ae83789ae150bdee1cd8a7cd3035b5d79e2
remote: https://github.com/ruby/gem_rbs_collection.git
repo_dir: gems
- name: strscan
Expand Down
29 changes: 29 additions & 0 deletions sig/lrama/counterexamples.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Lrama
class Counterexamples
@states: States
@transitions: Hash[[StateItem, Grammar::Symbol], StateItem]
@reverse_transitions: Hash[[StateItem, Grammar::Symbol], Set[StateItem]]
@productions: Hash[StateItem, Set[States::Item]]
@reverse_productions: Hash[[State, Grammar::Symbol], Set[States::Item]]

attr_reader transitions: Hash[[StateItem, Grammar::Symbol], StateItem]
attr_reader productions: Hash[StateItem, Set[States::Item]]

def initialize: (States states) -> void
def to_s: () -> "#<Counterexamples>"
alias inspect to_s
def compute: (State conflict_state) -> Array[Example]

private

def setup_transitions: () -> void
def setup_productions: () -> void
def shift_reduce_example: (State conflict_state, State::ShiftReduceConflict conflict) -> Example
def reduce_reduce_examples: (State conflict_state, State::ReduceReduceConflict conflict) -> Example
def find_shift_conflict_shortest_path: (::Array[StartPath|TransitionPath|ProductionPath]? reduce_path, State conflict_state, States::Item conflict_item) -> ::Array[StartPath|TransitionPath|ProductionPath]
def find_shift_conflict_shortest_state_items: (::Array[StartPath|TransitionPath|ProductionPath]? reduce_path, State conflict_state, States::Item conflict_item) -> Array[StateItem]
def build_paths_from_state_items: (Array[StateItem] state_items) -> ::Array[StartPath|TransitionPath|ProductionPath]
def shortest_path: (State conflict_state, States::Item conflict_reduce_item, Grammar::Symbol conflict_term) -> ::Array[StartPath|TransitionPath|ProductionPath]?
def follow_l: (States::Item item, Set[Grammar::Symbol] current_l) -> Set[Grammar::Symbol]
end
end
33 changes: 33 additions & 0 deletions sig/lrama/counterexamples/derivation.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Lrama
class Counterexamples
class Derivation
@item: States::Item

@left: Derivation?

@right: Derivation?

attr_reader item: States::Item

attr_reader left: Derivation?

attr_reader right: Derivation?

attr_writer right: Derivation?

def initialize: (States::Item item, Derivation? left, ?Derivation? right) -> void

def to_s: () -> ::String

alias inspect to_s

def render_strings_for_report: () -> Array[String]

def render_for_report: () -> String

private

def _render_for_report: (Derivation derivation, Integer offset, Array[String] strings, Integer index) -> Integer
end
end
end
45 changes: 45 additions & 0 deletions sig/lrama/counterexamples/example.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module Lrama
class Counterexamples
class Example
@path1: ::Array[StartPath | TransitionPath | ProductionPath]

@path2: ::Array[StartPath | TransitionPath | ProductionPath]

@conflict: (State::ShiftReduceConflict | State::ReduceReduceConflict)

@conflict_symbol: Grammar::Symbol

@counterexamples: Counterexamples

@derivations1: Derivation

@derivations2: Derivation

attr_reader path1: ::Array[StartPath | TransitionPath | ProductionPath]

attr_reader path2: ::Array[StartPath | TransitionPath | ProductionPath]

attr_reader conflict: (State::ShiftReduceConflict | State::ReduceReduceConflict)

attr_reader conflict_symbol: Grammar::Symbol

def initialize: (::Array[StartPath | TransitionPath | ProductionPath]? path1, ::Array[StartPath | TransitionPath | ProductionPath]? path2, (State::ShiftReduceConflict | State::ReduceReduceConflict) conflict, Grammar::Symbol conflict_symbol, Counterexamples counterexamples) -> void

def type: () -> (:shift_reduce | :reduce_reduce)

def path1_item: () -> States::Item

def path2_item: () -> States::Item

def derivations1: () -> Derivation

def derivations2: () -> Derivation

private

def _derivations: (::Array[StartPath | TransitionPath | ProductionPath] paths) -> Derivation

def find_derivation_for_symbol: (StateItem state_item, Grammar::Symbol sym) -> Derivation?
end
end
end
21 changes: 21 additions & 0 deletions sig/lrama/counterexamples/path.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Lrama
class Counterexamples
class Path
@from_state_item: StateItem?

@to_state_item: StateItem

def initialize: (StateItem? from_state_item, StateItem to_state_item) -> void

def from: () -> StateItem?

def to: () -> StateItem

def to_s: () -> ::String

alias inspect to_s

def type: -> bot
end
end
end
11 changes: 11 additions & 0 deletions sig/lrama/counterexamples/production_path.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Lrama
class Counterexamples
class ProductionPath < Path
def type: () -> :production

def transition?: () -> false

def production?: () -> true
end
end
end
13 changes: 13 additions & 0 deletions sig/lrama/counterexamples/start_path.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Lrama
class Counterexamples
class StartPath < Path
def initialize: (StateItem to_state_item) -> void

def type: () -> :start

def transition?: () -> false

def production?: () -> false
end
end
end
10 changes: 10 additions & 0 deletions sig/lrama/counterexamples/state_item.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module Lrama
class Counterexamples
class StateItem
attr_accessor state: State
attr_accessor item: States::Item

def initialize: (State state, States::Item item) -> void
end
end
end
Loading
Loading