lrama 0.6.4 → 0.6.6
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.
- checksums.yaml +4 -4
- data/NEWS.md +40 -0
- data/lib/lrama/command.rb +5 -0
- data/lib/lrama/grammar/parameterizing_rule/resolver.rb +15 -6
- data/lib/lrama/grammar/parameterizing_rule/rule.rb +3 -2
- data/lib/lrama/grammar/rule.rb +5 -1
- data/lib/lrama/grammar/rule_builder.rb +69 -18
- data/lib/lrama/lexer/grammar_file.rb +11 -1
- data/lib/lrama/lexer/token/user_code.rb +2 -0
- data/lib/lrama/lexer.rb +1 -0
- data/lib/lrama/option_parser.rb +3 -2
- data/lib/lrama/parser.rb +539 -518
- data/lib/lrama/state.rb +3 -25
- data/lib/lrama/version.rb +1 -1
- data/parser.y +9 -1
- data/sample/calc.y +7 -4
- data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +5 -3
- data/sig/lrama/grammar/parameterizing_rule/rule.rbs +2 -1
- data/sig/lrama/grammar/rule_builder.rbs +5 -1
- data/sig/lrama/lexer/grammar_file.rbs +2 -0
- data/sig/lrama/lexer/token/user_code.rbs +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a24c7fd3c35d08a7e602fe74d4be9987f0415a1dc621ceb02ec4a722b1e16a0
|
4
|
+
data.tar.gz: fa3e0819afd1a454c17189c05f4c02260e35a252b09fdc828238f01b7ad3c58e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a5268674e4e8630a8efad69e82af94202f66da34530fdb87b7bd8d0e4cee93cf3881e1509d441fade31d1886f39e48b43c9f25178511983002a30fe19047266
|
7
|
+
data.tar.gz: 54122863a527a29a6279b9ad4c2732a378a138743d5d91e9c611ba9d66c7929f14385ee228b1dde7e20f2a4efc60fe1d9d5046fcb753c828daf64e4d9d465350
|
data/NEWS.md
CHANGED
@@ -1,5 +1,45 @@
|
|
1
1
|
# NEWS for Lrama
|
2
2
|
|
3
|
+
## Lrama 0.6.5 (2024-03-25)
|
4
|
+
|
5
|
+
### Typed Midrule Actions
|
6
|
+
|
7
|
+
User can specify the type of mid rule action by tag (`<bar>`) instead of specifying it with in an action.
|
8
|
+
|
9
|
+
```
|
10
|
+
primary: k_case expr_value terms?
|
11
|
+
{
|
12
|
+
$<val>$ = p->case_labels;
|
13
|
+
p->case_labels = Qnil;
|
14
|
+
}
|
15
|
+
case_body
|
16
|
+
k_end
|
17
|
+
{
|
18
|
+
...
|
19
|
+
}
|
20
|
+
```
|
21
|
+
|
22
|
+
can be written as
|
23
|
+
|
24
|
+
```
|
25
|
+
primary: k_case expr_value terms?
|
26
|
+
{
|
27
|
+
$$ = p->case_labels;
|
28
|
+
p->case_labels = Qnil;
|
29
|
+
}<val>
|
30
|
+
case_body
|
31
|
+
k_end
|
32
|
+
{
|
33
|
+
...
|
34
|
+
}
|
35
|
+
```
|
36
|
+
|
37
|
+
`%destructor` for midrule action is invoked only when tag is specified by Typed Midrule Actions.
|
38
|
+
|
39
|
+
Difference from Bison's Typed Midrule Actions is that tag is postposed in Lrama however it's preposed in Bison.
|
40
|
+
|
41
|
+
Bison supports this feature from 3.1.
|
42
|
+
|
3
43
|
## Lrama 0.6.4 (2024-03-22)
|
4
44
|
|
5
45
|
### Parameterizing rules (preceded, terminated, delimited)
|
data/lib/lrama/command.rb
CHANGED
@@ -47,6 +47,11 @@ module Lrama
|
|
47
47
|
puts grammar.rules
|
48
48
|
end
|
49
49
|
|
50
|
+
if options.trace_opts && options.trace_opts[:actions]
|
51
|
+
puts "Grammar rules with actions:"
|
52
|
+
grammar.rules.each { |rule| puts rule.with_actions }
|
53
|
+
end
|
54
|
+
|
50
55
|
File.open(options.outfile, "w+") do |f|
|
51
56
|
Lrama::Output.new(
|
52
57
|
out: f,
|
@@ -13,8 +13,12 @@ module Lrama
|
|
13
13
|
@rules << rule
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
select_rules(token).last
|
16
|
+
def find_rule(token)
|
17
|
+
select_rules(@rules, token).last
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_inline(token)
|
21
|
+
@rules.select { |rule| rule.name == token.s_value && rule.is_inline }.last
|
18
22
|
end
|
19
23
|
|
20
24
|
def created_lhs(lhs_s_value)
|
@@ -23,8 +27,9 @@ module Lrama
|
|
23
27
|
|
24
28
|
private
|
25
29
|
|
26
|
-
def select_rules(token)
|
27
|
-
rules =
|
30
|
+
def select_rules(rules, token)
|
31
|
+
rules = select_not_inline_rules(rules)
|
32
|
+
rules = select_rules_by_name(rules, token.rule_name)
|
28
33
|
rules = rules.select { |rule| rule.required_parameters_count == token.args_count }
|
29
34
|
if rules.empty?
|
30
35
|
raise "Invalid number of arguments. `#{token.rule_name}`"
|
@@ -33,8 +38,12 @@ module Lrama
|
|
33
38
|
end
|
34
39
|
end
|
35
40
|
|
36
|
-
def
|
37
|
-
rules
|
41
|
+
def select_not_inline_rules(rules)
|
42
|
+
rules.select { |rule| !rule.is_inline }
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_rules_by_name(rules, rule_name)
|
46
|
+
rules = rules.select { |rule| rule.name == rule_name }
|
38
47
|
if rules.empty?
|
39
48
|
raise "Parameterizing rule does not exist. `#{rule_name}`"
|
40
49
|
else
|
@@ -2,12 +2,13 @@ module Lrama
|
|
2
2
|
class Grammar
|
3
3
|
class ParameterizingRule
|
4
4
|
class Rule
|
5
|
-
attr_reader :name, :parameters, :rhs_list, :required_parameters_count
|
5
|
+
attr_reader :name, :parameters, :rhs_list, :required_parameters_count, :is_inline
|
6
6
|
|
7
|
-
def initialize(name, parameters, rhs_list)
|
7
|
+
def initialize(name, parameters, rhs_list, is_inline: false)
|
8
8
|
@name = name
|
9
9
|
@parameters = parameters
|
10
10
|
@rhs_list = rhs_list
|
11
|
+
@is_inline = is_inline
|
11
12
|
@required_parameters_count = parameters.count
|
12
13
|
end
|
13
14
|
end
|
data/lib/lrama/grammar/rule.rb
CHANGED
@@ -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 = empty_rule? ? "ε" : 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
|
@@ -32,6 +32,10 @@ module Lrama
|
|
32
32
|
"#{l}: #{r}"
|
33
33
|
end
|
34
34
|
|
35
|
+
def with_actions
|
36
|
+
"#{to_s} {#{token_code&.s_value}}"
|
37
|
+
end
|
38
|
+
|
35
39
|
# opt_nl: ε <-- empty_rule
|
36
40
|
# | '\n' <-- not empty_rule
|
37
41
|
def empty_rule?
|
@@ -16,8 +16,13 @@ module Lrama
|
|
16
16
|
@user_code = nil
|
17
17
|
@precedence_sym = nil
|
18
18
|
@line = nil
|
19
|
+
@rules = []
|
19
20
|
@rule_builders_for_parameterizing_rules = []
|
20
21
|
@rule_builders_for_derived_rules = []
|
22
|
+
@rule_builders_for_inline_rules = []
|
23
|
+
@parameterizing_rules = []
|
24
|
+
@inline_rules = []
|
25
|
+
@midrule_action_rules = []
|
21
26
|
end
|
22
27
|
|
23
28
|
def add_rhs(rhs)
|
@@ -52,12 +57,16 @@ module Lrama
|
|
52
57
|
|
53
58
|
def setup_rules(parameterizing_rule_resolver)
|
54
59
|
preprocess_references unless @skip_preprocess_references
|
55
|
-
|
60
|
+
if rhs.any? { |token| parameterizing_rule_resolver.find_inline(token) }
|
61
|
+
resolve_inline(parameterizing_rule_resolver)
|
62
|
+
else
|
63
|
+
process_rhs(parameterizing_rule_resolver)
|
64
|
+
end
|
56
65
|
build_rules
|
57
66
|
end
|
58
67
|
|
59
68
|
def rules
|
60
|
-
@parameterizing_rules + @midrule_action_rules + @rules
|
69
|
+
@parameterizing_rules + @inline_rules + @midrule_action_rules + @rules
|
61
70
|
end
|
62
71
|
|
63
72
|
private
|
@@ -73,19 +82,25 @@ module Lrama
|
|
73
82
|
def build_rules
|
74
83
|
tokens = @replaced_rhs
|
75
84
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
rule_builder
|
83
|
-
|
84
|
-
|
85
|
-
rule_builder
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
if tokens
|
86
|
+
rule = Rule.new(
|
87
|
+
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
|
88
|
+
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
|
89
|
+
)
|
90
|
+
@rules = [rule]
|
91
|
+
@parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
|
92
|
+
rule_builder.rules
|
93
|
+
end.flatten
|
94
|
+
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
|
95
|
+
rule_builder.rules
|
96
|
+
end.flatten
|
97
|
+
@midrule_action_rules.each do |r|
|
98
|
+
r.original_rule = rule
|
99
|
+
end
|
100
|
+
else
|
101
|
+
@inline_rules = @rule_builders_for_inline_rules.map do |rule_builder|
|
102
|
+
rule_builder.rules
|
103
|
+
end.flatten
|
89
104
|
end
|
90
105
|
end
|
91
106
|
|
@@ -103,7 +118,7 @@ module Lrama
|
|
103
118
|
when Lrama::Lexer::Token::Ident
|
104
119
|
@replaced_rhs << token
|
105
120
|
when Lrama::Lexer::Token::InstantiateRule
|
106
|
-
parameterizing_rule = parameterizing_rule_resolver.
|
121
|
+
parameterizing_rule = parameterizing_rule_resolver.find_rule(token)
|
107
122
|
raise "Unexpected token. #{token}" unless parameterizing_rule
|
108
123
|
|
109
124
|
bindings = Binding.new(parameterizing_rule, token.args)
|
@@ -115,7 +130,7 @@ module Lrama
|
|
115
130
|
@replaced_rhs << lhs_token
|
116
131
|
parameterizing_rule_resolver.created_lhs_list << lhs_token
|
117
132
|
parameterizing_rule.rhs_list.each do |r|
|
118
|
-
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag
|
133
|
+
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag)
|
119
134
|
rule_builder.lhs = lhs_token
|
120
135
|
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
|
121
136
|
rule_builder.line = line
|
@@ -128,10 +143,11 @@ module Lrama
|
|
128
143
|
end
|
129
144
|
when Lrama::Lexer::Token::UserCode
|
130
145
|
prefix = token.referred ? "@" : "$@"
|
146
|
+
tag = token.tag || lhs_tag
|
131
147
|
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
|
132
148
|
@replaced_rhs << new_token
|
133
149
|
|
134
|
-
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag:
|
150
|
+
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: tag, skip_preprocess_references: true)
|
135
151
|
rule_builder.lhs = new_token
|
136
152
|
rule_builder.user_code = token
|
137
153
|
rule_builder.complete_input
|
@@ -156,6 +172,41 @@ module Lrama
|
|
156
172
|
"#{token.rule_name}_#{s_values.join('_')}"
|
157
173
|
end
|
158
174
|
|
175
|
+
def resolve_inline(parameterizing_rule_resolver)
|
176
|
+
rhs.each_with_index do |token, i|
|
177
|
+
if inline_rule = parameterizing_rule_resolver.find_inline(token)
|
178
|
+
inline_rule.rhs_list.each_with_index do |inline_rhs|
|
179
|
+
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: lhs_tag, skip_preprocess_references: true)
|
180
|
+
resolve_inline_rhs(rule_builder, inline_rhs, i)
|
181
|
+
rule_builder.lhs = lhs
|
182
|
+
rule_builder.line = line
|
183
|
+
rule_builder.user_code = replace_inline_user_code(inline_rhs, i)
|
184
|
+
rule_builder.complete_input
|
185
|
+
rule_builder.setup_rules(parameterizing_rule_resolver)
|
186
|
+
@rule_builders_for_inline_rules << rule_builder
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def resolve_inline_rhs(rule_builder, inline_rhs, index)
|
193
|
+
rhs.each_with_index do |token, i|
|
194
|
+
if index == i
|
195
|
+
inline_rhs.symbols.each { |sym| rule_builder.add_rhs(sym) }
|
196
|
+
else
|
197
|
+
rule_builder.add_rhs(token)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def replace_inline_user_code(inline_rhs, index)
|
203
|
+
return user_code if inline_rhs.user_code.nil?
|
204
|
+
return user_code if user_code.nil?
|
205
|
+
|
206
|
+
code = user_code.s_value.gsub(/\$#{index + 1}/, inline_rhs.user_code.s_value)
|
207
|
+
Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
|
208
|
+
end
|
209
|
+
|
159
210
|
def numberize_references
|
160
211
|
# Bison n'th component is 1-origin
|
161
212
|
(rhs + [user_code]).compact.each.with_index(1) do |token, i|
|
@@ -1,11 +1,21 @@
|
|
1
1
|
module Lrama
|
2
2
|
class Lexer
|
3
3
|
class GrammarFile
|
4
|
+
class Text < String
|
5
|
+
def inspect
|
6
|
+
length <= 50 ? super : "#{self[0..47]}...".inspect
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
attr_reader :path, :text
|
5
11
|
|
6
12
|
def initialize(path, text)
|
7
13
|
@path = path
|
8
|
-
@text = text.freeze
|
14
|
+
@text = Text.new(text).freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"<#{self.class}: @path=#{path}, @text=#{text.inspect}>"
|
9
19
|
end
|
10
20
|
|
11
21
|
def ==(other)
|
data/lib/lrama/lexer.rb
CHANGED
data/lib/lrama/option_parser.rb
CHANGED
@@ -119,8 +119,9 @@ module Lrama
|
|
119
119
|
|
120
120
|
VALID_TRACES = %w[
|
121
121
|
none locations scan parse automaton bitsets
|
122
|
-
closure grammar rules resource
|
123
|
-
m4-early m4 skeleton time
|
122
|
+
closure grammar rules actions resource
|
123
|
+
sets muscles tools m4-early m4 skeleton time
|
124
|
+
ielr cex all
|
124
125
|
]
|
125
126
|
|
126
127
|
def validate_trace(trace)
|