--- /dev/null
+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