(*
This file is part of licht.
licht is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
licht is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with licht. If not, see .
*)
%{
open ScTypes
open ScTypes.Result
module S = Symbols
let u = UTF8.from_utf8string
let extractColumnNameFromNum (fixed, (str, value)) = (fixed, value)
let build_call ident = function
| [] -> Expr.call0 ident
| [p1] -> Expr.call1 ident p1
| [p1;p2] -> Expr.call2 ident p1 p2
| [p1;p2;p3] -> Expr.call3 ident p1 p2 p3
| n -> Expr.callN ident n
%}
%token REAL
%token NUM
%token STR
%token LETTERS
%token DOLLAR
%token LPAREN
%token RPAREN
%token PLUS
%token TIMES
%token DIVIDE
%token MINUS
%token EQ NEQ
%token LT LE GT GE
%token EOF
%token SEMICOLON
%token COLON
%token POW
%nonassoc EQ NEQ LT LE GT GE
%left PLUS MINUS
%left TIMES DIVIDE
%left POW
%start value
%start content
%%
value:
| EQ expr EOF {$2}
content:
| basic EOF {$1}
basic:
| PLUS num {Ok (Type.number $2)}
| MINUS num {Ok (Type.number (DataType.Num.neg $2))}
| num {Ok (Type.number $1)}
| NUM DIVIDE NUM DIVIDE NUM {Ok (
Type.date (
DataType.Date.get_julian_day
(int_of_string $1)
(int_of_string $3)
(int_of_string $5)
))}
| NUM COLON NUM COLON NUM {Ok (
Type.date (
let nhour = DataType.Num.div (DataType.Num.of_int @@ int_of_string $1) (DataType.Num.of_int 24)
and nmin = DataType.Num.div (DataType.Num.of_int @@ int_of_string $3) (DataType.Num.of_int 1440)
and nsec = DataType.Num.div (DataType.Num.of_int @@ int_of_string $5) (DataType.Num.of_int 86400)
in DataType.Num.add (DataType.Num.add nhour nmin) nsec
)
)}
expr:
| num {Expr.value (Type.number ($1))}
| MINUS expr {Expr.call1 S.sub $2}
| PLUS expr {Expr.call1 S.add $2}
| LETTERS ident LPAREN separated_list(SEMICOLON, expr) RPAREN { build_call (u($1 ^ $2)) $4 }
| cell {Expr.ref (Refs.cell $1)}
| cell COLON cell {Expr.ref (Refs.range $1 $3)}
| LPAREN expr RPAREN {Expr.expression $2}
| STR {Expr.value (Type.string (u $1))}
(* Mathematical operators *)
| expr MINUS expr {Expr.call2 S.sub $1 $3}
| expr DIVIDE expr {Expr.call2 S.div $1 $3}
| expr TIMES expr {Expr.call2 S.mul $1 $3}
| expr PLUS expr {Expr.call2 S.add $1 $3}
| expr POW expr {Expr.call2 S.pow $1 $3}
(* Comparaison *)
| expr EQ expr {Expr.call2 S.eq $1 $3}
| expr NEQ expr {Expr.call2 S.neq $1 $3}
| expr LT expr {Expr.call2 S.lt $1 $3}
| expr GT expr {Expr.call2 S.gt $1 $3}
| expr LE expr {Expr.call2 S.le $1 $3}
| expr GE expr {Expr.call2 S.ge $1 $3}
%inline cell:
| LETTERS NUM { Cell.from_string (false, $1) (false, int_of_string $2) }
| DOLLAR LETTERS NUM { Cell.from_string (true, $2) (false, int_of_string $3) }
| LETTERS DOLLAR NUM { Cell.from_string (false, $1) (true, int_of_string $3) }
| DOLLAR LETTERS DOLLAR NUM { Cell.from_string (true, $2) (true, int_of_string $4) }
num:
| REAL {DataType.Num.of_float @@ float_of_string $1}
| NUM {DataType.Num.of_int @@ int_of_string $1}
ident:
| text* { String.concat "" $1 }
text:
| LETTERS { $1 }
| NUM { $1 }