Store parser values according to the rule/pattern type
This commit is contained in:
1 parent
e4a160f918
commit
c6ea4f83c2
8 files changed
+87
-24
No files matched your search
@@ -33,6 +33,7 @@ class Propane
|
||||
pattern.mode = "default"
|
||||
found_default = true
|
||||
end
|
||||
pattern.ptypename ||= "default"
|
||||
end
|
||||
unless found_default
|
||||
raise Error.new("No patterns found for default mode")
|
||||
@@ -43,6 +44,8 @@ class Propane
|
||||
@grammar.tokens.each_with_index do |token, token_id|
|
||||
# Assign token ID.
|
||||
token.id = token_id
|
||||
# Set default ptypename if none given.
|
||||
token.ptypename ||= "default"
|
||||
# Check for token name conflicts.
|
||||
if tokens_by_name.include?(token.name)
|
||||
raise Error.new("Duplicate token name #{token.name.inspect}")
|
||||
@@ -69,8 +72,20 @@ class Propane
|
||||
rule_sets[rule.name] = RuleSet.new(rule.name, rule_set_id)
|
||||
rule_set_id += 1
|
||||
end
|
||||
rule.rule_set = rule_sets[rule.name]
|
||||
rule_sets[rule.name] << rule
|
||||
rule_set = rule_sets[rule.name]
|
||||
if rule_set.ptypename && rule.ptypename && rule_set.ptypename != rule.ptypename
|
||||
raise Error.new("Conflicting ptypes for rule #{rule.name}")
|
||||
end
|
||||
rule_set.ptypename ||= rule.ptypename
|
||||
rule.rule_set = rule_set
|
||||
rule_set << rule
|
||||
end
|
||||
rule_sets.each do |name, rule_set|
|
||||
rule_set.ptypename ||= "default"
|
||||
# Assign rule set ptypenames back to rules.
|
||||
rule_set.rules.each do |rule|
|
||||
rule.ptypename = rule_set.ptypename
|
||||
end
|
||||
end
|
||||
# Generate lexer user code IDs for lexer patterns with user code blocks.
|
||||
@grammar.patterns.select do |pattern|
|
||||
@@ -159,24 +174,28 @@ class Propane
|
||||
# User code block.
|
||||
# @param parser [Boolean]
|
||||
# Whether the user code is for the parser or lexer.
|
||||
# @param rule [Rule, nil]
|
||||
# The Rule associated with the user code if user code is for the parser.
|
||||
# @param pattern [Pattern, nil]
|
||||
# The Pattern associated with the user code if user code is for the lexer.
|
||||
#
|
||||
# @return [String]
|
||||
# Expanded user code block.
|
||||
def expand_code(code, parser)
|
||||
def expand_code(code, parser, rule, pattern)
|
||||
code = code.gsub(/\$token\(([$\w]+)\)/) do |match|
|
||||
"TOKEN_#{Token.code_name($1)}"
|
||||
end
|
||||
if parser
|
||||
code = code.gsub(/\$\$/) do |match|
|
||||
"_pvalue"
|
||||
"_pvalue.v_#{rule.ptypename}"
|
||||
end
|
||||
code = code.gsub(/\$(\d+)/) do |match|
|
||||
index = $1.to_i
|
||||
"statevalues[$-1-n_states+#{index}].pvalue"
|
||||
"statevalues[$-1-n_states+#{index}].pvalue.v_#{rule.ptypename}"
|
||||
end
|
||||
else
|
||||
code = code.gsub(/\$\$/) do |match|
|
||||
"lt.pvalue"
|
||||
"lt.pvalue.v_#{pattern.ptypename}"
|
||||
end
|
||||
code = code.gsub(/\$mode\(([a-zA-Z_][a-zA-Z_0-9]*)\)/) do |match|
|
||||
mode_name = $1
|
||||
@@ -190,6 +209,17 @@ class Propane
|
||||
code
|
||||
end
|
||||
|
||||
# Get the parser value type for the start rule.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
# Start rule parser value type name and type string.
|
||||
def start_rule_type
|
||||
start_rule = @grammar.rules.find do |rule|
|
||||
rule.name == "Start"
|
||||
end
|
||||
[start_rule.ptypename, @grammar.ptypes[start_rule.ptypename]]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -117,7 +117,7 @@ class Propane
|
||||
end
|
||||
token = Token.new(name, ptypename, @line_number)
|
||||
@tokens << token
|
||||
pattern = Pattern.new(pattern: pattern, token: token, line_number: @line_number, code: code, mode: @mode)
|
||||
pattern = Pattern.new(pattern: pattern, token: token, line_number: @line_number, code: code, mode: @mode, ptypename: ptypename)
|
||||
@patterns << pattern
|
||||
@mode = nil
|
||||
true
|
||||
@@ -170,10 +170,13 @@ class Propane
|
||||
def parse_pattern_statement!
|
||||
if pattern = parse_pattern!
|
||||
consume!(/\s+/)
|
||||
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
|
||||
ptypename = md[1]
|
||||
end
|
||||
unless code = parse_code_block!
|
||||
raise Error.new("Line #{@line_number}: expected code block to follow pattern")
|
||||
end
|
||||
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, mode: @mode)
|
||||
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, mode: @mode, ptypename: ptypename)
|
||||
@mode = nil
|
||||
true
|
||||
end
|
||||
|
||||
@@ -30,6 +30,10 @@ class Propane
|
||||
# Lexer mode for this pattern.
|
||||
attr_accessor :mode
|
||||
|
||||
# @return [String, nil]
|
||||
# Parser value type name.
|
||||
attr_accessor :ptypename
|
||||
|
||||
# Construct a Pattern.
|
||||
#
|
||||
# @param options [Hash]
|
||||
@@ -53,6 +57,7 @@ class Propane
|
||||
@token = options[:token]
|
||||
@line_number = options[:line_number]
|
||||
@mode = options[:mode]
|
||||
@ptypename = options[:ptypename]
|
||||
regex = Regex.new(@pattern)
|
||||
regex.nfa.end_state.accepts = self
|
||||
@nfa = regex.nfa
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ class Propane
|
||||
|
||||
# @return [String, nil]
|
||||
# Parser type name.
|
||||
attr_reader :ptypename
|
||||
attr_accessor :ptypename
|
||||
|
||||
# @return [Integer]
|
||||
# Line number where the rule was defined in the input grammar.
|
||||
|
||||
@@ -10,6 +10,10 @@ class Propane
|
||||
# Name of the RuleSet.
|
||||
attr_reader :name
|
||||
|
||||
# @return [String, nil]
|
||||
# Parser type name.
|
||||
attr_accessor :ptypename
|
||||
|
||||
# @return [Array<Rule>]
|
||||
# Rules in the RuleSet.
|
||||
attr_reader :rules
|
||||
|
||||
@@ -20,7 +20,7 @@ class Propane
|
||||
|
||||
# @return [String, nil]
|
||||
# Parser value type name.
|
||||
attr_reader :ptypename
|
||||
attr_accessor :ptypename
|
||||
|
||||
# @return [Integer, nil]
|
||||
# Token ID.
|
||||
|
||||
Reference in new issue
Block a user