lrama 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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)