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*
{}
|