parser.mly 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. %{
  2. module T = Qsp_syntax.T
  3. open StdLabels
  4. type action_block =
  5. { loc : Qsp_syntax.S.pos
  6. ; expression :
  7. Analyzer.Expression.t'
  8. ; body : Analyzer.Instruction.t list
  9. ; pos : Qsp_syntax.S.pos
  10. ; clauses : (
  11. ( (Analyzer.Expression.t', Analyzer.Instruction.t) Qsp_syntax.S.clause list
  12. * (Qsp_syntax.S.pos * Analyzer.Instruction.t list) option
  13. ) option )
  14. }
  15. module Helper = Qsp_syntax.S.Helper(Analyzer.Expression)
  16. %}
  17. %parameter<Analyzer: Qsp_syntax.S.Analyzer>
  18. %start <(Analyzer.context -> Analyzer.Location.t)>main
  19. %on_error_reduce expression instruction unary_operator assignation_operator
  20. %%
  21. main:
  22. | before_location*
  23. start_location
  24. EOL+
  25. instructions = line_statement*
  26. LOCATION_END
  27. {
  28. let instructions = List.map instructions ~f:(Analyzer.Instruction.v) in
  29. fun context -> Analyzer.Location.location context $loc instructions
  30. }
  31. before_location:
  32. | EOL {}
  33. | COMMENT EOL { }
  34. (* Defer the registration here, and ensure we get a valid rule. *)
  35. start_location:
  36. | l = LOCATION_START
  37. {
  38. ignore (l ())
  39. }
  40. (* All these statement should terminate with EOL *)
  41. line_statement:
  42. | COMMENT EOL+ { Analyzer.Instruction.comment $loc }
  43. | COLUMN i=IDENT EOL* { Analyzer.Instruction.location $loc i }
  44. | s = terminated(instruction, line_sep)
  45. | s = terminated(inline_action, line_sep)
  46. { s }
  47. | a = action_bloc(IF, elif_else_body)
  48. { let {loc; expression; body; pos; clauses } = a in
  49. let elifs, else_ = match clauses with
  50. | None -> [], None
  51. | Some (elifs, else_) -> (elifs, else_)
  52. in
  53. Analyzer.Instruction.if_
  54. loc
  55. (pos, expression, body)
  56. ~elifs
  57. ~else_
  58. }
  59. | a = action_bloc(ACT, empty_body)
  60. { let {loc; expression; body; _} = a in
  61. Analyzer.Instruction.act loc ~label:expression body
  62. }
  63. | FOR
  64. variable = variable
  65. EQUAL
  66. start = expression
  67. TO
  68. to_ = expression
  69. step = option(pair(STEP, expression))
  70. COLUMN EOL+
  71. s = line_statement*
  72. END EOL+
  73. {
  74. let variable = Helper.variable variable in
  75. let start = Analyzer.Expression.v start in
  76. let to_ = Analyzer.Expression.v to_ in
  77. let step = Option.map (fun v -> Analyzer.Expression.v (snd v)) step in
  78. Analyzer.Instruction.for_ $loc variable ~start ~to_ ~step s
  79. }
  80. (** Represent an instruction which can either be on a single line,
  81. or created in a block until an END
  82. *)
  83. %inline action_bloc(TOKEN, BODY):
  84. | TOKEN
  85. e = expression
  86. COLUMN EOL+
  87. s = line_statement*
  88. b = BODY
  89. END
  90. line_sep
  91. {
  92. let expression = Analyzer.Expression.v e in
  93. let clauses = match b with
  94. | None -> None
  95. | Some (elifs, clauses) ->
  96. let elifs = begin match elifs with
  97. | [] -> []
  98. | _ ->
  99. List.map elifs
  100. ~f:(fun ((pos:Qsp_syntax.S.pos), e, instructions) ->
  101. let e = Analyzer.Expression.v e in
  102. (pos, e, instructions)
  103. )
  104. end in
  105. Some (elifs, clauses)
  106. in
  107. { loc = $loc
  108. ; expression
  109. ; body = s
  110. ; clauses
  111. ; pos = $loc(s)
  112. }
  113. }
  114. empty_body:
  115. | { None }
  116. elif:
  117. | ELIF
  118. e = expression
  119. COLUMN EOL+
  120. s = line_statement*
  121. { $loc, e, s }
  122. else_:
  123. | ELSE EOL+
  124. expressions = line_statement*
  125. { Some ($loc, expressions) }
  126. | { None }
  127. elif_else_body:
  128. | elifs = elif*
  129. else_ = else_
  130. { Some (elifs, else_) }
  131. %inline line_sep:
  132. | EOL+
  133. | AMPERSAND+ EOL*
  134. {}