lrama 0.6.2 → 0.6.4

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