lrama 0.5.11 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +2 -2
  3. data/Gemfile +1 -1
  4. data/LEGAL.md +1 -0
  5. data/NEWS.md +187 -0
  6. data/README.md +15 -4
  7. data/Steepfile +3 -0
  8. data/lib/lrama/grammar/code/printer_code.rb +1 -1
  9. data/lib/lrama/grammar/code/rule_action.rb +19 -3
  10. data/lib/lrama/grammar/code.rb +19 -7
  11. data/lib/lrama/grammar/parameterizing_rule.rb +6 -0
  12. data/lib/lrama/grammar/parameterizing_rule_builder.rb +34 -0
  13. data/lib/lrama/grammar/parameterizing_rule_resolver.rb +30 -0
  14. data/lib/lrama/grammar/parameterizing_rule_rhs_builder.rb +53 -0
  15. data/lib/lrama/grammar/rule_builder.rb +26 -22
  16. data/lib/lrama/grammar.rb +15 -41
  17. data/lib/lrama/lexer/grammar_file.rb +21 -0
  18. data/lib/lrama/lexer/location.rb +77 -2
  19. data/lib/lrama/lexer/token/instantiate_rule.rb +18 -0
  20. data/lib/lrama/lexer/token/user_code.rb +10 -10
  21. data/lib/lrama/lexer/token.rb +1 -1
  22. data/lib/lrama/lexer.rb +21 -11
  23. data/lib/lrama/parser.rb +619 -454
  24. data/lib/lrama/states_reporter.rb +1 -1
  25. data/lib/lrama/version.rb +1 -1
  26. data/parser.y +95 -30
  27. data/sig/lrama/grammar/code/printer_code.rbs +1 -1
  28. data/sig/lrama/grammar/code.rbs +5 -5
  29. data/sig/lrama/grammar/parameterizing_rule.rbs +10 -0
  30. data/sig/lrama/grammar/parameterizing_rule_builder.rbs +19 -0
  31. data/sig/lrama/grammar/parameterizing_rule_resolver.rbs +16 -0
  32. data/sig/lrama/grammar/parameterizing_rule_rhs_builder.rbs +18 -0
  33. data/sig/lrama/grammar/parameterizing_rules/builder/base.rbs +5 -3
  34. data/sig/lrama/grammar/parameterizing_rules/builder/separated_list.rbs +2 -0
  35. data/sig/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rbs +2 -0
  36. data/sig/lrama/grammar/parameterizing_rules/builder.rbs +4 -3
  37. data/sig/lrama/grammar/rule_builder.rbs +2 -4
  38. data/sig/lrama/lexer/grammar_file.rbs +15 -0
  39. data/sig/lrama/lexer/location.rbs +13 -1
  40. data/sig/lrama/lexer/token/instantiate_rule.rbs +12 -0
  41. metadata +16 -6
  42. data/doc/TODO.md +0 -59
  43. data/lib/lrama/lexer/token/parameterizing.rb +0 -34
  44. data/sig/lrama/lexer/token/parameterizing.rbs +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 634093bc73fd1504910364bffa6827a66fa7479f1f5b5238fdf577f0bb6d3d9d
4
- data.tar.gz: 96db570d049f47f20bf619535ee91e7f0f846a492404a54f7fe41a6addcce484
3
+ metadata.gz: 7b1a3e3181fc7060235e167ea97a92809b31aa5b74ef5978ab70415252bb87e3
4
+ data.tar.gz: 51a6ee0620321936fcd9d81c44ece3f9e444b977dc8fa940ddf920a5bb3b1dad
5
5
  SHA512:
6
- metadata.gz: 6b09e84cd16cd162f263e68abf7ada808418212ca449fab0f4a380c42c0193f479cad3d0d1afcc1d5f17d81b890e3754642d1a9433f7be5f6fc71fdcb2df3f97
7
- data.tar.gz: 1994a670f1033e737f2193e2e71ccaa0818e4144ac7f4424ebf24046ece23efc3f67eeb0927c5336663a244f270b321247b39dbbdbe76cfacc13b94da6289a8b
6
+ metadata.gz: f2b8805ad79cc0c3f125eba2715d274387191e6a355910d11c88f918eae4906b9398444162210c7ce955b1ba3f67cabf3b0679569a65d63bdc52328f2d7dc2f7
7
+ data.tar.gz: 93de8cc0c7f9154f37825d59010a4850cc81b8a66f460d70f95aed44c0eb1224e583d1afb95155be2d9ae063d286a4fa719c133c993c6ec9bfba1c490dfc997b
@@ -13,7 +13,7 @@ jobs:
13
13
  strategy:
14
14
  fail-fast: false
15
15
  matrix:
16
- ruby: ['head', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5']
16
+ ruby: ['head', '3.3', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5']
17
17
  steps:
18
18
  - uses: actions/checkout@v4
19
19
  - uses: ruby/setup-ruby@v1
@@ -122,7 +122,7 @@ jobs:
122
122
  - run: mkdir -p tool/lrama
123
123
  working-directory: ../ruby
124
124
  - name: Copy Lrama to ruby/tool
125
- run: cp -r LEGAL.md MIT exe lib template ../ruby/tool/lrama
125
+ run: cp -r LEGAL.md NEWS.md MIT exe lib template ../ruby/tool/lrama
126
126
  working-directory:
127
127
  - run: tree tool/lrama
128
128
  working-directory: ../ruby
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.3.0", require: false
15
+ gem "rbs", "3.4.0", require: false
16
16
  gem "steep", "1.6.0", require: false
17
17
  end
data/LEGAL.md CHANGED
@@ -7,5 +7,6 @@ mentioned below.
7
7
 
8
8
  These files are licensed under the GNU General Public License version 3 or later. See these files for more information.
9
9
 
10
+ * template/bison/_yacc.h
10
11
  * template/bison/yacc.c
11
12
  * template/bison/yacc.h
data/NEWS.md ADDED
@@ -0,0 +1,187 @@
1
+ # NEWS for Lrama
2
+
3
+ ## Lrama 0.6.0 (2023-12-25)
4
+
5
+ ### User defined parameterizing rules
6
+
7
+ Allow to define parameterizing rule by `%rule` directive.
8
+
9
+ ```
10
+ %rule pair(X, Y): X Y { $$ = $1 + $2; }
11
+ ;
12
+
13
+ %%
14
+
15
+ program: stmt
16
+ ;
17
+
18
+ stmt: pair(ODD, EVEN) <num>
19
+ | pair(EVEN, ODD) <num>
20
+ ;
21
+ ```
22
+
23
+ ## Lrama 0.5.11 (2023-12-02)
24
+
25
+ ### Type specification of parameterizing rules
26
+
27
+ Allow to specify type of rules by specifying tag, `<i>` in below example.
28
+ Tag is post-modification style.
29
+
30
+ ```
31
+ %union {
32
+ int i;
33
+ }
34
+
35
+ %%
36
+
37
+ program : option(number) <i>
38
+ | number_alias? <i>
39
+ ;
40
+ ```
41
+
42
+ https://github.com/ruby/lrama/pull/272
43
+
44
+
45
+ ## Lrama 0.5.10 (2023-11-18)
46
+
47
+ ### Parameterizing rules (option, nonempty_list, list)
48
+
49
+ Support function call style parameterizing rules for `option`, `nonempty_list` and `list`.
50
+
51
+ https://github.com/ruby/lrama/pull/197
52
+
53
+ ### Parameterizing rules (separated_list)
54
+
55
+ Support `separated_list` and `separated_nonempty_list` parameterizing rules.
56
+
57
+ ```
58
+ program: separated_list(',', number)
59
+
60
+ // Expanded to
61
+
62
+ program: separated_list_number
63
+ separated_list_number: ε
64
+ separated_list_number: separated_nonempty_list_number
65
+ separated_nonempty_list_number: number
66
+ separated_nonempty_list_number: separated_nonempty_list_number ',' number
67
+ ```
68
+
69
+ ```
70
+ program: separated_nonempty_list(',', number)
71
+
72
+ // Expanded to
73
+
74
+ program: separated_nonempty_list_number
75
+ separated_nonempty_list_number: number
76
+ separated_nonempty_list_number: separated_nonempty_list_number ',' number
77
+ ```
78
+
79
+ https://github.com/ruby/lrama/pull/204
80
+
81
+ ## Lrama 0.5.9 (2023-11-05)
82
+
83
+ ### Parameterizing rules (suffix)
84
+
85
+ Parameterizing rules are template of rules.
86
+ It's very common pattern to write "list" grammar rule like:
87
+
88
+ ```
89
+ opt_args: /* none */
90
+ | args
91
+ ;
92
+
93
+ args: arg
94
+ | args arg
95
+ ```
96
+
97
+ Lrama supports these suffixes:
98
+
99
+ * `?`: option
100
+ * `+`: nonempty list
101
+ * `*`: list
102
+
103
+ Idea of Parameterizing rules comes from Menhir LR(1) parser generator (https://gallium.inria.fr/~fpottier/menhir/manual.html#sec32).
104
+
105
+ https://github.com/ruby/lrama/pull/181
106
+
107
+ ## Lrama 0.5.7 (2023-10-23)
108
+
109
+ ### Racc parser
110
+
111
+ Replace Lrama's parser from hand written parser to LR parser generated by Racc.
112
+ Lrama uses `--embedded` option to generate LR parser because Racc is changed from default gem to bundled gem by Ruby 3.3 (https://github.com/ruby/lrama/pull/132).
113
+
114
+ https://github.com/ruby/lrama/pull/62
115
+
116
+ ## Lrama 0.5.4 (2023-08-17)
117
+
118
+ ### Runtime configuration for error recovery
119
+
120
+ Meke error recovery function configurable on runtime by two new macros.
121
+
122
+ * `YYMAXREPAIR`: Expected to return max length of repair operations. `%parse-param` is passed to this function.
123
+ * `YYERROR_RECOVERY_ENABLED`: Expected to return bool value to determine error recovery is enabled or not. `%parse-param` is passed to this function.
124
+
125
+ https://github.com/ruby/lrama/pull/74
126
+
127
+ ## Lrama 0.5.3 (2023-08-05)
128
+
129
+ ### Error Recovery
130
+
131
+ Support token insert base Error Recovery.
132
+ `-e` option is needed to generate parser with error recovery functions.
133
+
134
+ https://github.com/ruby/lrama/pull/44
135
+
136
+ ## Lrama 0.5.2 (2023-06-14)
137
+
138
+ ### Named References
139
+
140
+ Instead of positional references like `$1` or `$$`,
141
+ named references allow to access to symbol by name.
142
+
143
+ ```
144
+ primary: k_class cpath superclass bodystmt k_end
145
+ {
146
+ $primary = new_class($cpath, $bodystmt, $superclass);
147
+ }
148
+ ```
149
+
150
+ Alias name can be declared.
151
+
152
+ ```
153
+ expr[result]: expr[ex-left] '+' expr[ex.right]
154
+ {
155
+ $result = $[ex-left] + $[ex.right];
156
+ }
157
+ ```
158
+
159
+ Bison supports this feature from 2.5.
160
+
161
+ ### Add parse params to some macros and functions
162
+
163
+ `%parse-param` are added to these macros and functions to remove ytab.sed hack from Ruby.
164
+
165
+ * `YY_LOCATION_PRINT`
166
+ * `YY_SYMBOL_PRINT`
167
+ * `yy_stack_print`
168
+ * `YY_STACK_PRINT`
169
+ * `YY_REDUCE_PRINT`
170
+ * `yysyntax_error`
171
+
172
+ https://github.com/ruby/lrama/pull/40
173
+
174
+ See also: https://github.com/ruby/ruby/pull/7807
175
+
176
+ ## Lrama 0.5.0 (2023-05-17)
177
+
178
+ ### stdin mode
179
+
180
+ When `-` is given as grammar file name, reads the grammar source from STDIN, and takes the next argument as the input file name. This mode helps pre-process a grammar source.
181
+
182
+ https://github.com/ruby/lrama/pull/8
183
+
184
+ ## Lrama 0.4.0 (2023-05-13)
185
+
186
+ This is the first version migrated to Ruby.
187
+ This version generates "parse.c" compatible with Bison 3.8.2.
data/README.md CHANGED
@@ -49,9 +49,13 @@ Enter the formula:
49
49
 
50
50
  ## Versions and Branches
51
51
 
52
- ### v0_5 (`master` branch)
52
+ ### v0_6 (`master` branch)
53
53
 
54
- This branch is for Ruby 3.3. `lrama_0_5` branch is created from this branch, once Ruby 3.3 is released.
54
+ This branch is for Ruby 3.4. `lrama_0_6` branch is created from this branch, once Ruby 3.4 is released.
55
+
56
+ ### v0_5 (`lrama_0_5` branch)
57
+
58
+ This branch is for Ruby 3.3.
55
59
 
56
60
  ### v0_4 (`lrama_0_4` branch)
57
61
 
@@ -91,6 +95,13 @@ $ bundle exec rbs collection install
91
95
  $ bundle exec steep check
92
96
  ```
93
97
 
98
+ Running both of them:
99
+
100
+ ```shell
101
+ $ bundle install
102
+ $ bundle exec rake
103
+ ```
104
+
94
105
  ### Profiling Lrama
95
106
 
96
107
  #### 1. Create parse.tmp.y in ruby/ruby
@@ -136,9 +147,9 @@ $ stackprof --d3-flamegraph tmp/stackprof-cpu-myapp.dump > tmp/flamegraph.html
136
147
 
137
148
  ## Release flow
138
149
 
139
- 1. Update `Lrama::VERSION`
150
+ 1. Update `Lrama::VERSION` and NEWS.md
140
151
  2. Release as a gem by `rake release`
141
- 3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib template ruby/tool/lrama`
152
+ 3. Update Lrama in ruby/ruby by `cp -r LEGAL.md NEWS.md MIT exe lib template ruby/tool/lrama`
142
153
  4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
143
154
 
144
155
  ## License
data/Steepfile CHANGED
@@ -8,6 +8,9 @@ target :lib do
8
8
  check "lib/lrama/grammar/code.rb"
9
9
  check "lib/lrama/grammar/counter.rb"
10
10
  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"
11
14
  check "lib/lrama/grammar/parameterizing_rules"
12
15
  check "lib/lrama/grammar/percent_code.rb"
13
16
  check "lib/lrama/grammar/precedence.rb"
@@ -2,7 +2,7 @@ module Lrama
2
2
  class Grammar
3
3
  class Code
4
4
  class PrinterCode < Code
5
- def initialize(type: nil, token_code: nil, tag: nil)
5
+ def initialize(type:, token_code:, tag:)
6
6
  super(type: type, token_code: token_code)
7
7
  @tag = tag
8
8
  end
@@ -2,7 +2,7 @@ module Lrama
2
2
  class Grammar
3
3
  class Code
4
4
  class RuleAction < Code
5
- def initialize(type: nil, token_code: nil, rule: nil)
5
+ def initialize(type:, token_code:, rule:)
6
6
  super(type: type, token_code: token_code)
7
7
  @rule = rule
8
8
  end
@@ -14,9 +14,23 @@ module Lrama
14
14
  # * ($1) yyvsp[i]
15
15
  # * (@1) yylsp[i]
16
16
  #
17
+ #
18
+ # Consider a rule like
19
+ #
20
+ # class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
21
+ #
22
+ # For the semantic action of original rule:
23
+ #
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
26
+ # "Index for yyvsp" -4 -3 -2 -1 0
27
+ #
28
+ #
29
+ # For the first midrule action:
30
+ #
17
31
  # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
18
- # "Position in grammar" $1 $2 $3 $4 $5 $6
19
- # "Index for yyvsp" -4 -3 -2 -1 0
32
+ # "Position in grammar" $1
33
+ # "Index for yyvsp" 0
20
34
  def reference_to_c(ref)
21
35
  case
22
36
  when ref.type == :dollar && ref.name == "$" # $$
@@ -45,10 +59,12 @@ module Lrama
45
59
  @rule.position_in_original_rule_rhs || @rule.rhs.count
46
60
  end
47
61
 
62
+ # If this is midrule action, RHS is a RHS of the original rule.
48
63
  def rhs
49
64
  (@rule.original_rule || @rule).rhs
50
65
  end
51
66
 
67
+ # Unlike `rhs`, LHS is always a LHS of the rule.
52
68
  def lhs
53
69
  @rule.lhs
54
70
  end
@@ -1,12 +1,29 @@
1
1
  require "forwardable"
2
+ require "lrama/grammar/code/initial_action_code"
3
+ require "lrama/grammar/code/no_reference_code"
4
+ require "lrama/grammar/code/printer_code"
5
+ require "lrama/grammar/code/rule_action"
2
6
 
3
7
  module Lrama
4
8
  class Grammar
5
- class Code < Struct.new(:type, :token_code, keyword_init: true)
9
+ class Code
6
10
  extend Forwardable
7
11
 
8
12
  def_delegators "token_code", :s_value, :line, :column, :references
9
13
 
14
+ attr_reader :type, :token_code
15
+
16
+ def initialize(type:, token_code:)
17
+ @type = type
18
+ @token_code = token_code
19
+ end
20
+
21
+ def ==(other)
22
+ self.class == other.class &&
23
+ self.type == other.type &&
24
+ self.token_code == other.token_code
25
+ end
26
+
10
27
  # $$, $n, @$, @n are translated to C code
11
28
  def translated_code
12
29
  t_code = s_value.dup
@@ -17,7 +34,7 @@ module Lrama
17
34
 
18
35
  str = reference_to_c(ref)
19
36
 
20
- t_code[first_column..last_column] = str
37
+ t_code[first_column...last_column] = str
21
38
  end
22
39
 
23
40
  return t_code
@@ -31,8 +48,3 @@ module Lrama
31
48
  end
32
49
  end
33
50
  end
34
-
35
- require "lrama/grammar/code/initial_action_code"
36
- require "lrama/grammar/code/no_reference_code"
37
- require "lrama/grammar/code/printer_code"
38
- require "lrama/grammar/code/rule_action"
@@ -0,0 +1,6 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule < Struct.new(:rules, :token, keyword_init: true)
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,34 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRuleBuilder
4
+ attr_reader :name, :parameters, :rhs
5
+
6
+ def initialize(name, parameters, rhs)
7
+ @name = name
8
+ @parameters = parameters
9
+ @rhs = rhs
10
+ @required_parameters_count = parameters.count
11
+ end
12
+
13
+ def build_rules(token, actual_args, rule_counter, lhs_tag, line, rule_builders)
14
+ validate_argument_number!(token)
15
+ lhs = lhs(actual_args)
16
+ @rhs.map do |rhs|
17
+ rhs.build_rules(token, actual_args, parameters, rule_counter, lhs, lhs_tag, line, rule_builders)
18
+ end.flatten
19
+ end
20
+
21
+ private
22
+
23
+ def validate_argument_number!(token)
24
+ unless @required_parameters_count == token.args.count
25
+ raise "Invalid number of arguments. expect: #{@required_parameters_count} actual: #{token.args.count}"
26
+ end
27
+ end
28
+
29
+ def lhs(actual_args)
30
+ Lrama::Lexer::Token::Ident.new(s_value: "#{name}_#{actual_args.map(&:s_value).join('_')}")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRuleResolver
4
+ def initialize
5
+ @parameterizing_rule_builders = []
6
+ end
7
+
8
+ def add_parameterizing_rule_builder(builder)
9
+ @parameterizing_rule_builders << builder
10
+ end
11
+
12
+ def defined?(name)
13
+ !rule_builders(name).empty?
14
+ end
15
+
16
+ def build_rules(token, rule_counter, lhs_tag, line)
17
+ builder = rule_builders(token.s_value).last
18
+ raise "Unknown parameterizing rule #{token.s_value} at line #{token.line}" unless builder
19
+
20
+ builder.build_rules(token, token.args, rule_counter, lhs_tag, line, @parameterizing_rule_builders)
21
+ end
22
+
23
+ private
24
+
25
+ def rule_builders(name)
26
+ @parameterizing_rule_builders.select { |builder| builder.name == name }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,53 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRuleRhsBuilder
4
+ attr_accessor :symbols, :user_code, :precedence_sym
5
+
6
+ def initialize
7
+ @symbols = []
8
+ @user_code = nil
9
+ @precedence_sym = nil
10
+ end
11
+
12
+ def build_rules(token, actual_args, parameters, rule_counter, lhs, lhs_tag, line, rule_builders)
13
+ nested_rules = build_nested_rules(token, actual_args, parameters, rule_counter, lhs_tag, line, rule_builders)
14
+ rule = Rule.new(id: rule_counter.increment, _lhs: lhs, _rhs: rhs(token, actual_args, parameters, nested_rules.last), lhs_tag: lhs_tag, token_code: user_code, precedence_sym: precedence_sym, lineno: line)
15
+ ParameterizingRule.new(rules: nested_rules.map(&:rules) + [rule], token: lhs)
16
+ end
17
+
18
+ private
19
+
20
+ def build_nested_rules(token, actual_args, parameters, rule_counter, lhs_tag, line, rule_builders)
21
+ symbols.each_with_index.map do |sym, i|
22
+ next unless sym.is_a?(Lexer::Token::InstantiateRule)
23
+
24
+ builder = rule_builders.select { |builder| builder.name == sym.s_value }.last
25
+ raise "Unknown parameterizing rule #{token.s_value} at line #{token.line}" unless builder
26
+
27
+ builder.build_rules(sym, nested_actual_args(actual_args, parameters, i), rule_counter, lhs_tag, line, rule_builders)
28
+ end.flatten.compact
29
+ end
30
+
31
+ def nested_actual_args(actual_args, parameters, idx)
32
+ symbols[idx].args.map do |arg|
33
+ i = parameters.index { |parameter| parameter.s_value == arg.s_value }
34
+ i.nil? ? arg : actual_args[i]
35
+ end
36
+ end
37
+
38
+ def rhs(token, actual_args, parameters, nested_rule)
39
+ symbols.map do |sym|
40
+ if sym.is_a?(Lexer::Token::InstantiateRule)
41
+ sym.args.map do |arg|
42
+ idx = parameters.index { |parameter| parameter.s_value == arg.s_value }
43
+ idx.nil? ? sym : nested_rule&.token
44
+ end
45
+ else
46
+ idx = parameters.index { |parameter| parameter.s_value == sym.s_value }
47
+ idx.nil? ? sym : actual_args[idx]
48
+ end
49
+ end.flatten
50
+ end
51
+ end
52
+ end
53
+ end
@@ -51,22 +51,14 @@ module Lrama
51
51
  freeze_rhs
52
52
  end
53
53
 
54
- def setup_rules
54
+ def setup_rules(parameterizing_resolver)
55
55
  preprocess_references unless @skip_preprocess_references
56
- process_rhs
56
+ process_rhs(parameterizing_resolver)
57
57
  build_rules
58
58
  end
59
59
 
60
- def parameterizing_rules
61
- @parameterizing_rules
62
- end
63
-
64
- def midrule_action_rules
65
- @midrule_action_rules
66
- end
67
-
68
60
  def rules
69
- @rules
61
+ @parameterizing_rules + @midrule_action_rules + @rules
70
62
  end
71
63
 
72
64
  private
@@ -95,9 +87,9 @@ module Lrama
95
87
  end
96
88
  end
97
89
 
98
- # rhs is a mixture of variety type of tokens like `Ident`, `Parameterizing`, `UserCode` and so on.
90
+ # rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on.
99
91
  # `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`.
100
- def process_rhs
92
+ def process_rhs(parameterizing_resolver)
101
93
  return if @replaced_rhs
102
94
 
103
95
  @replaced_rhs = []
@@ -109,12 +101,17 @@ module Lrama
109
101
  @replaced_rhs << token
110
102
  when Lrama::Lexer::Token::Ident
111
103
  @replaced_rhs << token
112
- when Lrama::Lexer::Token::Parameterizing
113
- parameterizing = ParameterizingRules::Builder.new(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
114
- parameterizing.build.each do |r|
115
- @parameterizing_rules << r
104
+ 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
+ else
110
+ # 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
116
114
  end
117
- @replaced_rhs << parameterizing.build_token
118
115
  when Lrama::Lexer::Token::UserCode
119
116
  prefix = token.referred ? "@" : "$@"
120
117
  new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
@@ -124,7 +121,7 @@ module Lrama
124
121
  rule_builder.lhs = new_token
125
122
  rule_builder.user_code = token
126
123
  rule_builder.complete_input
127
- rule_builder.setup_rules
124
+ rule_builder.setup_rules(parameterizing_resolver)
128
125
 
129
126
  @rule_builders_for_derived_rules << rule_builder
130
127
  else
@@ -146,8 +143,15 @@ module Lrama
146
143
  else
147
144
  candidates = rhs.each_with_index.select {|token, i| token.referred_by?(ref_name) }
148
145
 
149
- raise "Referring symbol `#{ref_name}` is duplicated. #{token}" if candidates.size >= 2
150
- raise "Referring symbol `#{ref_name}` is not found. #{token}" unless referring_symbol = candidates.first
146
+ 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.")
149
+ end
150
+
151
+ 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.")
154
+ end
151
155
 
152
156
  ref.index = referring_symbol[1] + 1
153
157
  end
@@ -167,7 +171,7 @@ module Lrama
167
171
  end
168
172
 
169
173
  def flush_user_code
170
- if c = @user_code
174
+ if (c = @user_code)
171
175
  @rhs << c
172
176
  @user_code = nil
173
177
  end