module MCollective module Matcher class Parser attr_reader :scanner, :execution_stack def initialize(args) @scanner = Scanner.new(args) @execution_stack = [] @parse_errors = [] @token_errors = [] @paren_errors = [] parse exit_with_token_errors if @token_errors.size > 0 exit_with_parse_errors if @parse_errors.size > 0 exit_with_paren_errors if @paren_errors.size > 0 end # Exit and highlight any malformed tokens def exit_with_token_errors @token_errors.each do |error_range| (error_range[0]..error_range[1]).each do |i| @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i]) end end raise "Malformed token(s) found while parsing -S input #{@scanner.arguments.join}" end def exit_with_parse_errors @parse_errors.each do |error_range| (error_range[0]..error_range[1]).each do |i| @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i]) end end raise "Parse errors found while parsing -S input #{ @scanner.arguments.join}" end def exit_with_paren_errors @paren_errors.each do |i| @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i]) end raise "Missing parenthesis found while parsing -S input #{@scanner.arguments.join}" end # Parse the input string, one token at a time a contruct the call stack def parse pre_index = @scanner.token_index p_token,p_token_value = nil c_token,c_token_value = @scanner.get_token parenth = 0 while (c_token != nil) @scanner.token_index += 1 n_token, n_token_value = @scanner.get_token unless n_token == " " case c_token when "bad_token" @token_errors << c_token_value when "and" unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !(n_token == nil) @parse_errors << [pre_index, scanner.token_index] end if p_token == nil @parse_errors << [pre_index - c_token.size, scanner.token_index] elsif (p_token == "and" || p_token == "or") @parse_errors << [pre_index - 1 - p_token.size, pre_index - 1] end when "or" unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !(n_token == nil) @parse_errors << [pre_index, scanner.token_index] end if p_token == nil @parse_errors << [pre_index - c_token.size, scanner.token_index] elsif (p_token == "and" || p_token == "or") @parse_errors << [pre_index - 1 - p_token.size, pre_index - 1] end when "not" unless n_token =~ /fstatement|statement|\(|not/ && !(n_token == nil) @parse_errors << [pre_index, scanner.token_index] end when "statement","fstatement" unless n_token =~ /and|or|\)/ unless scanner.token_index == scanner.arguments.size @parse_errors << [pre_index, scanner.token_index] end end when ")" unless (n_token =~ /|and|or|not|\(/) unless(scanner.token_index == scanner.arguments.size) @parse_errors << [pre_index, scanner.token_index] end end unless @paren_errors.empty? @paren_errors.pop else @paren_errors.push((n_token.nil?) ? scanner.token_index - 1: scanner.token_index - n_token_value.size) end when "(" unless n_token =~ /fstatement|statement|not|\(/ @parse_errors << [pre_index, scanner.token_index] end @paren_errors.push((n_token.nil?) ? scanner.token_index - 1: scanner.token_index - n_token_value.size) else @parse_errors << [pre_index, scanner.token_index] end unless n_token == " " ||c_token == "bad_token" @execution_stack << {c_token => c_token_value} end p_token, p_token_value = c_token, c_token_value c_token, c_token_value = n_token, n_token_value end pre_index = @scanner.token_index end end end end end