parser.mly 3.2 KB

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