lrama 0.6.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +27 -7
  3. data/Gemfile +1 -1
  4. data/NEWS.md +55 -0
  5. data/Steepfile +2 -3
  6. data/lib/lrama/command.rb +25 -3
  7. data/lib/lrama/context.rb +3 -23
  8. data/lib/lrama/counterexamples/example.rb +2 -2
  9. data/lib/lrama/grammar/binding.rb +24 -0
  10. data/lib/lrama/grammar/code/rule_action.rb +1 -1
  11. data/lib/lrama/grammar/code.rb +1 -1
  12. data/lib/lrama/grammar/parameterizing_rule/resolver.rb +47 -0
  13. data/lib/lrama/grammar/parameterizing_rule/rhs.rb +15 -0
  14. data/lib/lrama/grammar/parameterizing_rule/rule.rb +16 -0
  15. data/lib/lrama/grammar/parameterizing_rule.rb +3 -6
  16. data/lib/lrama/grammar/percent_code.rb +3 -3
  17. data/lib/lrama/grammar/rule.rb +2 -2
  18. data/lib/lrama/grammar/rule_builder.rb +60 -31
  19. data/lib/lrama/grammar/stdlib.y +80 -0
  20. data/lib/lrama/grammar/type.rb +13 -1
  21. data/lib/lrama/grammar.rb +18 -11
  22. data/lib/lrama/lexer/grammar_file.rb +1 -1
  23. data/lib/lrama/lexer/token/instantiate_rule.rb +7 -2
  24. data/lib/lrama/lexer/token.rb +5 -0
  25. data/lib/lrama/lexer.rb +3 -7
  26. data/lib/lrama/output.rb +2 -2
  27. data/lib/lrama/parser.rb +508 -467
  28. data/lib/lrama/states/item.rb +17 -13
  29. data/lib/lrama/states_reporter.rb +8 -10
  30. data/lib/lrama/version.rb +1 -1
  31. data/parser.y +12 -13
  32. data/sig/lrama/grammar/binding.rbs +16 -0
  33. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +22 -0
  34. data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +13 -0
  35. data/sig/lrama/grammar/parameterizing_rule/rule.rbs +14 -0
  36. data/sig/lrama/grammar/parameterizing_rule.rbs +0 -4
  37. data/sig/lrama/grammar/percent_code.rbs +3 -3
  38. data/sig/lrama/grammar/rule_builder.rbs +9 -6
  39. data/sig/lrama/lexer/token/instantiate_rule.rbs +4 -2
  40. data/sig/lrama/lexer/token.rbs +1 -0
  41. metadata +12 -23
  42. data/lib/lrama/grammar/parameterizing_rule_builder.rb +0 -34
  43. data/lib/lrama/grammar/parameterizing_rule_resolver.rb +0 -30
  44. data/lib/lrama/grammar/parameterizing_rule_rhs_builder.rb +0 -53
  45. data/lib/lrama/grammar/parameterizing_rules/builder/base.rb +0 -36
  46. data/lib/lrama/grammar/parameterizing_rules/builder/list.rb +0 -28
  47. data/lib/lrama/grammar/parameterizing_rules/builder/nonempty_list.rb +0 -28
  48. data/lib/lrama/grammar/parameterizing_rules/builder/option.rb +0 -28
  49. data/lib/lrama/grammar/parameterizing_rules/builder/separated_list.rb +0 -39
  50. data/lib/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rb +0 -34
  51. data/lib/lrama/grammar/parameterizing_rules/builder.rb +0 -60
  52. data/sig/lrama/grammar/parameterizing_rule_builder.rbs +0 -19
  53. data/sig/lrama/grammar/parameterizing_rule_resolver.rbs +0 -16
  54. data/sig/lrama/grammar/parameterizing_rule_rhs_builder.rbs +0 -18
  55. data/sig/lrama/grammar/parameterizing_rules/builder/base.rbs +0 -28
  56. data/sig/lrama/grammar/parameterizing_rules/builder/list.rbs +0 -10
  57. data/sig/lrama/grammar/parameterizing_rules/builder/nonempty_list.rbs +0 -10
  58. data/sig/lrama/grammar/parameterizing_rules/builder/option.rbs +0 -10
  59. data/sig/lrama/grammar/parameterizing_rules/builder/separated_list.rbs +0 -13
  60. data/sig/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rbs +0 -13
  61. 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: 7b1a3e3181fc7060235e167ea97a92809b31aa5b74ef5978ab70415252bb87e3
4
- data.tar.gz: 51a6ee0620321936fcd9d81c44ece3f9e444b977dc8fa940ddf920a5bb3b1dad
3
+ metadata.gz: e4158de45c42ff62eacfb00737261feaa49d8f0cc646004e30da74ba4e2e69c6
4
+ data.tar.gz: 734830227f701e18df2e9e8bc3da55d15f49c890e08530e6ac55ef87ae5f952d
5
5
  SHA512:
6
- metadata.gz: f2b8805ad79cc0c3f125eba2715d274387191e6a355910d11c88f918eae4906b9398444162210c7ce955b1ba3f67cabf3b0679569a65d63bdc52328f2d7dc2f7
7
- data.tar.gz: 93de8cc0c7f9154f37825d59010a4850cc81b8a66f460d70f95aed44c0eb1224e583d1afb95155be2d9ae063d286a4fa719c133c993c6ec9bfba1c490dfc997b
6
+ metadata.gz: 52ebbe4d099ae63d73aa995bddc8e966f989a4d00ad3b39634d2abe2448da404dd9bff8f15e0dedd0577716089329c804ef2c4edcadd39ca6ba47f8d293d101d
7
+ data.tar.gz: 72e91c79618071b5850c85335cfe3f1b63ff89f11cd332b0141623a4e2a7e2c2c389dd0db9afe38a5a84b7aa891ac1834fc7a2d6c6eed8f62d87734f6b99cbbf
@@ -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:
@@ -72,6 +87,11 @@ jobs:
72
87
  bundler-cache: true
73
88
  - run: bundle install
74
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
+
75
95
  # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
76
96
  - name: Check for trailing spaces
77
97
  run: |
@@ -105,8 +125,8 @@ jobs:
105
125
  fail-fast: false
106
126
  matrix:
107
127
  # '3.0' is the oldest living ruby version
108
- # '2.5' is for BASERUBY
109
- baseruby: ['head', '3.0', '2.5']
128
+ # '2.7' is for BASERUBY
129
+ baseruby: ['head', '3.0', '2.7']
110
130
  ruby_branch: ['master']
111
131
  defaults:
112
132
  run:
@@ -118,12 +138,12 @@ jobs:
118
138
  ruby-version: ${{ matrix.baseruby }}
119
139
  bundler-cache: true
120
140
  - run: git clone --depth=1 https://github.com/ruby/ruby.git -b ${{ matrix.ruby_branch }} ../ruby
121
- working-directory:
141
+ working-directory: .
122
142
  - run: mkdir -p tool/lrama
123
143
  working-directory: ../ruby
124
144
  - name: Copy Lrama to ruby/tool
125
145
  run: cp -r LEGAL.md NEWS.md MIT exe lib template ../ruby/tool/lrama
126
- working-directory:
146
+ working-directory: .
127
147
  - run: tree tool/lrama
128
148
  working-directory: ../ruby
129
149
  # 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,58 @@
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
+
12
+ ## Lrama 0.6.1 (2024-01-13)
13
+
14
+ ### Nested parameterizing rules
15
+
16
+ Allow to pass an instantiated rule to other parameterizing rules.
17
+
18
+ ```
19
+ %rule constant(X) : X
20
+ ;
21
+
22
+ %rule option(Y) : /* empty */
23
+ | Y
24
+ ;
25
+
26
+ %%
27
+
28
+ program : option(constant(number)) // Nested rule
29
+ ;
30
+ %%
31
+ ```
32
+
33
+ Allow to use nested parameterizing rules when define parameterizing rules.
34
+
35
+ ```
36
+ %rule option(x) : /* empty */
37
+ | X
38
+ ;
39
+
40
+ %rule double(Y) : Y Y
41
+ ;
42
+
43
+ %rule double_opt(A) : option(double(A)) // Nested rule
44
+ ;
45
+
46
+ %%
47
+
48
+ program : double_opt(number)
49
+ ;
50
+
51
+ %%
52
+ ```
53
+
54
+ https://github.com/ruby/lrama/pull/337
55
+
3
56
  ## Lrama 0.6.0 (2023-12-25)
4
57
 
5
58
  ### User defined parameterizing rules
@@ -20,6 +73,8 @@ stmt: pair(ODD, EVEN) <num>
20
73
  ;
21
74
  ```
22
75
 
76
+ https://github.com/ruby/lrama/pull/285
77
+
23
78
  ## Lrama 0.5.11 (2023-12-02)
24
79
 
25
80
  ### 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,36 @@
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
- options = OptionParser.new.parse(argv)
7
+ begin
8
+ options = OptionParser.new.parse(argv)
9
+ rescue => e
10
+ message = e.message
11
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
12
+ abort message
13
+ end
5
14
 
6
15
  Report::Duration.enable if options.trace_opts[:time]
7
16
 
8
17
  warning = Lrama::Warning.new
9
18
  text = options.y.read
10
19
  options.y.close if options.y != STDIN
11
- grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
20
+ begin
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!
28
+ rescue => e
29
+ raise e if options.debug
30
+ message = e.message
31
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
32
+ abort message
33
+ end
12
34
  states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
13
35
  states.compute
14
36
  context = Lrama::Context.new(states)
@@ -39,7 +61,7 @@ module Lrama
39
61
  end
40
62
 
41
63
  if warning.has_error?
42
- exit 1
64
+ exit false
43
65
  end
44
66
  end
45
67
  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.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
@@ -241,7 +221,7 @@ module Lrama
241
221
 
242
222
  if state.reduces.map(&:selected_look_ahead).any? {|la| !la.empty? }
243
223
  # Iterate reduces with reverse order so that first rule is used.
244
- state.reduces.reverse.each do |reduce|
224
+ state.reduces.reverse_each do |reduce|
245
225
  reduce.look_ahead.each do |term|
246
226
  actions[term.number] = rule_id_to_action_number(reduce.rule.id)
247
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
 
@@ -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
  #
@@ -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
 
@@ -0,0 +1,47 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Resolver
5
+ attr_accessor :rules, :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 find(token)
17
+ select_rules(token).last
18
+ end
19
+
20
+ def created_lhs(lhs_s_value)
21
+ @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
22
+ end
23
+
24
+ private
25
+
26
+ def select_rules(token)
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
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ 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
@@ -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