lrama 0.5.12 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +20 -5
  3. data/Gemfile +1 -1
  4. data/NEWS.md +66 -0
  5. data/README.md +14 -3
  6. data/Steepfile +2 -0
  7. data/lib/lrama/command.rb +17 -3
  8. data/lib/lrama/context.rb +2 -22
  9. data/lib/lrama/grammar/binding.rb +24 -0
  10. data/lib/lrama/grammar/code/printer_code.rb +1 -1
  11. data/lib/lrama/grammar/code/rule_action.rb +2 -2
  12. data/lib/lrama/grammar/code.rb +19 -7
  13. data/lib/lrama/grammar/parameterizing_rule/resolver.rb +39 -0
  14. data/lib/lrama/grammar/parameterizing_rule/rhs.rb +15 -0
  15. data/lib/lrama/grammar/parameterizing_rule/rule.rb +16 -0
  16. data/lib/lrama/grammar/parameterizing_rule.rb +3 -0
  17. data/lib/lrama/grammar/percent_code.rb +3 -3
  18. data/lib/lrama/grammar/rule_builder.rb +69 -31
  19. data/lib/lrama/grammar/type.rb +13 -1
  20. data/lib/lrama/grammar.rb +15 -43
  21. data/lib/lrama/lexer/grammar_file.rb +21 -0
  22. data/lib/lrama/lexer/location.rb +77 -2
  23. data/lib/lrama/lexer/token/instantiate_rule.rb +23 -0
  24. data/lib/lrama/lexer/token/user_code.rb +10 -10
  25. data/lib/lrama/lexer/token.rb +6 -1
  26. data/lib/lrama/lexer.rb +23 -18
  27. data/lib/lrama/output.rb +2 -2
  28. data/lib/lrama/parser.rb +641 -458
  29. data/lib/lrama/states_reporter.rb +1 -1
  30. data/lib/lrama/version.rb +1 -1
  31. data/parser.y +97 -32
  32. data/sig/lrama/grammar/binding.rbs +16 -0
  33. data/sig/lrama/grammar/code/printer_code.rbs +1 -1
  34. data/sig/lrama/grammar/code.rbs +5 -5
  35. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +21 -0
  36. data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +13 -0
  37. data/sig/lrama/grammar/parameterizing_rule/rule.rbs +14 -0
  38. data/sig/lrama/grammar/parameterizing_rule.rbs +6 -0
  39. data/sig/lrama/grammar/parameterizing_rules/builder/base.rbs +2 -2
  40. data/sig/lrama/grammar/parameterizing_rules/builder.rbs +1 -1
  41. data/sig/lrama/grammar/percent_code.rbs +3 -3
  42. data/sig/lrama/grammar/rule_builder.rbs +9 -8
  43. data/sig/lrama/lexer/grammar_file.rbs +15 -0
  44. data/sig/lrama/lexer/location.rbs +13 -1
  45. data/sig/lrama/lexer/token/instantiate_rule.rbs +14 -0
  46. data/sig/lrama/lexer/token.rbs +1 -0
  47. metadata +17 -5
  48. data/lib/lrama/lexer/token/parameterizing.rb +0 -34
  49. data/sig/lrama/lexer/token/parameterizing.rbs +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '008f1a5df39b115123be84cb5e1edd379d88458bc95256b0e4fe4659481ceb51'
4
- data.tar.gz: 02af30da8cf4cb2cad841f43b603433edafab09b0cf0e8993201c2e9aea12029
3
+ metadata.gz: 50dc10cc2d790e778dcb6a35b789f146e69157b3c99d5b66059d95c025546ea6
4
+ data.tar.gz: cbc16ede0db21b5d22f74c47dfd7a87af2ae20e15f72afc9ea8a79980531861d
5
5
  SHA512:
6
- metadata.gz: 12cf8b98035052e89f9060dd73ec2b32ad9c5bec2fe4076e6ee0416832039962cf973c7ca895b482f2f434500648638c01a717d67357aa055eccce851995adaf
7
- data.tar.gz: a4cffc85bb5945a3d4d037c0eadee0df22e30236085e01f06bffe1646d0acafd09fdb606860752cdea9dbfdf45baa1fc8d244504b7a0ca29c37ab60f9a727367
6
+ metadata.gz: 7567e78e28cb912eb6dae8182827b5c6555924757bffe4fd9db81f79dd117aaf00f0918c90ead79d3567eeee802b90556540141fd5d4083bf5d6013c075cb20c
7
+ data.tar.gz: e58f803bc04114bdeb69b74a5e34ab9649241dafb9fe69a62f7d17ea87026411e3f743c54537fa092a9d6cea547a046fc762a78d9daebf92c3184be5502a24c1
@@ -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.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:
@@ -118,12 +133,12 @@ jobs:
118
133
  ruby-version: ${{ matrix.baseruby }}
119
134
  bundler-cache: true
120
135
  - run: git clone --depth=1 https://github.com/ruby/ruby.git -b ${{ matrix.ruby_branch }} ../ruby
121
- working-directory:
136
+ working-directory: .
122
137
  - run: mkdir -p tool/lrama
123
138
  working-directory: ../ruby
124
139
  - name: Copy Lrama to ruby/tool
125
140
  run: cp -r LEGAL.md NEWS.md MIT exe lib template ../ruby/tool/lrama
126
- working-directory:
141
+ working-directory: .
127
142
  - run: tree tool/lrama
128
143
  working-directory: ../ruby
129
144
  # 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.3.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,71 @@
1
1
  # NEWS for Lrama
2
2
 
3
+ ## Lrama 0.6.1 (2024-01-13)
4
+
5
+ ### Nested parameterizing rules
6
+
7
+ Allow to pass an instantiated rule to other parameterizing rules.
8
+
9
+ ```
10
+ %rule constant(X) : X
11
+ ;
12
+
13
+ %rule option(Y) : /* empty */
14
+ | Y
15
+ ;
16
+
17
+ %%
18
+
19
+ program : option(constant(number)) // Nested rule
20
+ ;
21
+ %%
22
+ ```
23
+
24
+ Allow to use nested parameterizing rules when define parameterizing rules.
25
+
26
+ ```
27
+ %rule option(x) : /* empty */
28
+ | X
29
+ ;
30
+
31
+ %rule double(Y) : Y Y
32
+ ;
33
+
34
+ %rule double_opt(A) : option(double(A)) // Nested rule
35
+ ;
36
+
37
+ %%
38
+
39
+ program : double_opt(number)
40
+ ;
41
+
42
+ %%
43
+ ```
44
+
45
+ https://github.com/ruby/lrama/pull/337
46
+
47
+ ## Lrama 0.6.0 (2023-12-25)
48
+
49
+ ### User defined parameterizing rules
50
+
51
+ Allow to define parameterizing rule by `%rule` directive.
52
+
53
+ ```
54
+ %rule pair(X, Y): X Y { $$ = $1 + $2; }
55
+ ;
56
+
57
+ %%
58
+
59
+ program: stmt
60
+ ;
61
+
62
+ stmt: pair(ODD, EVEN) <num>
63
+ | pair(EVEN, ODD) <num>
64
+ ;
65
+ ```
66
+
67
+ https://github.com/ruby/lrama/pull/285
68
+
3
69
  ## Lrama 0.5.11 (2023-12-02)
4
70
 
5
71
  ### Type specification of parameterizing rules
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,7 +147,7 @@ $ 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
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)
data/Steepfile CHANGED
@@ -4,10 +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"
12
+ check "lib/lrama/grammar/parameterizing_rule"
11
13
  check "lib/lrama/grammar/parameterizing_rules"
12
14
  check "lib/lrama/grammar/percent_code.rb"
13
15
  check "lib/lrama/grammar/precedence.rb"
data/lib/lrama/command.rb CHANGED
@@ -1,14 +1,28 @@
1
1
  module Lrama
2
2
  class Command
3
3
  def run(argv)
4
- options = OptionParser.new.parse(argv)
4
+ begin
5
+ options = OptionParser.new.parse(argv)
6
+ rescue => e
7
+ message = e.message
8
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
9
+ abort message
10
+ end
5
11
 
6
12
  Report::Duration.enable if options.trace_opts[:time]
7
13
 
8
14
  warning = Lrama::Warning.new
9
15
  text = options.y.read
10
16
  options.y.close if options.y != STDIN
11
- grammar = Lrama::Parser.new(text, options.grammar_file, options.debug).parse
17
+ parser = Lrama::Parser.new(text, options.grammar_file, options.debug)
18
+ begin
19
+ grammar = parser.parse
20
+ rescue => e
21
+ raise e if options.debug
22
+ message = e.message
23
+ message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
24
+ abort message
25
+ end
12
26
  states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
13
27
  states.compute
14
28
  context = Lrama::Context.new(states)
@@ -39,7 +53,7 @@ module Lrama
39
53
  end
40
54
 
41
55
  if warning.has_error?
42
- exit 1
56
+ exit false
43
57
  end
44
58
  end
45
59
  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.rule.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
@@ -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
@@ -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
@@ -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
  #
@@ -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,39 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ParameterizingRule
4
+ class Resolver
5
+ attr_accessor :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 defined?(token)
17
+ !select_rules(token).empty?
18
+ end
19
+
20
+ def find(token)
21
+ select_rules(token).last
22
+ end
23
+
24
+ def created_lhs(lhs_s_value)
25
+ @created_lhs_list.select { |created_lhs| created_lhs.s_value == lhs_s_value }.last
26
+ end
27
+
28
+ private
29
+
30
+ def select_rules(token)
31
+ @rules.select do |rule|
32
+ rule.name == token.rule_name &&
33
+ rule.required_parameters_count == token.args_count
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ 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
@@ -0,0 +1,3 @@
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