Allow parser user code blocks in tree mode
This commit is contained in:
1 parent
b04c0ad205
commit
98390429a8
9 files changed
+281
-31
No files matched your search
+61
-19
@@ -185,7 +185,8 @@ class Propane
|
||||
end
|
||||
end
|
||||
@grammar.rules << Rule.new(component, [], nil, ptypename, rule.line_number)
|
||||
@grammar.rules << Rule.new(component, [c], "$$ = $1;\n", ptypename, rule.line_number)
|
||||
optcode = @grammar.tree ? nil : "$$ = $1;\n"
|
||||
@grammar.rules << Rule.new(component, [c], optcode, ptypename, rule.line_number)
|
||||
optional_rules_added << component
|
||||
end
|
||||
end
|
||||
@@ -296,21 +297,24 @@ class Propane
|
||||
end
|
||||
if parser
|
||||
code = code.gsub(/\$\$/) do |match|
|
||||
case @language
|
||||
when "c"
|
||||
"_pvalue->v_#{rule.ptypename}"
|
||||
when "d"
|
||||
"_pvalue.v_#{rule.ptypename}"
|
||||
if @grammar.tree
|
||||
case @language
|
||||
when "c"
|
||||
"((#{@grammar.tree_prefix}#{rule.name}#{@grammar.tree_suffix} *)_pvalue)"
|
||||
when "d"
|
||||
"(cast(#{@grammar.tree_prefix}#{rule.name}#{@grammar.tree_suffix} *)_pvalue)"
|
||||
end
|
||||
else
|
||||
case @language
|
||||
when "c"
|
||||
"_pvalue->v_#{rule.ptypename}"
|
||||
when "d"
|
||||
"_pvalue.v_#{rule.ptypename}"
|
||||
end
|
||||
end
|
||||
end
|
||||
code = code.gsub(/\$(\d+)/) do |match|
|
||||
index = $1.to_i
|
||||
case @language
|
||||
when "c"
|
||||
"state_values_stack_index(statevalues, -1 - (int)n_states + #{index})->pvalue.v_#{rule.components[index - 1].ptypename}"
|
||||
when "d"
|
||||
"statevalues[$-1-n_states+#{index}].pvalue.v_#{rule.components[index - 1].ptypename}"
|
||||
end
|
||||
parser_component_reference(rule, $1.to_i)
|
||||
end
|
||||
code = code.gsub(/\$\{(\$|\d+)\.position\}/) do |match|
|
||||
index = $1.to_i
|
||||
@@ -323,12 +327,11 @@ class Propane
|
||||
code = code.gsub(/\$\{(\w+)\}/) do |match|
|
||||
aliasname = $1
|
||||
if index = rule.aliases[aliasname]
|
||||
case @language
|
||||
when "c"
|
||||
"state_values_stack_index(statevalues, -(int)n_states + #{index})->pvalue.v_#{rule.components[index].ptypename}"
|
||||
when "d"
|
||||
"statevalues[$-n_states+#{index}].pvalue.v_#{rule.components[index].ptypename}"
|
||||
end
|
||||
# Field aliases are just a named reference to a positional rule
|
||||
# component, so reuse the same expansion as `$1', `$2', etc. Note
|
||||
# that rule.aliases stores a 0-based component index, so add 1 to
|
||||
# convert it to the 1-based index used for positional references.
|
||||
parser_component_reference(rule, index + 1)
|
||||
else
|
||||
raise Error.new("Field alias '#{aliasname}' not found")
|
||||
end
|
||||
@@ -384,6 +387,45 @@ class Propane
|
||||
code
|
||||
end
|
||||
|
||||
# Expand a positional reference to a parser rule component.
|
||||
#
|
||||
# This is used to expand `$1', `$2', etc. as well as field aliases (which
|
||||
# are just named references to a positional rule component).
|
||||
#
|
||||
# @param rule [Rule]
|
||||
# The Rule containing the user code.
|
||||
# @param index [Integer]
|
||||
# 1-based index of the rule component to reference.
|
||||
#
|
||||
# @return [String]
|
||||
# Expanded rule component reference.
|
||||
def parser_component_reference(rule, index)
|
||||
component = rule.components[index - 1]
|
||||
if @grammar.tree
|
||||
# In tree mode a component reference yields a pointer to that
|
||||
# component's tree node. An optional component propagates its target
|
||||
# node (or null), so use the optional target's node type.
|
||||
if component.is_a?(RuleSet) && component.optional?
|
||||
component = component.option_target
|
||||
end
|
||||
node_name = component.is_a?(Token) ? "Token" : component.name
|
||||
typename = "#{@grammar.tree_prefix}#{node_name}#{@grammar.tree_suffix}"
|
||||
case @language
|
||||
when "c"
|
||||
"((#{typename} *)state_values_stack_index(statevalues, -1 - (int)n_states + #{index})->tree_node)"
|
||||
when "d"
|
||||
"(cast(#{typename} *)statevalues[$-1-n_states+#{index}].tree_node)"
|
||||
end
|
||||
else
|
||||
case @language
|
||||
when "c"
|
||||
"state_values_stack_index(statevalues, -1 - (int)n_states + #{index})->pvalue.v_#{component.ptypename}"
|
||||
when "d"
|
||||
"statevalues[$-1-n_states+#{index}].pvalue.v_#{component.ptypename}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Get the lex function to use.
|
||||
#
|
||||
# @return [String]
|
||||
|
||||
@@ -58,6 +58,10 @@ class Propane
|
||||
@tokens.size + 1
|
||||
end
|
||||
|
||||
def parser_user_code_used?
|
||||
@rules.any? {|r| r.code}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_grammar!
|
||||
@@ -263,12 +267,8 @@ class Propane
|
||||
end
|
||||
md = consume!(/((?:#{IDENTIFIER_REGEX}\??(?::#{IDENTIFIER_REGEX})?\s*)*)\s*/, "expected rule component list")
|
||||
components = md[1].strip.split(/\s+/)
|
||||
if @tree
|
||||
consume!(/;/, "expected `;'")
|
||||
else
|
||||
unless code = parse_code_block!
|
||||
consume!(/;/, "expected `;' or code block")
|
||||
end
|
||||
unless code = parse_code_block!
|
||||
consume!(/;/, "expected `;' or code block")
|
||||
end
|
||||
@rules << Rule.new(rule_name, components, code, ptypename, @line_number)
|
||||
@modeline = nil
|
||||
|
||||
Reference in new issue
Block a user