lrama 0.6.1 → 0.6.2

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +7 -2
  3. data/NEWS.md +9 -0
  4. data/lib/lrama/command.rb +10 -2
  5. data/lib/lrama/context.rb +2 -2
  6. data/lib/lrama/counterexamples/example.rb +2 -2
  7. data/lib/lrama/grammar/code.rb +1 -1
  8. data/lib/lrama/grammar/parameterizing_rule/resolver.rb +17 -9
  9. data/lib/lrama/grammar/rule.rb +2 -2
  10. data/lib/lrama/grammar/rule_builder.rb +31 -36
  11. data/lib/lrama/grammar/stdlib.y +80 -0
  12. data/lib/lrama/grammar.rb +11 -2
  13. data/lib/lrama/lexer.rb +1 -0
  14. data/lib/lrama/parser.rb +474 -451
  15. data/lib/lrama/states/item.rb +17 -13
  16. data/lib/lrama/states_reporter.rb +8 -10
  17. data/lib/lrama/version.rb +1 -1
  18. data/parser.y +4 -5
  19. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +1 -0
  20. metadata +3 -16
  21. data/lib/lrama/grammar/parameterizing_rules/builder/base.rb +0 -36
  22. data/lib/lrama/grammar/parameterizing_rules/builder/list.rb +0 -28
  23. data/lib/lrama/grammar/parameterizing_rules/builder/nonempty_list.rb +0 -28
  24. data/lib/lrama/grammar/parameterizing_rules/builder/option.rb +0 -28
  25. data/lib/lrama/grammar/parameterizing_rules/builder/separated_list.rb +0 -39
  26. data/lib/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rb +0 -34
  27. data/lib/lrama/grammar/parameterizing_rules/builder.rb +0 -60
  28. data/sig/lrama/grammar/parameterizing_rules/builder/base.rbs +0 -28
  29. data/sig/lrama/grammar/parameterizing_rules/builder/list.rbs +0 -10
  30. data/sig/lrama/grammar/parameterizing_rules/builder/nonempty_list.rbs +0 -10
  31. data/sig/lrama/grammar/parameterizing_rules/builder/option.rbs +0 -10
  32. data/sig/lrama/grammar/parameterizing_rules/builder/separated_list.rbs +0 -13
  33. data/sig/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rbs +0 -13
  34. data/sig/lrama/grammar/parameterizing_rules/builder.rbs +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50dc10cc2d790e778dcb6a35b789f146e69157b3c99d5b66059d95c025546ea6
4
- data.tar.gz: cbc16ede0db21b5d22f74c47dfd7a87af2ae20e15f72afc9ea8a79980531861d
3
+ metadata.gz: e4158de45c42ff62eacfb00737261feaa49d8f0cc646004e30da74ba4e2e69c6
4
+ data.tar.gz: 734830227f701e18df2e9e8bc3da55d15f49c890e08530e6ac55ef87ae5f952d
5
5
  SHA512:
6
- metadata.gz: 7567e78e28cb912eb6dae8182827b5c6555924757bffe4fd9db81f79dd117aaf00f0918c90ead79d3567eeee802b90556540141fd5d4083bf5d6013c075cb20c
7
- data.tar.gz: e58f803bc04114bdeb69b74a5e34ab9649241dafb9fe69a62f7d17ea87026411e3f743c54537fa092a9d6cea547a046fc762a78d9daebf92c3184be5502a24c1
6
+ metadata.gz: 52ebbe4d099ae63d73aa995bddc8e966f989a4d00ad3b39634d2abe2448da404dd9bff8f15e0dedd0577716089329c804ef2c4edcadd39ca6ba47f8d293d101d
7
+ data.tar.gz: 72e91c79618071b5850c85335cfe3f1b63ff89f11cd332b0141623a4e2a7e2c2c389dd0db9afe38a5a84b7aa891ac1834fc7a2d6c6eed8f62d87734f6b99cbbf
@@ -87,6 +87,11 @@ jobs:
87
87
  bundler-cache: true
88
88
  - run: bundle install
89
89
 
90
+ # Copy from https://github.com/ruby/ruby/blob/cb9a47f2acd6e373ef868b890a9d07da6f565dd4/.github/workflows/check_misc.yml#L31
91
+ - name: Check if C-sources are US-ASCII
92
+ run: |
93
+ grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
94
+
90
95
  # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
91
96
  - name: Check for trailing spaces
92
97
  run: |
@@ -120,8 +125,8 @@ jobs:
120
125
  fail-fast: false
121
126
  matrix:
122
127
  # '3.0' is the oldest living ruby version
123
- # '2.5' is for BASERUBY
124
- baseruby: ['head', '3.0', '2.5']
128
+ # '2.7' is for BASERUBY
129
+ baseruby: ['head', '3.0', '2.7']
125
130
  ruby_branch: ['master']
126
131
  defaults:
127
132
  run:
data/NEWS.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # NEWS for Lrama
2
2
 
3
+ ## Lrama 0.6.2 (2024-01-27)
4
+
5
+ ### %no-stdlib directive
6
+
7
+ If `%no-stdlib` directive is set, Lrama doesn't load Lrama standard library for
8
+ parameterizing rules, stdlib.y.
9
+
10
+ https://github.com/ruby/lrama/pull/344
11
+
3
12
  ## Lrama 0.6.1 (2024-01-13)
4
13
 
5
14
  ### Nested parameterizing rules
data/lib/lrama/command.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  module Lrama
2
2
  class Command
3
+ LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
4
+ STDLIB_FILE_PATH = File.join(LRAMA_LIB, 'grammar', 'stdlib.y')
5
+
3
6
  def run(argv)
4
7
  begin
5
8
  options = OptionParser.new.parse(argv)
@@ -14,9 +17,14 @@ module Lrama
14
17
  warning = Lrama::Warning.new
15
18
  text = options.y.read
16
19
  options.y.close if options.y != STDIN
17
- parser = Lrama::Parser.new(text, options.grammar_file, options.debug)
18
20
  begin
19
- grammar = parser.parse
21
+ grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
22
+ unless grammar.no_stdlib
23
+ stdlib_grammar = Lrama::Parser.new(File.read(STDLIB_FILE_PATH), STDLIB_FILE_PATH, options.debug).parse
24
+ grammar.insert_before_parameterizing_rules(stdlib_grammar.parameterizing_rules)
25
+ end
26
+ grammar.prepare
27
+ grammar.validate!
20
28
  rescue => e
21
29
  raise e if options.debug
22
30
  message = e.message
data/lib/lrama/context.rb CHANGED
@@ -41,7 +41,7 @@ module Lrama
41
41
  def yyfinal
42
42
  @states.states.find do |state|
43
43
  state.items.find do |item|
44
- item.rule.lhs.accept_symbol? && item.end_of_rule?
44
+ item.lhs.accept_symbol? && item.end_of_rule?
45
45
  end
46
46
  end.id
47
47
  end
@@ -221,7 +221,7 @@ module Lrama
221
221
 
222
222
  if state.reduces.map(&:selected_look_ahead).any? {|la| !la.empty? }
223
223
  # Iterate reduces with reverse order so that first rule is used.
224
- state.reduces.reverse.each do |reduce|
224
+ state.reduces.reverse_each do |reduce|
225
225
  reduce.look_ahead.each do |term|
226
226
  actions[term.number] = rule_id_to_action_number(reduce.rule.id)
227
227
  end
@@ -40,7 +40,7 @@ module Lrama
40
40
  current = :production
41
41
  lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
42
42
 
43
- paths.reverse.each do |path|
43
+ paths.reverse_each do |path|
44
44
  item = path.to.item
45
45
 
46
46
  case current
@@ -97,7 +97,7 @@ module Lrama
97
97
  if next_sym == sym
98
98
  derivation = nil
99
99
 
100
- sis.reverse.each do |si|
100
+ sis.reverse_each do |si|
101
101
  derivation = Derivation.new(si.item, derivation)
102
102
  end
103
103
 
@@ -28,7 +28,7 @@ module Lrama
28
28
  def translated_code
29
29
  t_code = s_value.dup
30
30
 
31
- references.reverse.each do |ref|
31
+ references.reverse_each do |ref|
32
32
  first_column = ref.first_column
33
33
  last_column = ref.last_column
34
34
 
@@ -2,7 +2,7 @@ module Lrama
2
2
  class Grammar
3
3
  class ParameterizingRule
4
4
  class Resolver
5
- attr_accessor :created_lhs_list
5
+ attr_accessor :rules, :created_lhs_list
6
6
 
7
7
  def initialize
8
8
  @rules = []
@@ -13,24 +13,32 @@ module Lrama
13
13
  @rules << rule
14
14
  end
15
15
 
16
- def defined?(token)
17
- !select_rules(token).empty?
18
- end
19
-
20
16
  def find(token)
21
17
  select_rules(token).last
22
18
  end
23
19
 
24
20
  def created_lhs(lhs_s_value)
25
- @created_lhs_list.select { |created_lhs| created_lhs.s_value == lhs_s_value }.last
21
+ @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
26
22
  end
27
23
 
28
24
  private
29
25
 
30
26
  def select_rules(token)
31
- @rules.select do |rule|
32
- rule.name == token.rule_name &&
33
- rule.required_parameters_count == token.args_count
27
+ rules = select_rules_by_name(token.rule_name)
28
+ rules = rules.select { |rule| rule.required_parameters_count == token.args_count }
29
+ if rules.empty?
30
+ raise "Invalid number of arguments. `#{token.rule_name}`"
31
+ else
32
+ rules
33
+ end
34
+ end
35
+
36
+ def select_rules_by_name(rule_name)
37
+ rules = @rules.select { |rule| rule.name == rule_name }
38
+ if rules.empty?
39
+ raise "Parameterizing rule does not exist. `#{rule_name}`"
40
+ else
41
+ rules
34
42
  end
35
43
  end
36
44
  end
@@ -19,7 +19,7 @@ module Lrama
19
19
  # TODO: Change this to display_name
20
20
  def to_s
21
21
  l = lhs.id.s_value
22
- r = rhs.empty? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
22
+ r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
23
23
 
24
24
  "#{l} -> #{r}"
25
25
  end
@@ -27,7 +27,7 @@ module Lrama
27
27
  # Used by #user_actions
28
28
  def as_comment
29
29
  l = lhs.id.s_value
30
- r = rhs.empty? ? "%empty" : rhs.map(&:display_name).join(" ")
30
+ r = empty_rule? ? "%empty" : rhs.map(&:display_name).join(" ")
31
31
 
32
32
  "#{l}: #{r}"
33
33
  end
@@ -1,5 +1,3 @@
1
- require 'lrama/grammar/parameterizing_rules/builder'
2
-
3
1
  module Lrama
4
2
  class Grammar
5
3
  class RuleBuilder
@@ -59,7 +57,7 @@ module Lrama
59
57
  end
60
58
 
61
59
  def rules
62
- @parameterizing_rules + @old_parameterizing_rules + @midrule_action_rules + @rules
60
+ @parameterizing_rules + @midrule_action_rules + @rules
63
61
  end
64
62
 
65
63
  private
@@ -97,7 +95,6 @@ module Lrama
97
95
  return if @replaced_rhs
98
96
 
99
97
  @replaced_rhs = []
100
- @old_parameterizing_rules = []
101
98
 
102
99
  rhs.each_with_index do |token, i|
103
100
  case token
@@ -106,35 +103,28 @@ module Lrama
106
103
  when Lrama::Lexer::Token::Ident
107
104
  @replaced_rhs << token
108
105
  when Lrama::Lexer::Token::InstantiateRule
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
106
+ parameterizing_rule = parameterizing_rule_resolver.find(token)
107
+ raise "Unexpected token. #{token}" unless parameterizing_rule
108
+
109
+ bindings = Binding.new(parameterizing_rule, token.args)
110
+ lhs_s_value = lhs_s_value(token, bindings)
111
+ if (created_lhs = parameterizing_rule_resolver.created_lhs(lhs_s_value))
112
+ @replaced_rhs << created_lhs
133
113
  else
134
- # TODO: Delete when the standard library will defined as a grammar file.
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
+ lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
115
+ @replaced_rhs << lhs_token
116
+ parameterizing_rule_resolver.created_lhs_list << lhs_token
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)
119
+ rule_builder.lhs = lhs_token
120
+ r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
121
+ rule_builder.line = line
122
+ rule_builder.user_code = r.user_code
123
+ rule_builder.precedence_sym = r.precedence_sym
124
+ rule_builder.complete_input
125
+ rule_builder.setup_rules(parameterizing_rule_resolver)
126
+ @rule_builders_for_parameterizing_rules << rule_builder
127
+ end
138
128
  end
139
129
  when Lrama::Lexer::Token::UserCode
140
130
  prefix = token.referred ? "@" : "$@"
@@ -173,11 +163,12 @@ module Lrama
173
163
 
174
164
  token.references.each do |ref|
175
165
  ref_name = ref.name
176
- if ref_name && ref_name != '$'
177
- if lhs.referred_by?(ref_name)
166
+
167
+ if ref_name
168
+ if ref_name == '$'
178
169
  ref.name = '$'
179
170
  else
180
- candidates = rhs.each_with_index.select {|token, i| token.referred_by?(ref_name) }
171
+ candidates = ([lhs] + rhs).each_with_index.select {|token, _i| token.referred_by?(ref_name) }
181
172
 
182
173
  if candidates.size >= 2
183
174
  token.invalid_ref(ref, "Referring symbol `#{ref_name}` is duplicated.")
@@ -187,7 +178,11 @@ module Lrama
187
178
  token.invalid_ref(ref, "Referring symbol `#{ref_name}` is not found.")
188
179
  end
189
180
 
190
- ref.index = referring_symbol[1] + 1
181
+ if referring_symbol[1] == 0 # Refers to LHS
182
+ ref.name = '$'
183
+ else
184
+ ref.index = referring_symbol[1]
185
+ end
191
186
  end
192
187
  end
193
188
 
@@ -0,0 +1,80 @@
1
+ /**********************************************************************
2
+
3
+ stdlib.y
4
+
5
+ This is lrama's standard library. It provides a number of
6
+ parameterizing rule definitions, such as options and lists,
7
+ that should be useful in a number of situations.
8
+
9
+ **********************************************************************/
10
+
11
+ /*
12
+ * program: option(number)
13
+ *
14
+ * =>
15
+ *
16
+ * program: option_number
17
+ * option_number: %empty
18
+ * option_number: number
19
+ */
20
+ %rule option(X): /* empty */
21
+ | X
22
+ ;
23
+
24
+ /*
25
+ * program: list(number)
26
+ *
27
+ * =>
28
+ *
29
+ * program: list_number
30
+ * list_number: %empty
31
+ * list_number: list_number number
32
+ */
33
+ %rule list(X): /* empty */
34
+ | list(X) X
35
+ ;
36
+
37
+ /*
38
+ * program: nonempty_list(number)
39
+ *
40
+ * =>
41
+ *
42
+ * program: nonempty_list_number
43
+ * nonempty_list_number: number
44
+ * nonempty_list_number: nonempty_list_number number
45
+ */
46
+ %rule nonempty_list(X): X
47
+ | nonempty_list(X) X
48
+ ;
49
+
50
+ /*
51
+ * program: separated_nonempty_list(comma, number)
52
+ *
53
+ * =>
54
+ *
55
+ * program: separated_nonempty_list_comma_number
56
+ * separated_nonempty_list_comma_number: number
57
+ * separated_nonempty_list_comma_number: separated_nonempty_list_comma_number comma number
58
+ */
59
+ %rule separated_nonempty_list(separator, X): X
60
+ | separated_nonempty_list(separator, X) separator X
61
+ ;
62
+
63
+ /*
64
+ * program: separated_list(comma, number)
65
+ *
66
+ * =>
67
+ *
68
+ * program: separated_list_comma_number
69
+ * separated_list_comma_number: option_separated_nonempty_list_comma_number
70
+ * option_separated_nonempty_list_comma_number: %empty
71
+ * option_separated_nonempty_list_comma_number: separated_nonempty_list_comma_number
72
+ * separated_nonempty_list_comma_number: number
73
+ * separated_nonempty_list_comma_number: comma separated_nonempty_list_comma_number number
74
+ */
75
+ %rule separated_list(separator, X): option(separated_nonempty_list(separator, X))
76
+ ;
77
+
78
+ %%
79
+
80
+ %union{};
data/lib/lrama/grammar.rb CHANGED
@@ -24,7 +24,7 @@ module Lrama
24
24
  :lex_param, :parse_param, :initial_action,
25
25
  :symbols, :types,
26
26
  :rules, :rule_builders,
27
- :sym_to_rules
27
+ :sym_to_rules, :no_stdlib
28
28
 
29
29
  def initialize(rule_counter)
30
30
  @rule_counter = rule_counter
@@ -45,6 +45,7 @@ module Lrama
45
45
  @undef_symbol = nil
46
46
  @accept_symbol = nil
47
47
  @aux = Auxiliary.new
48
+ @no_stdlib = false
48
49
 
49
50
  append_special_symbols
50
51
  end
@@ -136,6 +137,14 @@ module Lrama
136
137
  @parameterizing_rule_resolver.add_parameterizing_rule(rule)
137
138
  end
138
139
 
140
+ def parameterizing_rules
141
+ @parameterizing_rule_resolver.rules
142
+ end
143
+
144
+ def insert_before_parameterizing_rules(rules)
145
+ @parameterizing_rule_resolver.rules = rules + @parameterizing_rule_resolver.rules
146
+ end
147
+
139
148
  def prologue_first_lineno=(prologue_first_lineno)
140
149
  @aux.prologue_first_lineno = prologue_first_lineno
141
150
  end
@@ -234,7 +243,7 @@ module Lrama
234
243
  def compute_nullable
235
244
  @rules.each do |rule|
236
245
  case
237
- when rule.rhs.empty?
246
+ when rule.empty_rule?
238
247
  rule.nullable = true
239
248
  when rule.rhs.any?(&:term)
240
249
  rule.nullable = false
data/lib/lrama/lexer.rb CHANGED
@@ -29,6 +29,7 @@ module Lrama
29
29
  %empty
30
30
  %code
31
31
  %rule
32
+ %no-stdlib
32
33
  )
33
34
 
34
35
  def initialize(grammar_file)