aboutsummaryrefslogtreecommitdiff
path: root/lib/qparser/parser.mly
blob: d84e534345979cb9af4da4c2f70e21947d993200 (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
%{
    module T = Qsp_syntax.T
    open StdLabels

    type action_block =
        { loc : Qsp_syntax.S.pos
        ; expression : 
          Analyzer.Expression.t' * Qsp_syntax.Report.t list 
        ; body : Analyzer.Instruction.t Qsp_syntax.S.repr list
        ; pos : Qsp_syntax.S.pos
        ; clauses : (
            ( (Analyzer.Instruction.expression, Analyzer.Instruction.t) Qsp_syntax.S.clause list 
            * (Qsp_syntax.S.pos *Analyzer.Instruction.t Qsp_syntax.S.repr list) option
            ) option )
        }

    module Helper = Qsp_syntax.S.Helper(Analyzer.Expression)
    module HelperI = Qsp_syntax.S.Helper(Analyzer.Instruction)
%}

%parameter<Analyzer: Qsp_syntax.S.Analyzer>
%start <(Analyzer.Location.t * Qsp_syntax.Report.t list) Qsp_syntax.S.repr>main
%on_error_reduce expression instruction unary_operator assignation_operator

%% 

main: 
    | before_location*
      LOCATION_START
      EOL+
      instructions = line_statement*
      LOCATION_END
    { 
        let instructions = List.map instructions ~f:(HelperI.v) in
        Analyzer.Location.location $loc instructions
    }

before_location:
    | EOL {}
    | COMMENT EOL { }

(* All these statement should terminate with EOL *)
line_statement:
    | COMMENT EOL+ { Analyzer.Instruction.comment $loc }
    | COLUMN i=IDENT EOL* { Analyzer.Instruction.location $loc i }
    | s = terminated(instruction, line_sep) 
    | s = terminated(inline_action, line_sep)
        { s }
    | a = action_bloc(IF, elif_else_body) 
    { let {loc; expression; body; pos; clauses } = a in 
        let elifs, else_ = match clauses with 
        | None -> [], None
        | Some (elifs, else_) -> (elifs, else_)
        in
        Analyzer.Instruction.if_
            loc 
            (pos, expression, body) 
            ~elifs
            ~else_
      }
    | a = action_bloc(ACT, empty_body) 
      { let {loc; expression; body;  _}  = a in 
        Analyzer.Instruction.act loc ~label:expression body
      }

(** Represent an instruction which can either be on a single line, 
    or created in a block until an END 
 *)
%inline action_bloc(TOKEN, BODY):
    | TOKEN
      e = expression 
      COLUMN EOL+
      s = line_statement*
      b = BODY
      END TOKEN?
      line_sep
      { 
        let expression = Helper.v' e in
        let clauses = match b with
        | None -> None
        | Some (elifs, clauses) -> 
            let elifs = begin match elifs with 
            | [] -> []
            | _ -> 
              List.map elifs
              ~f:(fun ((pos:Qsp_syntax.S.pos), e, instructions) -> 
                let e = Helper.v' e in
                (pos, e, instructions)
              )

            end in
          Some (elifs, clauses)
        in 

        { loc = $loc 
        ; expression
        ; body = s
        ; clauses
        ; pos = $loc(s)
        }
      }

empty_body:
    | { None }

elif:
    | ELIF
      e = expression 
      COLUMN EOL+
      s = line_statement*
      { $loc, e, s }

else_:
    | ELSE EOL+
      expressions = line_statement*
      { Some ($loc, expressions) }
    | { None }


elif_else_body: 
    | elifs = elif*
      else_ = else_
      { Some (elifs, else_) }


%inline line_sep:
    | EOL+
    | AMPERSAND+ EOL*
    {}