X-Git-Url: https://review.fuel-infra.org/gitweb?a=blobdiff_plain;f=lib%2Fmcollective%2Fmatcher%2Fscanner.rb;fp=lib%2Fmcollective%2Fmatcher%2Fscanner.rb;h=5d817856a0f132db014d7fc0a6efe72cc0598e51;hb=b87d2f4e68281062df1913440ca5753ae63314a9;hp=0000000000000000000000000000000000000000;hpb=ab0ea530b8ac956091f17b104ab2311336cfc250;p=packages%2Fprecise%2Fmcollective.git diff --git a/lib/mcollective/matcher/scanner.rb b/lib/mcollective/matcher/scanner.rb new file mode 100644 index 0000000..5d81785 --- /dev/null +++ b/lib/mcollective/matcher/scanner.rb @@ -0,0 +1,201 @@ +module MCollective + module Matcher + class Scanner + attr_accessor :arguments, :token_index + + def initialize(arguments) + @token_index = 0 + @arguments = arguments.split("") + @seperation_counter = 0 + @white_spaces = 0 + end + + # Scans the input string and identifies single language tokens + def get_token + if @token_index >= @arguments.size + return nil + end + + case @arguments[@token_index] + when "(" + return "(", "(" + + when ")" + return ")", ")" + + when "n" + if (@arguments[@token_index + 1] == "o") && (@arguments[@token_index + 2] == "t") && ((@arguments[@token_index + 3] == " ") || (@arguments[@token_index + 3] == "(")) + @token_index += 2 + return "not", "not" + else + gen_statement + end + + when "!" + return "not", "not" + + when "a" + if (@arguments[@token_index + 1] == "n") && (@arguments[@token_index + 2] == "d") && ((@arguments[@token_index + 3] == " ") || (@arguments[@token_index + 3] == "(")) + @token_index += 2 + return "and", "and" + else + gen_statement + end + + when "o" + if (@arguments[@token_index + 1] == "r") && ((@arguments[@token_index + 2] == " ") || (@arguments[@token_index + 2] == "(")) + @token_index += 1 + return "or", "or" + else + gen_statement + end + + when " " + return " ", " " + + else + gen_statement + end + end + + private + # Helper generates a statement token + def gen_statement + func = false + current_token_value = "" + j = @token_index + + begin + if (@arguments[j] == "/") + begin + current_token_value << @arguments[j] + j += 1 + end until (j >= @arguments.size) || (@arguments[j] =~ /\s/) + elsif (@arguments[j] =~ /=|<|>/) + while !(@arguments[j] =~ /=|<|>/) + current_token_value << @arguments[j] + j += 1 + end + + current_token_value << @arguments[j] + j += 1 + + if @arguments[j] == "/" + begin + current_token_value << @arguments[j] + j += 1 + if @arguments[j] == "/" + current_token_value << "/" + break + end + end until (j >= @arguments.size) || (@arguments[j] =~ /\//) + else + while (j < @arguments.size) && ((@arguments[j] != " ") && (@arguments[j] != ")")) + current_token_value << @arguments[j] + j += 1 + end + end + else + begin + # Identify and tokenize regular expressions by ignoring everything between /'s + if @arguments[j] == '/' + current_token_value << '/' + j+=1 + while(j < @arguments.size && @arguments[j] != '/') + current_token_value << @arguments[j] + j += 1 + end + current_token_value << @arguments[j] if @arguments[j] + break + end + if @arguments[j+1] == "(" + func = true + be_greedy = true + end + current_token_value << @arguments[j] + if be_greedy + while !(j+1 >= @arguments.size) && @arguments[j] != ')' + j += 1 + current_token_value << @arguments[j] + end + j += 1 + be_greedy = false + else + j += 1 + end + if(@arguments[j] == ' ') + break if(is_klass?(j) && !(@arguments[j-1] =~ /=|<|>/)) + end + if( (@arguments[j] == ' ') && (@seperation_counter < 2) && !(current_token_value.match(/^.+(=|<|>).+$/)) ) + if((index = lookahead(j))) + j = index + end + end + end until (j >= @arguments.size) || (@arguments[j] =~ /\s|\)/) + @seperation_counter = 0 + end + rescue Exception => e + raise "An exception was raised while trying to tokenize '#{current_token_value} - #{e}'" + end + + @token_index += current_token_value.size + @white_spaces - 1 + @white_spaces = 0 + + # bar( + if current_token_value.match(/.+?\($/) + return "bad_token", [@token_index - current_token_value.size + 1, @token_index] + # /foo/=bar + elsif current_token_value.match(/^\/.+?\/(<|>|=).+/) + return "bad_token", [@token_index - current_token_value.size + 1, @token_index] + elsif current_token_value.match(/^.+?\/(<|>|=).+/) + return "bad_token", [@token_index - current_token_value.size + 1, @token_index] + else + if func + if current_token_value.match(/^.+?\((\s*(')[^']*(')\s*(,\s*(')[^']*('))*)?\)(\.[a-zA-Z0-9_]+)?((!=|<=|>=|=|>|<).+)?$/) || + current_token_value.match(/^.+?\((\s*(")[^"]*(")\s*(,\s*(")[^"]*("))*)?\)(\.[a-zA-Z0-9_]+)?((!=|<=|>=|=|>|<).+)?$/) + return "fstatement", current_token_value + else + return "bad_token", [@token_index - current_token_value.size + 1, @token_index] + end + else + slash_err = false + current_token_value.split('').each do |c| + if c == '/' + slash_err = !slash_err + end + end + return "bad_token", [@token_index - current_token_value.size + 1, @token_index] if slash_err + return "statement", current_token_value + end + end + end + + # Deal with special puppet class statement + def is_klass?(j) + while(j < @arguments.size && @arguments[j] == ' ') + j += 1 + end + + if @arguments[j] =~ /=|<|>/ + return false + else + return true + end + end + + # Eat spaces while looking for the next comparison symbol + def lookahead(index) + index += 1 + while(index <= @arguments.size) + @white_spaces += 1 + unless(@arguments[index] =~ /\s/) + @seperation_counter +=1 + return index + end + index += 1 + end + return nil + end + end + end +end