lrama 0.6.0 → 0.6.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +20 -5
  3. data/Gemfile +1 -1
  4. data/NEWS.md +46 -0
  5. data/Steepfile +2 -3
  6. data/lib/lrama/command.rb +17 -3
  7. data/lib/lrama/context.rb +2 -22
  8. data/lib/lrama/grammar/binding.rb +24 -0
  9. data/lib/lrama/grammar/code/rule_action.rb +1 -1
  10. data/lib/lrama/grammar/parameterizing_rule/resolver.rb +39 -0
  11. data/lib/lrama/grammar/parameterizing_rule/rhs.rb +15 -0
  12. data/lib/lrama/grammar/parameterizing_rule/rule.rb +16 -0
  13. data/lib/lrama/grammar/parameterizing_rule.rb +3 -6
  14. data/lib/lrama/grammar/percent_code.rb +3 -3
  15. data/lib/lrama/grammar/rule_builder.rb +59 -25
  16. data/lib/lrama/grammar/type.rb +13 -1
  17. data/lib/lrama/grammar.rb +7 -9
  18. data/lib/lrama/lexer/grammar_file.rb +1 -1
  19. data/lib/lrama/lexer/token/instantiate_rule.rb +7 -2
  20. data/lib/lrama/lexer/token.rb +5 -0
  21. data/lib/lrama/lexer.rb +2 -7
  22. data/lib/lrama/output.rb +2 -2
  23. data/lib/lrama/parser.rb +166 -148
  24. data/lib/lrama/version.rb +1 -1
  25. data/parser.y +8 -8
  26. data/sig/lrama/grammar/binding.rbs +16 -0
  27. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +21 -0
  28. data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +13 -0
  29. data/sig/lrama/grammar/parameterizing_rule/rule.rbs +14 -0
  30. data/sig/lrama/grammar/parameterizing_rule.rbs +0 -4
  31. data/sig/lrama/grammar/percent_code.rbs +3 -3
  32. data/sig/lrama/grammar/rule_builder.rbs +9 -6
  33. data/sig/lrama/lexer/token/instantiate_rule.rbs +4 -2
  34. data/sig/lrama/lexer/token.rbs +1 -0
  35. metadata +11 -9
  36. data/lib/lrama/grammar/parameterizing_rule_builder.rb +0 -34
  37. data/lib/lrama/grammar/parameterizing_rule_resolver.rb +0 -30
  38. data/lib/lrama/grammar/parameterizing_rule_rhs_builder.rb +0 -53
  39. data/sig/lrama/grammar/parameterizing_rule_builder.rbs +0 -19
  40. data/sig/lrama/grammar/parameterizing_rule_resolver.rbs +0 -16
  41. data/sig/lrama/grammar/parameterizing_rule_rhs_builder.rbs +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b1a3e3181fc7060235e167ea97a92809b31aa5b74ef5978ab70415252bb87e3
4
- data.tar.gz: 51a6ee0620321936fcd9d81c44ece3f9e444b977dc8fa940ddf920a5bb3b1dad
3
+ metadata.gz: 50dc10cc2d790e778dcb6a35b789f146e69157b3c99d5b66059d95c025546ea6
4
+ data.tar.gz: cbc16ede0db21b5d22f74c47dfd7a87af2ae20e15f72afc9ea8a79980531861d
5
5
  SHA512:
6
- metadata.gz: f2b8805ad79cc0c3f125eba2715d274387191e6a355910d11c88f918eae4906b9398444162210c7ce955b1ba3f67cabf3b0679569a65d63bdc52328f2d7dc2f7
7
- data.tar.gz: 93de8cc0c7f9154f37825d59010a4850cc81b8a66f460d70f95aed44c0eb1224e583d1afb95155be2d9ae063d286a4fa719c133c993c6ec9bfba1c490dfc997b
6
+ metadata.gz: 7567e78e28cb912eb6dae8182827b5c6555924757bffe4fd9db81f79dd117aaf00f0918c90ead79d3567eeee802b90556540141fd5d4083bf5d6013c075cb20c
7
+ data.tar.gz: e58f803bc04114bdeb69b74a5e34ab9649241dafb9fe69a62f7d17ea87026411e3f743c54537fa092a9d6cea547a046fc762a78d9daebf92c3184be5502a24c1
@@ -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:
@@ -118,12 +133,12 @@ jobs:
118
133
  ruby-version: ${{ matrix.baseruby }}
119
134
  bundler-cache: true
120
135
  - run: git clone --depth=1 https://github.com/ruby/ruby.git -b ${{ matrix.ruby_branch }} ../ruby
121
- working-directory:
136
+ working-directory: .
122
137
  - run: mkdir -p tool/lrama
123
138
  working-directory: ../ruby
124
139
  - name: Copy Lrama to ruby/tool
125
140
  run: cp -r LEGAL.md NEWS.md MIT exe lib template ../ruby/tool/lrama
126
- working-directory:
141
+ working-directory: .
127
142
  - run: tree tool/lrama
128
143
  working-directory: ../ruby
129
144
  # 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,49 @@
1
1
  # NEWS for Lrama
2
2
 
3
+ ## Lrama 0.6.1 (2024-01-13)
4
+
5
+ ### Nested parameterizing rules
6
+
7
+ Allow to pass an instantiated rule to other parameterizing rules.
8
+
9
+ ```
10
+ %rule constant(X) : X
11
+ ;
12
+
13
+ %rule option(Y) : /* empty */
14
+ | Y
15
+ ;
16
+
17
+ %%
18
+
19
+ program : option(constant(number)) // Nested rule
20
+ ;
21
+ %%
22
+ ```
23
+
24
+ Allow to use nested parameterizing rules when define parameterizing rules.
25
+
26
+ ```
27
+ %rule option(x) : /* empty */
28
+ | X
29
+ ;
30
+
31
+ %rule double(Y) : Y Y
32
+ ;
33
+
34
+ %rule double_opt(A) : option(double(A)) // Nested rule
35
+ ;
36
+
37
+ %%
38
+
39
+ program : double_opt(number)
40
+ ;
41
+
42
+ %%
43
+ ```
44
+
45
+ https://github.com/ruby/lrama/pull/337
46
+
3
47
  ## Lrama 0.6.0 (2023-12-25)
4
48
 
5
49
  ### User defined parameterizing rules
@@ -20,6 +64,8 @@ stmt: pair(ODD, EVEN) <num>
20
64
  ;
21
65
  ```
22
66
 
67
+ https://github.com/ruby/lrama/pull/285
68
+
23
69
  ## Lrama 0.5.11 (2023-12-02)
24
70
 
25
71
  ### 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,28 @@
1
1
  module Lrama
2
2
  class Command
3
3
  def run(argv)
4
- options = OptionParser.new.parse(argv)
4
+ begin
5
+ options = OptionParser.new.parse(argv)
6
+ rescue => e
7
+ message = e.message
8
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
9
+ abort message
10
+ end
5
11
 
6
12
  Report::Duration.enable if options.trace_opts[:time]
7
13
 
8
14
  warning = Lrama::Warning.new
9
15
  text = options.y.read
10
16
  options.y.close if options.y != STDIN
11
- grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
17
+ parser = Lrama::Parser.new(text, options.grammar_file, options.debug)
18
+ begin
19
+ grammar = parser.parse
20
+ rescue => e
21
+ raise e if options.debug
22
+ message = e.message
23
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
24
+ abort message
25
+ end
12
26
  states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
13
27
  states.compute
14
28
  context = Lrama::Context.new(states)
@@ -39,7 +53,7 @@ module Lrama
39
53
  end
40
54
 
41
55
  if warning.has_error?
42
- exit 1
56
+ exit false
43
57
  end
44
58
  end
45
59
  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.rule.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
@@ -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
  #
@@ -0,0 +1,39 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Resolver
5
+ attr_accessor :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 defined?(token)
17
+ !select_rules(token).empty?
18
+ end
19
+
20
+ def find(token)
21
+ select_rules(token).last
22
+ end
23
+
24
+ def created_lhs(lhs_s_value)
25
+ @created_lhs_list.select { |created_lhs| created_lhs.s_value == lhs_s_value }.last
26
+ end
27
+
28
+ private
29
+
30
+ def select_rules(token)
31
+ @rules.select do |rule|
32
+ rule.name == token.rule_name &&
33
+ rule.required_parameters_count == token.args_count
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ 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
@@ -3,21 +3,22 @@ require 'lrama/grammar/parameterizing_rules/builder'
3
3
  module Lrama
4
4
  class Grammar
5
5
  class RuleBuilder
6
- attr_accessor :lhs, :lhs_tag, :line
7
- attr_reader :rhs, :user_code, :precedence_sym
6
+ attr_accessor :lhs, :line
7
+ attr_reader :lhs_tag, :rhs, :user_code, :precedence_sym
8
8
 
9
- def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, skip_preprocess_references: false)
9
+ def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false)
10
10
  @rule_counter = rule_counter
11
11
  @midrule_action_counter = midrule_action_counter
12
12
  @position_in_original_rule_rhs = position_in_original_rule_rhs
13
13
  @skip_preprocess_references = skip_preprocess_references
14
14
 
15
15
  @lhs = nil
16
+ @lhs_tag = lhs_tag
16
17
  @rhs = []
17
- @lhs_tag = nil
18
18
  @user_code = nil
19
19
  @precedence_sym = nil
20
20
  @line = nil
21
+ @rule_builders_for_parameterizing_rules = []
21
22
  @rule_builders_for_derived_rules = []
22
23
  end
23
24
 
@@ -33,7 +34,7 @@ module Lrama
33
34
 
34
35
  def user_code=(user_code)
35
36
  if !@line
36
- @line = user_code.line
37
+ @line = user_code&.line
37
38
  end
38
39
 
39
40
  flush_user_code
@@ -51,14 +52,14 @@ module Lrama
51
52
  freeze_rhs
52
53
  end
53
54
 
54
- def setup_rules(parameterizing_resolver)
55
+ def setup_rules(parameterizing_rule_resolver)
55
56
  preprocess_references unless @skip_preprocess_references
56
- process_rhs(parameterizing_resolver)
57
+ process_rhs(parameterizing_rule_resolver)
57
58
  build_rules
58
59
  end
59
60
 
60
61
  def rules
61
- @parameterizing_rules + @midrule_action_rules + @rules
62
+ @parameterizing_rules + @old_parameterizing_rules + @midrule_action_rules + @rules
62
63
  end
63
64
 
64
65
  private
@@ -75,10 +76,13 @@ module Lrama
75
76
  tokens = @replaced_rhs
76
77
 
77
78
  rule = Rule.new(
78
- id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, token_code: user_code,
79
+ id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
79
80
  position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
80
81
  )
81
82
  @rules = [rule]
83
+ @parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
84
+ rule_builder.rules
85
+ end.flatten
82
86
  @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
83
87
  rule_builder.rules
84
88
  end.flatten
@@ -89,11 +93,11 @@ module Lrama
89
93
 
90
94
  # rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on.
91
95
  # `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`.
92
- def process_rhs(parameterizing_resolver)
96
+ def process_rhs(parameterizing_rule_resolver)
93
97
  return if @replaced_rhs
94
98
 
95
99
  @replaced_rhs = []
96
- @parameterizing_rules = []
100
+ @old_parameterizing_rules = []
97
101
 
98
102
  rhs.each_with_index do |token, i|
99
103
  case token
@@ -102,26 +106,46 @@ module Lrama
102
106
  when Lrama::Lexer::Token::Ident
103
107
  @replaced_rhs << token
104
108
  when Lrama::Lexer::Token::InstantiateRule
105
- if parameterizing_resolver.defined?(token.rule_name)
106
- parameterizing = parameterizing_resolver.build_rules(token, @rule_counter, @lhs_tag, line)
107
- @parameterizing_rules = @parameterizing_rules + parameterizing.map(&:rules).flatten
108
- @replaced_rhs = @replaced_rhs + parameterizing.map(&:token).flatten.uniq
109
+ if parameterizing_rule_resolver.defined?(token)
110
+ parameterizing_rule = parameterizing_rule_resolver.find(token)
111
+ raise "Unexpected token. #{token}" unless parameterizing_rule
112
+
113
+ bindings = Binding.new(parameterizing_rule, token.args)
114
+ lhs_s_value = lhs_s_value(token, bindings)
115
+ if (created_lhs = parameterizing_rule_resolver.created_lhs(lhs_s_value))
116
+ @replaced_rhs << created_lhs
117
+ else
118
+ lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
119
+ @replaced_rhs << lhs_token
120
+ parameterizing_rule_resolver.created_lhs_list << lhs_token
121
+ parameterizing_rule.rhs_list.each do |r|
122
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
123
+ rule_builder.lhs = lhs_token
124
+ r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
125
+ rule_builder.line = line
126
+ rule_builder.user_code = r.user_code
127
+ rule_builder.precedence_sym = r.precedence_sym
128
+ rule_builder.complete_input
129
+ rule_builder.setup_rules(parameterizing_rule_resolver)
130
+ @rule_builders_for_parameterizing_rules << rule_builder
131
+ end
132
+ end
109
133
  else
110
134
  # TODO: Delete when the standard library will defined as a grammar file.
111
- parameterizing = ParameterizingRules::Builder.new(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
112
- @parameterizing_rules = @parameterizing_rules + parameterizing.build
113
- @replaced_rhs << parameterizing.build_token
135
+ parameterizing_rule = ParameterizingRules::Builder.new(token, @rule_counter, token.lhs_tag, user_code, precedence_sym, line)
136
+ @old_parameterizing_rules = @old_parameterizing_rules + parameterizing_rule.build
137
+ @replaced_rhs << parameterizing_rule.build_token
114
138
  end
115
139
  when Lrama::Lexer::Token::UserCode
116
140
  prefix = token.referred ? "@" : "$@"
117
141
  new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
118
142
  @replaced_rhs << new_token
119
143
 
120
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, skip_preprocess_references: true)
144
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: lhs_tag, skip_preprocess_references: true)
121
145
  rule_builder.lhs = new_token
122
146
  rule_builder.user_code = token
123
147
  rule_builder.complete_input
124
- rule_builder.setup_rules(parameterizing_resolver)
148
+ rule_builder.setup_rules(parameterizing_rule_resolver)
125
149
 
126
150
  @rule_builders_for_derived_rules << rule_builder
127
151
  else
@@ -130,6 +154,18 @@ module Lrama
130
154
  end
131
155
  end
132
156
 
157
+ def lhs_s_value(token, bindings)
158
+ s_values = token.args.map do |arg|
159
+ resolved = bindings.resolve_symbol(arg)
160
+ if resolved.is_a?(Lexer::Token::InstantiateRule)
161
+ [resolved.s_value, resolved.args.map(&:s_value)]
162
+ else
163
+ resolved.s_value
164
+ end
165
+ end
166
+ "#{token.rule_name}_#{s_values.join('_')}"
167
+ end
168
+
133
169
  def numberize_references
134
170
  # Bison n'th component is 1-origin
135
171
  (rhs + [user_code]).compact.each.with_index(1) do |token, i|
@@ -144,13 +180,11 @@ module Lrama
144
180
  candidates = rhs.each_with_index.select {|token, i| token.referred_by?(ref_name) }
145
181
 
146
182
  if candidates.size >= 2
147
- location = token.location.partial_location(ref.first_column, ref.last_column)
148
- raise location.generate_error_message("Referring symbol `#{ref_name}` is duplicated.")
183
+ token.invalid_ref(ref, "Referring symbol `#{ref_name}` is duplicated.")
149
184
  end
150
185
 
151
186
  unless (referring_symbol = candidates.first)
152
- location = token.location.partial_location(ref.first_column, ref.last_column)
153
- raise location.generate_error_message("Referring symbol `#{ref_name}` is not found.")
187
+ token.invalid_ref(ref, "Referring symbol `#{ref_name}` is not found.")
154
188
  end
155
189
 
156
190
  ref.index = referring_symbol[1] + 1
@@ -163,7 +197,7 @@ module Lrama
163
197
  if ref.index
164
198
  # TODO: Prohibit $0 even so Bison allows it?
165
199
  # See: https://www.gnu.org/software/bison/manual/html_node/Actions.html
166
- raise "Can not refer following component. #{ref.index} >= #{i}. #{token}" if ref.index >= i
200
+ token.invalid_ref(ref, "Can not refer following component. #{ref.index} >= #{i}.") if ref.index >= i
167
201
  rhs[ref.index - 1].referred = true
168
202
  end
169
203
  end
@@ -1,6 +1,18 @@
1
1
  module Lrama
2
2
  class Grammar
3
- class Type < Struct.new(:id, :tag, keyword_init: true)
3
+ class Type
4
+ attr_reader :id, :tag
5
+
6
+ def initialize(id:, tag:)
7
+ @id = id
8
+ @tag = tag
9
+ end
10
+
11
+ def ==(other)
12
+ self.class == other.class &&
13
+ self.id == other.id &&
14
+ self.tag == other.tag
15
+ end
4
16
  end
5
17
  end
6
18
  end
data/lib/lrama/grammar.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "lrama/grammar/auxiliary"
2
+ require "lrama/grammar/binding"
2
3
  require "lrama/grammar/code"
3
4
  require "lrama/grammar/counter"
4
5
  require "lrama/grammar/error_token"
@@ -8,9 +9,6 @@ require "lrama/grammar/printer"
8
9
  require "lrama/grammar/reference"
9
10
  require "lrama/grammar/rule"
10
11
  require "lrama/grammar/rule_builder"
11
- require "lrama/grammar/parameterizing_rule_builder"
12
- require "lrama/grammar/parameterizing_rule_resolver"
13
- require "lrama/grammar/parameterizing_rule_rhs_builder"
14
12
  require "lrama/grammar/parameterizing_rule"
15
13
  require "lrama/grammar/symbol"
16
14
  require "lrama/grammar/type"
@@ -40,7 +38,7 @@ module Lrama
40
38
  @rule_builders = []
41
39
  @rules = []
42
40
  @sym_to_rules = {}
43
- @parameterizing_resolver = ParameterizingRuleResolver.new
41
+ @parameterizing_rule_resolver = ParameterizingRule::Resolver.new
44
42
  @empty_symbol = nil
45
43
  @eof_symbol = nil
46
44
  @error_symbol = nil
@@ -52,7 +50,7 @@ module Lrama
52
50
  end
53
51
 
54
52
  def add_percent_code(id:, code:)
55
- @percent_codes << PercentCode.new(id, code)
53
+ @percent_codes << PercentCode.new(id.s_value, code.s_value)
56
54
  end
57
55
 
58
56
  def add_printer(ident_or_tags:, token_code:, lineno:)
@@ -134,8 +132,8 @@ module Lrama
134
132
  @rule_builders << builder
135
133
  end
136
134
 
137
- def add_parameterizing_rule_builder(builder)
138
- @parameterizing_resolver.add_parameterizing_rule_builder(builder)
135
+ def add_parameterizing_rule(rule)
136
+ @parameterizing_rule_resolver.add_parameterizing_rule(rule)
139
137
  end
140
138
 
141
139
  def prologue_first_lineno=(prologue_first_lineno)
@@ -171,7 +169,7 @@ module Lrama
171
169
 
172
170
  # TODO: More validation methods
173
171
  #
174
- # * Validaiton for no_declared_type_reference
172
+ # * Validation for no_declared_type_reference
175
173
  def validate!
176
174
  validate_symbol_number_uniqueness!
177
175
  validate_symbol_alias_name_uniqueness!
@@ -319,7 +317,7 @@ module Lrama
319
317
 
320
318
  def setup_rules
321
319
  @rule_builders.each do |builder|
322
- builder.setup_rules(@parameterizing_resolver)
320
+ builder.setup_rules(@parameterizing_rule_resolver)
323
321
  end
324
322
  end
325
323
 
@@ -5,7 +5,7 @@ module Lrama
5
5
 
6
6
  def initialize(path, text)
7
7
  @path = path
8
- @text = text
8
+ @text = text.freeze
9
9
  end
10
10
 
11
11
  def ==(other)