98 lines
4.0 KiB
OCaml
98 lines
4.0 KiB
OCaml
(** A program source file, read by the reader its extension names: [.fln] is
|
|
the indented syntax ([Indent_reader]), anything else the paren syntax
|
|
([Reader]). Both give the same [Form.t], so nothing past this point knows
|
|
which one a file was written in, and a program may mix them freely.
|
|
|
|
Only program sources come through here. The prelude is indented text
|
|
embedded in the compiler and read by [Prelude.read]; the wire protocol and
|
|
the registry's spellings are paren text the compiler writes itself, and
|
|
read it with [Reader] directly. *)
|
|
|
|
let indented_ext = ".fln"
|
|
let paren_ext = ".flan"
|
|
|
|
let is_indented path = Filename.check_suffix path indented_ext
|
|
|
|
(** A file a package directory contributes, in either syntax. *)
|
|
let is_source path =
|
|
Filename.check_suffix path paren_ext || is_indented path
|
|
|
|
let read_file path =
|
|
if is_indented path then Indent_reader.read_file path else Reader.read_file path
|
|
|
|
(* ── Code from the editor ─────────────────────────────────────────────
|
|
|
|
The dev loop's code-carrying requests say which syntax their [:code] is in
|
|
([:syntax]), and where in the buffer it starts ([:line], [:col]), rather
|
|
than having it guessed from [:file]: an expansion shown in paren syntax is
|
|
sent back under the name of the .fln file it came from, and a REPL line has
|
|
no file at all. [Dev] sets these for the length of one request, and every
|
|
place the session reads editor code reads it through [read_code]. *)
|
|
|
|
type syntax = Paren | Indented
|
|
|
|
let code_syntax = ref Paren
|
|
let code_at : (int * int) option ref = ref None
|
|
|
|
(* The column of the statement editor code was cut out of, when the code
|
|
starts after that statement's first word: see [Indent_reader.layout]. *)
|
|
let code_indent : int option ref = ref None
|
|
|
|
let syntax_of_field = function
|
|
| Some ("indented" | "fln") -> Indented
|
|
| _ -> Paren
|
|
|
|
let in_request = ref false
|
|
|
|
let with_code ?indent ~syntax ~at f =
|
|
let s = !code_syntax and a = !code_at and i = !code_indent
|
|
and r = !in_request in
|
|
code_syntax := syntax;
|
|
code_at := at;
|
|
code_indent := indent;
|
|
in_request := true;
|
|
Fun.protect
|
|
~finally:(fun () ->
|
|
code_syntax := s; code_at := a; code_indent := i; in_request := r) f
|
|
|
|
(* Was the code at [loc] written in the indented syntax? Inside an editor
|
|
request the request says; outside one a file's name does, as
|
|
[read_file] decides. *)
|
|
let indented_at (loc : Loc.t) =
|
|
if !in_request then !code_syntax = Indented else is_indented loc.Loc.file
|
|
|
|
(* The paren reader started at a line and column: [Reader.read_all] always
|
|
starts at 1:1. *)
|
|
let read_paren ?(line = 1) ?(col = 1) ~file src =
|
|
let st = Reader.of_string ~file src in
|
|
st.Reader.line <- line;
|
|
st.Reader.col <- col;
|
|
let rec go acc =
|
|
Reader.skip_ignorable st;
|
|
if Reader.at_end st then List.rev acc else go (Reader.read_form st :: acc)
|
|
in
|
|
go []
|
|
|
|
(** Editor code, in the request's syntax and at its position. With [expr],
|
|
an indented snippet of several statements is one expression,
|
|
[(do ...)]: a block of lines means its lines in order. A [let] is a
|
|
global only in code from column 1 that is not an expression: a form cut
|
|
from inside a body, for a macroexpansion say, keeps its lets local. *)
|
|
let read_code ?(expr = false) ~file code =
|
|
let line, col =
|
|
match !code_at with Some (l, c) -> (l, c) | None -> (1, 1)
|
|
in
|
|
match !code_syntax with
|
|
| Paren -> read_paren ~line ~col ~file code
|
|
| Indented ->
|
|
(match Indent_reader.read_all ~line ~col ?indent:!code_indent ~global_let:(not expr && col = 1)
|
|
~file code with
|
|
| (first :: _ :: _ as forms) when expr ->
|
|
let last = List.nth forms (List.length forms - 1) in
|
|
let loc =
|
|
{ first.Form.loc with Loc.eline = last.Form.loc.Loc.eline;
|
|
ecol = last.Form.loc.Loc.ecol }
|
|
in
|
|
[ Form.make (Form.List (Form.make (Form.Sym "do") first.Form.loc :: forms)) loc ]
|
|
| forms -> forms)
|