File: Toplevel_lexer.mll

package info (click to toggle)
ocamlformat 0.27.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 12,068 kB
  • sloc: ml: 61,288; pascal: 4,739; lisp: 229; sh: 217; makefile: 121
file content (83 lines) | stat: -rw-r--r-- 3,243 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
(**************************************************************************)
(*                                                                        *)
(*                              OCamlFormat                               *)
(*                                                                        *)
(*            Copyright (c) Facebook, Inc. and its affiliates.            *)
(*                                                                        *)
(*      This source code is licensed under the MIT license found in       *)
(*      the LICENSE file in the root directory of this source tree.       *)
(*                                                                        *)
(**************************************************************************)

{
open Stdlib
open Migrate_ast

let newline lexbuf = Lexing.new_line lexbuf
}

let eol = ('\013'* '\010')
let ws = ' ' | '\t' | eol

rule token = parse
 | eof           { [] }
 | eol           { newline lexbuf;
                   `Output ("", Location.curr lexbuf) :: token lexbuf }
 | "#" ws+       { let pos_start = Lexing.lexeme_end_p lexbuf in
                   let c = phrase (Buffer.create 8) lexbuf in
                   `Command (c, pos_start) :: token lexbuf }
 | ([^'#' '\n'] [^'\n']* as str) eol
                 { newline lexbuf;
                   `Output (str, Location.curr lexbuf) :: token lexbuf }
 | _ as c        {
     let msg =
       Format.sprintf
         "unexpected character '%c'.\n\
          Hint: did you forget a space after the '#' at the start of the line?"
         c
     in
     raise (Syntaxerr.Error (Not_expecting (Location.curr lexbuf, msg))) }

and phrase buf = parse
  | eof      {
     let msg = "a toplevel phrase must end with `;;`." in
     raise (Syntaxerr.Error (Expecting (Location.curr lexbuf, msg))) }
  | ((eol* eol) as nl) ("  " | "\t")
      { for _ = 1 to (Base.String.count ~f:(Char.equal '\n') nl) do
          newline lexbuf;
          Buffer.add_char buf '\n'
        done;
        phrase buf lexbuf }
  | ";;"     { Buffer.add_string buf ";;"; Buffer.contents buf }
  | _ as c   { Buffer.add_char buf c; phrase buf lexbuf }

{
let repl_file ~ocaml_version lx =
  let x = token lx in
  let open Ocamlformat_parser_extended.Parsetree in
  List.fold_left (fun acc -> function
      | `Command (cmd, pos_start) ->
          let cmd_lexbuf = Lexing.from_string cmd in
          let filename = (Location.curr lx).loc_start.pos_fname in
          Lexing.set_filename cmd_lexbuf filename ;
          Lexing.set_position cmd_lexbuf pos_start ;
          { prepl_phrase= Parse.toplevel_phrase ~ocaml_version cmd_lexbuf
          ; prepl_output= "" }
          :: acc
      | `Output ("", _) -> acc
      | `Output (line, loc) -> (
          match acc with
          | [] ->
              let msg =
                Format.sprintf
                  "%S.\n\
                   Hint: A toplevel block must start with a toplevel phrase \
                   starting with `# `." line
              in
              raise (Syntaxerr.Error (Not_expecting (loc, msg)))
          | {prepl_phrase; prepl_output} :: t ->
              {prepl_phrase; prepl_output= prepl_output ^ line}
              :: t )
    ) [] x
  |> List.rev
}