/~ Token definitions ~/

! ' |\t' ;

' |\t' WHITESPACE ;
'\(' LEFT_PARENTHESE ;
'\)' RIGHT_PARENTHESE ;
'AND' AND ;
'OR' OR ;
'NOT' NOT ;
'[^><!= :\(\)"][^ :\(\)"]*:' COLUMN ;
'"(\\.|[^\\"])*"' STRING ;
'[^><!= :\(\)"][^ :\(\)"]*' WORD ;
'(>=?|<=?|!?=)' OPERATOR ;

##

/~ Grammar specification ~/

begin: search_text [* result = %1; *];

search_text
    : and_expression                [* %% = %1; *]
    | and_expression search_text    [* %% = mkComplexQuery('OR',[%1,%2]); *]
    | and_expression OR search_text [* %% = mkComplexQuery('OR',[%1,%3]); *]
    ;

and_expression
    : boolean_expression                    [* %% = %1 ; *]
    | boolean_expression AND and_expression [* %% = mkComplexQuery('AND',[%1,%3]); *]
    ;

boolean_expression
    : NOT expression [* %% = mkNotQuery(%2); *]
    | expression     [* %% = %1; *]
    ;

expression
    : LEFT_PARENTHESE search_text RIGHT_PARENTHESE [* %% = %2; *]
    | COLUMN expression                            [* simpleQuerySetKey(%2,%1.split(':').slice(0,-1).join(':')); %% = %2; *]
    | value                                        [* %% = %1; *]
    ;

value
    : OPERATOR string [* %2.operator = %1 ; %% = %2; *]
    | string          [* %% = %1; *]
    ;

string
    : WORD   [* %% = mkSimpleQuery('',%1); *]
    | STRING [* %% = mkSimpleQuery('',%1.split('"').slice(1,-1).join('"')); *]
    ;

[*
var arrayExtend = function () {
  var j, i, newlist = [], list_list = arguments;
  for (j = 0; j < list_list.length; j += 1) {
    for (i = 0; i < list_list[j].length; i += 1) {
      newlist.push(list_list[j][i]);
    }
  }
  return newlist;

}, mkSimpleQuery = function (key, value, operator) {
  var object = {"type": "simple", "key": key, "value": value};
  if (operator !== undefined) {
    object.operator = operator;
  }
  return object;

}, mkNotQuery = function (query) {
  if (query.operator === "NOT") {
    return query.query_list[0];
  }
  return {"type": "complex", "operator": "NOT", "query_list": [query]};

}, mkComplexQuery = function (operator, query_list) {
  var i, query_list2 = [];
  for (i = 0; i < query_list.length; i += 1) {
    if (query_list[i].operator === operator) {
      query_list2 = arrayExtend(query_list2, query_list[i].query_list);
    } else {
      query_list2.push(query_list[i]);
    }
  }
  return {type:"complex",operator:operator,query_list:query_list2};

}, simpleQuerySetKey = function (query, key) {
  var i;
  if (query.type === "complex") {
    for (i = 0; i < query.query_list.length; ++i) {
      simpleQuerySetKey (query.query_list[i],key);
    }
    return true;
  }
  if (query.type === "simple" && !query.key) {
    query.key = key;
    return true;
  }
  return false;
},
  error_offsets = [],
  error_lookaheads = [],
  error_count = 0,
  result;

if ((error_count = __##PREFIX##parse(string, error_offsets, error_lookaheads)) > 0) {
  var i;
  for (i = 0; i < error_count; i += 1) {
    throw new Error("Parse error near \"" +
                    string.substr(error_offsets[i]) +
                    "\", expecting \"" +
                    error_lookaheads[i].join() + "\"");
  }
}
*]