String_with_vars: Distinguish quoted and unquoted strings

This implies that an atom can only contain a single variable, such as
${@}, and not something like xxx${@}xxx.  The internal representation
was changed not to be able to represent the latter.
This commit is contained in:
Christophe Troestler 2018-01-30 18:08:28 +01:00
parent cc9c71661e
commit 754aa59cc3
2 changed files with 30 additions and 38 deletions

View File

@ -6,12 +6,10 @@ type item =
| Text of string | Text of string
| Var of var_syntax * string | Var of var_syntax * string
(* A single unquoted variable is encoded as the list [Var v]. A
quoted variable is encoded as [Var v; Text ""]. *)
type t = type t =
{ items : item list { items : item list
; loc : Loc.t ; loc : Loc.t
} ; quoted : bool }
module Token = struct module Token = struct
type t = type t =
@ -48,6 +46,7 @@ module Token = struct
| Close Parens -> ")" | Close Parens -> ")"
end end
(* Remark: Consecutive [Text] items are concatenated. *)
let rec of_tokens : Token.t list -> item list = function let rec of_tokens : Token.t list -> item list = function
| [] -> [] | [] -> []
| Open a :: String s :: Close b :: rest when a = b -> | Open a :: String s :: Close b :: rest when a = b ->
@ -58,33 +57,27 @@ let rec of_tokens : Token.t list -> item list = function
| Text s' :: l -> Text (s ^ s') :: l | Text s' :: l -> Text (s ^ s') :: l
| l -> Text s :: l | l -> Text s :: l
let of_string ~loc s = let items_of_string s = of_tokens (Token.tokenise s)
{ items = of_tokens (Token.tokenise s)
; loc
}
let unquoted_var t = let unquoted_var t =
match t.items with match t.quoted, t.items with
| [Var (_, s)] -> Some s | true, [Var(_, s)] -> Some s
| _ -> None | _ -> None
let t : Sexp.Of_sexp.ast -> t = function let t : Sexp.Of_sexp.ast -> t = function
| Atom(loc, s) -> of_string ~loc s | Atom(loc, s) -> { items = items_of_string s; loc; quoted = false }
| Quoted_string (loc, s) -> | Quoted_string (loc, s) ->
(* If [unquoted_var], then add [""] at the end (see [type t]). *) { items = items_of_string s; loc; quoted = true }
let t = of_string ~loc s in
(match t.items with
| [Var _ as v] -> {t with items = [v; Text ""] }
| _ -> t)
| List _ as sexp -> Sexp.Of_sexp.of_sexp_error sexp "Atom expected" | List _ as sexp -> Sexp.Of_sexp.of_sexp_error sexp "Atom expected"
let loc t = t.loc let loc t = t.loc
let virt pos s = of_string ~loc:(Loc.of_pos pos) s let virt ?(quoted=true) pos s =
let virt_var pos s = { loc = Loc.of_pos pos; items = [Var (Braces, s)] } { items = items_of_string s; loc = Loc.of_pos pos; quoted }
let virt_quoted_var pos s = { loc = Loc.of_pos pos; let virt_var ?(quoted=true) pos s =
items = [Var (Braces, s); Text ""] } { items = [Var (Braces, s)]; loc = Loc.of_pos pos; quoted }
let virt_text pos s = { loc = Loc.of_pos pos; items = [Text s] } let virt_text pos s =
{ items = [Text s]; loc = Loc.of_pos pos; quoted = true }
let sexp_of_var_syntax = function let sexp_of_var_syntax = function
| Parens -> Sexp.Atom "parens" | Parens -> Sexp.Atom "parens"
@ -100,14 +93,13 @@ let sexp_of_t t = Sexp.To_sexp.list sexp_of_item t.items
let fold t ~init ~f = let fold t ~init ~f =
List.fold_left t.items ~init ~f:(fun acc item -> List.fold_left t.items ~init ~f:(fun acc item ->
match item with match item with
| Text _ -> acc | Text _ -> acc
| Var (_, v) -> f acc t.loc v) | Var (_, v) -> f acc t.loc v)
let iter t ~f = let iter t ~f = List.iter t.items ~f:(function
List.iter t.items ~f:(function | Text _ -> ()
| Text _ -> () | Var (_, v) -> f t.loc v)
| Var (_, v) -> f t.loc v)
let vars t = fold t ~init:String_set.empty ~f:(fun acc _ x -> String_set.add x acc) let vars t = fold t ~init:String_set.empty ~f:(fun acc _ x -> String_set.add x acc)
@ -118,11 +110,11 @@ let string_of_var syntax v =
let expand t ~f = let expand t ~f =
List.map t.items ~f:(function List.map t.items ~f:(function
| Text s -> s | Text s -> s
| Var (syntax, v) -> | Var (syntax, v) ->
match f t.loc v with match f t.loc v with
| Some x -> x | Some x -> x
| None -> string_of_var syntax v) | None -> string_of_var syntax v)
|> String.concat ~sep:"" |> String.concat ~sep:""
let concat_rev = function let concat_rev = function
@ -140,7 +132,8 @@ let partial_expand t ~f =
| [] -> begin | [] -> begin
match acc with match acc with
| [] -> Inl (concat_rev acc_text) | [] -> Inl (concat_rev acc_text)
| _ -> Inr { t with items = List.rev (commit_text acc_text acc) } | _ ->
Inr { t with items = List.rev (commit_text acc_text acc) }
end end
| Text s :: items -> loop (s :: acc_text) acc items | Text s :: items -> loop (s :: acc_text) acc items
| Var (_, v) as it :: items -> | Var (_, v) as it :: items ->

View File

@ -23,10 +23,9 @@ val to_string : t -> string
(** [t] generated by the OCaml code. The first argument should be (** [t] generated by the OCaml code. The first argument should be
[__POS__]. The second is either a string to parse, a variable name [__POS__]. The second is either a string to parse, a variable name
or plain text. *) or plain text. *)
val virt : (string * int * int * int) -> string -> t val virt : ?quoted: bool -> (string * int * int * int) -> string -> t
val virt_var : (string * int * int * int) -> string -> t val virt_var : ?quoted: bool -> (string * int * int * int) -> string -> t
val virt_quoted_var : (string * int * int * int) -> string -> t val virt_text : (string * int * int * int) -> string -> t
val virt_text : (string * int * int * int) -> string -> t
val unquoted_var : t -> string option val unquoted_var : t -> string option
(** [unquoted_var t] return the [Some name] where [name] is the name of (** [unquoted_var t] return the [Some name] where [name] is the name of