lrama 0.7.0 → 0.7.1
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 +4 -4
- data/.gitattributes +2 -0
- data/.github/workflows/codespell.yaml +1 -1
- data/.github/workflows/gh-pages.yml +5 -6
- data/.github/workflows/test.yaml +25 -14
- data/Gemfile +4 -3
- data/NEWS.md +370 -35
- data/README.md +7 -88
- data/Rakefile +3 -2
- data/Steepfile +11 -5
- data/doc/Index.md +1 -1
- data/doc/development/compressed_state_table/parser.rb +2 -0
- data/doc/development/profiling.md +44 -0
- data/exe/lrama +1 -1
- data/lib/lrama/bitmap.rb +18 -5
- data/lib/lrama/command.rb +95 -43
- data/lib/lrama/context.rb +22 -24
- data/lib/lrama/counterexamples/derivation.rb +14 -4
- data/lib/lrama/counterexamples/example.rb +47 -22
- data/lib/lrama/counterexamples/node.rb +30 -0
- data/lib/lrama/counterexamples/path.rb +12 -14
- data/lib/lrama/counterexamples/state_item.rb +24 -1
- data/lib/lrama/counterexamples/triple.rb +27 -9
- data/lib/lrama/counterexamples.rb +216 -88
- data/lib/lrama/diagram.rb +77 -0
- data/lib/lrama/digraph.rb +28 -7
- data/lib/lrama/erb.rb +29 -0
- data/lib/lrama/grammar/auxiliary.rb +6 -1
- data/lib/lrama/grammar/binding.rb +37 -25
- data/lib/lrama/grammar/code/destructor_code.rb +11 -0
- data/lib/lrama/grammar/code/initial_action_code.rb +3 -0
- data/lib/lrama/grammar/code/no_reference_code.rb +3 -0
- data/lib/lrama/grammar/code/printer_code.rb +11 -0
- data/lib/lrama/grammar/code/rule_action.rb +17 -0
- data/lib/lrama/grammar/code.rb +16 -1
- data/lib/lrama/grammar/counter.rb +10 -0
- data/lib/lrama/grammar/destructor.rb +14 -1
- data/lib/lrama/grammar/error_token.rb +14 -1
- data/lib/lrama/grammar/inline/resolver.rb +80 -0
- data/lib/lrama/grammar/inline.rb +3 -0
- data/lib/lrama/grammar/{parameterizing_rule → parameterized}/resolver.rb +19 -8
- data/lib/lrama/grammar/{parameterizing_rule → parameterized}/rhs.rb +7 -2
- data/lib/lrama/grammar/parameterized/rule.rb +36 -0
- data/lib/lrama/grammar/parameterized.rb +5 -0
- data/lib/lrama/grammar/percent_code.rb +12 -1
- data/lib/lrama/grammar/precedence.rb +43 -1
- data/lib/lrama/grammar/printer.rb +9 -0
- data/lib/lrama/grammar/reference.rb +13 -0
- data/lib/lrama/grammar/rule.rb +61 -1
- data/lib/lrama/grammar/rule_builder.rb +84 -69
- data/lib/lrama/grammar/stdlib.y +68 -48
- data/lib/lrama/grammar/symbol.rb +63 -19
- data/lib/lrama/grammar/symbols/resolver.rb +64 -3
- data/lib/lrama/grammar/type.rb +13 -1
- data/lib/lrama/grammar/union.rb +12 -1
- data/lib/lrama/grammar.rb +231 -35
- data/lib/lrama/lexer/location.rb +25 -8
- data/lib/lrama/lexer/token/base.rb +73 -0
- data/lib/lrama/lexer/token/char.rb +15 -2
- data/lib/lrama/lexer/token/empty.rb +14 -0
- data/lib/lrama/lexer/token/ident.rb +2 -2
- data/lib/lrama/lexer/token/instantiate_rule.rb +4 -4
- data/lib/lrama/lexer/token/int.rb +14 -0
- data/lib/lrama/lexer/token/str.rb +11 -0
- data/lib/lrama/lexer/token/tag.rb +2 -2
- data/lib/lrama/lexer/token/token.rb +11 -0
- data/lib/lrama/lexer/token/user_code.rb +63 -37
- data/lib/lrama/lexer/token.rb +6 -56
- data/lib/lrama/lexer.rb +51 -23
- data/lib/lrama/logger.rb +12 -2
- data/lib/lrama/option_parser.rb +63 -9
- data/lib/lrama/options.rb +25 -7
- data/lib/lrama/output.rb +4 -11
- data/lib/lrama/parser.rb +854 -723
- data/lib/lrama/reporter/conflicts.rb +44 -0
- data/lib/lrama/reporter/grammar.rb +39 -0
- data/lib/lrama/reporter/precedences.rb +54 -0
- data/lib/lrama/reporter/profile/call_stack.rb +45 -0
- data/lib/lrama/reporter/profile/memory.rb +44 -0
- data/lib/lrama/reporter/profile.rb +4 -0
- data/lib/lrama/reporter/rules.rb +43 -0
- data/lib/lrama/reporter/states.rb +387 -0
- data/lib/lrama/reporter/terms.rb +44 -0
- data/lib/lrama/reporter.rb +39 -0
- data/lib/lrama/state/action/goto.rb +33 -0
- data/lib/lrama/state/action/reduce.rb +71 -0
- data/lib/lrama/state/action/shift.rb +39 -0
- data/lib/lrama/state/action.rb +5 -0
- data/lib/lrama/state/inadequacy_annotation.rb +140 -0
- data/lib/lrama/{states → state}/item.rb +33 -4
- data/lib/lrama/state/reduce_reduce_conflict.rb +14 -1
- data/lib/lrama/state/resolved_conflict.rb +38 -4
- data/lib/lrama/state/shift_reduce_conflict.rb +14 -1
- data/lib/lrama/state.rb +301 -200
- data/lib/lrama/states.rb +447 -175
- data/lib/lrama/tracer/actions.rb +22 -0
- data/lib/lrama/tracer/closure.rb +30 -0
- data/lib/lrama/tracer/duration.rb +38 -0
- data/lib/lrama/tracer/only_explicit_rules.rb +24 -0
- data/lib/lrama/tracer/rules.rb +23 -0
- data/lib/lrama/tracer/state.rb +33 -0
- data/lib/lrama/tracer.rb +51 -0
- data/lib/lrama/version.rb +2 -1
- data/lib/lrama/warnings/conflicts.rb +27 -0
- data/lib/lrama/warnings/implicit_empty.rb +29 -0
- data/lib/lrama/warnings/name_conflicts.rb +63 -0
- data/lib/lrama/warnings/redefined_rules.rb +23 -0
- data/lib/lrama/warnings/required.rb +23 -0
- data/lib/lrama/warnings/useless_precedence.rb +25 -0
- data/lib/lrama/warnings.rb +33 -0
- data/lib/lrama.rb +5 -5
- data/parser.y +495 -404
- data/rbs_collection.lock.yaml +27 -3
- data/rbs_collection.yaml +2 -0
- data/sig/generated/lrama/bitmap.rbs +12 -4
- data/sig/generated/lrama/counterexamples/derivation.rbs +36 -0
- data/sig/generated/lrama/counterexamples/example.rbs +58 -0
- data/sig/generated/lrama/counterexamples/node.rbs +18 -0
- data/sig/generated/lrama/counterexamples/path.rbs +23 -0
- data/sig/generated/lrama/counterexamples/state_item.rbs +19 -0
- data/sig/generated/lrama/counterexamples/triple.rbs +32 -0
- data/sig/generated/lrama/counterexamples.rbs +98 -0
- data/sig/generated/lrama/diagram.rbs +34 -0
- data/sig/generated/lrama/digraph.rbs +26 -6
- data/sig/generated/lrama/erb.rbs +14 -0
- data/sig/generated/lrama/grammar/auxiliary.rbs +16 -0
- data/sig/generated/lrama/grammar/binding.rbs +18 -12
- data/sig/generated/lrama/grammar/code/destructor_code.rbs +26 -0
- data/sig/{lrama → generated/lrama}/grammar/code/initial_action_code.rbs +6 -0
- data/sig/{lrama → generated/lrama}/grammar/code/no_reference_code.rbs +6 -0
- data/sig/generated/lrama/grammar/code/printer_code.rbs +26 -0
- data/sig/generated/lrama/grammar/code/rule_action.rbs +63 -0
- data/sig/generated/lrama/grammar/code.rbs +38 -0
- data/sig/{lrama → generated/lrama}/grammar/counter.rbs +4 -0
- data/sig/generated/lrama/grammar/destructor.rbs +19 -0
- data/sig/generated/lrama/grammar/error_token.rbs +19 -0
- data/sig/generated/lrama/grammar/inline/resolver.rbs +26 -0
- data/sig/generated/lrama/grammar/parameterized/resolver.rbs +42 -0
- data/sig/generated/lrama/grammar/parameterized/rhs.rbs +21 -0
- data/sig/generated/lrama/grammar/parameterized/rule.rbs +28 -0
- data/sig/{lrama → generated/lrama}/grammar/percent_code.rbs +8 -0
- data/sig/generated/lrama/grammar/precedence.rbs +45 -0
- data/sig/{lrama/grammar/error_token.rbs → generated/lrama/grammar/printer.rbs} +8 -3
- data/sig/generated/lrama/grammar/reference.rbs +31 -0
- data/sig/generated/lrama/grammar/rule.rbs +83 -0
- data/sig/generated/lrama/grammar/rule_builder.rbs +91 -0
- data/sig/generated/lrama/grammar/symbol.rbs +89 -0
- data/sig/generated/lrama/grammar/symbols/resolver.rbs +131 -0
- data/sig/generated/lrama/grammar/type.rbs +21 -0
- data/sig/generated/lrama/grammar/union.rbs +17 -0
- data/sig/generated/lrama/grammar.rbs +289 -0
- data/sig/generated/lrama/lexer/location.rbs +12 -3
- data/sig/generated/lrama/lexer/token/base.rbs +53 -0
- data/sig/generated/lrama/lexer/token/char.rbs +9 -2
- data/sig/generated/lrama/lexer/token/empty.rbs +11 -0
- data/sig/generated/lrama/lexer/token/ident.rbs +2 -2
- data/sig/generated/lrama/lexer/token/instantiate_rule.rbs +5 -5
- data/sig/generated/lrama/lexer/token/int.rbs +13 -0
- data/sig/generated/lrama/lexer/token/str.rbs +10 -0
- data/sig/generated/lrama/lexer/token/tag.rbs +2 -2
- data/sig/generated/lrama/lexer/token/token.rbs +10 -0
- data/sig/generated/lrama/lexer/token/user_code.rbs +2 -2
- data/sig/generated/lrama/lexer/token.rbs +1 -39
- data/sig/generated/lrama/lexer.rbs +54 -0
- data/sig/generated/lrama/logger.rbs +6 -0
- data/sig/generated/lrama/option_parser.rbs +52 -0
- data/sig/{lrama → generated/lrama}/options.rbs +27 -3
- data/sig/generated/lrama/reporter/conflicts.rbs +18 -0
- data/sig/generated/lrama/reporter/grammar.rbs +13 -0
- data/sig/generated/lrama/reporter/precedences.rbs +15 -0
- data/sig/generated/lrama/reporter/profile/call_stack.rbs +19 -0
- data/sig/generated/lrama/reporter/profile/memory.rbs +19 -0
- data/sig/generated/lrama/reporter/rules.rbs +13 -0
- data/sig/generated/lrama/reporter/states.rbs +69 -0
- data/sig/generated/lrama/reporter/terms.rbs +13 -0
- data/sig/generated/lrama/reporter.rbs +13 -0
- data/sig/generated/lrama/state/action/goto.rbs +28 -0
- data/sig/generated/lrama/state/action/reduce.rbs +49 -0
- data/sig/generated/lrama/state/action/shift.rbs +33 -0
- data/sig/generated/lrama/state/inadequacy_annotation.rbs +45 -0
- data/sig/generated/lrama/state/item.rbs +75 -0
- data/sig/generated/lrama/state/reduce_reduce_conflict.rbs +19 -0
- data/sig/generated/lrama/state/resolved_conflict.rbs +38 -0
- data/sig/generated/lrama/state/shift_reduce_conflict.rbs +19 -0
- data/sig/generated/lrama/state.rbs +231 -0
- data/sig/generated/lrama/states.rbs +215 -0
- data/sig/generated/lrama/tracer/actions.rbs +13 -0
- data/sig/generated/lrama/tracer/closure.rbs +13 -0
- data/sig/generated/lrama/tracer/duration.rbs +18 -0
- data/sig/generated/lrama/tracer/only_explicit_rules.rbs +13 -0
- data/sig/generated/lrama/tracer/rules.rbs +13 -0
- data/sig/generated/lrama/tracer/state.rbs +16 -0
- data/sig/generated/lrama/tracer.rbs +23 -0
- data/sig/generated/lrama/version.rbs +5 -0
- data/sig/generated/lrama/warnings/conflicts.rbs +13 -0
- data/sig/generated/lrama/warnings/implicit_empty.rbs +17 -0
- data/sig/generated/lrama/warnings/name_conflicts.rbs +31 -0
- data/sig/generated/lrama/warnings/redefined_rules.rbs +13 -0
- data/sig/generated/lrama/warnings/required.rbs +13 -0
- data/sig/generated/lrama/warnings/useless_precedence.rbs +13 -0
- data/sig/generated/lrama/warnings.rbs +11 -0
- data/sig/railroad_diagrams/railroad_diagrams.rbs +16 -0
- data/template/bison/_yacc.h +8 -0
- data/template/diagram/diagram.html +102 -0
- metadata +126 -66
- data/lib/lrama/counterexamples/production_path.rb +0 -19
- data/lib/lrama/counterexamples/start_path.rb +0 -23
- data/lib/lrama/counterexamples/transition_path.rb +0 -19
- data/lib/lrama/diagnostics.rb +0 -36
- data/lib/lrama/grammar/parameterizing_rule/rule.rb +0 -24
- data/lib/lrama/grammar/parameterizing_rule.rb +0 -5
- data/lib/lrama/grammar_validator.rb +0 -37
- data/lib/lrama/report/duration.rb +0 -27
- data/lib/lrama/report/profile.rb +0 -16
- data/lib/lrama/report.rb +0 -4
- data/lib/lrama/state/reduce.rb +0 -37
- data/lib/lrama/state/shift.rb +0 -15
- data/lib/lrama/states_reporter.rb +0 -362
- data/lib/lrama/trace_reporter.rb +0 -45
- data/sig/generated/lrama/trace_reporter.rbs +0 -25
- data/sig/lrama/counterexamples/derivation.rbs +0 -33
- data/sig/lrama/counterexamples/example.rbs +0 -45
- data/sig/lrama/counterexamples/path.rbs +0 -21
- data/sig/lrama/counterexamples/production_path.rbs +0 -11
- data/sig/lrama/counterexamples/start_path.rbs +0 -13
- data/sig/lrama/counterexamples/state_item.rbs +0 -10
- data/sig/lrama/counterexamples/transition_path.rbs +0 -11
- data/sig/lrama/counterexamples/triple.rbs +0 -20
- data/sig/lrama/counterexamples.rbs +0 -29
- data/sig/lrama/grammar/auxiliary.rbs +0 -10
- data/sig/lrama/grammar/code/destructor_code.rbs +0 -14
- data/sig/lrama/grammar/code/printer_code.rbs +0 -14
- data/sig/lrama/grammar/code/rule_action.rbs +0 -19
- data/sig/lrama/grammar/code.rbs +0 -24
- data/sig/lrama/grammar/destructor.rbs +0 -13
- data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +0 -24
- data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +0 -14
- data/sig/lrama/grammar/parameterizing_rule/rule.rbs +0 -16
- data/sig/lrama/grammar/parameterizing_rule.rbs +0 -6
- data/sig/lrama/grammar/precedence.rbs +0 -13
- data/sig/lrama/grammar/printer.rbs +0 -13
- data/sig/lrama/grammar/reference.rbs +0 -22
- data/sig/lrama/grammar/rule.rbs +0 -45
- data/sig/lrama/grammar/rule_builder.rbs +0 -47
- data/sig/lrama/grammar/symbol.rbs +0 -38
- data/sig/lrama/grammar/symbols/resolver.rbs +0 -60
- data/sig/lrama/grammar/type.rbs +0 -11
- data/sig/lrama/grammar/union.rbs +0 -12
- data/sig/lrama/grammar.rbs +0 -108
- data/sig/lrama/report/duration.rbs +0 -11
- data/sig/lrama/report/profile.rbs +0 -7
- data/sig/lrama/state/reduce.rbs +0 -20
- data/sig/lrama/state/reduce_reduce_conflict.rbs +0 -13
- data/sig/lrama/state/resolved_conflict.rbs +0 -14
- data/sig/lrama/state/shift.rbs +0 -14
- data/sig/lrama/state/shift_reduce_conflict.rbs +0 -13
- data/sig/lrama/state.rbs +0 -79
- data/sig/lrama/states/item.rbs +0 -30
- data/sig/lrama/states.rbs +0 -101
- data/sig/lrama/warning.rbs +0 -16
|
@@ -1,29 +1,27 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Lrama
|
|
4
5
|
class Counterexamples
|
|
5
6
|
class Path
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
end
|
|
7
|
+
# @rbs!
|
|
8
|
+
# @state_item: StateItem
|
|
9
|
+
# @parent: Path?
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
11
|
+
attr_reader :state_item #: StateItem
|
|
12
|
+
attr_reader :parent #: Path?
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
# @rbs (StateItem state_item, Path? parent) -> void
|
|
15
|
+
def initialize(state_item, parent)
|
|
16
|
+
@state_item = state_item
|
|
17
|
+
@parent = parent
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
# @rbs () -> ::String
|
|
19
21
|
def to_s
|
|
20
|
-
"#<Path
|
|
22
|
+
"#<Path>"
|
|
21
23
|
end
|
|
22
24
|
alias :inspect :to_s
|
|
23
|
-
|
|
24
|
-
def type
|
|
25
|
-
raise NotImplementedError
|
|
26
|
-
end
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
end
|
|
@@ -1,8 +1,31 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Lrama
|
|
4
5
|
class Counterexamples
|
|
5
|
-
class StateItem
|
|
6
|
+
class StateItem
|
|
7
|
+
attr_reader :id #: Integer
|
|
8
|
+
attr_reader :state #: State
|
|
9
|
+
attr_reader :item #: State::Item
|
|
10
|
+
|
|
11
|
+
# @rbs (Integer id, State state, State::Item item) -> void
|
|
12
|
+
def initialize(id, state, item)
|
|
13
|
+
@id = id
|
|
14
|
+
@state = state
|
|
15
|
+
@item = item
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @rbs () -> (:start | :transition | :production)
|
|
19
|
+
def type
|
|
20
|
+
case
|
|
21
|
+
when item.start_item?
|
|
22
|
+
:start
|
|
23
|
+
when item.beginning_of_rule?
|
|
24
|
+
:production
|
|
25
|
+
else
|
|
26
|
+
:transition
|
|
27
|
+
end
|
|
28
|
+
end
|
|
6
29
|
end
|
|
7
30
|
end
|
|
8
31
|
end
|
|
@@ -1,21 +1,39 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Lrama
|
|
4
5
|
class Counterexamples
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# l: precise lookahead set
|
|
8
|
-
class Triple < Struct.new(:s, :itm, :l)
|
|
9
|
-
alias :state :s
|
|
10
|
-
alias :item :itm
|
|
11
|
-
alias :precise_lookahead_set :l
|
|
6
|
+
class Triple
|
|
7
|
+
attr_reader :precise_lookahead_set #: Bitmap::bitmap
|
|
12
8
|
|
|
9
|
+
alias :l :precise_lookahead_set
|
|
10
|
+
|
|
11
|
+
# @rbs (StateItem state_item, Bitmap::bitmap precise_lookahead_set) -> void
|
|
12
|
+
def initialize(state_item, precise_lookahead_set)
|
|
13
|
+
@state_item = state_item
|
|
14
|
+
@precise_lookahead_set = precise_lookahead_set
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @rbs () -> State
|
|
18
|
+
def state
|
|
19
|
+
@state_item.state
|
|
20
|
+
end
|
|
21
|
+
alias :s :state
|
|
22
|
+
|
|
23
|
+
# @rbs () -> State::Item
|
|
24
|
+
def item
|
|
25
|
+
@state_item.item
|
|
26
|
+
end
|
|
27
|
+
alias :itm :item
|
|
28
|
+
|
|
29
|
+
# @rbs () -> StateItem
|
|
13
30
|
def state_item
|
|
14
|
-
|
|
31
|
+
@state_item
|
|
15
32
|
end
|
|
16
33
|
|
|
34
|
+
# @rbs () -> ::String
|
|
17
35
|
def inspect
|
|
18
|
-
"#{state.inspect}. #{item.display_name}. #{l.
|
|
36
|
+
"#{state.inspect}. #{item.display_name}. #{l.to_s(2)}"
|
|
19
37
|
end
|
|
20
38
|
alias :to_s :inspect
|
|
21
39
|
end
|
|
@@ -1,35 +1,64 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "set"
|
|
5
|
+
require "timeout"
|
|
4
6
|
|
|
5
7
|
require_relative "counterexamples/derivation"
|
|
6
8
|
require_relative "counterexamples/example"
|
|
9
|
+
require_relative "counterexamples/node"
|
|
7
10
|
require_relative "counterexamples/path"
|
|
8
|
-
require_relative "counterexamples/production_path"
|
|
9
|
-
require_relative "counterexamples/start_path"
|
|
10
11
|
require_relative "counterexamples/state_item"
|
|
11
|
-
require_relative "counterexamples/transition_path"
|
|
12
12
|
require_relative "counterexamples/triple"
|
|
13
13
|
|
|
14
14
|
module Lrama
|
|
15
15
|
# See: https://www.cs.cornell.edu/andru/papers/cupex/cupex.pdf
|
|
16
16
|
# 4. Constructing Nonunifying Counterexamples
|
|
17
17
|
class Counterexamples
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
PathSearchTimeLimit = 10 # 10 sec
|
|
19
|
+
CumulativeTimeLimit = 120 # 120 sec
|
|
20
|
+
|
|
21
|
+
# @rbs!
|
|
22
|
+
# @states: States
|
|
23
|
+
# @iterate_count: Integer
|
|
24
|
+
# @total_duration: Float
|
|
25
|
+
# @exceed_cumulative_time_limit: bool
|
|
26
|
+
# @state_items: Hash[[State, State::Item], StateItem]
|
|
27
|
+
# @triples: Hash[Integer, Triple]
|
|
28
|
+
# @transitions: Hash[[StateItem, Grammar::Symbol], StateItem]
|
|
29
|
+
# @reverse_transitions: Hash[[StateItem, Grammar::Symbol], Set[StateItem]]
|
|
30
|
+
# @productions: Hash[StateItem, Set[StateItem]]
|
|
31
|
+
# @reverse_productions: Hash[[State, Grammar::Symbol], Set[StateItem]] # Grammar::Symbol is nterm
|
|
32
|
+
# @state_item_shift: Integer
|
|
33
|
+
|
|
34
|
+
attr_reader :transitions #: Hash[[StateItem, Grammar::Symbol], StateItem]
|
|
35
|
+
attr_reader :productions #: Hash[StateItem, Set[StateItem]]
|
|
36
|
+
|
|
37
|
+
# @rbs (States states) -> void
|
|
20
38
|
def initialize(states)
|
|
21
39
|
@states = states
|
|
40
|
+
@iterate_count = 0
|
|
41
|
+
@total_duration = 0
|
|
42
|
+
@exceed_cumulative_time_limit = false
|
|
43
|
+
@triples = {}
|
|
44
|
+
setup_state_items
|
|
22
45
|
setup_transitions
|
|
23
46
|
setup_productions
|
|
24
47
|
end
|
|
25
48
|
|
|
49
|
+
# @rbs () -> "#<Counterexamples>"
|
|
26
50
|
def to_s
|
|
27
51
|
"#<Counterexamples>"
|
|
28
52
|
end
|
|
29
53
|
alias :inspect :to_s
|
|
30
54
|
|
|
55
|
+
# @rbs (State conflict_state) -> Array[Example]
|
|
31
56
|
def compute(conflict_state)
|
|
32
57
|
conflict_state.conflicts.flat_map do |conflict|
|
|
58
|
+
# Check cumulative time limit for not each path search method call but each conflict
|
|
59
|
+
# to avoid one of example's path to be nil.
|
|
60
|
+
next if @exceed_cumulative_time_limit
|
|
61
|
+
|
|
33
62
|
case conflict.type
|
|
34
63
|
when :shift_reduce
|
|
35
64
|
# @type var conflict: State::ShiftReduceConflict
|
|
@@ -38,22 +67,50 @@ module Lrama
|
|
|
38
67
|
# @type var conflict: State::ReduceReduceConflict
|
|
39
68
|
reduce_reduce_examples(conflict_state, conflict)
|
|
40
69
|
end
|
|
70
|
+
rescue Timeout::Error => e
|
|
71
|
+
STDERR.puts "Counterexamples calculation for state #{conflict_state.id} #{e.message} with #{@iterate_count} iteration"
|
|
72
|
+
increment_total_duration(PathSearchTimeLimit)
|
|
73
|
+
nil
|
|
41
74
|
end.compact
|
|
42
75
|
end
|
|
43
76
|
|
|
44
77
|
private
|
|
45
78
|
|
|
79
|
+
# @rbs (State state, State::Item item) -> StateItem
|
|
80
|
+
def get_state_item(state, item)
|
|
81
|
+
@state_items[[state, item]]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# For optimization, create all StateItem in advance
|
|
85
|
+
# and use them by fetching an instance from `@state_items`.
|
|
86
|
+
# Do not create new StateItem instance in the shortest path search process
|
|
87
|
+
# to avoid miss hash lookup.
|
|
88
|
+
#
|
|
89
|
+
# @rbs () -> void
|
|
90
|
+
def setup_state_items
|
|
91
|
+
@state_items = {}
|
|
92
|
+
count = 0
|
|
93
|
+
|
|
94
|
+
@states.states.each do |state|
|
|
95
|
+
state.items.each do |item|
|
|
96
|
+
@state_items[[state, item]] = StateItem.new(count, state, item)
|
|
97
|
+
count += 1
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
@state_item_shift = Math.log(count, 2).ceil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @rbs () -> void
|
|
46
105
|
def setup_transitions
|
|
47
|
-
# Hash [StateItem, Symbol] => StateItem
|
|
48
106
|
@transitions = {}
|
|
49
|
-
# Hash [StateItem, Symbol] => Set(StateItem)
|
|
50
107
|
@reverse_transitions = {}
|
|
51
108
|
|
|
52
109
|
@states.states.each do |src_state|
|
|
53
110
|
trans = {} #: Hash[Grammar::Symbol, State]
|
|
54
111
|
|
|
55
|
-
src_state.transitions.each do |
|
|
56
|
-
trans[
|
|
112
|
+
src_state.transitions.each do |transition|
|
|
113
|
+
trans[transition.next_sym] = transition.to_state
|
|
57
114
|
end
|
|
58
115
|
|
|
59
116
|
src_state.items.each do |src_item|
|
|
@@ -63,8 +120,8 @@ module Lrama
|
|
|
63
120
|
|
|
64
121
|
dest_state.kernels.each do |dest_item|
|
|
65
122
|
next unless (src_item.rule == dest_item.rule) && (src_item.position + 1 == dest_item.position)
|
|
66
|
-
src_state_item =
|
|
67
|
-
dest_state_item =
|
|
123
|
+
src_state_item = get_state_item(src_state, src_item)
|
|
124
|
+
dest_state_item = get_state_item(dest_state, dest_item)
|
|
68
125
|
|
|
69
126
|
@transitions[[src_state_item, sym]] = dest_state_item
|
|
70
127
|
|
|
@@ -77,21 +134,20 @@ module Lrama
|
|
|
77
134
|
end
|
|
78
135
|
end
|
|
79
136
|
|
|
137
|
+
# @rbs () -> void
|
|
80
138
|
def setup_productions
|
|
81
|
-
# Hash [StateItem] => Set(Item)
|
|
82
139
|
@productions = {}
|
|
83
|
-
# Hash [State, Symbol] => Set(Item). Symbol is nterm
|
|
84
140
|
@reverse_productions = {}
|
|
85
141
|
|
|
86
142
|
@states.states.each do |state|
|
|
87
|
-
#
|
|
88
|
-
h = {} #: Hash[Grammar::Symbol, Set[
|
|
143
|
+
# Grammar::Symbol is LHS
|
|
144
|
+
h = {} #: Hash[Grammar::Symbol, Set[StateItem]]
|
|
89
145
|
|
|
90
146
|
state.closure.each do |item|
|
|
91
147
|
sym = item.lhs
|
|
92
148
|
|
|
93
149
|
h[sym] ||= Set.new
|
|
94
|
-
h[sym] << item
|
|
150
|
+
h[sym] << get_state_item(state, item)
|
|
95
151
|
end
|
|
96
152
|
|
|
97
153
|
state.items.each do |item|
|
|
@@ -99,101 +155,118 @@ module Lrama
|
|
|
99
155
|
next if item.next_sym.term?
|
|
100
156
|
|
|
101
157
|
sym = item.next_sym
|
|
102
|
-
state_item =
|
|
103
|
-
# @type var key: [State, Grammar::Symbol]
|
|
104
|
-
key = [state, sym]
|
|
105
|
-
|
|
158
|
+
state_item = get_state_item(state, item)
|
|
106
159
|
@productions[state_item] = h[sym]
|
|
107
160
|
|
|
161
|
+
# @type var key: [State, Grammar::Symbol]
|
|
162
|
+
key = [state, sym]
|
|
108
163
|
@reverse_productions[key] ||= Set.new
|
|
109
|
-
@reverse_productions[key] <<
|
|
164
|
+
@reverse_productions[key] << state_item
|
|
110
165
|
end
|
|
111
166
|
end
|
|
112
167
|
end
|
|
113
168
|
|
|
169
|
+
# For optimization, use same Triple if it's already created.
|
|
170
|
+
# Do not create new Triple instance anywhere else
|
|
171
|
+
# to avoid miss hash lookup.
|
|
172
|
+
#
|
|
173
|
+
# @rbs (StateItem state_item, Bitmap::bitmap precise_lookahead_set) -> Triple
|
|
174
|
+
def get_triple(state_item, precise_lookahead_set)
|
|
175
|
+
key = (precise_lookahead_set << @state_item_shift) | state_item.id
|
|
176
|
+
@triples[key] ||= Triple.new(state_item, precise_lookahead_set)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# @rbs (State conflict_state, State::ShiftReduceConflict conflict) -> Example
|
|
114
180
|
def shift_reduce_example(conflict_state, conflict)
|
|
115
181
|
conflict_symbol = conflict.symbols.first
|
|
116
|
-
# @type var shift_conflict_item: ::Lrama::
|
|
182
|
+
# @type var shift_conflict_item: ::Lrama::State::Item
|
|
117
183
|
shift_conflict_item = conflict_state.items.find { |item| item.next_sym == conflict_symbol }
|
|
118
|
-
path2 = shortest_path
|
|
119
|
-
|
|
184
|
+
path2 = with_timeout("#shortest_path:") do
|
|
185
|
+
shortest_path(conflict_state, conflict.reduce.item, conflict_symbol)
|
|
186
|
+
end
|
|
187
|
+
path1 = with_timeout("#find_shift_conflict_shortest_path:") do
|
|
188
|
+
find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item)
|
|
189
|
+
end
|
|
120
190
|
|
|
121
191
|
Example.new(path1, path2, conflict, conflict_symbol, self)
|
|
122
192
|
end
|
|
123
193
|
|
|
194
|
+
# @rbs (State conflict_state, State::ReduceReduceConflict conflict) -> Example
|
|
124
195
|
def reduce_reduce_examples(conflict_state, conflict)
|
|
125
196
|
conflict_symbol = conflict.symbols.first
|
|
126
|
-
path1 = shortest_path
|
|
127
|
-
|
|
197
|
+
path1 = with_timeout("#shortest_path:") do
|
|
198
|
+
shortest_path(conflict_state, conflict.reduce1.item, conflict_symbol)
|
|
199
|
+
end
|
|
200
|
+
path2 = with_timeout("#shortest_path:") do
|
|
201
|
+
shortest_path(conflict_state, conflict.reduce2.item, conflict_symbol)
|
|
202
|
+
end
|
|
128
203
|
|
|
129
204
|
Example.new(path1, path2, conflict, conflict_symbol, self)
|
|
130
205
|
end
|
|
131
206
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
207
|
+
# @rbs (Array[StateItem]? reduce_state_items, State conflict_state, State::Item conflict_item) -> Array[StateItem]
|
|
208
|
+
def find_shift_conflict_shortest_path(reduce_state_items, conflict_state, conflict_item)
|
|
209
|
+
time1 = Time.now.to_f
|
|
210
|
+
@iterate_count = 0
|
|
136
211
|
|
|
137
|
-
|
|
138
|
-
target_state_item = StateItem.new(conflict_state, conflict_item)
|
|
212
|
+
target_state_item = get_state_item(conflict_state, conflict_item)
|
|
139
213
|
result = [target_state_item]
|
|
140
|
-
|
|
214
|
+
reversed_state_items = reduce_state_items.to_a.reverse
|
|
141
215
|
# Index for state_item
|
|
142
216
|
i = 0
|
|
143
217
|
|
|
144
|
-
while (
|
|
218
|
+
while (state_item = reversed_state_items[i])
|
|
145
219
|
# Index for prev_state_item
|
|
146
220
|
j = i + 1
|
|
147
221
|
_j = j
|
|
148
222
|
|
|
149
|
-
while (
|
|
150
|
-
if
|
|
223
|
+
while (prev_state_item = reversed_state_items[j])
|
|
224
|
+
if prev_state_item.type == :production
|
|
151
225
|
j += 1
|
|
152
226
|
else
|
|
153
227
|
break
|
|
154
228
|
end
|
|
155
229
|
end
|
|
156
230
|
|
|
157
|
-
state_item = path.to
|
|
158
|
-
prev_state_item = prev_path&.to
|
|
159
|
-
|
|
160
231
|
if target_state_item == state_item || target_state_item.item.start_item?
|
|
161
232
|
result.concat(
|
|
162
|
-
|
|
163
|
-
|
|
233
|
+
reversed_state_items[_j..-1] #: Array[StateItem]
|
|
234
|
+
)
|
|
164
235
|
break
|
|
165
236
|
end
|
|
166
237
|
|
|
167
|
-
if target_state_item.
|
|
168
|
-
queue = [] #: Array[
|
|
169
|
-
queue <<
|
|
238
|
+
if target_state_item.type == :production
|
|
239
|
+
queue = [] #: Array[Node[StateItem]]
|
|
240
|
+
queue << Node.new(target_state_item, nil)
|
|
170
241
|
|
|
171
242
|
# Find reverse production
|
|
172
243
|
while (sis = queue.shift)
|
|
173
|
-
|
|
244
|
+
@iterate_count += 1
|
|
245
|
+
si = sis.elem
|
|
174
246
|
|
|
175
247
|
# Reach to start state
|
|
176
248
|
if si.item.start_item?
|
|
177
|
-
sis.
|
|
178
|
-
|
|
249
|
+
a = Node.to_a(sis).reverse
|
|
250
|
+
a.shift
|
|
251
|
+
result.concat(a)
|
|
179
252
|
target_state_item = si
|
|
180
253
|
break
|
|
181
254
|
end
|
|
182
255
|
|
|
183
|
-
if si.
|
|
256
|
+
if si.type == :production
|
|
184
257
|
# @type var key: [State, Grammar::Symbol]
|
|
185
258
|
key = [si.state, si.item.lhs]
|
|
186
|
-
@reverse_productions[key].each do |
|
|
187
|
-
|
|
188
|
-
queue << (sis + [state_item])
|
|
259
|
+
@reverse_productions[key].each do |state_item|
|
|
260
|
+
queue << Node.new(state_item, sis)
|
|
189
261
|
end
|
|
190
262
|
else
|
|
191
263
|
# @type var key: [StateItem, Grammar::Symbol]
|
|
192
264
|
key = [si, si.item.previous_sym]
|
|
193
265
|
@reverse_transitions[key].each do |prev_target_state_item|
|
|
194
266
|
next if prev_target_state_item.state != prev_state_item&.state
|
|
195
|
-
sis.
|
|
196
|
-
|
|
267
|
+
a = Node.to_a(sis).reverse
|
|
268
|
+
a.shift
|
|
269
|
+
result.concat(a)
|
|
197
270
|
result << prev_target_state_item
|
|
198
271
|
target_state_item = prev_target_state_item
|
|
199
272
|
i = j
|
|
@@ -216,68 +289,106 @@ module Lrama
|
|
|
216
289
|
end
|
|
217
290
|
end
|
|
218
291
|
|
|
292
|
+
time2 = Time.now.to_f
|
|
293
|
+
duration = time2 - time1
|
|
294
|
+
increment_total_duration(duration)
|
|
295
|
+
|
|
296
|
+
if Tracer::Duration.enabled?
|
|
297
|
+
STDERR.puts sprintf(" %s %10.5f s", "find_shift_conflict_shortest_path #{@iterate_count} iteration", duration)
|
|
298
|
+
end
|
|
299
|
+
|
|
219
300
|
result.reverse
|
|
220
301
|
end
|
|
221
302
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
303
|
+
# @rbs (StateItem target) -> Set[StateItem]
|
|
304
|
+
def reachable_state_items(target)
|
|
305
|
+
result = Set.new
|
|
306
|
+
queue = [target]
|
|
307
|
+
|
|
308
|
+
while (state_item = queue.shift)
|
|
309
|
+
next if result.include?(state_item)
|
|
310
|
+
result << state_item
|
|
311
|
+
|
|
312
|
+
@reverse_transitions[[state_item, state_item.item.previous_sym]]&.each do |prev_state_item|
|
|
313
|
+
queue << prev_state_item
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
if state_item.item.beginning_of_rule?
|
|
317
|
+
@reverse_productions[[state_item.state, state_item.item.lhs]]&.each do |si|
|
|
318
|
+
queue << si
|
|
319
|
+
end
|
|
231
320
|
end
|
|
232
321
|
end
|
|
322
|
+
|
|
323
|
+
result
|
|
233
324
|
end
|
|
234
325
|
|
|
326
|
+
# @rbs (State conflict_state, State::Item conflict_reduce_item, Grammar::Symbol conflict_term) -> ::Array[StateItem]?
|
|
235
327
|
def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
|
|
236
|
-
|
|
237
|
-
|
|
328
|
+
time1 = Time.now.to_f
|
|
329
|
+
@iterate_count = 0
|
|
330
|
+
|
|
331
|
+
queue = [] #: Array[[Triple, Path]]
|
|
238
332
|
visited = {} #: Hash[Triple, true]
|
|
239
333
|
start_state = @states.states.first #: Lrama::State
|
|
334
|
+
conflict_term_bit = Bitmap::from_integer(conflict_term.number)
|
|
240
335
|
raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
|
|
336
|
+
reachable = reachable_state_items(get_state_item(conflict_state, conflict_reduce_item))
|
|
337
|
+
start = get_triple(get_state_item(start_state, start_state.kernels.first), Bitmap::from_integer(@states.eof_symbol.number))
|
|
241
338
|
|
|
242
|
-
start
|
|
339
|
+
queue << [start, Path.new(start.state_item, nil)]
|
|
243
340
|
|
|
244
|
-
|
|
341
|
+
while (triple, path = queue.shift)
|
|
342
|
+
@iterate_count += 1
|
|
245
343
|
|
|
246
|
-
|
|
247
|
-
triple
|
|
344
|
+
# Found
|
|
345
|
+
if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
|
|
346
|
+
state_items = [path.state_item]
|
|
248
347
|
|
|
249
|
-
|
|
250
|
-
|
|
348
|
+
while (path = path.parent)
|
|
349
|
+
state_items << path.state_item
|
|
350
|
+
end
|
|
251
351
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
352
|
+
time2 = Time.now.to_f
|
|
353
|
+
duration = time2 - time1
|
|
354
|
+
increment_total_duration(duration)
|
|
355
|
+
|
|
356
|
+
if Tracer::Duration.enabled?
|
|
357
|
+
STDERR.puts sprintf(" %s %10.5f s", "shortest_path #{@iterate_count} iteration", duration)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
return state_items.reverse
|
|
255
361
|
end
|
|
256
362
|
|
|
257
363
|
# transition
|
|
258
|
-
triple.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
364
|
+
next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
|
|
365
|
+
if next_state_item && reachable.include?(next_state_item)
|
|
366
|
+
# @type var t: Triple
|
|
367
|
+
t = get_triple(next_state_item, triple.l)
|
|
368
|
+
unless visited[t]
|
|
369
|
+
visited[t] = true
|
|
370
|
+
queue << [t, Path.new(t.state_item, path)]
|
|
264
371
|
end
|
|
265
372
|
end
|
|
266
373
|
|
|
267
374
|
# production step
|
|
268
|
-
triple.
|
|
269
|
-
next unless
|
|
375
|
+
@productions[triple.state_item]&.each do |si|
|
|
376
|
+
next unless reachable.include?(si)
|
|
377
|
+
|
|
270
378
|
l = follow_l(triple.item, triple.l)
|
|
271
|
-
|
|
272
|
-
|
|
379
|
+
# @type var t: Triple
|
|
380
|
+
t = get_triple(si, l)
|
|
381
|
+
unless visited[t]
|
|
382
|
+
visited[t] = true
|
|
383
|
+
queue << [t, Path.new(t.state_item, path)]
|
|
384
|
+
end
|
|
273
385
|
end
|
|
274
|
-
|
|
275
|
-
break if queue.empty?
|
|
276
386
|
end
|
|
277
387
|
|
|
278
388
|
return nil
|
|
279
389
|
end
|
|
280
390
|
|
|
391
|
+
# @rbs (State::Item item, Bitmap::bitmap current_l) -> Bitmap::bitmap
|
|
281
392
|
def follow_l(item, current_l)
|
|
282
393
|
# 1. follow_L (A -> X1 ... Xn-1 • Xn) = L
|
|
283
394
|
# 2. follow_L (A -> X1 ... Xk • Xk+1 Xk+2 ... Xn) = {Xk+2} if Xk+2 is a terminal
|
|
@@ -287,11 +398,28 @@ module Lrama
|
|
|
287
398
|
when item.number_of_rest_symbols == 1
|
|
288
399
|
current_l
|
|
289
400
|
when item.next_next_sym.term?
|
|
290
|
-
|
|
401
|
+
item.next_next_sym.number_bitmap
|
|
291
402
|
when !item.next_next_sym.nullable
|
|
292
|
-
item.next_next_sym.
|
|
403
|
+
item.next_next_sym.first_set_bitmap
|
|
293
404
|
else
|
|
294
|
-
item.next_next_sym.
|
|
405
|
+
item.next_next_sym.first_set_bitmap | follow_l(item.new_by_next_position, current_l)
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# @rbs [T] (String message) { -> T } -> T
|
|
410
|
+
def with_timeout(message)
|
|
411
|
+
Timeout.timeout(PathSearchTimeLimit, Timeout::Error, message + " timeout of #{PathSearchTimeLimit} sec exceeded") do
|
|
412
|
+
yield
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# @rbs (Float|Integer duration) -> void
|
|
417
|
+
def increment_total_duration(duration)
|
|
418
|
+
@total_duration += duration
|
|
419
|
+
|
|
420
|
+
if !@exceed_cumulative_time_limit && @total_duration > CumulativeTimeLimit
|
|
421
|
+
@exceed_cumulative_time_limit = true
|
|
422
|
+
STDERR.puts "CumulativeTimeLimit #{CumulativeTimeLimit} sec exceeded then skip following Counterexamples calculation"
|
|
295
423
|
end
|
|
296
424
|
end
|
|
297
425
|
end
|