lrama 0.6.0 → 0.6.2

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +27 -7
  3. data/Gemfile +1 -1
  4. data/NEWS.md +55 -0
  5. data/Steepfile +2 -3
  6. data/lib/lrama/command.rb +25 -3
  7. data/lib/lrama/context.rb +3 -23
  8. data/lib/lrama/counterexamples/example.rb +2 -2
  9. data/lib/lrama/grammar/binding.rb +24 -0
  10. data/lib/lrama/grammar/code/rule_action.rb +1 -1
  11. data/lib/lrama/grammar/code.rb +1 -1
  12. data/lib/lrama/grammar/parameterizing_rule/resolver.rb +47 -0
  13. data/lib/lrama/grammar/parameterizing_rule/rhs.rb +15 -0
  14. data/lib/lrama/grammar/parameterizing_rule/rule.rb +16 -0
  15. data/lib/lrama/grammar/parameterizing_rule.rb +3 -6
  16. data/lib/lrama/grammar/percent_code.rb +3 -3
  17. data/lib/lrama/grammar/rule.rb +2 -2
  18. data/lib/lrama/grammar/rule_builder.rb +60 -31
  19. data/lib/lrama/grammar/stdlib.y +80 -0
  20. data/lib/lrama/grammar/type.rb +13 -1
  21. data/lib/lrama/grammar.rb +18 -11
  22. data/lib/lrama/lexer/grammar_file.rb +1 -1
  23. data/lib/lrama/lexer/token/instantiate_rule.rb +7 -2
  24. data/lib/lrama/lexer/token.rb +5 -0
  25. data/lib/lrama/lexer.rb +3 -7
  26. data/lib/lrama/output.rb +2 -2
  27. data/lib/lrama/parser.rb +508 -467
  28. data/lib/lrama/states/item.rb +17 -13
  29. data/lib/lrama/states_reporter.rb +8 -10
  30. data/lib/lrama/version.rb +1 -1
  31. data/parser.y +12 -13
  32. data/sig/lrama/grammar/binding.rbs +16 -0
  33. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +22 -0
  34. data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +13 -0
  35. data/sig/lrama/grammar/parameterizing_rule/rule.rbs +14 -0
  36. data/sig/lrama/grammar/parameterizing_rule.rbs +0 -4
  37. data/sig/lrama/grammar/percent_code.rbs +3 -3
  38. data/sig/lrama/grammar/rule_builder.rbs +9 -6
  39. data/sig/lrama/lexer/token/instantiate_rule.rbs +4 -2
  40. data/sig/lrama/lexer/token.rbs +1 -0
  41. metadata +12 -23
  42. data/lib/lrama/grammar/parameterizing_rule_builder.rb +0 -34
  43. data/lib/lrama/grammar/parameterizing_rule_resolver.rb +0 -30
  44. data/lib/lrama/grammar/parameterizing_rule_rhs_builder.rb +0 -53
  45. data/lib/lrama/grammar/parameterizing_rules/builder/base.rb +0 -36
  46. data/lib/lrama/grammar/parameterizing_rules/builder/list.rb +0 -28
  47. data/lib/lrama/grammar/parameterizing_rules/builder/nonempty_list.rb +0 -28
  48. data/lib/lrama/grammar/parameterizing_rules/builder/option.rb +0 -28
  49. data/lib/lrama/grammar/parameterizing_rules/builder/separated_list.rb +0 -39
  50. data/lib/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rb +0 -34
  51. data/lib/lrama/grammar/parameterizing_rules/builder.rb +0 -60
  52. data/sig/lrama/grammar/parameterizing_rule_builder.rbs +0 -19
  53. data/sig/lrama/grammar/parameterizing_rule_resolver.rbs +0 -16
  54. data/sig/lrama/grammar/parameterizing_rule_rhs_builder.rbs +0 -18
  55. data/sig/lrama/grammar/parameterizing_rules/builder/base.rbs +0 -28
  56. data/sig/lrama/grammar/parameterizing_rules/builder/list.rbs +0 -10
  57. data/sig/lrama/grammar/parameterizing_rules/builder/nonempty_list.rbs +0 -10
  58. data/sig/lrama/grammar/parameterizing_rules/builder/option.rbs +0 -10
  59. data/sig/lrama/grammar/parameterizing_rules/builder/separated_list.rbs +0 -13
  60. data/sig/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rbs +0 -13
  61. data/sig/lrama/grammar/parameterizing_rules/builder.rbs +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b1a3e3181fc7060235e167ea97a92809b31aa5b74ef5978ab70415252bb87e3
4
- data.tar.gz: 51a6ee0620321936fcd9d81c44ece3f9e444b977dc8fa940ddf920a5bb3b1dad
3
+ metadata.gz: e4158de45c42ff62eacfb00737261feaa49d8f0cc646004e30da74ba4e2e69c6
4
+ data.tar.gz: 734830227f701e18df2e9e8bc3da55d15f49c890e08530e6ac55ef87ae5f952d
5
5
  SHA512:
6
- metadata.gz: f2b8805ad79cc0c3f125eba2715d274387191e6a355910d11c88f918eae4906b9398444162210c7ce955b1ba3f67cabf3b0679569a65d63bdc52328f2d7dc2f7
7
- data.tar.gz: 93de8cc0c7f9154f37825d59010a4850cc81b8a66f460d70f95aed44c0eb1224e583d1afb95155be2d9ae063d286a4fa719c133c993c6ec9bfba1c490dfc997b
6
+ metadata.gz: 52ebbe4d099ae63d73aa995bddc8e966f989a4d00ad3b39634d2abe2448da404dd9bff8f15e0dedd0577716089329c804ef2c4edcadd39ca6ba47f8d293d101d
7
+ data.tar.gz: 72e91c79618071b5850c85335cfe3f1b63ff89f11cd332b0141623a4e2a7e2c2c389dd0db9afe38a5a84b7aa891ac1834fc7a2d6c6eed8f62d87734f6b99cbbf
@@ -8,12 +8,19 @@ permissions:
8
8
  contents: read
9
9
 
10
10
  jobs:
11
+ ruby-versions:
12
+ uses: ruby/actions/.github/workflows/ruby_versions.yml@master
13
+ with:
14
+ engine: cruby
15
+ min_version: 2.5
16
+
11
17
  test:
18
+ needs: ruby-versions
12
19
  runs-on: ubuntu-20.04
13
20
  strategy:
14
21
  fail-fast: false
15
22
  matrix:
16
- ruby: ['head', '3.3', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5']
23
+ ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
17
24
  steps:
18
25
  - uses: actions/checkout@v4
19
26
  - uses: ruby/setup-ruby@v1
@@ -29,14 +36,22 @@ jobs:
29
36
  fail-fast: false
30
37
  matrix:
31
38
  ruby: ['head']
39
+ defaults:
40
+ run:
41
+ shell: msys2 {0}
32
42
  steps:
33
43
  - uses: actions/checkout@v4
34
44
  - uses: ruby/setup-ruby@v1
35
45
  with:
36
46
  ruby-version: ${{ matrix.ruby }}
37
47
  bundler-cache: true
38
- - run: choco install winflexbison || choco install winflexbison
39
- - run: win_flex --help
48
+ - uses: msys2/setup-msys2@v2
49
+ id: setup-msys2
50
+ with:
51
+ update: true
52
+ install: >-
53
+ flex
54
+ - run: flex --help
40
55
  - run: bundle install
41
56
  - run: bundle exec rspec
42
57
  test-memory:
@@ -72,6 +87,11 @@ jobs:
72
87
  bundler-cache: true
73
88
  - run: bundle install
74
89
 
90
+ # Copy from https://github.com/ruby/ruby/blob/cb9a47f2acd6e373ef868b890a9d07da6f565dd4/.github/workflows/check_misc.yml#L31
91
+ - name: Check if C-sources are US-ASCII
92
+ run: |
93
+ grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
94
+
75
95
  # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
76
96
  - name: Check for trailing spaces
77
97
  run: |
@@ -105,8 +125,8 @@ jobs:
105
125
  fail-fast: false
106
126
  matrix:
107
127
  # '3.0' is the oldest living ruby version
108
- # '2.5' is for BASERUBY
109
- baseruby: ['head', '3.0', '2.5']
128
+ # '2.7' is for BASERUBY
129
+ baseruby: ['head', '3.0', '2.7']
110
130
  ruby_branch: ['master']
111
131
  defaults:
112
132
  run:
@@ -118,12 +138,12 @@ jobs:
118
138
  ruby-version: ${{ matrix.baseruby }}
119
139
  bundler-cache: true
120
140
  - run: git clone --depth=1 https://github.com/ruby/ruby.git -b ${{ matrix.ruby_branch }} ../ruby
121
- working-directory:
141
+ working-directory: .
122
142
  - run: mkdir -p tool/lrama
123
143
  working-directory: ../ruby
124
144
  - name: Copy Lrama to ruby/tool
125
145
  run: cp -r LEGAL.md NEWS.md MIT exe lib template ../ruby/tool/lrama
126
- working-directory:
146
+ working-directory: .
127
147
  - run: tree tool/lrama
128
148
  working-directory: ../ruby
129
149
  # See also https://github.com/ruby/ruby/blob/master/.github/workflows/ubuntu.yml
data/Gemfile CHANGED
@@ -12,6 +12,6 @@ gem "stackprof", platforms: [:ruby] # stackprof doesn't support Windows
12
12
  # Recent steep requires Ruby >= 3.0.0.
13
13
  # Then skip install on some CI jobs.
14
14
  if !ENV['GITHUB_ACTION'] || ENV['INSTALL_STEEP'] == 'true'
15
- gem "rbs", "3.4.0", require: false
15
+ gem "rbs", "3.4.1", require: false
16
16
  gem "steep", "1.6.0", require: false
17
17
  end
data/NEWS.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # NEWS for Lrama
2
2
 
3
+ ## Lrama 0.6.2 (2024-01-27)
4
+
5
+ ### %no-stdlib directive
6
+
7
+ If `%no-stdlib` directive is set, Lrama doesn't load Lrama standard library for
8
+ parameterizing rules, stdlib.y.
9
+
10
+ https://github.com/ruby/lrama/pull/344
11
+
12
+ ## Lrama 0.6.1 (2024-01-13)
13
+
14
+ ### Nested parameterizing rules
15
+
16
+ Allow to pass an instantiated rule to other parameterizing rules.
17
+
18
+ ```
19
+ %rule constant(X) : X
20
+ ;
21
+
22
+ %rule option(Y) : /* empty */
23
+ | Y
24
+ ;
25
+
26
+ %%
27
+
28
+ program : option(constant(number)) // Nested rule
29
+ ;
30
+ %%
31
+ ```
32
+
33
+ Allow to use nested parameterizing rules when define parameterizing rules.
34
+
35
+ ```
36
+ %rule option(x) : /* empty */
37
+ | X
38
+ ;
39
+
40
+ %rule double(Y) : Y Y
41
+ ;
42
+
43
+ %rule double_opt(A) : option(double(A)) // Nested rule
44
+ ;
45
+
46
+ %%
47
+
48
+ program : double_opt(number)
49
+ ;
50
+
51
+ %%
52
+ ```
53
+
54
+ https://github.com/ruby/lrama/pull/337
55
+
3
56
  ## Lrama 0.6.0 (2023-12-25)
4
57
 
5
58
  ### User defined parameterizing rules
@@ -20,6 +73,8 @@ stmt: pair(ODD, EVEN) <num>
20
73
  ;
21
74
  ```
22
75
 
76
+ https://github.com/ruby/lrama/pull/285
77
+
23
78
  ## Lrama 0.5.11 (2023-12-02)
24
79
 
25
80
  ### Type specification of parameterizing rules
data/Steepfile CHANGED
@@ -4,13 +4,12 @@ target :lib do
4
4
  repo_path '.gem_rbs_collection/'
5
5
  signature "sig"
6
6
 
7
+ check "lib/lrama/grammar/binding.rb"
7
8
  check "lib/lrama/grammar/code/printer_code.rb"
8
9
  check "lib/lrama/grammar/code.rb"
9
10
  check "lib/lrama/grammar/counter.rb"
10
11
  check "lib/lrama/grammar/error_token.rb"
11
- check "lib/lrama/grammar/parameterizing_rule_builder.rb"
12
- check "lib/lrama/grammar/parameterizing_rule_resolver.rb"
13
- check "lib/lrama/grammar/parameterizing_rule_rhs_builder.rb"
12
+ check "lib/lrama/grammar/parameterizing_rule"
14
13
  check "lib/lrama/grammar/parameterizing_rules"
15
14
  check "lib/lrama/grammar/percent_code.rb"
16
15
  check "lib/lrama/grammar/precedence.rb"
data/lib/lrama/command.rb CHANGED
@@ -1,14 +1,36 @@
1
1
  module Lrama
2
2
  class Command
3
+ LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
4
+ STDLIB_FILE_PATH = File.join(LRAMA_LIB, 'grammar', 'stdlib.y')
5
+
3
6
  def run(argv)
4
- options = OptionParser.new.parse(argv)
7
+ begin
8
+ options = OptionParser.new.parse(argv)
9
+ rescue => e
10
+ message = e.message
11
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
12
+ abort message
13
+ end
5
14
 
6
15
  Report::Duration.enable if options.trace_opts[:time]
7
16
 
8
17
  warning = Lrama::Warning.new
9
18
  text = options.y.read
10
19
  options.y.close if options.y != STDIN
11
- grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
20
+ begin
21
+ grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
22
+ unless grammar.no_stdlib
23
+ stdlib_grammar = Lrama::Parser.new(File.read(STDLIB_FILE_PATH), STDLIB_FILE_PATH, options.debug).parse
24
+ grammar.insert_before_parameterizing_rules(stdlib_grammar.parameterizing_rules)
25
+ end
26
+ grammar.prepare
27
+ grammar.validate!
28
+ rescue => e
29
+ raise e if options.debug
30
+ message = e.message
31
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
32
+ abort message
33
+ end
12
34
  states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
13
35
  states.compute
14
36
  context = Lrama::Context.new(states)
@@ -39,7 +61,7 @@ module Lrama
39
61
  end
40
62
 
41
63
  if warning.has_error?
42
- exit 1
64
+ exit false
43
65
  end
44
66
  end
45
67
  end
data/lib/lrama/context.rb CHANGED
@@ -9,7 +9,7 @@ module Lrama
9
9
  BaseMin = -Float::INFINITY
10
10
 
11
11
  # TODO: It might be better to pass `states` to Output directly?
12
- attr_reader :states
12
+ attr_reader :states, :yylast, :yypact_ninf, :yytable_ninf, :yydefact, :yydefgoto
13
13
 
14
14
  def initialize(states)
15
15
  @states = states
@@ -41,15 +41,11 @@ module Lrama
41
41
  def yyfinal
42
42
  @states.states.find do |state|
43
43
  state.items.find do |item|
44
- item.rule.lhs.id.s_value == "$accept" && item.end_of_rule?
44
+ item.lhs.accept_symbol? && item.end_of_rule?
45
45
  end
46
46
  end.id
47
47
  end
48
48
 
49
- def yylast
50
- @yylast
51
- end
52
-
53
49
  # Number of terms
54
50
  def yyntokens
55
51
  @states.terms.count
@@ -119,30 +115,14 @@ module Lrama
119
115
  end
120
116
  end
121
117
 
122
- def yypact_ninf
123
- @yypact_ninf
124
- end
125
-
126
- def yytable_ninf
127
- @yytable_ninf
128
- end
129
-
130
118
  def yypact
131
119
  @base[0...yynstates]
132
120
  end
133
121
 
134
- def yydefact
135
- @yydefact
136
- end
137
-
138
122
  def yypgoto
139
123
  @base[yynstates..-1]
140
124
  end
141
125
 
142
- def yydefgoto
143
- @yydefgoto
144
- end
145
-
146
126
  def yytable
147
127
  @table
148
128
  end
@@ -241,7 +221,7 @@ module Lrama
241
221
 
242
222
  if state.reduces.map(&:selected_look_ahead).any? {|la| !la.empty? }
243
223
  # Iterate reduces with reverse order so that first rule is used.
244
- state.reduces.reverse.each do |reduce|
224
+ state.reduces.reverse_each do |reduce|
245
225
  reduce.look_ahead.each do |term|
246
226
  actions[term.number] = rule_id_to_action_number(reduce.rule.id)
247
227
  end
@@ -40,7 +40,7 @@ module Lrama
40
40
  current = :production
41
41
  lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
42
42
 
43
- paths.reverse.each do |path|
43
+ paths.reverse_each do |path|
44
44
  item = path.to.item
45
45
 
46
46
  case current
@@ -97,7 +97,7 @@ module Lrama
97
97
  if next_sym == sym
98
98
  derivation = nil
99
99
 
100
- sis.reverse.each do |si|
100
+ sis.reverse_each do |si|
101
101
  derivation = Derivation.new(si.item, derivation)
102
102
  end
103
103
 
@@ -0,0 +1,24 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Binding
4
+ attr_reader :actual_args, :count
5
+
6
+ def initialize(parameterizing_rule, actual_args)
7
+ @parameters = parameterizing_rule.parameters
8
+ @actual_args = actual_args
9
+ @parameter_to_arg = @parameters.zip(actual_args).map do |param, arg|
10
+ [param.s_value, arg]
11
+ end.to_h
12
+ end
13
+
14
+ def resolve_symbol(symbol)
15
+ if symbol.is_a?(Lexer::Token::InstantiateRule)
16
+ resolved_args = symbol.args.map { |arg| resolve_symbol(arg) }
17
+ Lrama::Lexer::Token::InstantiateRule.new(s_value: symbol.s_value, location: symbol.location, args: resolved_args, lhs_tag: symbol.lhs_tag)
18
+ else
19
+ @parameter_to_arg[symbol.s_value] || symbol
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -22,7 +22,7 @@ module Lrama
22
22
  # For the semantic action of original rule:
23
23
  #
24
24
  # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
25
- # "Position in grammar" $1 $2 $3 $4 $5 $6
25
+ # "Position in grammar" $1 $2 $3 $4 $5
26
26
  # "Index for yyvsp" -4 -3 -2 -1 0
27
27
  #
28
28
  #
@@ -28,7 +28,7 @@ module Lrama
28
28
  def translated_code
29
29
  t_code = s_value.dup
30
30
 
31
- references.reverse.each do |ref|
31
+ references.reverse_each do |ref|
32
32
  first_column = ref.first_column
33
33
  last_column = ref.last_column
34
34
 
@@ -0,0 +1,47 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Resolver
5
+ attr_accessor :rules, :created_lhs_list
6
+
7
+ def initialize
8
+ @rules = []
9
+ @created_lhs_list = []
10
+ end
11
+
12
+ def add_parameterizing_rule(rule)
13
+ @rules << rule
14
+ end
15
+
16
+ def find(token)
17
+ select_rules(token).last
18
+ end
19
+
20
+ def created_lhs(lhs_s_value)
21
+ @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
22
+ end
23
+
24
+ private
25
+
26
+ def select_rules(token)
27
+ rules = select_rules_by_name(token.rule_name)
28
+ rules = rules.select { |rule| rule.required_parameters_count == token.args_count }
29
+ if rules.empty?
30
+ raise "Invalid number of arguments. `#{token.rule_name}`"
31
+ else
32
+ rules
33
+ end
34
+ end
35
+
36
+ def select_rules_by_name(rule_name)
37
+ rules = @rules.select { |rule| rule.name == rule_name }
38
+ if rules.empty?
39
+ raise "Parameterizing rule does not exist. `#{rule_name}`"
40
+ else
41
+ rules
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Rhs
5
+ attr_accessor :symbols, :user_code, :precedence_sym
6
+
7
+ def initialize
8
+ @symbols = []
9
+ @user_code = nil
10
+ @precedence_sym = nil
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Rule
5
+ attr_reader :name, :parameters, :rhs_list, :required_parameters_count
6
+
7
+ def initialize(name, parameters, rhs_list)
8
+ @name = name
9
+ @parameters = parameters
10
+ @rhs_list = rhs_list
11
+ @required_parameters_count = parameters.count
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,3 @@
1
- module Lrama
2
- class Grammar
3
- class ParameterizingRule < Struct.new(:rules, :token, keyword_init: true)
4
- end
5
- end
6
- end
1
+ require_relative 'parameterizing_rule/resolver'
2
+ require_relative 'parameterizing_rule/rhs'
3
+ require_relative 'parameterizing_rule/rule'
@@ -1,10 +1,10 @@
1
1
  module Lrama
2
2
  class Grammar
3
3
  class PercentCode
4
- attr_reader :id, :code
4
+ attr_reader :name, :code
5
5
 
6
- def initialize(id, code)
7
- @id = id
6
+ def initialize(name, code)
7
+ @name = name
8
8
  @code = code
9
9
  end
10
10
  end
@@ -19,7 +19,7 @@ module Lrama
19
19
  # TODO: Change this to display_name
20
20
  def to_s
21
21
  l = lhs.id.s_value
22
- r = rhs.empty? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
22
+ r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
23
23
 
24
24
  "#{l} -> #{r}"
25
25
  end
@@ -27,7 +27,7 @@ module Lrama
27
27
  # Used by #user_actions
28
28
  def as_comment
29
29
  l = lhs.id.s_value
30
- r = rhs.empty? ? "%empty" : rhs.map(&:display_name).join(" ")
30
+ r = empty_rule? ? "%empty" : rhs.map(&:display_name).join(" ")
31
31
 
32
32
  "#{l}: #{r}"
33
33
  end