parser.mly 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. (** Represent an instruction which can either be on a single line,
  63. or created in a block until an END
  64. *)
  65. %inline action_bloc(TOKEN, BODY):
  66. | TOKEN
  67. e = expression
  68. COLUMN EOL+
  69. s = line_statement*
  70. b = BODY
  71. END
  72. line_sep
  73. {
  74. let expression = Analyzer.Expression.v e in
  75. let clauses = match b with
  76. | None -> None
  77. | Some (elifs, clauses) ->
  78. let elifs = begin match elifs with
  79. | [] -> []
  80. | _ ->
  81. List.map elifs
  82. ~f:(fun ((pos:Qsp_syntax.S.pos), e, instructions) ->
  83. let e = Analyzer.Expression.v e in
  84. (pos, e, instructions)
  85. )
  86. end in
  87. Some (elifs, clauses)
  88. in
  89. { loc = $loc
  90. ; expression
  91. ; body = s
  92. ; clauses
  93. ; pos = $loc(s)
  94. }
  95. }
  96. empty_body:
  97. | { None }
  98. elif:
  99. | ELIF
  100. e = expression
  101. COLUMN EOL+
  102. s = line_statement*
  103. { $loc, e, s }
  104. else_:
  105. | ELSE EOL+
  106. expressions = line_statement*
  107. { Some ($loc, expressions) }
  108. | { None }
  109. elif_else_body:
  110. | elifs = elif*
  111. else_ = else_
  112. { Some (elifs, else_) }
  113. %inline line_sep:
  114. | EOL+
  115. | AMPERSAND+ EOL*
  116. {}