Skip to content

Commit

Permalink
Merge pull request #210 from yui-knk/separate_reference_index_and_name
Browse files Browse the repository at this point in the history
Separate Reference value into index and name
yui-knk authored Nov 9, 2023
2 parents b1a23cb + 2a5e1e2 commit 6b0e22b
Showing 8 changed files with 79 additions and 54 deletions.
4 changes: 2 additions & 2 deletions lib/lrama/grammar/code/initial_action_code.rb
Original file line number Diff line number Diff line change
@@ -10,9 +10,9 @@ class InitialActionCode < Code
# * (@1) error
def reference_to_c(ref)
case
when ref.type == :dollar && ref.value == "$" # $$
when ref.type == :dollar && ref.name == "$" # $$
"yylval"
when ref.type == :at && ref.value == "$" # @$
when ref.type == :at && ref.name == "$" # @$
"yylloc"
when ref.type == :dollar # $n
raise "$#{ref.value} can not be used in initial_action."
4 changes: 2 additions & 2 deletions lib/lrama/grammar/code/printer_code.rb
Original file line number Diff line number Diff line change
@@ -15,10 +15,10 @@ def initialize(type: nil, token_code: nil, tag: nil)
# * (@1) error
def reference_to_c(ref)
case
when ref.type == :dollar && ref.value == "$" # $$
when ref.type == :dollar && ref.name == "$" # $$
member = @tag.member
"((*yyvaluep).#{member})"
when ref.type == :at && ref.value == "$" # @$
when ref.type == :at && ref.name == "$" # @$
"(*yylocationp)"
when ref.type == :dollar # $n
raise "$#{ref.value} can not be used in #{type}."
8 changes: 4 additions & 4 deletions lib/lrama/grammar/code/rule_action.rb
Original file line number Diff line number Diff line change
@@ -10,17 +10,17 @@ class RuleAction < Code
# * (@1) yylsp[i]
def reference_to_c(ref)
case
when ref.type == :dollar && ref.value == "$" # $$
when ref.type == :dollar && ref.name == "$" # $$
member = ref.tag.member
"(yyval.#{member})"
when ref.type == :at && ref.value == "$" # @$
when ref.type == :at && ref.name == "$" # @$
"(yyloc)"
when ref.type == :dollar # $n
i = -ref.position_in_rhs + ref.value
i = -ref.position_in_rhs + ref.index
member = ref.tag.member
"(yyvsp[#{i}].#{member})"
when ref.type == :at # @n
i = -ref.position_in_rhs + ref.value
i = -ref.position_in_rhs + ref.index
"(yylsp[#{i}])"
else
raise "Unexpected. #{self}, #{ref}"
9 changes: 7 additions & 2 deletions lib/lrama/grammar/reference.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
module Lrama
class Grammar
# type: :dollar or :at
# value: Integer (e.g. $1) or String (e.g. $$, $foo, $expr.right)
# name: String (e.g. $$, $foo, $expr.right)
# index: Integer (e.g. $1)
# ex_tag: "$<tag>1" (Optional)
class Reference < Struct.new(:type, :value, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true)
class Reference < Struct.new(:type, :name, :index, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true)
def value
name || index
end

def tag
if ex_tag
ex_tag
40 changes: 18 additions & 22 deletions lib/lrama/grammar/rule_builder.rb
Original file line number Diff line number Diff line change
@@ -125,22 +125,18 @@ def numberize_references
next unless token.is_a?(Lrama::Lexer::Token::UserCode)

token.references.each do |ref|
ref_name = ref.value
if ref_name.is_a?(::String) && ref_name != '$'
value =
if lhs.referred_by?(ref_name)
'$'
else
candidates = rhs.each_with_index.select {|token, i| token.referred_by?(ref_name) }

raise "Referring symbol `#{ref.value}` is duplicated. #{token}" if candidates.size >= 2
raise "Referring symbol `#{ref.value}` is not found. #{token}" unless referring_symbol = candidates.first

referring_symbol[1] + 1
end

ref.value = value
ref
ref_name = ref.name
if ref_name && ref_name != '$'
if lhs.referred_by?(ref_name)
ref.name = '$'
else
candidates = rhs.each_with_index.select {|token, i| token.referred_by?(ref_name) }

raise "Referring symbol `#{ref_name}` is duplicated. #{token}" if candidates.size >= 2
raise "Referring symbol `#{ref_name}` is not found. #{token}" unless referring_symbol = candidates.first

ref.index = referring_symbol[1] + 1
end
end
end
end
@@ -156,14 +152,14 @@ def setup_references
next if ref.type == :at
# $$, $n, @$, @n can be used in any actions

if ref.value == "$"
if ref.name == "$"
# TODO: Should be postponed after middle actions are extracted?
ref.referring_symbol = lhs
elsif ref.value.is_a?(Integer)
raise "Can not refer following component. #{ref.value} >= #{i}. #{token}" if ref.value >= i
rhs[ref.value - 1].referred = true
ref.referring_symbol = rhs[ref.value - 1]
elsif ref.value.is_a?(String)
elsif ref.index
raise "Can not refer following component. #{ref.index} >= #{i}. #{token}" if ref.index >= i
rhs[ref.index - 1].referred = true
ref.referring_symbol = rhs[ref.index - 1]
else
raise "[BUG] Unreachable #{token}."
end
end
16 changes: 8 additions & 8 deletions lib/lrama/lexer/token/user_code.rb
Original file line number Diff line number Diff line change
@@ -35,27 +35,27 @@ def scan_reference(scanner)
# It need to wrap an identifier with brackets to use ".-" for identifiers
when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $<long>$
tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
return Lrama::Grammar::Reference.new(type: :dollar, value: "$", ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :dollar, name: "$", ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
return Lrama::Grammar::Reference.new(type: :dollar, value: Integer(scanner[2]), ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :dollar, index: Integer(scanner[2]), ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_][a-zA-Z0-9_]*)/) # $foo, $expr, $<long>program (named reference without brackets)
tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
return Lrama::Grammar::Reference.new(type: :dollar, value: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # $expr.right, $expr-right, $<long>program (named reference with brackets)
tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
return Lrama::Grammar::Reference.new(type: :dollar, value: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos - 1)

# @ references
# It need to wrap an identifier with brackets to use ".-" for identifiers
when scanner.scan(/@\$/) # @$
return Lrama::Grammar::Reference.new(type: :at, value: "$", first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :at, name: "$", first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/@(\d+)/) # @1
return Lrama::Grammar::Reference.new(type: :at, value: Integer(scanner[1]), first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :at, index: Integer(scanner[1]), first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/@([a-zA-Z][a-zA-Z0-9_]*)/) # @foo, @expr (named reference without brackets)
return Lrama::Grammar::Reference.new(type: :at, value: scanner[1], first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :at, name: scanner[1], first_column: start, last_column: scanner.pos - 1)
when scanner.scan(/@\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # @expr.right, @expr-right (named reference with brackets)
return Lrama::Grammar::Reference.new(type: :at, value: scanner[1], first_column: start, last_column: scanner.pos - 1)
return Lrama::Grammar::Reference.new(type: :at, name: scanner[1], first_column: start, last_column: scanner.pos - 1)
end
end
end
6 changes: 4 additions & 2 deletions sig/lrama/grammar/reference.rbs
Original file line number Diff line number Diff line change
@@ -3,19 +3,21 @@ module Lrama
class Reference
# TODO: Replace untyped referring_symbol with (Grammar::Symbol|Lexer::Token)
attr_accessor type: Symbol
attr_accessor value: (String|Integer)
attr_accessor name: String
attr_accessor index: Integer
attr_accessor ex_tag: Lexer::Token?
attr_accessor first_column: Integer
attr_accessor last_column: Integer
attr_accessor referring_symbol: untyped
attr_accessor position_in_rhs: Integer?

def initialize: (
type: Symbol, value: (String|Integer), ?ex_tag: Lexer::Token?,
type: Symbol, ?name: String, ?index: Integer, ?ex_tag: Lexer::Token?,
first_column: Integer, last_column: Integer,
?referring_symbol: untyped, ?position_in_rhs: Integer?
) -> void

def value: () -> (String|Integer)
def tag: () -> untyped
end
end
46 changes: 34 additions & 12 deletions spec/lrama/grammar/rule_builder_spec.rb
Original file line number Diff line number Diff line change
@@ -115,17 +115,28 @@

expect(token_5.references.count).to eq 6
expect(token_5.references[0].type).to eq :dollar
expect(token_5.references[0].value).to eq '$'
expect(token_5.references[0].name).to eq '$'
expect(token_5.references[0].index).to eq nil

expect(token_5.references[1].type).to eq :dollar
expect(token_5.references[1].value).to eq 1
expect(token_5.references[1].name).to eq nil
expect(token_5.references[1].index).to eq 1

expect(token_5.references[2].type).to eq :dollar
expect(token_5.references[2].value).to eq 3
expect(token_5.references[2].name).to eq 'keyword_end'
expect(token_5.references[2].index).to eq 3

expect(token_5.references[3].type).to eq :at
expect(token_5.references[3].value).to eq '$'
expect(token_5.references[3].name).to eq '$'
expect(token_5.references[3].index).to eq nil

expect(token_5.references[4].type).to eq :at
expect(token_5.references[4].value).to eq 1
expect(token_5.references[4].name).to eq nil
expect(token_5.references[4].index).to eq 1

expect(token_5.references[5].type).to eq :at
expect(token_5.references[5].value).to eq 3
expect(token_5.references[5].name).to eq 'keyword_end'
expect(token_5.references[5].index).to eq 3
end
end

@@ -150,17 +161,28 @@

expect(token_4.references.count).to eq 6
expect(token_4.references[0].type).to eq :dollar
expect(token_4.references[0].value).to eq '$'
expect(token_4.references[0].name).to eq '$'
expect(token_4.references[0].index).to eq nil

expect(token_4.references[1].type).to eq :dollar
expect(token_4.references[1].value).to eq 1
expect(token_4.references[1].name).to eq 'keyword_class'
expect(token_4.references[1].index).to eq 1

expect(token_4.references[2].type).to eq :dollar
expect(token_4.references[2].value).to eq 2
expect(token_4.references[2].name).to eq nil
expect(token_4.references[2].index).to eq 2

expect(token_4.references[3].type).to eq :at
expect(token_4.references[3].value).to eq '$'
expect(token_4.references[3].name).to eq '$'
expect(token_4.references[3].index).to eq nil

expect(token_4.references[4].type).to eq :at
expect(token_4.references[4].value).to eq 1
expect(token_4.references[4].name).to eq 'keyword_class'
expect(token_4.references[4].index).to eq 1

expect(token_4.references[5].type).to eq :at
expect(token_4.references[5].value).to eq 2
expect(token_4.references[5].name).to eq nil
expect(token_4.references[5].index).to eq 2
end
end

0 comments on commit 6b0e22b

Please sign in to comment.