lrama 0.6.2 → 0.6.4

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +2 -3
  3. data/Gemfile +1 -1
  4. data/NEWS.md +101 -1
  5. data/README.md +23 -0
  6. data/Steepfile +5 -0
  7. data/lib/lrama/context.rb +4 -4
  8. data/lib/lrama/grammar/code/destructor_code.rb +40 -0
  9. data/lib/lrama/grammar/code/initial_action_code.rb +6 -0
  10. data/lib/lrama/grammar/code/no_reference_code.rb +4 -0
  11. data/lib/lrama/grammar/code/printer_code.rb +6 -0
  12. data/lib/lrama/grammar/code/rule_action.rb +11 -1
  13. data/lib/lrama/grammar/code.rb +1 -0
  14. data/lib/lrama/grammar/destructor.rb +9 -0
  15. data/lib/lrama/grammar/reference.rb +4 -3
  16. data/lib/lrama/grammar/rule_builder.rb +10 -3
  17. data/lib/lrama/grammar/stdlib.y +42 -0
  18. data/lib/lrama/grammar/symbol.rb +4 -2
  19. data/lib/lrama/grammar/symbols/resolver.rb +293 -0
  20. data/lib/lrama/grammar/symbols.rb +1 -0
  21. data/lib/lrama/grammar.rb +32 -244
  22. data/lib/lrama/lexer/token/user_code.rb +13 -2
  23. data/lib/lrama/lexer/token.rb +1 -1
  24. data/lib/lrama/lexer.rb +7 -0
  25. data/lib/lrama/option_parser.rb +25 -12
  26. data/lib/lrama/options.rb +1 -0
  27. data/lib/lrama/output.rb +75 -2
  28. data/lib/lrama/parser.rb +537 -464
  29. data/lib/lrama/state.rb +4 -4
  30. data/lib/lrama/states/item.rb +6 -8
  31. data/lib/lrama/states_reporter.rb +2 -2
  32. data/lib/lrama/version.rb +1 -1
  33. data/lrama.gemspec +7 -0
  34. data/parser.y +27 -0
  35. data/sig/lrama/grammar/binding.rbs +0 -1
  36. data/sig/lrama/grammar/code/destructor_code.rbs +15 -0
  37. data/sig/lrama/grammar/destructor.rbs +11 -0
  38. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +0 -1
  39. data/sig/lrama/grammar/reference.rbs +2 -2
  40. data/sig/lrama/grammar/symbol.rbs +5 -4
  41. data/sig/lrama/grammar/symbols/resolver.rbs +41 -0
  42. data/sig/lrama/grammar/type.rbs +11 -0
  43. data/sig/lrama/options.rbs +17 -0
  44. data/template/bison/yacc.c +12 -1
  45. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4158de45c42ff62eacfb00737261feaa49d8f0cc646004e30da74ba4e2e69c6
4
- data.tar.gz: 734830227f701e18df2e9e8bc3da55d15f49c890e08530e6ac55ef87ae5f952d
3
+ metadata.gz: ce98751a4b4d20c20addf8eebf2a4eb22150b401abbb994941d73f2b2ef81a09
4
+ data.tar.gz: 94b83050b10ec5d01d61093cd2af595e52b3761cc8e86423fa8f30110e44e330
5
5
  SHA512:
6
- metadata.gz: 52ebbe4d099ae63d73aa995bddc8e966f989a4d00ad3b39634d2abe2448da404dd9bff8f15e0dedd0577716089329c804ef2c4edcadd39ca6ba47f8d293d101d
7
- data.tar.gz: 72e91c79618071b5850c85335cfe3f1b63ff89f11cd332b0141623a4e2a7e2c2c389dd0db9afe38a5a84b7aa891ac1834fc7a2d6c6eed8f62d87734f6b99cbbf
6
+ metadata.gz: e9e194703ec0b1657389f289b7c4d9cfd13326b1efe25e656080e5260ef2b7f3d4e93fd3d5d49e0934cfb394bc46b994c167a74c3dd2fb2ed3f3ebaaaf31647d
7
+ data.tar.gz: 59e1ed986bbea4ea4a56295d799f6ef5afee24e128fec66bc7ea8184f9bd849aa0807b5995b201e3dda274f6f0f023899a8c287e9a25818dae75c05e5c45cf6a
@@ -124,9 +124,8 @@ jobs:
124
124
  strategy:
125
125
  fail-fast: false
126
126
  matrix:
127
- # '3.0' is the oldest living ruby version
128
- # '2.7' is for BASERUBY
129
- baseruby: ['head', '3.0', '2.7']
127
+ # '3.0' is the oldest living ruby version and minimal BASERUBY version
128
+ baseruby: ['head', '3.0']
130
129
  ruby_branch: ['master']
131
130
  defaults:
132
131
  run:
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.1", require: false
15
+ gem "rbs", "3.4.4", require: false
16
16
  gem "steep", "1.6.0", require: false
17
17
  end
data/NEWS.md CHANGED
@@ -1,5 +1,105 @@
1
1
  # NEWS for Lrama
2
2
 
3
+ ## Lrama 0.6.4 (2024-03-22)
4
+
5
+ ### Parameterizing rules (preceded, terminated, delimited)
6
+
7
+ Support `preceded`, `terminated` and `delimited` rules.
8
+
9
+ ```
10
+ program: preceded(opening, X)
11
+
12
+ // Expanded to
13
+
14
+ program: preceded_opening_X
15
+ preceded_opening_X: opening X
16
+ ```
17
+
18
+ ```
19
+ program: terminated(X, closing)
20
+
21
+ // Expanded to
22
+
23
+ program: terminated_X_closing
24
+ terminated_X_closing: X closing
25
+ ```
26
+
27
+ ```
28
+ program: delimited(opening, X, closing)
29
+
30
+ // Expanded to
31
+
32
+ program: delimited_opening_X_closing
33
+ delimited_opening_X_closing: opening X closing
34
+ ```
35
+
36
+ https://github.com/ruby/lrama/pull/382
37
+
38
+ ### Support `%destructor` declaration
39
+
40
+ User can set codes for freeing semantic value resources by using `%destructor`.
41
+ In general, these resources are freed by actions or after parsing.
42
+ However if syntax error happens in parsing, these codes may not be executed.
43
+ Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error.
44
+
45
+ ```
46
+ %token <val1> NUM
47
+ %type <val2> expr2
48
+ %type <val3> expr
49
+
50
+ %destructor {
51
+ printf("destructor for val1: %d\n", $$);
52
+ } <val1> // printer for TAG
53
+
54
+ %destructor {
55
+ printf("destructor for val2: %d\n", $$);
56
+ } <val2>
57
+
58
+ %destructor {
59
+ printf("destructor for expr: %d\n", $$);
60
+ } expr // printer for symbol
61
+ ```
62
+
63
+ Bison supports this feature from 1.75b.
64
+
65
+ https://github.com/ruby/lrama/pull/385
66
+
67
+ ## Lrama 0.6.3 (2024-02-15)
68
+
69
+ ### Bring Your Own Stack
70
+
71
+ Provide functionalities for Bring Your Own Stack.
72
+
73
+ Ruby’s Ripper library requires their own semantic value stack to manage Ruby Objects returned by user defined callback method. Currently Ripper uses semantic value stack (`yyvsa`) which is used by parser to manage Node. This hack introduces some limitation on Ripper. For example, Ripper can not execute semantic analysis depending on Node structure.
74
+
75
+ Lrama introduces two features to support another semantic value stack by parser generator users.
76
+
77
+ 1. Callback entry points
78
+
79
+ User can emulate semantic value stack by these callbacks.
80
+ Lrama provides these five callbacks. Registered functions are called when each event happen. For example %after-shift function is called when shift happens on original semantic value stack.
81
+
82
+ * `%after-shift` function_name
83
+ * `%before-reduce` function_name
84
+ * `%after-reduce` function_name
85
+ * `%after-shift-error-token` function_name
86
+ * `%after-pop-stack` function_name
87
+
88
+ 2. `$:n` variable to access index of each grammar symbols
89
+
90
+ User also needs to access semantic value of their stack in grammar action. `$:n` provides the way to access to it. `$:n` is translated to the minus index from the top of the stack.
91
+ For example
92
+
93
+ ```
94
+ primary: k_if expr_value then compstmt if_tail k_end
95
+ {
96
+ /*% ripper: if!($:2, $:4, $:5) %*/
97
+ /* $:2 = -5, $:4 = -3, $:5 = -2. */
98
+ }
99
+ ```
100
+
101
+ https://github.com/ruby/lrama/pull/367
102
+
3
103
  ## Lrama 0.6.2 (2024-01-27)
4
104
 
5
105
  ### %no-stdlib directive
@@ -17,7 +117,7 @@ Allow to pass an instantiated rule to other parameterizing rules.
17
117
 
18
118
  ```
19
119
  %rule constant(X) : X
20
- ;
120
+ ;
21
121
 
22
122
  %rule option(Y) : /* empty */
23
123
  | Y
data/README.md CHANGED
@@ -1,7 +1,23 @@
1
1
  # Lrama
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/lrama.svg)](https://badge.fury.io/rb/lrama)
4
+ [![build](https://github.com/ruby/lrama/actions/workflows/test.yaml/badge.svg)](https://github.com/ruby/lrama/actions/workflows/test.yaml)
5
+
3
6
  Lrama is LALR (1) parser generator written by Ruby. The first goal of this project is providing error tolerant parser for CRuby with minimal changes on CRuby parse.y file.
4
7
 
8
+ * [Features](#features)
9
+ * [Installation](#installation)
10
+ * [Usage](#usage)
11
+ * [Versions and Branches](#versions-and-branches)
12
+ * [Supported Ruby version](#supported-ruby-version)
13
+ * [Development](#development)
14
+ * [How to generate parser.rb](#how-to-generate-parserrb)
15
+ * [Test](#test)
16
+ * [Profiling Lrama](#profiling-lrama)
17
+ * [Build Ruby](#build-ruby)
18
+ * [Release flow](#release-flow)
19
+ * [License](#license)
20
+
5
21
  ## Features
6
22
 
7
23
  * Bison style grammar file is supported with some assumptions
@@ -11,6 +27,9 @@ Lrama is LALR (1) parser generator written by Ruby. The first goal of this proje
11
27
  * b4_lac_if is always false
12
28
  * Error Tolerance parser
13
29
  * Subset of [Repairing Syntax Errors in LR Parsers (Corchuelo et al.)](https://idus.us.es/bitstream/handle/11441/65631/Repairing%20syntax%20errors.pdf) algorithm is supported
30
+ * Parameterizing rules
31
+ * The definition of a non-terminal symbol can be parameterized with other (terminal or non-terminal) symbols.
32
+ * Providing a generic definition of parameterizing rules as a [standard library](lib/lrama/grammar/stdlib.y).
14
33
 
15
34
  ## Installation
16
35
 
@@ -85,6 +104,8 @@ Running tests:
85
104
  ```shell
86
105
  $ bundle install
87
106
  $ bundle exec rspec
107
+ # or
108
+ $ bundle exec rake spec
88
109
  ```
89
110
 
90
111
  Running type check:
@@ -93,6 +114,8 @@ Running type check:
93
114
  $ bundle install
94
115
  $ bundle exec rbs collection install
95
116
  $ bundle exec steep check
117
+ # or
118
+ $ bundle exec rake steep
96
119
  ```
97
120
 
98
121
  Running both of them:
data/Steepfile CHANGED
@@ -5,21 +5,26 @@ target :lib do
5
5
  signature "sig"
6
6
 
7
7
  check "lib/lrama/grammar/binding.rb"
8
+ check "lib/lrama/grammar/code/destructor_code.rb"
8
9
  check "lib/lrama/grammar/code/printer_code.rb"
9
10
  check "lib/lrama/grammar/code.rb"
10
11
  check "lib/lrama/grammar/counter.rb"
11
12
  check "lib/lrama/grammar/error_token.rb"
12
13
  check "lib/lrama/grammar/parameterizing_rule"
13
14
  check "lib/lrama/grammar/parameterizing_rules"
15
+ check "lib/lrama/grammar/symbols"
14
16
  check "lib/lrama/grammar/percent_code.rb"
15
17
  check "lib/lrama/grammar/precedence.rb"
18
+ check "lib/lrama/grammar/destructor.rb"
16
19
  check "lib/lrama/grammar/printer.rb"
17
20
  check "lib/lrama/grammar/reference.rb"
18
21
  check "lib/lrama/grammar/rule_builder.rb"
19
22
  check "lib/lrama/grammar/symbol.rb"
23
+ check "lib/lrama/grammar/type.rb"
20
24
  check "lib/lrama/lexer"
21
25
  check "lib/lrama/report"
22
26
  check "lib/lrama/bitmap.rb"
23
27
  check "lib/lrama/digraph.rb"
28
+ check "lib/lrama/options.rb"
24
29
  check "lib/lrama/warning.rb"
25
30
  end
data/lib/lrama/context.rb CHANGED
@@ -265,9 +265,9 @@ module Lrama
265
265
 
266
266
  s = actions.each_with_index.map do |n, i|
267
267
  [i, n]
268
- end.select do |i, n|
268
+ end.reject do |i, n|
269
269
  # Remove default_reduction_rule entries
270
- n != 0
270
+ n == 0
271
271
  end
272
272
 
273
273
  if s.count != 0
@@ -462,7 +462,7 @@ module Lrama
462
462
  @yylast = high
463
463
 
464
464
  # replace_ninf
465
- @yypact_ninf = (@base.select {|i| i != BaseMin } + [0]).min - 1
465
+ @yypact_ninf = (@base.reject {|i| i == BaseMin } + [0]).min - 1
466
466
  @base.map! do |i|
467
467
  case i
468
468
  when BaseMin
@@ -472,7 +472,7 @@ module Lrama
472
472
  end
473
473
  end
474
474
 
475
- @yytable_ninf = (@table.compact.select {|i| i != ErrorActionNumber } + [0]).min - 1
475
+ @yytable_ninf = (@table.compact.reject {|i| i == ErrorActionNumber } + [0]).min - 1
476
476
  @table.map! do |i|
477
477
  case i
478
478
  when nil
@@ -0,0 +1,40 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Code
4
+ class DestructorCode < Code
5
+ def initialize(type:, token_code:, tag:)
6
+ super(type: type, token_code: token_code)
7
+ @tag = tag
8
+ end
9
+
10
+ private
11
+
12
+ # * ($$) *yyvaluep
13
+ # * (@$) *yylocationp
14
+ # * ($:$) error
15
+ # * ($1) error
16
+ # * (@1) error
17
+ # * ($:1) error
18
+ def reference_to_c(ref)
19
+ case
20
+ when ref.type == :dollar && ref.name == "$" # $$
21
+ member = @tag.member
22
+ "((*yyvaluep).#{member})"
23
+ when ref.type == :at && ref.name == "$" # @$
24
+ "(*yylocationp)"
25
+ when ref.type == :index && ref.name == "$" # $:$
26
+ raise "$:#{ref.value} can not be used in #{type}."
27
+ when ref.type == :dollar # $n
28
+ raise "$#{ref.value} can not be used in #{type}."
29
+ when ref.type == :at # @n
30
+ raise "@#{ref.value} can not be used in #{type}."
31
+ when ref.type == :index # $:n
32
+ raise "$:#{ref.value} can not be used in #{type}."
33
+ else
34
+ raise "Unexpected. #{self}, #{ref}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -6,18 +6,24 @@ module Lrama
6
6
 
7
7
  # * ($$) yylval
8
8
  # * (@$) yylloc
9
+ # * ($:$) error
9
10
  # * ($1) error
10
11
  # * (@1) error
12
+ # * ($:1) error
11
13
  def reference_to_c(ref)
12
14
  case
13
15
  when ref.type == :dollar && ref.name == "$" # $$
14
16
  "yylval"
15
17
  when ref.type == :at && ref.name == "$" # @$
16
18
  "yylloc"
19
+ when ref.type == :index && ref.name == "$" # $:$
20
+ raise "$:#{ref.value} can not be used in initial_action."
17
21
  when ref.type == :dollar # $n
18
22
  raise "$#{ref.value} can not be used in initial_action."
19
23
  when ref.type == :at # @n
20
24
  raise "@#{ref.value} can not be used in initial_action."
25
+ when ref.type == :index # $:n
26
+ raise "$:#{ref.value} can not be used in initial_action."
21
27
  else
22
28
  raise "Unexpected. #{self}, #{ref}"
23
29
  end
@@ -6,14 +6,18 @@ module Lrama
6
6
 
7
7
  # * ($$) error
8
8
  # * (@$) error
9
+ # * ($:$) error
9
10
  # * ($1) error
10
11
  # * (@1) error
12
+ # * ($:1) error
11
13
  def reference_to_c(ref)
12
14
  case
13
15
  when ref.type == :dollar # $$, $n
14
16
  raise "$#{ref.value} can not be used in #{type}."
15
17
  when ref.type == :at # @$, @n
16
18
  raise "@#{ref.value} can not be used in #{type}."
19
+ when ref.type == :index # $:$, $:n
20
+ raise "$:#{ref.value} can not be used in #{type}."
17
21
  else
18
22
  raise "Unexpected. #{self}, #{ref}"
19
23
  end
@@ -11,8 +11,10 @@ module Lrama
11
11
 
12
12
  # * ($$) *yyvaluep
13
13
  # * (@$) *yylocationp
14
+ # * ($:$) error
14
15
  # * ($1) error
15
16
  # * (@1) error
17
+ # * ($:1) error
16
18
  def reference_to_c(ref)
17
19
  case
18
20
  when ref.type == :dollar && ref.name == "$" # $$
@@ -20,10 +22,14 @@ module Lrama
20
22
  "((*yyvaluep).#{member})"
21
23
  when ref.type == :at && ref.name == "$" # @$
22
24
  "(*yylocationp)"
25
+ when ref.type == :index && ref.name == "$" # $:$
26
+ raise "$:#{ref.value} can not be used in #{type}."
23
27
  when ref.type == :dollar # $n
24
28
  raise "$#{ref.value} can not be used in #{type}."
25
29
  when ref.type == :at # @n
26
30
  raise "@#{ref.value} can not be used in #{type}."
31
+ when ref.type == :index # $:n
32
+ raise "$:#{ref.value} can not be used in #{type}."
27
33
  else
28
34
  raise "Unexpected. #{self}, #{ref}"
29
35
  end
@@ -11,8 +11,10 @@ module Lrama
11
11
 
12
12
  # * ($$) yyval
13
13
  # * (@$) yyloc
14
+ # * ($:$) error
14
15
  # * ($1) yyvsp[i]
15
16
  # * (@1) yylsp[i]
17
+ # * ($:1) i - 1
16
18
  #
17
19
  #
18
20
  # Consider a rule like
@@ -24,6 +26,8 @@ module Lrama
24
26
  # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
25
27
  # "Position in grammar" $1 $2 $3 $4 $5
26
28
  # "Index for yyvsp" -4 -3 -2 -1 0
29
+ # "$:n" $:1 $:2 $:3 $:4 $:5
30
+ # "index of $:n" -5 -4 -3 -2 -1
27
31
  #
28
32
  #
29
33
  # For the first midrule action:
@@ -31,6 +35,7 @@ module Lrama
31
35
  # "Rule" class: keyword_class { $1 } tSTRING { $2 + $3 } keyword_end { $class = $1 + $keyword_end }
32
36
  # "Position in grammar" $1
33
37
  # "Index for yyvsp" 0
38
+ # "$:n" $:1
34
39
  def reference_to_c(ref)
35
40
  case
36
41
  when ref.type == :dollar && ref.name == "$" # $$
@@ -39,6 +44,8 @@ module Lrama
39
44
  "(yyval.#{tag.member})"
40
45
  when ref.type == :at && ref.name == "$" # @$
41
46
  "(yyloc)"
47
+ when ref.type == :index && ref.name == "$" # $:$
48
+ raise "$:$ is not supported"
42
49
  when ref.type == :dollar # $n
43
50
  i = -position_in_rhs + ref.index
44
51
  tag = ref.ex_tag || rhs[ref.index - 1].tag
@@ -47,6 +54,9 @@ module Lrama
47
54
  when ref.type == :at # @n
48
55
  i = -position_in_rhs + ref.index
49
56
  "(yylsp[#{i}])"
57
+ when ref.type == :index # $:n
58
+ i = -position_in_rhs + ref.index
59
+ "(#{i} - 1)"
50
60
  else
51
61
  raise "Unexpected. #{self}, #{ref}"
52
62
  end
@@ -70,7 +80,7 @@ module Lrama
70
80
  end
71
81
 
72
82
  def raise_tag_not_found_error(ref)
73
- raise "Tag is not specified for '$#{ref.value}' in '#{@rule.to_s}'"
83
+ raise "Tag is not specified for '$#{ref.value}' in '#{@rule}'"
74
84
  end
75
85
  end
76
86
  end
@@ -1,4 +1,5 @@
1
1
  require "forwardable"
2
+ require "lrama/grammar/code/destructor_code"
2
3
  require "lrama/grammar/code/initial_action_code"
3
4
  require "lrama/grammar/code/no_reference_code"
4
5
  require "lrama/grammar/code/printer_code"
@@ -0,0 +1,9 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
4
+ def translated_code(tag)
5
+ Code::DestructorCode.new(type: :destructor, token_code: token_code, tag: tag).translated_code
6
+ end
7
+ end
8
+ end
9
+ end
@@ -2,11 +2,12 @@ module Lrama
2
2
  class Grammar
3
3
  # type: :dollar or :at
4
4
  # name: String (e.g. $$, $foo, $expr.right)
5
- # index: Integer (e.g. $1)
5
+ # number: Integer (e.g. $1)
6
+ # index: Integer
6
7
  # ex_tag: "$<tag>1" (Optional)
7
- class Reference < Struct.new(:type, :name, :index, :ex_tag, :first_column, :last_column, keyword_init: true)
8
+ class Reference < Struct.new(:type, :name, :number, :index, :ex_tag, :first_column, :last_column, keyword_init: true)
8
9
  def value
9
- name || index
10
+ name || number
10
11
  end
11
12
  end
12
13
  end
@@ -115,12 +115,12 @@ module Lrama
115
115
  @replaced_rhs << lhs_token
116
116
  parameterizing_rule_resolver.created_lhs_list << lhs_token
117
117
  parameterizing_rule.rhs_list.each do |r|
118
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
118
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
119
119
  rule_builder.lhs = lhs_token
120
120
  r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
121
121
  rule_builder.line = line
122
- rule_builder.user_code = r.user_code
123
122
  rule_builder.precedence_sym = r.precedence_sym
123
+ rule_builder.user_code = r.user_code
124
124
  rule_builder.complete_input
125
125
  rule_builder.setup_rules(parameterizing_rule_resolver)
126
126
  @rule_builders_for_parameterizing_rules << rule_builder
@@ -181,11 +181,18 @@ module Lrama
181
181
  if referring_symbol[1] == 0 # Refers to LHS
182
182
  ref.name = '$'
183
183
  else
184
- ref.index = referring_symbol[1]
184
+ ref.number = referring_symbol[1]
185
185
  end
186
186
  end
187
187
  end
188
188
 
189
+ if ref.number
190
+ # TODO: When Inlining is implemented, for example, if `$1` is expanded to multiple RHS tokens,
191
+ # `$2` needs to access `$2 + n` to actually access it. So, after the Inlining implementation,
192
+ # it needs resolves from number to index.
193
+ ref.index = ref.number
194
+ end
195
+
189
196
  # TODO: Need to check index of @ too?
190
197
  next if ref.type == :at
191
198
 
@@ -8,6 +8,9 @@
8
8
 
9
9
  **********************************************************************/
10
10
 
11
+ // -------------------------------------------------------------------
12
+ // Options
13
+
11
14
  /*
12
15
  * program: option(number)
13
16
  *
@@ -21,6 +24,45 @@
21
24
  | X
22
25
  ;
23
26
 
27
+ // -------------------------------------------------------------------
28
+ // Sequences
29
+
30
+ /*
31
+ * program: preceded(opening, X)
32
+ *
33
+ * =>
34
+ *
35
+ * program: preceded_opening_X
36
+ * preceded_opening_X: opening X
37
+ */
38
+ %rule preceded(opening, X): opening X { $$ = $2; }
39
+ ;
40
+
41
+ /*
42
+ * program: terminated(X, closing)
43
+ *
44
+ * =>
45
+ *
46
+ * program: terminated_X_closing
47
+ * terminated_X_closing: X closing
48
+ */
49
+ %rule terminated(X, closing): X closing { $$ = $1; }
50
+ ;
51
+
52
+ /*
53
+ * program: delimited(opening, X, closing)
54
+ *
55
+ * =>
56
+ *
57
+ * program: delimited_opening_X_closing
58
+ * delimited_opening_X_closing: opening X closing
59
+ */
60
+ %rule delimited(opening, X, closing): opening X closing { $$ = $2; }
61
+ ;
62
+
63
+ // -------------------------------------------------------------------
64
+ // Lists
65
+
24
66
  /*
25
67
  * program: list(number)
26
68
  *
@@ -7,11 +7,12 @@
7
7
  module Lrama
8
8
  class Grammar
9
9
  class Symbol
10
- attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, :printer, :error_token, :first_set, :first_set_bitmap
10
+ attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence,
11
+ :printer, :destructor, :error_token, :first_set, :first_set_bitmap
11
12
  attr_reader :term
12
13
  attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
13
14
 
14
- def initialize(id:, alias_name: nil, number: nil, tag: nil, term:, token_id: nil, nullable: nil, precedence: nil, printer: nil)
15
+ def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil, destructor: nil)
15
16
  @id = id
16
17
  @alias_name = alias_name
17
18
  @number = number
@@ -21,6 +22,7 @@ module Lrama
21
22
  @nullable = nullable
22
23
  @precedence = precedence
23
24
  @printer = printer
25
+ @destructor = destructor
24
26
  end
25
27
 
26
28
  def term?