%lex
%%
\s+                                                                                             {/* skip whitespace */}
'"'("\\"["]|[^"])*'"'                                                                           {return 'STRING';}
"'"('\\'[']|[^'])*"'"                                                                           {return 'STRING';}
[A-Za-z]{1,}[A-Za-z_0-9\.]*(?=[(])                                                              {return 'FUNCTION';}
'#'[A-Z0-9\/]+('!'|'?')?                                                                        {return 'ERROR';}
[A-Za-z]+[0-9]+                                                                                 {return 'CELL';}
\{\{[^}]+\}\}                                                                                    {return 'CELL';}
[A-Za-z]{1,}[A-Za-z_0-9]+                                                                       {return 'VARIABLE';}
[A-Za-z_]+                                                                                      {return 'VARIABLE';}
[0-9]+                                                                                          {return 'NUMBER';}
'['(.*)?']'                                                                                     {return 'ARRAY';}
"&"                                                                                             {return '&';}
" "                                                                                             {return ' ';}
[.]                                                                                             {return 'DECIMAL';}
":"                                                                                             {return ':';}
";"                                                                                             {return ';';}
","                                                                                             {return ',';}
"*"                                                                                             {return '*';}
"/"                                                                                             {return '/';}
"-"                                                                                             {return '-';}
"+"                                                                                             {return '+';}
"^"                                                                                             {return '^';}
"("                                                                                             {return '(';}
")"                                                                                             {return ')';}
">"                                                                                             {return '>';}
"<"                                                                                             {return '<';}
"NOT"                                                                                           {return 'NOT';}
'"'                                                                                             {return '"';}
"'"                                                                                             {return "'";}
"!"                                                                                             {return "!";}
"="                                                                                             {return '=';}
"%"                                                                                             {return '%';}
[#]                                                                                             {return '#';}
<<EOF>>                                                                                         {return 'EOF';}
/lex

%left '='
%left '<=' '>=' '<>' 'NOT' '||'
%left '>' '<'
%left '+' '-'
%left '*' '/'
%left '^'
%left '&'
%left '%'
%left UMINUS

%start expressions
%% 

expressions :
  expression EOF {
      return $1;
    }
;

expression : 
  VARIABLE {$$ = yy.getVariable($1);}
  |
  number {$$ = yy.toNumber($1)} 
  |
  STRING { $$ = $1.slice(1, $1.length-1);}
  |
  expression '&' expression {$$ = yy.evaluateByOperator('&', [$1, $3])}
  | 
  expression '=' expression {$$ = yy.evaluateByOperator('=', [$1, $3])}
  |
  expression '+' expression {$$ = yy.evaluateByOperator('+', [$1, $3])}
  |
  expression '-' expression {$$ = yy.evaluateByOperator('-', [$1, $3])}
  |
  expression '*' expression {$$ = yy.evaluateByOperator('*', [$1, $3])}
  |
  expression '/' expression {$$ = yy.evaluateByOperator('/', [$1, $3])}
  |
  expression '^' expression {$$ = yy.evaluateByOperator('^', [$1, $3])}
  |
  '-' expression {var n1 = yy.invertNumber($2); $$ = isNaN(n1)?0:n1}
  |
  '+' expression {var n1 = yy.toNumber($2); $$ = isNaN(n1)? 0 : n1}
  |
  '(' expression ')' {$$ = $2}
  |
  expression '<' '=' expression {$$ = yy.evaluateByOperator('<=', [$1, $4])}
  |
  expression '>' '=' expression {$$ = yy.evaluateByOperator('>=', [$1, $4])}
  |
  expression '>' expression {$$ = yy.evaluateByOperator('>', [$1, $3])}
  |
  expression '<' expression {$$ = yy.evaluateByOperator('<', [$1, $3])}
  |
  FUNCTION '(' ')' { $$ = yy.callFunction($1);}
  | 
  FUNCTION '(' expseq ')' {$$ = yy.callFunction($1, $3);}
  |
  cell 
  |
  error
;

cell:
  CELL {$$ = yy.callFunction('getCellValue', $1);}
  |
  CELL ':' CELL {$$ = yy.callFunction('getRangeValue', [$1, $3]);}
  ;

expseq:
  expression {$$ = [$1]}
  |
  ARRAY {$$=JSON.parse($1);}
  | 
  expseq ';' expression {
    $$ = [...$1, $3];
  }
  |
  expseq ',' expression {
    $$ = [...$1, $3];
  }
  ;

number:
  NUMBER { $$ = $1; }
  |
  NUMBER DECIMAL NUMBER { $$ = yy.toNumber($1 + '.' + $3); }
  |
  number '%' { $$ = $1 * 0.01; }
  ;

error:
  ERROR { $$ = yy.throwError($1); }
  ;

%%

