123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- %{
- module T = Qsp_syntax.T
- open StdLabels
- type action_block =
- { loc : Qsp_syntax.S.pos
- ; expression :
- Analyzer.Expression.t'
- ; body : Analyzer.Instruction.t list
- ; pos : Qsp_syntax.S.pos
- ; clauses : (
- ( (Analyzer.Expression.t', Analyzer.Instruction.t) Qsp_syntax.S.clause list
- * (Qsp_syntax.S.pos * Analyzer.Instruction.t list) option
- ) option )
- }
- module Helper = Qsp_syntax.S.Helper(Analyzer.Expression)
- %}
- %parameter<Analyzer: Qsp_syntax.S.Analyzer>
- %start <(Analyzer.context -> Analyzer.Location.t)>main
- %on_error_reduce expression instruction unary_operator assignation_operator
- %%
- main:
- | before_location*
- start_location
- EOL+
- instructions = line_statement*
- LOCATION_END
- {
- let instructions = List.map instructions ~f:(Analyzer.Instruction.v) in
- fun context -> Analyzer.Location.location context $loc instructions
- }
- before_location:
- | EOL {}
- | COMMENT EOL { }
- (* Defer the registration here, and ensure we get a valid rule. *)
- start_location:
- | l = LOCATION_START
- {
- ignore (l ())
- }
- (* 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
- }
- | FOR
- variable = variable
- EQUAL
- start = expression
- TO
- to_ = expression
- step = option(pair(STEP, expression))
- COLUMN EOL+
- s = line_statement*
- END EOL+
- {
- let variable = Helper.variable variable in
- let start = Analyzer.Expression.v start in
- let to_ = Analyzer.Expression.v to_ in
- let step = Option.map (fun v -> Analyzer.Expression.v (snd v)) step in
- Analyzer.Instruction.for_ $loc variable ~start ~to_ ~step s
- }
- (** 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
- line_sep
- {
- let expression = Analyzer.Expression.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 = Analyzer.Expression.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*
- {}
|