aboutsummaryrefslogtreecommitdiff
path: root/src/expressionParser.mly
blob: a2218a6c432be916de2695ba3107bddacaede0d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(*
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 <http://www.gnu.org/licenses/>.
*)

%{
    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 <string> REAL
%token <string> NUM
%token <string> STR

%token <string> 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<ScTypes.Expr.t> value
%start<ScTypes.Result.t> 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 }