Skip to content

Commit

Permalink
Merge pull request #196 from yui-knk/lazy_initialization_codes
Browse files Browse the repository at this point in the history
Lazy initialization codes
  • Loading branch information
yui-knk authored Nov 5, 2023
2 parents 74735f1 + 6726470 commit b1b3fb4
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 117 deletions.
43 changes: 21 additions & 22 deletions lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ def add_percent_code(id:, code:)
@percent_codes << PercentCode.new(id, code)
end

def add_printer(ident_or_tags:, code:, lineno:)
@printers << Printer.new(ident_or_tags: ident_or_tags, code: code, lineno: lineno)
def add_printer(ident_or_tags:, token_code:, lineno:)
@printers << Printer.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end

def add_error_token(ident_or_tags:, code:, lineno:)
@error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, code: code, lineno: lineno)
def add_error_token(ident_or_tags:, token_code:, lineno:)
@error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end

def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false)
Expand Down Expand Up @@ -399,7 +399,7 @@ def normalize_rules
accept = find_symbol_by_s_value!("$accept")
eof = find_symbol_by_number!(0)
lineno = @_rules.first ? @_rules.first[2] : 0
@rules << Rule.new(id: @rules.count, lhs: accept, rhs: [@_rules.first[0], eof], code: nil, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: accept, rhs: [@_rules.first[0], eof], token_code: nil, lineno: lineno)

extracted_action_number = 1 # @n as nterm

Expand Down Expand Up @@ -467,15 +467,14 @@ def normalize_rules
# Extract actions in the middle of RHS
# into new rules.
a.each do |new_token, code|
@rules << Rule.new(id: @rules.count, lhs: new_token, rhs: [], code: Code::RuleAction.new(type: :rule_action, token_code: code), lineno: code.line)
@rules << Rule.new(id: @rules.count, lhs: new_token, rhs: [], token_code: code, lineno: code.line)
end

c = code ? Code::RuleAction.new(type: :rule_action, token_code: code) : nil
# Expand Parameterizing rules
if rhs2.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) }
expand_parameterizing_rules(lhs, rhs2, c, precedence_sym, lineno)
expand_parameterizing_rules(lhs, rhs2, code, precedence_sym, lineno)
else
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: rhs2, code: c, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: rhs2, token_code: code, precedence_sym: precedence_sym, lineno: lineno)
end
add_nterm(id: lhs)
a.each do |new_token, _|
Expand All @@ -489,21 +488,21 @@ def expand_parameterizing_rules(lhs, rhs, code, precedence_sym, lineno)
if rhs.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) && r.option? }
option_token = Lrama::Lexer::Token::Ident.new(s_value: "option_#{rhs[0].s_value}")
add_term(id: option_token)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [option_token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: option_token, rhs: [], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: option_token, rhs: [token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [option_token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: option_token, rhs: [], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: option_token, rhs: [token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
elsif rhs.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) && r.nonempty_list? }
nonempty_list_token = Lrama::Lexer::Token::Ident.new(s_value: "nonempty_list_#{rhs[0].s_value}")
add_term(id: nonempty_list_token)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [nonempty_list_token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: nonempty_list_token, rhs: [token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: nonempty_list_token, rhs: [nonempty_list_token, token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [nonempty_list_token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: nonempty_list_token, rhs: [token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: nonempty_list_token, rhs: [nonempty_list_token, token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
elsif rhs.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) && r.list? }
list_token = Lrama::Lexer::Token::Ident.new(s_value: "list_#{rhs[0].s_value}")
add_term(id: list_token)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [list_token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: list_token, rhs: [], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: list_token, rhs: [list_token, token], code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: lhs, rhs: [list_token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: list_token, rhs: [], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
@rules << Rule.new(id: @rules.count, lhs: list_token, rhs: [list_token, token], token_code: code, precedence_sym: precedence_sym, lineno: lineno)
end
end

Expand Down Expand Up @@ -604,8 +603,8 @@ def replace_token_with_symbol
token_to_symbol(t)
end

if rule.code
rule.code.references.each do |ref|
if rule.token_code
rule.token_code.references.each do |ref|
next if ref.type == :at

if !ref.referring_symbol.is_a?(Lrama::Lexer::Token::UserCode)
Expand Down Expand Up @@ -708,9 +707,9 @@ def validate_no_declared_type_reference!
errors = []

rules.each do |rule|
next unless rule.code
next unless rule.token_code

rule.code.references.select do |ref|
rule.token_code.references.select do |ref|
ref.type == :dollar && !ref.tag
end.each do |ref|
errors << "$#{ref.value} of '#{rule.lhs.id.s_value}' has no declared type"
Expand Down
5 changes: 4 additions & 1 deletion lib/lrama/grammar/code/printer_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module Lrama
class Grammar
class Code
class PrinterCode < Code
attr_accessor :tag
def initialize(type: nil, token_code: nil, tag: nil)
super(type: type, token_code: token_code)
@tag = tag
end

private

Expand Down
5 changes: 2 additions & 3 deletions lib/lrama/grammar/error_token.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module Lrama
class Grammar
class ErrorToken < Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true)
class ErrorToken < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
def translated_code(tag)
code.tag = tag
code.translated_code
Code::PrinterCode.new(type: :error_token, token_code: token_code, tag: tag).translated_code
end
end
end
Expand Down
5 changes: 2 additions & 3 deletions lib/lrama/grammar/printer.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module Lrama
class Grammar
class Printer < Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true)
class Printer < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
def translated_code(tag)
code.tag = tag
code.translated_code
Code::PrinterCode.new(type: :printer, token_code: token_code, tag: tag).translated_code
end
end
end
Expand Down
6 changes: 4 additions & 2 deletions lib/lrama/grammar/rule.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Lrama
class Grammar
class Rule < Struct.new(:id, :lhs, :rhs, :code, :nullable, :precedence_sym, :lineno, keyword_init: true)
class Rule < Struct.new(:id, :lhs, :rhs, :token_code, :nullable, :precedence_sym, :lineno, keyword_init: true)
# TODO: Change this to display_name
def to_s
l = lhs.id.s_value
Expand Down Expand Up @@ -32,7 +32,9 @@ def initial_rule?
end

def translated_code
code&.translated_code
return nil unless token_code

Code::RuleAction.new(type: :rule_action, token_code: token_code).translated_code
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/lrama/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ def user_actions
str = ""

@context.states.rules.each do |rule|
next unless rule.code
next unless rule.token_code

code = rule.code
code = rule.token_code
spaces = " " * (code.column - 1)

str << <<-STR
Expand Down
4 changes: 2 additions & 2 deletions lib/lrama/parser.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ rule
{
@grammar.add_printer(
ident_or_tags: val[6],
code: Grammar::Code::PrinterCode.new(type: :printer, token_code: val[3]),
token_code: val[3],
lineno: val[3].line
)
}
Expand All @@ -124,7 +124,7 @@ rule
{
@grammar.add_error_token(
ident_or_tags: val[6],
code: Grammar::Code::PrinterCode.new(type: :error_token, token_code: val[3]),
token_code: val[3],
lineno: val[3].line
)
}
Expand Down
12 changes: 4 additions & 8 deletions spec/lrama/grammar/code_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,22 @@
let(:tag) { token_class::Tag.new(s_value: '<val>') }

it "translats '$$' to '((*yyvaluep).val)'" do
code = described_class.new(type: :printer, token_code: user_code_dollar_dollar)
code.tag = tag
code = described_class.new(type: :printer, token_code: user_code_dollar_dollar, tag: tag)
expect(code.translated_code).to eq("print(((*yyvaluep).val));")
end

it "translats '@$' to '(*yylocationp)'" do
code = described_class.new(type: :printer, token_code: user_code_at_dollar)
code.tag = tag
code = described_class.new(type: :printer, token_code: user_code_at_dollar, tag: tag)
expect(code.translated_code).to eq("print((*yylocationp));")
end

it "raises error for '$n'" do
code = described_class.new(type: :printer, token_code: user_code_dollar_n)
code.tag = tag
code = described_class.new(type: :printer, token_code: user_code_dollar_n, tag: tag)
expect { code.translated_code }.to raise_error("$n can not be used in printer.")
end

it "raises error for '@n'" do
code = described_class.new(type: :printer, token_code: user_code_at_n)
code.tag = tag
code = described_class.new(type: :printer, token_code: user_code_at_n, tag: tag)
expect { code.translated_code }.to raise_error("@n can not be used in printer.")
end
end
Expand Down
Loading

0 comments on commit b1b3fb4

Please sign in to comment.