Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for adjusting Index to Inline #394

Merged
merged 11 commits into from
May 17, 2024
13 changes: 13 additions & 0 deletions lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def epilogue=(epilogue)
end

def prepare
resolve_inline_rules
normalize_rules
collect_symbols
set_lhs_and_rhs
Expand Down Expand Up @@ -292,6 +293,18 @@ def append_special_symbols
@accept_symbol = term
end

def resolve_inline_rules
while @rule_builders.any? {|r| r.has_inline_rules? } do
@rule_builders.map! do |builder|
if builder.has_inline_rules?
builder.resolve_inline_rules
else
builder
end
end.flatten!
end
end

def normalize_rules
# Add $accept rule to the top of rules
lineno = @rule_builders.first ? @rule_builders.first.line : 0
Expand Down
98 changes: 49 additions & 49 deletions lib/lrama/grammar/rule_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ def initialize(rule_counter, midrule_action_counter, parameterizing_rule_resolve
@rules = []
@rule_builders_for_parameterizing_rules = []
@rule_builders_for_derived_rules = []
@rule_builders_for_inline_rules = []
@parameterizing_rules = []
@inline_rules = []
@midrule_action_rules = []
end

Expand Down Expand Up @@ -58,16 +56,39 @@ def complete_input

def setup_rules
preprocess_references unless @skip_preprocess_references
if rhs.any? { |token| @parameterizing_rule_resolver.find_inline(token) }
resolve_inline
else
process_rhs
end
process_rhs
build_rules
end

def rules
@parameterizing_rules + @inline_rules + @midrule_action_rules + @rules
@parameterizing_rules + @midrule_action_rules + @rules
end

def has_inline_rules?
rhs.any? { |token| @parameterizing_rule_resolver.find_inline(token) }
end

def resolve_inline_rules
resolved_builders = []
rhs.each_with_index do |token, i|
if inline_rule = @parameterizing_rule_resolver.find_inline(token)
inline_rule.rhs_list.each do |inline_rhs|
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: lhs_tag)
if token.is_a?(Lexer::Token::InstantiateRule)
resolve_inline_rhs(rule_builder, inline_rhs, i, Binding.new(inline_rule, token.args))
else
resolve_inline_rhs(rule_builder, inline_rhs, i)
end
rule_builder.lhs = lhs
rule_builder.line = line
rule_builder.precedence_sym = precedence_sym
rule_builder.user_code = replace_inline_user_code(inline_rhs, i)
resolved_builders << rule_builder
end
break
end
end
resolved_builders
end

private
Expand All @@ -83,25 +104,19 @@ def preprocess_references
def build_rules
tokens = @replaced_rhs

if tokens
rule = Rule.new(
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
)
@rules = [rule]
@parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules.each do |r|
r.original_rule = rule
end
else
@inline_rules = @rule_builders_for_inline_rules.map do |rule_builder|
rule_builder.rules
end.flatten
rule = Rule.new(
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
)
@rules = [rule]
@parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules.each do |r|
r.original_rule = rule
end
end

Expand Down Expand Up @@ -173,27 +188,10 @@ def lhs_s_value(token, bindings)
"#{token.rule_name}_#{s_values.join('_')}"
end

def resolve_inline
rhs.each_with_index do |token, i|
if (inline_rule = @parameterizing_rule_resolver.find_inline(token))
inline_rule.rhs_list.each_with_index do |inline_rhs|
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: lhs_tag, skip_preprocess_references: true)
resolve_inline_rhs(rule_builder, inline_rhs, i)
rule_builder.lhs = lhs
rule_builder.line = line
rule_builder.user_code = replace_inline_user_code(inline_rhs, i)
rule_builder.complete_input
rule_builder.setup_rules
@rule_builders_for_inline_rules << rule_builder
end
end
end
end

def resolve_inline_rhs(rule_builder, inline_rhs, index)
def resolve_inline_rhs(rule_builder, inline_rhs, index, bindings = nil)
rhs.each_with_index do |token, i|
if index == i
inline_rhs.symbols.each { |sym| rule_builder.add_rhs(sym) }
inline_rhs.symbols.each { |sym| rule_builder.add_rhs(bindings.nil? ? sym : bindings.resolve_symbol(sym)) }
else
rule_builder.add_rhs(token)
end
Expand All @@ -205,6 +203,11 @@ def replace_inline_user_code(inline_rhs, index)
return user_code if user_code.nil?

code = user_code.s_value.gsub(/\$#{index + 1}/, inline_rhs.user_code.s_value)
user_code.references.each do |ref|
next if ref.index.nil? || ref.index <= index # nil is a case for `$$`
code = code.gsub(/\$#{ref.index}/, "$#{ref.index + (inline_rhs.symbols.count-1)}")
code = code.gsub(/@#{ref.index}/, "@#{ref.index + (inline_rhs.symbols.count-1)}")
end
Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
end

Expand Down Expand Up @@ -239,9 +242,6 @@ def numberize_references
end

if ref.number
# TODO: When Inlining is implemented, for example, if `$1` is expanded to multiple RHS tokens,
# `$2` needs to access `$2 + n` to actually access it. So, after the Inlining implementation,
# it needs resolves from number to index.
ref.index = ref.number
end

Expand Down
Loading