lib/lrama/grammar/rule_builder.rb in lrama-0.6.9 vs lib/lrama/grammar/rule_builder.rb in lrama-0.6.10
- old
+ new
@@ -1,14 +1,17 @@
+# frozen_string_literal: true
+
module Lrama
class Grammar
class RuleBuilder
attr_accessor :lhs, :line
attr_reader :lhs_tag, :rhs, :user_code, :precedence_sym
- def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false)
+ def initialize(rule_counter, midrule_action_counter, parameterizing_rule_resolver, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false)
@rule_counter = rule_counter
@midrule_action_counter = midrule_action_counter
+ @parameterizing_rule_resolver = parameterizing_rule_resolver
@position_in_original_rule_rhs = position_in_original_rule_rhs
@skip_preprocess_references = skip_preprocess_references
@lhs = nil
@lhs_tag = lhs_tag
@@ -17,30 +20,24 @@
@precedence_sym = nil
@line = nil
@rules = []
@rule_builders_for_parameterizing_rules = []
@rule_builders_for_derived_rules = []
- @rule_builders_for_inline_rules = []
@parameterizing_rules = []
- @inline_rules = []
@midrule_action_rules = []
end
def add_rhs(rhs)
- if !@line
- @line = rhs.line
- end
+ @line ||= rhs.line
flush_user_code
@rhs << rhs
end
def user_code=(user_code)
- if !@line
- @line = user_code&.line
- end
+ @line ||= user_code&.line
flush_user_code
@user_code = user_code
end
@@ -53,24 +50,47 @@
def complete_input
freeze_rhs
end
- def setup_rules(parameterizing_rule_resolver)
+ def setup_rules
preprocess_references unless @skip_preprocess_references
- if rhs.any? { |token| parameterizing_rule_resolver.find_inline(token) }
- resolve_inline(parameterizing_rule_resolver)
- else
- process_rhs(parameterizing_rule_resolver)
- 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
def freeze_rhs
@rhs.freeze
end
@@ -80,35 +100,29 @@
end
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
# rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on.
# `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`.
- def process_rhs(parameterizing_rule_resolver)
+ def process_rhs
return if @replaced_rhs
@replaced_rhs = []
rhs.each_with_index do |token, i|
@@ -116,44 +130,44 @@
when Lrama::Lexer::Token::Char
@replaced_rhs << token
when Lrama::Lexer::Token::Ident
@replaced_rhs << token
when Lrama::Lexer::Token::InstantiateRule
- parameterizing_rule = parameterizing_rule_resolver.find_rule(token)
+ parameterizing_rule = @parameterizing_rule_resolver.find_rule(token)
raise "Unexpected token. #{token}" unless parameterizing_rule
bindings = Binding.new(parameterizing_rule, token.args)
lhs_s_value = lhs_s_value(token, bindings)
- if (created_lhs = parameterizing_rule_resolver.created_lhs(lhs_s_value))
+ if (created_lhs = @parameterizing_rule_resolver.created_lhs(lhs_s_value))
@replaced_rhs << created_lhs
else
lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
@replaced_rhs << lhs_token
- parameterizing_rule_resolver.created_lhs_list << lhs_token
+ @parameterizing_rule_resolver.created_lhs_list << lhs_token
parameterizing_rule.rhs_list.each do |r|
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag || parameterizing_rule.tag)
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: token.lhs_tag || parameterizing_rule.tag)
rule_builder.lhs = lhs_token
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
rule_builder.line = line
rule_builder.precedence_sym = r.precedence_sym
rule_builder.user_code = r.resolve_user_code(bindings)
rule_builder.complete_input
- rule_builder.setup_rules(parameterizing_rule_resolver)
+ rule_builder.setup_rules
@rule_builders_for_parameterizing_rules << rule_builder
end
end
when Lrama::Lexer::Token::UserCode
prefix = token.referred ? "@" : "$@"
tag = token.tag || lhs_tag
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
@replaced_rhs << new_token
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: tag, skip_preprocess_references: true)
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, i, lhs_tag: tag, skip_preprocess_references: true)
rule_builder.lhs = new_token
rule_builder.user_code = token
rule_builder.complete_input
- rule_builder.setup_rules(parameterizing_rule_resolver)
+ rule_builder.setup_rules
@rule_builders_for_derived_rules << rule_builder
else
raise "Unexpected token. #{token}"
end
@@ -170,31 +184,14 @@
end
end
"#{token.rule_name}_#{s_values.join('_')}"
end
- def resolve_inline(parameterizing_rule_resolver)
+ def resolve_inline_rhs(rule_builder, inline_rhs, index, bindings = nil)
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, 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(parameterizing_rule_resolver)
- @rule_builders_for_inline_rules << rule_builder
- end
- end
- end
- end
-
- def resolve_inline_rhs(rule_builder, inline_rhs, index)
- 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
end
end
@@ -202,10 +199,15 @@
def replace_inline_user_code(inline_rhs, index)
return user_code if inline_rhs.user_code.nil?
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
def numberize_references
# Bison n'th component is 1-origin
@@ -236,12 +238,9 @@
end
end
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
# TODO: Need to check index of @ too?
next if ref.type == :at