parser.mly 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. | a = action_bloc(IF, elif_else_body)
  45. { let {loc; expression; body; pos; clauses } = a in
  46. let elifs, else_ = match clauses with
  47. | None -> [], None
  48. | Some (elifs, else_) -> (elifs, else_)
  49. in
  50. Analyzer.Instruction.if_
  51. loc
  52. (pos, expression, body)
  53. ~elifs
  54. ~else_
  55. }
  56. | a = action_bloc(ACT, empty_body)
  57. { let {loc; expression; body; _} = a in
  58. Analyzer.Instruction.act loc ~label:expression body
  59. }
  60. | b = inlined_block(line_sep)
  61. { b }
  62. | FOR
  63. variable = variable
  64. EQUAL
  65. start = expression
  66. TO
  67. to_ = expression
  68. step = option(pair(STEP, expression))
  69. COLUMN EOL+
  70. s = line_statement*
  71. END
  72. {
  73. let variable = Helper.variable variable in
  74. let start = Analyzer.Expression.v start in
  75. let to_ = Analyzer.Expression.v to_ in
  76. let step = Option.map (fun v -> Analyzer.Expression.v (snd v)) step in
  77. Analyzer.Instruction.for_ $loc variable ~start ~to_ ~step s
  78. }
  79. (** Represent an instruction which can either be on a single line,
  80. or created in a block until an END
  81. *)
  82. %inline action_bloc(TOKEN, BODY):
  83. | TOKEN
  84. e = expression
  85. COLUMN EOL+
  86. s = line_statement*
  87. b = BODY
  88. END
  89. line_sep
  90. {
  91. let expression = Analyzer.Expression.v e in
  92. let clauses = match b with
  93. | None -> None
  94. | Some (elifs, clauses) ->
  95. let elifs = begin match elifs with
  96. | [] -> []
  97. | _ ->
  98. List.map elifs
  99. ~f:(fun ((pos:Qsp_syntax.S.pos), e, instructions) ->
  100. let e = Analyzer.Expression.v e in
  101. (pos, e, instructions)
  102. )
  103. end in
  104. Some (elifs, clauses)
  105. in
  106. { loc = $loc
  107. ; expression
  108. ; body = s
  109. ; clauses
  110. ; pos = $loc(s)
  111. }
  112. }
  113. empty_body:
  114. | { None }
  115. elif:
  116. | ELIF
  117. e = expression
  118. COLUMN EOL+
  119. s = line_statement*
  120. { $loc, e, s }
  121. else_:
  122. | ELSE EOL+
  123. expressions = line_statement*
  124. { Some ($loc, expressions) }
  125. | { None }
  126. elif_else_body:
  127. | elifs = elif*
  128. else_ = else_
  129. { Some (elifs, else_) }
  130. %inline line_sep:
  131. | EOL+
  132. | AMPERSAND+ EOL*
  133. {}