lrama 0.5.3 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32eaf486545ca4143a227a34cee2bfdb94928e002a85fcb2e098dba3dedb71c7
4
- data.tar.gz: b80a7402d9f6caf9f0e8b5396e4bd6b80d84487a35c8cd4b4d711e51ffb56601
3
+ metadata.gz: d79363afacc07dac12ab5c1a861123e099626591104079c962e02f3df74a24f3
4
+ data.tar.gz: d8ddf78087e27510ab9da808301505a10ec0151ef55d1df3a59cc80ffde81b53
5
5
  SHA512:
6
- metadata.gz: 1d118074af8984d85e27485a0c9fb2f8c7eab9a55b771ea3eff17e26d84fe56316404f6316ba5a9c83e61591c83ff9048c6625a904529aa686417f6f295499d9
7
- data.tar.gz: e3591cc5f70e6fe8a04af5070a7b5d6ee60e98718c4c6dc6db1fbef2b3be9f5239155da91bb51ba10611b5017925f1bf71aa1259fd5550b5af6d0ba458e2ab96
6
+ metadata.gz: acc15bb56862ea03c6b195253ba881786acf498719f930b8a8435a60f86b44d4383778cc215e7497971833c4be596a9c41a6c5134f77703a9f5cd0a6b5714ad2
7
+ data.tar.gz: d45b2ec3a22ce2e29beb6a5ec0f4d7b142cebca3b6ca76786fa19b841c257d3841d5a7a43d7d564459b8f9c5b05faa7229bd9b2e2178592ec3988b64f77b535c
@@ -22,6 +22,29 @@ jobs:
22
22
  bundler-cache: true
23
23
  - run: bundle install
24
24
  - run: bundle exec rspec
25
+ test-windows:
26
+ runs-on: windows-2022
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ ruby: ['head']
31
+ steps:
32
+ - uses: actions/checkout@v3
33
+ - uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: ${{ matrix.ruby }}
36
+ bundler-cache: true
37
+ - run: bundle install
38
+ - run: bundle exec rspec
39
+ check-misc:
40
+ runs-on: ubuntu-20.04
41
+ steps:
42
+ - uses: actions/checkout@v3
43
+ # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
44
+ - name: Check for trailing spaces
45
+ run: |
46
+ git grep -I -n '[ ]$' -- '*.rb' '*.[chy]' '*.rs' && exit 1 || :
47
+ git grep -n '^[ ][ ]*$' -- '*.md' && exit 1 || :
25
48
  steep-check:
26
49
  runs-on: ubuntu-20.04
27
50
  strategy:
@@ -58,7 +81,7 @@ jobs:
58
81
  - run: mkdir -p tool/lrama
59
82
  working-directory: ../ruby
60
83
  - name: Copy Lrama to ruby/tool
61
- run: cp -r exe lib template ../ruby/tool/lrama
84
+ run: cp -r LEGAL.md MIT exe lib template ../ruby/tool/lrama
62
85
  working-directory:
63
86
  - run: tree tool/lrama
64
87
  working-directory: ../ruby
data/Gemfile CHANGED
@@ -4,8 +4,9 @@ gemspec
4
4
 
5
5
  gem "rspec"
6
6
  gem "pry"
7
- gem "stackprof"
7
+ # stackprof doesn't support Windows
8
+ gem "stackprof", platforms: [:ruby]
8
9
  gem "rake"
9
10
  gem "rbs", require: false
10
11
  gem "steep", require: false
11
- gem "simplecov", require: false
12
+ gem "simplecov", require: false
data/README.md CHANGED
@@ -49,10 +49,20 @@ Enter the formula:
49
49
 
50
50
  ## Versions and Branches
51
51
 
52
+ ### v0_5 (`master` branch)
53
+
54
+ This branch is for Ruby 3.3. `lrama_0_5` branch is created from this branch, once Ruby 3.3 is released.
55
+
52
56
  ### v0_4 (`lrama_0_4` branch)
53
57
 
54
58
  This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3.2. The first version migrated to ruby is ["0.4.0"](https://github.com/ruby/ruby/pull/7798) therefore keep this branch for Bison compatible branch.
55
59
 
60
+ ## Supported Ruby version
61
+
62
+ Lrama is executed with BASERUBY when building ruby from source code. Therefore Lrama needs to support BASERUBY, currently 2.5, or later version.
63
+
64
+ This also requires Lrama to be able to run with only default gems and bundled gems.
65
+
56
66
  ## Build Ruby
57
67
 
58
68
  1. Install Lrama
@@ -62,7 +72,7 @@ This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3
62
72
 
63
73
  1. Update `Lrama::VERSION`
64
74
  2. Release as a gem by `rake release`
65
- 3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib ruby/tool/lrama`
75
+ 3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib template ruby/tool/lrama`
66
76
  4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
67
77
 
68
78
  ## License
data/doc/TODO.md CHANGED
@@ -44,10 +44,14 @@
44
44
  * Reporting
45
45
  * [ ] Bison style
46
46
  * [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
47
+ * Counterexamples
48
+ * [x] Nonunifying Counterexamples
49
+ * [ ] Unifying Counterexamples
50
+ * [ ] Performance improvement using reverse_transitions and reverse_productions
47
51
  * Error Tolerance
48
52
  * [x] Corchuelo et al. algorithm with N = 1 (this means the next token when error is raised)
49
53
  * [x] Add new decl for error token semantic value initialization (%error-token)
50
- * [ ] Use YYMALLOC & YYFREE
54
+ * [x] Use YYMALLOC & YYFREE
51
55
  * Lex state
52
56
  * CI
53
57
  * [x] Setup CI
data/exe/lrama CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
-
4
3
  $LOAD_PATH << File.join(__dir__, "../lib")
5
4
  require "lrama"
6
5
 
data/lib/lrama/command.rb CHANGED
@@ -5,7 +5,6 @@ module Lrama
5
5
  def initialize(argv)
6
6
  @argv = argv
7
7
 
8
- @version = nil
9
8
  @skeleton = "bison/yacc.c"
10
9
  @header = false
11
10
  @header_file = nil
@@ -23,15 +22,11 @@ module Lrama
23
22
  def run
24
23
  parse_option
25
24
 
26
- if @version
27
- puts Lrama::VERSION
28
- exit 0
29
- end
30
-
31
25
  Report::Duration.enable if @trace_opts[:time]
32
26
 
33
27
  warning = Lrama::Warning.new
34
28
  grammar = Lrama::Parser.new(@y.read).parse
29
+ @y.close if @y != STDIN
35
30
  states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
36
31
  states.compute
37
32
  context = Lrama::Context.new(states)
@@ -67,7 +62,7 @@ module Lrama
67
62
  bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
68
63
  others = %w[verbose]
69
64
  list = bison_list + others
70
- not_supported = %w[counterexamples cex none]
65
+ not_supported = %w[cex none]
71
66
  h = { grammar: true }
72
67
 
73
68
  report.each do |r|
@@ -112,7 +107,7 @@ module Lrama
112
107
  opt = OptionParser.new
113
108
 
114
109
  # opt.on('-h') {|v| p v }
115
- opt.on('-V', '--version') {|v| @version = true }
110
+ opt.on('-V', '--version') {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
116
111
 
117
112
  # Tuning the Parser
118
113
  opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
@@ -121,13 +116,13 @@ module Lrama
121
116
  # Output Files:
122
117
  opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
123
118
  opt.on('-d') { @header = true }
124
- opt.on('-r', '--report=THINGS') {|v| @report = v.split(',') }
119
+ opt.on('-r', '--report=THINGS', Array) {|v| @report = v }
125
120
  opt.on('--report-file=FILE') {|v| @report_file = v }
126
121
  opt.on('-v') { } # Do nothing
127
122
  opt.on('-o', '--output=FILE') {|v| @outfile = v }
128
123
 
129
124
  # Hidden
130
- opt.on('--trace=THINGS') {|v| @trace = v.split(',') }
125
+ opt.on('--trace=THINGS', Array) {|v| @trace = v }
131
126
 
132
127
  # Error Recovery
133
128
  opt.on('-e') {|v| @error_recovery = true }
data/lib/lrama/context.rb CHANGED
@@ -401,7 +401,6 @@ module Lrama
401
401
  end
402
402
  print sprintf("]\n\n")
403
403
 
404
-
405
404
  print sprintf("width [\n")
406
405
  vectors_count.times do |i|
407
406
  print sprintf("%d, ", ary[i] ? ary[i][3] : 0)
@@ -409,7 +408,6 @@ module Lrama
409
408
  end
410
409
  print sprintf("]\n\n")
411
410
 
412
-
413
411
  print sprintf("tally [\n")
414
412
  vectors_count.times do |i|
415
413
  print sprintf("%d, ", ary[i] ? ary[i][2] : 0)
@@ -0,0 +1,63 @@
1
+ module Lrama
2
+ class Counterexamples
3
+ class Derivation
4
+ attr_reader :item, :left, :right
5
+ attr_writer :right
6
+
7
+ def initialize(item, left, right = nil)
8
+ @item = item
9
+ @left = left
10
+ @right = right
11
+ end
12
+
13
+ def to_s
14
+ "#<Derivation(#{item.display_name})>"
15
+ end
16
+ alias :inspect :to_s
17
+
18
+ def render_strings_for_report
19
+ result = []
20
+ _render_for_report(self, 0, result, 0)
21
+ result.map(&:rstrip)
22
+ end
23
+
24
+ def render_for_report
25
+ render_strings_for_report.join("\n")
26
+ end
27
+
28
+ private
29
+
30
+ def _render_for_report(derivation, offset, strings, index)
31
+ item = derivation.item
32
+ if strings[index]
33
+ strings[index] << " " * (offset - strings[index].length)
34
+ else
35
+ strings[index] = " " * offset
36
+ end
37
+ str = strings[index]
38
+ str << "#{item.rule_id}: #{item.symbols_before_dot.map(&:display_name).join(" ")} "
39
+
40
+ if derivation.left
41
+ len = str.length
42
+ str << "#{item.next_sym.display_name}"
43
+ length = _render_for_report(derivation.left, len, strings, index + 1)
44
+ # I want String#ljust!
45
+ str << " " * (length - str.length)
46
+ else
47
+ str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} "
48
+ return str.length
49
+ end
50
+
51
+ if derivation.right&.left
52
+ length = _render_for_report(derivation.right.left, str.length, strings, index + 1)
53
+ str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
54
+ str << " " * (length - str.length) if length > str.length
55
+ elsif item.next_next_sym
56
+ str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
57
+ end
58
+
59
+ return str.length
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,124 @@
1
+ module Lrama
2
+ class Counterexamples
3
+ class Example
4
+ attr_reader :path1, :path2, :conflict, :conflict_symbol
5
+
6
+ # path1 is shift conflict when S/R conflict
7
+ # path2 is always reduce conflict
8
+ def initialize(path1, path2, conflict, conflict_symbol, counterexamples)
9
+ @path1 = path1
10
+ @path2 = path2
11
+ @conflict = conflict
12
+ @conflict_symbol = conflict_symbol
13
+ @counterexamples = counterexamples
14
+ end
15
+
16
+ def type
17
+ @conflict.type
18
+ end
19
+
20
+ def path1_item
21
+ @path1.last.to.item
22
+ end
23
+
24
+ def path2_item
25
+ @path2.last.to.item
26
+ end
27
+
28
+ def derivations1
29
+ @derivations1 ||= _derivations(path1)
30
+ end
31
+
32
+ def derivations2
33
+ @derivations2 ||= _derivations(path2)
34
+ end
35
+
36
+ private
37
+
38
+ def _derivations(paths)
39
+ derivation = nil
40
+ current = :production
41
+ lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
42
+
43
+ paths.reverse.each do |path|
44
+ item = path.to.item
45
+
46
+ case current
47
+ when :production
48
+ case path
49
+ when StartPath
50
+ derivation = Derivation.new(item, derivation)
51
+ current = :start
52
+ when TransitionPath
53
+ derivation = Derivation.new(item, derivation)
54
+ current = :transition
55
+ when ProductionPath
56
+ derivation = Derivation.new(item, derivation)
57
+ current = :production
58
+ end
59
+
60
+ if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
61
+ state_item = @counterexamples.transitions[[path.to, item.next_sym]]
62
+ derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
63
+ derivation.right = derivation2
64
+ lookahead_sym = nil
65
+ end
66
+
67
+ when :transition
68
+ case path
69
+ when StartPath
70
+ derivation = Derivation.new(item, derivation)
71
+ current = :start
72
+ when TransitionPath
73
+ # ignore
74
+ current = :transition
75
+ when ProductionPath
76
+ # ignore
77
+ current = :production
78
+ end
79
+ else
80
+ raise "BUG: Unknown #{current}"
81
+ end
82
+
83
+ break if current == :start
84
+ end
85
+
86
+ derivation
87
+ end
88
+
89
+ def find_derivation_for_symbol(state_item, sym)
90
+ queue = []
91
+ queue << [state_item]
92
+
93
+ while (sis = queue.shift)
94
+ si = sis.last
95
+ next_sym = si.item.next_sym
96
+
97
+ if next_sym == sym
98
+ derivation = nil
99
+
100
+ sis.reverse.each do |si|
101
+ derivation = Derivation.new(si.item, derivation)
102
+ end
103
+
104
+ return derivation
105
+ end
106
+
107
+ if next_sym.nterm? && next_sym.first_set.include?(sym)
108
+ @counterexamples.productions[si].each do |next_item|
109
+ next if next_item.empty_rule?
110
+ next_si = StateItem.new(si.state, next_item)
111
+ next if sis.include?(next_si)
112
+ queue << (sis + [next_si])
113
+ end
114
+
115
+ if next_sym.nullable
116
+ next_si = @counterexamples.transitions[[si, next_sym]]
117
+ queue << (sis + [next_si])
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,69 @@
1
+ module Lrama
2
+ class Counterexamples
3
+ class Path
4
+ def initialize(from_state_item, to_state_item)
5
+ @from_state_item = from_state_item
6
+ @to_state_item = to_state_item
7
+ end
8
+
9
+ def from
10
+ @from_state_item
11
+ end
12
+
13
+ def to
14
+ @to_state_item
15
+ end
16
+
17
+ def to_s
18
+ "#<Path(#{type})>"
19
+ end
20
+ alias :inspect :to_s
21
+ end
22
+
23
+ class StartPath < Path
24
+ def initialize(to_state_item)
25
+ super nil, to_state_item
26
+ end
27
+
28
+ def type
29
+ :start
30
+ end
31
+
32
+ def transition?
33
+ false
34
+ end
35
+
36
+ def production?
37
+ false
38
+ end
39
+ end
40
+
41
+ class TransitionPath < Path
42
+ def type
43
+ :transition
44
+ end
45
+
46
+ def transition?
47
+ true
48
+ end
49
+
50
+ def production?
51
+ false
52
+ end
53
+ end
54
+
55
+ class ProductionPath < Path
56
+ def type
57
+ :production
58
+ end
59
+
60
+ def transition?
61
+ false
62
+ end
63
+
64
+ def production?
65
+ true
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,6 @@
1
+ module Lrama
2
+ class Counterexamples
3
+ class StateItem < Struct.new(:state, :item)
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ module Lrama
2
+ class Counterexamples
3
+ # s: state
4
+ # itm: item within s
5
+ # l: precise lookahead set
6
+ class Triple < Struct.new(:s, :itm, :l)
7
+ alias :state :s
8
+ alias :item :itm
9
+ alias :precise_lookahead_set :l
10
+
11
+ def state_item
12
+ StateItem.new(state, item)
13
+ end
14
+
15
+ def inspect
16
+ "#{state.inspect}. #{item.display_name}. #{l.map(&:id).map(&:s_value)}"
17
+ end
18
+ alias :to_s :inspect
19
+ end
20
+ end
21
+ end