Allow multiple lexer modes to be specified for a lexer pattern - close #35
This commit is contained in:
1 parent
54bb3307cd
commit
eb9d9026fc
11 files changed
+166
-30
No files matched your search
@@ -43,8 +43,8 @@ class Propane
|
||||
# Assign default pattern mode to patterns without a mode assigned.
|
||||
found_default = false
|
||||
@grammar.patterns.each do |pattern|
|
||||
if pattern.mode.nil?
|
||||
pattern.mode = "default"
|
||||
if pattern.modes.empty?
|
||||
pattern.modes << "default"
|
||||
found_default = true
|
||||
end
|
||||
pattern.ptypename ||= "default"
|
||||
|
||||
+22
-14
@@ -25,7 +25,7 @@ class Propane
|
||||
@code_blocks = {}
|
||||
@line_number = 1
|
||||
@next_line_number = @line_number
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
@input = input.gsub("\r\n", "\n")
|
||||
@ptypes = {"default" => "void *"}
|
||||
@prefix = "p_"
|
||||
@@ -58,7 +58,7 @@ class Propane
|
||||
def parse_statement!
|
||||
if parse_white_space!
|
||||
elsif parse_comment_line!
|
||||
elsif @mode.nil? && parse_mode_label!
|
||||
elsif @modeline.nil? && parse_mode_label!
|
||||
elsif parse_ast_statement!
|
||||
elsif parse_ast_prefix_statement!
|
||||
elsif parse_ast_suffix_statement!
|
||||
@@ -81,8 +81,8 @@ class Propane
|
||||
end
|
||||
|
||||
def parse_mode_label!
|
||||
if md = consume!(/(#{IDENTIFIER_REGEX})\s*:/)
|
||||
@mode = md[1]
|
||||
if md = consume!(/(#{IDENTIFIER_REGEX}(?:\s*,\s*#{IDENTIFIER_REGEX})*)\s*:/)
|
||||
@modeline = md[1]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -117,7 +117,7 @@ class Propane
|
||||
md = consume!(/([\w.]+)\s*/, "expected module name")
|
||||
@modulename = md[1]
|
||||
consume!(/;/, "expected `;'")
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -153,9 +153,9 @@ 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, ptypename: ptypename)
|
||||
pattern = Pattern.new(pattern: pattern, token: token, line_number: @line_number, code: code, modes: get_modes_from_modeline, ptypename: ptypename)
|
||||
@patterns << pattern
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -173,7 +173,7 @@ class Propane
|
||||
consume!(/;/, "expected `;'");
|
||||
token = Token.new(name, ptypename, @line_number)
|
||||
@tokens << token
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -186,8 +186,8 @@ class Propane
|
||||
end
|
||||
consume!(/\s+/)
|
||||
consume!(/;/, "expected `;'")
|
||||
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, mode: @mode)
|
||||
@mode = nil
|
||||
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, modes: get_modes_from_modeline)
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -208,7 +208,7 @@ class Propane
|
||||
end
|
||||
end
|
||||
@rules << Rule.new(rule_name, components, code, ptypename, @line_number)
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -225,8 +225,8 @@ class Propane
|
||||
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, ptypename: ptypename)
|
||||
@mode = nil
|
||||
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, modes: get_modes_from_modeline, ptypename: ptypename)
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -247,7 +247,7 @@ class Propane
|
||||
else
|
||||
@code_blocks[name] = code
|
||||
end
|
||||
@mode = nil
|
||||
@modeline = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -315,6 +315,14 @@ class Propane
|
||||
end
|
||||
end
|
||||
|
||||
def get_modes_from_modeline
|
||||
if @modeline
|
||||
Set[*@modeline.split(",").map(&:strip)]
|
||||
else
|
||||
Set.new
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -26,8 +26,14 @@ class Propane
|
||||
private
|
||||
|
||||
def build_tables!
|
||||
@modes = @grammar.patterns.group_by do |pattern|
|
||||
pattern.mode
|
||||
modenames = @grammar.patterns.reduce(Set.new) do |result, pattern|
|
||||
result + pattern.modes
|
||||
end
|
||||
@modes = modenames.reduce({}) do |result, modename|
|
||||
result[modename] = @grammar.patterns.select do |pattern|
|
||||
pattern.modes.include?(modename)
|
||||
end
|
||||
result
|
||||
end.transform_values do |patterns|
|
||||
{dfa: DFA.new(patterns)}
|
||||
end
|
||||
|
||||
@@ -26,9 +26,9 @@ class Propane
|
||||
# Regex NFA for matching the pattern.
|
||||
attr_reader :nfa
|
||||
|
||||
# @return [String, nil]
|
||||
# Lexer mode for this pattern.
|
||||
attr_accessor :mode
|
||||
# @return [Set]
|
||||
# Lexer modes for this pattern.
|
||||
attr_accessor :modes
|
||||
|
||||
# @return [String, nil]
|
||||
# Parser value type name.
|
||||
@@ -46,14 +46,14 @@ class Propane
|
||||
# Token to be returned by this pattern.
|
||||
# @option options [Integer, nil] :line_number
|
||||
# Line number where the token was defined in the input grammar.
|
||||
# @option options [String, nil] :mode
|
||||
# Lexer mode for this pattern.
|
||||
# @option options [String, nil] :modes
|
||||
# Lexer modes for this pattern.
|
||||
def initialize(options)
|
||||
@code = options[:code]
|
||||
@pattern = options[:pattern]
|
||||
@token = options[:token]
|
||||
@line_number = options[:line_number]
|
||||
@mode = options[:mode]
|
||||
@modes = options[:modes]
|
||||
@ptypename = options[:ptypename]
|
||||
regex = Regex.new(@pattern)
|
||||
regex.nfa.end_state.accepts = self
|
||||
|
||||
Reference in new issue
Block a user