#156: start of support for quoted strings

This commit is contained in:
Jérémie Dimino 2016-02-04 08:06:11 +00:00
parent b63e0f9225
commit fd7c663264
3 changed files with 37 additions and 19 deletions

View File

@ -74,7 +74,7 @@ let parse_longident tokens =
| l -> Some (longident_of_list l)) | l -> Some (longident_of_list l))
in in
match tokens with match tokens with
| ((Comment (_, false) | String false | Quotation (_, false)), _) :: _ -> | ((Comment (_, false) | String (_, false) | Quotation (_, false)), _) :: _ ->
(* An unterminated command, string, or quotation. *) (* An unterminated command, string, or quotation. *)
None None
| ((Uident id | Lident id), { idx1 = start }) :: tokens -> | ((Uident id | Lident id), { idx1 = start }) :: tokens ->
@ -847,23 +847,23 @@ let complete ~syntax ~phrase_terminator ~input =
(start, lookup_assoc src (list_directives phrase_terminator)) (start, lookup_assoc src (list_directives phrase_terminator))
(* Complete with ";;" when possible. *) (* Complete with ";;" when possible. *)
| [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, { idx2 = stop })] | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), { idx2 = stop })]
| [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, _); (Blanks, { idx2 = stop })] -> | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Blanks, { idx2 = stop })] ->
(stop, [(phrase_terminator, "")]) (stop, [(phrase_terminator, "")])
| [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, _); (Symbol sym, { idx1 = start })] -> | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Symbol sym, { idx1 = start })] ->
if Zed_utf8.starts_with phrase_terminator sym then if Zed_utf8.starts_with phrase_terminator sym then
(start, [(phrase_terminator, "")]) (start, [(phrase_terminator, "")])
else else
(0, []) (0, [])
(* Completion on #require. *) (* Completion on #require. *)
| [(Symbol "#", _); (Lident "require", _); (String false, loc)] -> | [(Symbol "#", _); (Lident "require", _); (String (tlen, false), loc)] ->
let pkg = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let pkg = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
let pkgs = lookup pkg (Fl_package_base.list_packages ()) in let pkgs = lookup pkg (Fl_package_base.list_packages ()) in
(loc.idx1 + 1, List.map (fun pkg -> (pkg, "\"" ^ phrase_terminator)) (List.sort compare pkgs)) (loc.idx1 + 1, List.map (fun pkg -> (pkg, "\"" ^ phrase_terminator)) (List.sort compare pkgs))
| [(Symbol "#", _); (Lident "typeof", _); (String false, loc)] -> | [(Symbol "#", _); (Lident "typeof", _); (String (tlen, false), loc)] ->
let prefix = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let prefix = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
begin match Longident.parse prefix with begin match Longident.parse prefix with
| Longident.Ldot (lident, last_prefix) -> | Longident.Ldot (lident, last_prefix) ->
let set = names_of_module lident in let set = names_of_module lident in
@ -877,8 +877,8 @@ let complete ~syntax ~phrase_terminator ~input =
end end
(* Completion on #load. *) (* Completion on #load. *)
| [(Symbol "#", _); (Lident ("load" | "load_rec"), _); (String false, loc)] -> | [(Symbol "#", _); (Lident ("load" | "load_rec"), _); (String (tlen, false), loc)] ->
let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
let filter name = Filename.check_suffix name ".cma" || Filename.check_suffix name ".cmo" in let filter name = Filename.check_suffix name ".cma" || Filename.check_suffix name ".cmo" in
let map = let map =
if Filename.is_relative file then if Filename.is_relative file then
@ -898,8 +898,8 @@ let complete ~syntax ~phrase_terminator ~input =
#if OCAML_VERSION >= (4, 02, 0) #if OCAML_VERSION >= (4, 02, 0)
(* Completion on #ppx. *) (* Completion on #ppx. *)
| [(Symbol "#", _); (Lident ("ppx"), _); (String false, loc)] -> | [(Symbol "#", _); (Lident ("ppx"), _); (String (tlen, false), loc)] ->
let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
let filter ~dir_ok name = let filter ~dir_ok name =
try try
Unix.access name [Unix.X_OK]; Unix.access name [Unix.X_OK];
@ -928,8 +928,8 @@ let complete ~syntax ~phrase_terminator ~input =
#endif #endif
(* Completion on #use. *) (* Completion on #use. *)
| [(Symbol "#", _); (Lident "use", _); (String false, loc)] -> | [(Symbol "#", _); (Lident "use", _); (String (tlen, false), loc)] ->
let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
let filter name = let filter name =
match try Some (String.rindex name '.') with Not_found -> None with match try Some (String.rindex name '.') with Not_found -> None with
| None -> | None ->
@ -955,8 +955,8 @@ let complete ~syntax ~phrase_terminator ~input =
List.map (function (w, Directory) -> (w, "") | (w, File) -> (w, "\"" ^ phrase_terminator)) result) List.map (function (w, Directory) -> (w, "") | (w, File) -> (w, "\"" ^ phrase_terminator)) result)
(* Completion on #directory and #cd. *) (* Completion on #directory and #cd. *)
| [(Symbol "#", _); (Lident ("cd" | "directory"), _); (String false, loc)] -> | [(Symbol "#", _); (Lident ("cd" | "directory"), _); (String (tlen, false), loc)] ->
let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
let list = list_directories (Filename.dirname file) in let list = list_directories (Filename.dirname file) in
let name = basename file in let name = basename file in
let result = lookup name list in let result = lookup name list in

View File

@ -117,7 +117,13 @@ rule tokens syntax context idx acc = parse
{ let ofs = lexeme_start lexbuf in { let ofs = lexeme_start lexbuf in
let idx2, terminated = string (idx + 1) lexbuf in let idx2, terminated = string (idx + 1) lexbuf in
let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
tokens syntax context idx2 ((String terminated, loc) :: acc) lexbuf } tokens syntax context idx2 ((String (1, terminated), loc) :: acc) lexbuf }
| '{' (lowercase* as tag) '|'
{ let ofs = lexeme_start lexbuf in
let delim_len = String.length tag + 2 in
let idx2, terminated = quoted_string (idx + delim_len) tag lexbuf in
let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
tokens syntax context idx2 ((String (delim_len, terminated), loc) :: acc) lexbuf }
| "'" [^'\'' '\\'] "'" | "'" [^'\'' '\\'] "'"
| "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\'' 'x' '0'-'9'] eof | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\'' 'x' '0'-'9'] eof
| "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\''] "'" | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\''] "'"
@ -217,6 +223,18 @@ and string idx = parse
| eof | eof
{ (idx, false) } { (idx, false) }
and quoted_string idx tag = parse
| '|' (lowercase* as tag2) '}'
{ let idx = idx + 2 + String.length tag2 in
if tag = tag2 then
(idx, true)
else
quoted_string idx tag lexbuf }
| eof
{ (idx, false) }
| uchar
{ quoted_string (idx + 1) tag lexbuf }
and quotation syntax depth idx1 idx2 ofs1 = parse and quotation syntax depth idx1 idx2 ofs1 = parse
| '<' (':' ident)? ('@' lident)? '<' | '<' (':' ident)? ('@' lident)? '<'
{ quotation syntax (depth + 1) idx1 (idx2 + lexeme_size lexbuf) ofs1 lexbuf } { quotation syntax (depth + 1) idx1 (idx2 + lexeme_size lexbuf) ofs1 lexbuf }

View File

@ -30,8 +30,8 @@ type t =
| Uident of string | Uident of string
| Constant of string | Constant of string
| Char | Char
| String of bool | String of int * bool
(** [String terminated]. *) (** [String (quote_size, terminated)]. *)
| Comment of comment_kind * bool | Comment of comment_kind * bool
(** [Comment (kind, terminated)]. *) (** [Comment (kind, terminated)]. *)
| Blanks | Blanks