mirror of
https://github.com/comby-tools/comby.git
synced 2024-09-11 13:25:36 +03:00
Add new matching engine (#127)
This commit is contained in:
parent
adea33d153
commit
1aacf1c057
@ -47,7 +47,7 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
| Some { delimiters; escape_character } ->
|
||||
List.map delimiters ~f:(fun delimiter ->
|
||||
let module M =
|
||||
Parsers.String_literals.Escapable.Make(struct
|
||||
Parsers.String_literals.Alpha.Escapable.Make(struct
|
||||
let delimiter = delimiter
|
||||
let escape = escape_character
|
||||
end)
|
||||
@ -59,7 +59,7 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
let raw_string_literal_parser (f : 'a literal_parser_callback) =
|
||||
List.map Syntax.raw_string_literals ~f:(fun (left_delimiter, right_delimiter) ->
|
||||
let module M =
|
||||
Parsers.String_literals.Raw.Make(struct
|
||||
Parsers.String_literals.Alpha.Raw.Make(struct
|
||||
let left_delimiter = left_delimiter
|
||||
let right_delimiter = right_delimiter
|
||||
end)
|
||||
@ -75,7 +75,7 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
List.map syntax ~f:(function
|
||||
| Multiline (left, right) ->
|
||||
let module M =
|
||||
Parsers.Comments.Multiline.Make(struct
|
||||
Parsers.Comments.Alpha.Multiline.Make(struct
|
||||
let left = left
|
||||
let right = right
|
||||
end)
|
||||
@ -83,7 +83,7 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
M.comment
|
||||
| Nested_multiline (left, right) ->
|
||||
let module M =
|
||||
Parsers.Comments.Nested_multiline.Make(struct
|
||||
Parsers.Comments.Alpha.Nested_multiline.Make(struct
|
||||
let left = left
|
||||
let right = right
|
||||
end)
|
||||
@ -91,7 +91,7 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
M.comment
|
||||
| Until_newline start ->
|
||||
let module M =
|
||||
Parsers.Comments.Until_newline.Make(struct
|
||||
Parsers.Comments.Alpha.Until_newline.Make(struct
|
||||
let start = start
|
||||
end)
|
||||
in
|
@ -1,5 +1,8 @@
|
||||
(copy_files# alpha/*.ml{,i})
|
||||
; (copy_files# omega/*.ml{,i})
|
||||
|
||||
(library
|
||||
(name matchers)
|
||||
(public_name comby.matchers)
|
||||
(preprocess (pps ppx_sexp_conv ppx_sexp_message ppx_deriving_yojson bisect_ppx --conditional))
|
||||
(libraries comby.parsers comby.match ppxlib core core.uuid mparser mparser.pcre yojson ppx_deriving_yojson))
|
||||
(preprocess (pps ppx_here ppx_sexp_conv ppx_sexp_message ppx_deriving_yojson bisect_ppx --conditional))
|
||||
(libraries comby.parsers comby.match angstrom ppxlib core core.uuid mparser mparser.pcre yojson ppx_deriving_yojson))
|
||||
|
510
lib/matchers/omega/matcher.ml
Normal file
510
lib/matchers/omega/matcher.ml
Normal file
@ -0,0 +1,510 @@
|
||||
open Core
|
||||
open Angstrom
|
||||
|
||||
open Types
|
||||
open Omega
|
||||
|
||||
let configuration_ref = ref (Configuration.create ())
|
||||
|
||||
let matches_ref : Match.t list ref = ref []
|
||||
|
||||
let source_ref : string ref = ref ""
|
||||
|
||||
let current_environment_ref : Match.Environment.t ref = ref (Match.Environment.create ())
|
||||
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let debug =
|
||||
Sys.getenv "DEBUG_COMBY"
|
||||
|> Option.is_some
|
||||
|
||||
|
||||
type signal_hole =
|
||||
| Signal_a_hole of Types.hole
|
||||
| Dont_care
|
||||
|
||||
let record_match_context pos_before pos_after =
|
||||
let open Match.Location in
|
||||
if debug then Format.printf "match context start pos: %d@." pos_before;
|
||||
if debug then Format.printf "match context end pos %d@." pos_after;
|
||||
(* FIXME this may be slow. Try (a) collecting this
|
||||
or (b) removing it by just doing a rewrite *)
|
||||
let extract_matched_text source { offset = match_start; _ } { offset = match_end; _ } =
|
||||
String.slice source match_start match_end
|
||||
in
|
||||
let match_context =
|
||||
let match_start =
|
||||
{ default with offset = pos_before }
|
||||
in
|
||||
let match_end =
|
||||
{ default with offset = pos_after }
|
||||
in
|
||||
Match.
|
||||
{ range = { match_start; match_end }
|
||||
; environment = !current_environment_ref
|
||||
; matched = extract_matched_text !source_ref match_start match_end
|
||||
}
|
||||
in
|
||||
matches_ref := match_context :: !matches_ref
|
||||
|
||||
module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
include Info
|
||||
|
||||
(* This is the init we will pass in with a functor later *)
|
||||
let acc = 0
|
||||
|
||||
(* This is the function we will pass in with a functor later *)
|
||||
let f acc _production =
|
||||
acc + 1
|
||||
|
||||
let r acc production : (signal_hole * 'a) t =
|
||||
let open Match in
|
||||
let open Range in
|
||||
let acc = f acc production in
|
||||
match production with
|
||||
| String s ->
|
||||
if debug then Format.printf "Matched String: %S@." s;
|
||||
return (Dont_care, acc)
|
||||
| Match { offset = pos_after; identifier; text = content } ->
|
||||
(* using just pos after for now, because thats what we do in matcher. lol *)
|
||||
if debug then Format.printf "Match: %S @@ %d for %s@." content pos_after identifier;
|
||||
let before = Location.default in (* FIXME *)
|
||||
let after = { Location.default with offset = pos_after } in
|
||||
let range = { match_start = before; match_end = after } in
|
||||
let environment = Environment.add ~range !current_environment_ref identifier content in
|
||||
current_environment_ref := environment;
|
||||
return (Dont_care, acc)
|
||||
| _ -> return (Dont_care, acc)
|
||||
|
||||
let between left right p =
|
||||
left *> p <* right
|
||||
|
||||
let zero =
|
||||
fail ""
|
||||
|
||||
let comment_parser =
|
||||
match Syntax.comments with
|
||||
| [] -> zero
|
||||
| syntax ->
|
||||
List.map syntax ~f:(function
|
||||
| Multiline (left, right) ->
|
||||
let module M = Parsers.Comments.Omega.Multiline.Make(struct
|
||||
let left = left
|
||||
let right = right
|
||||
end)
|
||||
in
|
||||
M.comment
|
||||
| Until_newline start ->
|
||||
let module M = Parsers.Comments.Omega.Until_newline.Make(struct
|
||||
let start = start
|
||||
end)
|
||||
in
|
||||
M.comment
|
||||
| Nested_multiline (_, _) -> zero) (* FIXME unimplemented nested multiline comments *)
|
||||
|> choice
|
||||
|
||||
let escapable_string_literal_parser =
|
||||
(match Syntax.escapable_string_literals with
|
||||
| None -> []
|
||||
| Some { delimiters; escape_character } ->
|
||||
List.map delimiters ~f:(fun delimiter ->
|
||||
let module M =
|
||||
Parsers.String_literals.Omega.Escapable.Make(struct
|
||||
let delimiter = delimiter
|
||||
let escape = escape_character
|
||||
end)
|
||||
in
|
||||
M.base_string_literal >>= fun contents ->
|
||||
(* FIXME figure out if we need to do the same callback thing here to communicate
|
||||
forward that we entered a string *)
|
||||
return contents
|
||||
))
|
||||
|> choice
|
||||
|
||||
let until_of_from from =
|
||||
Syntax.user_defined_delimiters
|
||||
|> List.find_map ~f:(fun (from', until) -> if from = from' then Some until else None)
|
||||
|> function
|
||||
| Some until -> until
|
||||
| None -> assert false
|
||||
|
||||
let alphanum =
|
||||
satisfy (function
|
||||
| 'a' .. 'z'
|
||||
| 'A' .. 'Z'
|
||||
| '0' .. '9' -> true
|
||||
| _ -> false)
|
||||
|
||||
let is_whitespace = function
|
||||
| ' ' | '\t' | '\r' | '\n' -> true
|
||||
| _ -> false
|
||||
|
||||
let reserved_delimiters =
|
||||
List.concat_map Syntax.user_defined_delimiters ~f:(fun (from, until) -> [from; until])
|
||||
|> List.append [":["; "]"]
|
||||
|> List.append [":[["; "]]"]
|
||||
|
||||
let reserved =
|
||||
reserved_delimiters @ [" "; "\n"; "\t"; "\r"]
|
||||
|> List.sort ~compare:(fun v2 v1 ->
|
||||
String.length v1 - String.length v2)
|
||||
|
||||
(* XXX can shortcircuit *)
|
||||
(* what if you hit a reserved
|
||||
seqence "{" and then attempt
|
||||
":[[" and then say "end of
|
||||
input" and then move ahead any_char. not good.
|
||||
going from longest to shortest works though *)
|
||||
let any_char_except ~reserved =
|
||||
List.fold reserved
|
||||
~init:(return `OK)
|
||||
~f:(fun acc reserved_sequence ->
|
||||
option `End_of_input
|
||||
(peek_string (String.length reserved_sequence)
|
||||
>>= fun s ->
|
||||
if s = reserved_sequence then
|
||||
return `Reserved_sequence
|
||||
else
|
||||
acc))
|
||||
>>= function
|
||||
| `OK -> any_char
|
||||
| `End_of_input -> any_char
|
||||
| `Reserved_sequence -> fail "reserved sequence hit"
|
||||
|
||||
let generate_single_hole_parser () =
|
||||
(alphanum <|> char '_') |>> String.of_char
|
||||
|
||||
let generate_greedy_hole_parser
|
||||
?priority_left_delimiter:left_delimiter
|
||||
?priority_right_delimiter:right_delimiter
|
||||
() =
|
||||
let between_nested_delims p from =
|
||||
let until = until_of_from from in
|
||||
between (string from) (string until) p
|
||||
>>= fun result -> return (String.concat @@ [from] @ result @ [until])
|
||||
in
|
||||
let between_nested_delims p =
|
||||
(match left_delimiter, right_delimiter with
|
||||
| Some left_delimiter, Some right_delimiter -> [ (left_delimiter, right_delimiter) ]
|
||||
| _ -> Syntax.user_defined_delimiters)
|
||||
|> List.map ~f:fst
|
||||
|> List.map ~f:(between_nested_delims p)
|
||||
|> choice
|
||||
in
|
||||
let reserved =
|
||||
(match left_delimiter, right_delimiter with
|
||||
| Some left_delimiter, Some right_delimiter -> [ (left_delimiter, right_delimiter) ]
|
||||
| _ -> Syntax.user_defined_delimiters)
|
||||
|> List.concat_map ~f:(fun (from, until) -> [from; until])
|
||||
in
|
||||
fix (fun grammar ->
|
||||
let delimsx = between_nested_delims (many grammar) in
|
||||
let other = any_char_except ~reserved |>> String.of_char in
|
||||
(* FIXME holes does not handle space here, but does in alpha *)
|
||||
choice
|
||||
[ comment_parser
|
||||
; escapable_string_literal_parser
|
||||
; delimsx
|
||||
; other
|
||||
])
|
||||
|
||||
let cons x xs = x :: xs
|
||||
|
||||
let many_till p t =
|
||||
fix (fun m -> (t *> return []) <|> (lift2 cons p m))
|
||||
|
||||
let many1_till p t =
|
||||
lift2 cons p (many_till p t)
|
||||
|
||||
let sequence_chain (p_list : (signal_hole * 'a) t list) =
|
||||
begin
|
||||
let i = ref 0 in
|
||||
List.fold_right p_list ~init:(return (Dont_care, acc)) ~f:(fun p acc ->
|
||||
let result =
|
||||
if debug then Format.printf "iterate fold_right %d@." !i;
|
||||
match parse_string p "_signal_hole" with
|
||||
| Error _ ->
|
||||
if debug then Format.printf "Composing p with terminating parser@.";
|
||||
p *> acc
|
||||
| Ok (f,user_state) ->
|
||||
(*Format.printf "Ok.@.";*)
|
||||
match f with
|
||||
| Signal_a_hole (Alphanum (identifier, _)) ->
|
||||
pos >>= fun pos_before ->
|
||||
many1 (generate_single_hole_parser ())
|
||||
>>= fun value ->
|
||||
(* acc must come after in order to sat. try mimic alpha to better express this. *)
|
||||
acc >>= fun _ ->
|
||||
r user_state
|
||||
(Match
|
||||
{ offset = pos_before; identifier; text = (String.concat value) }
|
||||
)
|
||||
| Signal_a_hole (Everything (identifier, _dimension)) ->
|
||||
if debug then Format.printf "do hole %s@." identifier;
|
||||
let first_pos = Set_once.create () in
|
||||
let pparser =
|
||||
let until =
|
||||
(* if this is the base case (the first time we go around the
|
||||
loop backwards, when the first parser is a hole), then it
|
||||
means there's a hole at the end without anything following
|
||||
it in the template. So it should always match to
|
||||
end_of_input (not empty string) *)
|
||||
if !i = 0 then
|
||||
(if debug then Format.printf "Yes this case@.";
|
||||
end_of_input)
|
||||
else
|
||||
(if debug then Format.printf "Yes this second case@.";
|
||||
acc >>= fun _ -> return ())
|
||||
in
|
||||
(many_till
|
||||
(pos >>= fun pos -> Set_once.set_if_none first_pos [%here] pos;
|
||||
generate_greedy_hole_parser ())
|
||||
(pos >>= fun pos -> Set_once.set_if_none first_pos [%here] pos;
|
||||
until)
|
||||
(* it may be that the many till for the first parser
|
||||
succeeds on 'empty string', specifically in the :[1]:[2]
|
||||
case for :[1]. We won't capture the pos of :[1] in the
|
||||
first parser since it doesn't fire, so, so we have to
|
||||
set the pos right before the until parser below, if that
|
||||
happens. *)
|
||||
) >>| String.concat
|
||||
in
|
||||
pparser >>= fun text ->
|
||||
(*Format.printf "have results %d@." @@ List.length results;*)
|
||||
let offset =
|
||||
match Set_once.get first_pos with
|
||||
| Some offset -> offset
|
||||
| _ -> failwith "Did not expect unset offset"
|
||||
in
|
||||
r
|
||||
user_state
|
||||
(Match
|
||||
{ offset
|
||||
; identifier
|
||||
; text
|
||||
})
|
||||
| _ -> assert false
|
||||
in
|
||||
i := !i + 1;
|
||||
result)
|
||||
end
|
||||
|
||||
(** must have at least one, otherwise spins on
|
||||
the empty string *)
|
||||
let spaces1 =
|
||||
satisfy is_whitespace >>= fun c ->
|
||||
(* XXX use skip_while once everything works.
|
||||
we don't need the string *)
|
||||
take_while is_whitespace >>= fun s ->
|
||||
return (Format.sprintf "%c%s" c s)
|
||||
|
||||
let spaces =
|
||||
take_while is_whitespace >>= fun s ->
|
||||
return s
|
||||
|
||||
(* XXX change ignore to unit once everything works.
|
||||
right now it's the string that was parsed by spaces1 *)
|
||||
let generate_spaces_parser _ignored =
|
||||
(* XXX still some parts ignored in the choice case in Alpha *)
|
||||
if debug then Format.printf "Template_spaces(%s)@." _ignored;
|
||||
spaces1 *> many comment_parser <* spaces
|
||||
>>= fun result -> r acc (String (String.concat result))
|
||||
|
||||
(** All code can have comments interpolated *)
|
||||
let generate_string_token_parser str =
|
||||
if debug then Format.printf "Template_string(%s)@." str;
|
||||
many comment_parser
|
||||
*> string str
|
||||
*> many comment_parser
|
||||
>>= fun result -> r acc (String (String.concat result))
|
||||
|
||||
let generate_single_hole_parser () =
|
||||
(alphanum <|> char '_') |>> String.of_char
|
||||
|
||||
let skip_unit p =
|
||||
p |>> ignore
|
||||
|
||||
let identifier_parser () =
|
||||
many (alphanum <|> char '_')
|
||||
|>> String.of_char_list
|
||||
|
||||
let single_hole_parser () =
|
||||
string ":[[" *> identifier_parser () <* string "]]"
|
||||
|
||||
let greedy_hole_parser () =
|
||||
string ":[" *> identifier_parser () <* string "]"
|
||||
|
||||
let many1_till p t =
|
||||
let cons x xs = x::xs in
|
||||
lift2 cons p (many_till p t)
|
||||
|
||||
let hole_parser sort dimension : (signal_hole * 'a) t t =
|
||||
match sort with
|
||||
| `Single ->
|
||||
single_hole_parser () |>> fun id ->
|
||||
skip_unit (string "_signal_hole") |>> fun () ->
|
||||
(Signal_a_hole (Alphanum (id, dimension)), acc)
|
||||
| `Greedy ->
|
||||
greedy_hole_parser () |>> fun id ->
|
||||
skip_unit (string "_signal_hole") |>> fun () ->
|
||||
(Signal_a_hole (Everything (id, dimension)), acc)
|
||||
|
||||
let general_parser_generator : (signal_hole * 'a) t t =
|
||||
fix (fun (generator : (signal_hole * 'a) t list t) ->
|
||||
if debug then Format.printf "Descends@.";
|
||||
let nested =
|
||||
(* FIXME nested needs comments and string literals (or does it not
|
||||
need one for string literals because we handle it in fix? Unsure,
|
||||
couldn't come up with a CLI test. Check against test suite. *)
|
||||
if debug then Format.printf "Nested@.";
|
||||
Syntax.user_defined_delimiters
|
||||
|> List.map ~f:(fun (left_delimiter, right_delimiter) ->
|
||||
(string left_delimiter
|
||||
*> generator
|
||||
<* string right_delimiter)
|
||||
>>= fun (g: (signal_hole * 'a) t list) ->
|
||||
if debug then Format.printf "G size: %d; delim %s@." (List.length g) left_delimiter;
|
||||
(([string left_delimiter
|
||||
>>= fun result -> r acc (String result)]
|
||||
@ g
|
||||
@ [ string right_delimiter
|
||||
>>= fun result -> r acc (String result)])
|
||||
|>
|
||||
sequence_chain)
|
||||
|> return)
|
||||
|> choice
|
||||
in
|
||||
let spaces : (signal_hole * 'a) t t= spaces1 |>> generate_spaces_parser in
|
||||
let escapable_string_literal_parser : (signal_hole * 'a) t t =
|
||||
escapable_string_literal_parser
|
||||
>>| fun string_literal_contents ->
|
||||
(* FIXME incomplete likely, may need info about delims. also, no hole
|
||||
matching yet. *)
|
||||
generate_string_token_parser string_literal_contents
|
||||
in
|
||||
let other =
|
||||
(* XXX many1_till would be cool, but it also parses the thing that
|
||||
causes it to fail, which i need restored. many_till is 'parse and
|
||||
include the parse of the exception', whereas I want parse and
|
||||
exclude the parse of the exception (hard to reintroduce ) *)
|
||||
(*
|
||||
(many1_till (any_char >>= fun c -> Format.printf "parsed %c@." c;
|
||||
return c) (List.map reserved ~f:string |> choice >>= fun x ->
|
||||
Format.printf "Fail on %s@." x; return x) |>> fun s ->
|
||||
Format.printf "Chars: %s@." @@ String.of_char_list s;
|
||||
String.of_char_list s) *)
|
||||
(many1 (any_char_except ~reserved) |>> String.of_char_list)
|
||||
|>> fun x ->
|
||||
if debug then Format.printf "Other: %s@." x;
|
||||
generate_string_token_parser x
|
||||
in
|
||||
if debug then Format.printf "Many... @.";
|
||||
(* can't be many1 because then {} isn't a valid template (delimiters have to
|
||||
contain something then and can't be empty *)
|
||||
(* don't want it to be many because empty string will satisfy and
|
||||
"" is a valid template, or even "{", because it generates 'seq' on chain *)
|
||||
many @@
|
||||
choice
|
||||
[ hole_parser `Single Code
|
||||
; hole_parser `Greedy Code
|
||||
; escapable_string_literal_parser
|
||||
; spaces
|
||||
; nested
|
||||
; other
|
||||
]
|
||||
>>= fun x ->
|
||||
if debug then Format.printf "Produced %d parsers in main generator@." @@ List.length x;
|
||||
return x
|
||||
)
|
||||
|>> fun p_list ->
|
||||
p_list
|
||||
|> sequence_chain
|
||||
|> fun matcher ->
|
||||
(* FIXME: skip_unit needs to be raw literals *)
|
||||
(* XXX: what is the difference does many vs many1 make here? Semantically,
|
||||
it should mean "0 or more matching contexts" vs "1 or more matching
|
||||
contexts". We only care about the 1 case anyway, so... *)
|
||||
many (skip_unit
|
||||
(many_till (skip_unit comment_parser
|
||||
<|> skip_unit escapable_string_literal_parser
|
||||
<|> skip_unit any_char)
|
||||
(
|
||||
at_end_of_input >>= fun res ->
|
||||
if debug then Format.printf "We are at the end? %b.@." res;
|
||||
if res then
|
||||
(if debug then Format.printf "We ended@.";
|
||||
fail "x")
|
||||
else
|
||||
(* we found a match *)
|
||||
pos >>= fun start_pos ->
|
||||
matcher >>= fun _access_last_production_herpe ->
|
||||
pos >>= fun end_pos ->
|
||||
record_match_context start_pos end_pos;
|
||||
current_environment_ref := Match.Environment.create ();
|
||||
return Unit)
|
||||
(*<|>
|
||||
(end_of_input >>= fun () -> return Unit)*)
|
||||
)
|
||||
)
|
||||
(*>>= fun _x -> end_of_input *)
|
||||
>>= fun _x -> r acc Unit
|
||||
|
||||
let to_template template =
|
||||
let state = Buffered.parse general_parser_generator in
|
||||
let state = Buffered.feed state (`String template) in
|
||||
Buffered.feed state `Eof
|
||||
|> function
|
||||
| Buffered.Done ({ len; _ }, p) ->
|
||||
if len <> 0 then failwith @@
|
||||
Format.sprintf "Input left over in template where not expected: %d" len;
|
||||
Ok p
|
||||
| _ -> Or_error.error_string "Template could not be parsed."
|
||||
|
||||
let run_the_parser_for_first p source : Match.t Or_error.t =
|
||||
source_ref := source;
|
||||
let state = Buffered.parse p in
|
||||
let state = Buffered.feed state (`String source) in
|
||||
let state = Buffered.feed state `Eof in
|
||||
match state with
|
||||
| Buffered.Done ({ len; off; _ }, _result) ->
|
||||
if len <> 0 then
|
||||
(if debug then
|
||||
Format.eprintf "Input left over in parse where not expected: off(%d) len(%d)" off len;
|
||||
Or_error.error_string "Does not match tempalte")
|
||||
else
|
||||
Ok (Match.create ()) (* Fake for now *)
|
||||
| _ -> Or_error.error_string "No matches"
|
||||
|
||||
let first_broken ?configuration:_ ?shift:_ template source : Match.t Or_error.t =
|
||||
match to_template template with
|
||||
| Ok p ->
|
||||
begin match run_the_parser_for_first p source with
|
||||
| Ok _ -> (* matches passed, ok to access *)
|
||||
begin
|
||||
match !matches_ref with
|
||||
| [] -> Or_error.error_string "not really"
|
||||
| hd::_ -> Ok hd
|
||||
end
|
||||
| Error e -> (* parse failed *)
|
||||
Error e
|
||||
end
|
||||
| Error e ->
|
||||
Format.printf "Template FAIL %s@." @@ Error.to_string_hum e;
|
||||
Error e
|
||||
|
||||
let all ?configuration:_ ~template ~source : Match.t list =
|
||||
matches_ref := [];
|
||||
match first_broken template source with
|
||||
| Ok _
|
||||
| Error _ -> List.rev !matches_ref
|
||||
|
||||
let first ?configuration ?shift:_ template source : Match.t Or_error.t =
|
||||
matches_ref := [];
|
||||
match all ?configuration ~template ~source with
|
||||
| [] -> Or_error.error_string "nothing"
|
||||
| (hd::_) as m ->
|
||||
if debug then List.iter m ~f:(fun { environment; _ } ->
|
||||
Format.printf "START:@.%s@.END@." (Match.Environment.to_string environment));
|
||||
Ok hd
|
||||
end
|
@ -55,11 +55,24 @@ type hole =
|
||||
| Line of (id * dimension)
|
||||
| Blank of (id * dimension)
|
||||
|
||||
module Omega = struct
|
||||
type omega_match_production =
|
||||
{ offset : int
|
||||
; identifier : string
|
||||
; text : string
|
||||
}
|
||||
|
||||
type production =
|
||||
| Unit
|
||||
| String of string
|
||||
| Hole of hole
|
||||
| Match of omega_match_production
|
||||
end
|
||||
|
||||
type production =
|
||||
| Unit
|
||||
| String of string
|
||||
| Hole of hole
|
||||
| Match of (int * string * string)
|
||||
|
||||
module Matcher = struct
|
||||
module type S = sig
|
||||
|
@ -1,94 +1,155 @@
|
||||
open Core
|
||||
open MParser
|
||||
|
||||
let to_string from until between : string =
|
||||
from ^ (String.of_char_list between) ^ until
|
||||
module Omega = struct
|
||||
open Angstrom
|
||||
|
||||
let anything_including_newlines ~until =
|
||||
(many
|
||||
(not_followed_by (string until) ""
|
||||
>>= fun () -> any_char_or_nl))
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let anything_excluding_newlines ~until =
|
||||
(many
|
||||
(not_followed_by (string until) ""
|
||||
>>= fun () -> any_char))
|
||||
let between left _right p =
|
||||
left *> p (*<* right*)
|
||||
|
||||
(** a parser for comments with delimiters [from] and [until] that do not nest *)
|
||||
let non_nested_comment from until s =
|
||||
(between
|
||||
(string from)
|
||||
(string until)
|
||||
(anything_including_newlines ~until)
|
||||
|>> to_string from until
|
||||
) s
|
||||
let to_string from until between : string =
|
||||
from ^ (String.of_char_list between) ^ until
|
||||
|
||||
let until_newline start s =
|
||||
(string start >> anything_excluding_newlines ~until:"\n"
|
||||
|>> fun l -> start^(String.of_char_list l)) s
|
||||
let anything_including_newlines ~until =
|
||||
(* until is not consumed in Alpha. Angstrom consumes it. It needs to not
|
||||
consume because we're doing that for 'between'; but now between is
|
||||
changed to not expect it. The point is: it does the right thing but
|
||||
diverges from Alpha and is a little bit... weird *)
|
||||
(many_till any_char (string until))
|
||||
|
||||
let any_newline comment_string s =
|
||||
(string comment_string >> anything_excluding_newlines ~until:"\n" |>> fun l -> (comment_string^String.of_char_list l)) s
|
||||
let anything_excluding_newlines () =
|
||||
anything_including_newlines ~until:"\n"
|
||||
|
||||
let is_not p s =
|
||||
if is_ok (p s) then
|
||||
Empty_failed (unknown_error s)
|
||||
else
|
||||
match read_char s with
|
||||
| Some c ->
|
||||
Consumed_ok (c, advance_state s 1, No_error)
|
||||
| None ->
|
||||
Empty_failed (unknown_error s)
|
||||
let non_nested_comment from until =
|
||||
between
|
||||
(string from)
|
||||
(string until)
|
||||
(anything_including_newlines ~until)
|
||||
|>> to_string from until
|
||||
|
||||
(** A nested comment parser *)
|
||||
let nested_comment from until s =
|
||||
let reserved = skip ((string from) <|> (string until)) in
|
||||
let rec grammar s =
|
||||
((comment_delimiters >>= fun string -> return string)
|
||||
<|>
|
||||
(is_not reserved >>= fun c -> return (Char.to_string c)))
|
||||
s
|
||||
|
||||
and comment_delimiters s =
|
||||
module Multiline = struct
|
||||
module type S = sig
|
||||
val left : string
|
||||
val right : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment = non_nested_comment M.left M.right
|
||||
end
|
||||
end
|
||||
|
||||
(* XXX consumes the newline *)
|
||||
let until_newline start =
|
||||
(string start *> anything_excluding_newlines ()
|
||||
|>> fun l -> start^(String.of_char_list l))
|
||||
|
||||
module Until_newline = struct
|
||||
module type S = sig
|
||||
val start : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment = until_newline M.start
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module Alpha = struct
|
||||
open MParser
|
||||
|
||||
let to_string from until between : string =
|
||||
from ^ (String.of_char_list between) ^ until
|
||||
|
||||
let anything_including_newlines ~until =
|
||||
(many
|
||||
(not_followed_by (string until) ""
|
||||
>>= fun () -> any_char_or_nl))
|
||||
|
||||
let anything_excluding_newlines ~until =
|
||||
(many
|
||||
(not_followed_by (string until) ""
|
||||
>>= fun () -> any_char))
|
||||
|
||||
(** a parser for comments with delimiters [from] and [until] that do not nest *)
|
||||
let non_nested_comment from until s =
|
||||
(between
|
||||
(string from)
|
||||
(string until)
|
||||
((many grammar) >>= fun result ->
|
||||
return (String.concat result)))
|
||||
s
|
||||
in
|
||||
(comment_delimiters |>> fun content ->
|
||||
from ^ content ^ until) s
|
||||
(anything_including_newlines ~until)
|
||||
|>> to_string from until
|
||||
) s
|
||||
|
||||
(** a parser for, e.g., /* ... */ style block comments. Non-nested. *)
|
||||
module Multiline = struct
|
||||
module type S = sig
|
||||
val left : string
|
||||
val right : string
|
||||
let until_newline start s =
|
||||
(string start >> anything_excluding_newlines ~until:"\n"
|
||||
|>> fun l -> start^(String.of_char_list l)) s
|
||||
|
||||
let any_newline comment_string s =
|
||||
(string comment_string >> anything_excluding_newlines ~until:"\n" |>> fun l -> (comment_string^String.of_char_list l)) s
|
||||
|
||||
let is_not p s =
|
||||
if is_ok (p s) then
|
||||
Empty_failed (unknown_error s)
|
||||
else
|
||||
match read_char s with
|
||||
| Some c ->
|
||||
Consumed_ok (c, advance_state s 1, No_error)
|
||||
| None ->
|
||||
Empty_failed (unknown_error s)
|
||||
|
||||
(** A nested comment parser *)
|
||||
let nested_comment from until s =
|
||||
let reserved = skip ((string from) <|> (string until)) in
|
||||
let rec grammar s =
|
||||
((comment_delimiters >>= fun string -> return string)
|
||||
<|>
|
||||
(is_not reserved >>= fun c -> return (Char.to_string c)))
|
||||
s
|
||||
|
||||
and comment_delimiters s =
|
||||
(between
|
||||
(string from)
|
||||
(string until)
|
||||
((many grammar) >>= fun result ->
|
||||
return (String.concat result)))
|
||||
s
|
||||
in
|
||||
(comment_delimiters |>> fun content ->
|
||||
from ^ content ^ until) s
|
||||
|
||||
(** a parser for, e.g., /* ... */ style block comments. Non-nested. *)
|
||||
module Multiline = struct
|
||||
module type S = sig
|
||||
val left : string
|
||||
val right : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = non_nested_comment M.left M.right s
|
||||
end
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = non_nested_comment M.left M.right s
|
||||
end
|
||||
end
|
||||
|
||||
module Until_newline = struct
|
||||
module type S = sig
|
||||
val start : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = until_newline M.start s
|
||||
end
|
||||
end
|
||||
|
||||
module Nested_multiline = struct
|
||||
module type S = sig
|
||||
val left : string
|
||||
val right : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = nested_comment M.left M.right s
|
||||
module Until_newline = struct
|
||||
module type S = sig
|
||||
val start : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = until_newline M.start s
|
||||
end
|
||||
end
|
||||
|
||||
module Nested_multiline = struct
|
||||
module type S = sig
|
||||
val left : string
|
||||
val right : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let comment s = nested_comment M.left M.right s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,4 +2,4 @@
|
||||
(name parsers)
|
||||
(public_name comby.parsers)
|
||||
(preprocess (pps ppx_sexp_conv bisect_ppx --conditional))
|
||||
(libraries ppxlib core mparser mparser.pcre))
|
||||
(libraries angstrom ppxlib core mparser mparser.pcre))
|
||||
|
@ -1,57 +1,94 @@
|
||||
open Core
|
||||
open MParser
|
||||
|
||||
(** Assumes the left and right delimiter are the same, and that these can be
|
||||
escaped. Does not parse a string body containing newlines (as usual when
|
||||
escaping with \n) *)
|
||||
module Escapable = struct
|
||||
module type S = sig
|
||||
val delimiter : string
|
||||
val escape : char
|
||||
end
|
||||
module Omega = struct
|
||||
open Angstrom
|
||||
|
||||
module Make (M : S) = struct
|
||||
(* delimiters can be escaped and parsing continues within the string body *)
|
||||
let escaped_char_s s =
|
||||
any_char s
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let char_token_s s =
|
||||
((char M.escape >> escaped_char_s >>= fun c -> return (Format.sprintf {|%c%c|} M.escape c))
|
||||
<|> (any_char |>> String.of_char)
|
||||
)
|
||||
s
|
||||
module Escapable = struct
|
||||
module type S = sig
|
||||
val delimiter : string
|
||||
val escape : char
|
||||
end
|
||||
|
||||
let base_string_literal s =
|
||||
((string M.delimiter >> (many_until char_token_s (string M.delimiter))
|
||||
|>> String.concat)
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s%s|} M.delimiter result M.delimiter)
|
||||
)
|
||||
s
|
||||
module Make (M : S) = struct
|
||||
(* delimiters can be escaped and parsing continues within the string body *)
|
||||
let escaped_char_s =
|
||||
any_char
|
||||
|
||||
let char_token_s =
|
||||
((char M.escape *> escaped_char_s >>= fun c -> return (Format.sprintf {|%c%c|} M.escape c))
|
||||
<|> (any_char |>> String.of_char)
|
||||
)
|
||||
|
||||
|
||||
let base_string_literal =
|
||||
((string M.delimiter *> (many_till char_token_s (string M.delimiter))
|
||||
|>> String.concat)
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s|} M.delimiter result)
|
||||
(* unlike Alpha, do not suffix the ending delimiter, it was captured by the delimiter parser in many_till *)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
(** Quoted or raw strings. Allows different left and right delimiters, and
|
||||
disallows any sort of escaping. Does not support raw strings with identifiers
|
||||
yet, e.g., {blah|<string body>|blah} (OCaml) or delim`<string body>`delim
|
||||
syntax (Go) *)
|
||||
module Raw = struct
|
||||
module type S = sig
|
||||
val left_delimiter : string
|
||||
val right_delimiter : string
|
||||
module Alpha = struct
|
||||
open MParser
|
||||
|
||||
(** Assumes the left and right delimiter are the same, and that these can be
|
||||
escaped. Does not parse a string body containing newlines (as usual when
|
||||
escaping with \n) *)
|
||||
module Escapable = struct
|
||||
module type S = sig
|
||||
val delimiter : string
|
||||
val escape : char
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
(* delimiters can be escaped and parsing continues within the string body *)
|
||||
let escaped_char_s s =
|
||||
any_char s
|
||||
|
||||
let char_token_s s =
|
||||
((char M.escape >> escaped_char_s >>= fun c -> return (Format.sprintf {|%c%c|} M.escape c))
|
||||
<|> (any_char |>> String.of_char)
|
||||
)
|
||||
s
|
||||
|
||||
let base_string_literal s =
|
||||
((string M.delimiter >> (many_until char_token_s (string M.delimiter))
|
||||
|>> String.concat)
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s%s|} M.delimiter result M.delimiter)
|
||||
)
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let char_token_s s =
|
||||
(any_char_or_nl |>> String.of_char) s
|
||||
(** Quoted or raw strings. Allows different left and right delimiters, and
|
||||
disallows any sort of escaping. Does not support raw strings with identifiers
|
||||
yet, e.g., {blah|<string body>|blah} (OCaml) or delim`<string body>`delim
|
||||
syntax (Go) *)
|
||||
module Raw = struct
|
||||
module type S = sig
|
||||
val left_delimiter : string
|
||||
val right_delimiter : string
|
||||
end
|
||||
|
||||
let base_string_literal s =
|
||||
((
|
||||
string M.left_delimiter >> (many_until char_token_s (string M.right_delimiter))
|
||||
|>> String.concat <?> "raw string literal body")
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s%s|} M.left_delimiter result M.right_delimiter)
|
||||
)
|
||||
s
|
||||
module Make (M : S) = struct
|
||||
let char_token_s s =
|
||||
(any_char_or_nl |>> String.of_char) s
|
||||
|
||||
let base_string_literal s =
|
||||
((
|
||||
string M.left_delimiter >> (many_until char_token_s (string M.right_delimiter))
|
||||
|>> String.concat <?> "raw string literal body")
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s%s|} M.left_delimiter result M.right_delimiter)
|
||||
)
|
||||
s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,14 @@ open Core
|
||||
open Match
|
||||
open Replacement
|
||||
|
||||
let debug =
|
||||
Sys.getenv "DEBUG_COMBY"
|
||||
|> Option.is_some
|
||||
|
||||
|
||||
let substitute_match_contexts (matches: Match.t list) source replacements =
|
||||
if debug then
|
||||
Format.printf "Matches: %d | Replacements: %d@." (List.length matches) (List.length replacements);
|
||||
let rewrite_template, environment =
|
||||
List.fold2_exn
|
||||
matches replacements
|
||||
@ -13,14 +20,21 @@ let substitute_match_contexts (matches: Match.t list) source replacements =
|
||||
{ replacement_content; _ } ->
|
||||
(* create a hole in the rewrite template based on this match context *)
|
||||
let hole_id, rewrite_template = Rewrite_template.of_match_context match_ ~source:rewrite_template in
|
||||
if debug then Format.printf "Hole: %s in %s@." hole_id rewrite_template;
|
||||
(* add this match context replacement to the environment *)
|
||||
let accumulator_environment = Environment.add accumulator_environment hole_id replacement_content in
|
||||
(* update match context replacements offset *)
|
||||
rewrite_template, accumulator_environment)
|
||||
in
|
||||
if debug then Format.printf "Env:@.%s" (Environment.to_string environment);
|
||||
if debug then Format.printf "Rewrite in:@.%s@." rewrite_template;
|
||||
let rewritten_source = Rewrite_template.substitute rewrite_template environment |> fst in
|
||||
let offsets = Rewrite_template.get_offsets_for_holes rewrite_template (Environment.vars environment) in
|
||||
if debug then
|
||||
Format.printf "Replacements: %d | Offsets 1: %d@." (List.length replacements) (List.length offsets);
|
||||
let offsets = Rewrite_template.get_offsets_after_substitution offsets environment in
|
||||
if debug then
|
||||
Format.printf "Replacements: %d | Offsets 2: %d@." (List.length replacements) (List.length offsets);
|
||||
let in_place_substitutions =
|
||||
List.map2_exn replacements offsets ~f:(fun replacement (_uid, offset) ->
|
||||
let match_start = { Location.default with offset } in
|
||||
|
@ -2,6 +2,11 @@ open Core
|
||||
|
||||
open Match
|
||||
|
||||
let debug =
|
||||
Sys.getenv "DEBUG_COMBY"
|
||||
|> Option.is_some
|
||||
|
||||
|
||||
let substitute template env =
|
||||
let substitution_formats =
|
||||
[ ":[ ", "]"
|
||||
@ -31,6 +36,7 @@ let of_match_context
|
||||
; _
|
||||
}
|
||||
~source =
|
||||
if debug then Format.printf "Start idx: %d@.End idx: %d@." start_index end_index;
|
||||
let before_part =
|
||||
if start_index = 0 then
|
||||
""
|
||||
|
27
test/alpha/dune
Normal file
27
test/alpha/dune
Normal file
@ -0,0 +1,27 @@
|
||||
(library
|
||||
(name alpha_test_integration)
|
||||
(modules
|
||||
test_match_rule
|
||||
test_hole_extensions
|
||||
test_python_string_literals
|
||||
test_integration
|
||||
test_statistics
|
||||
test_cli
|
||||
test_c_style_comments
|
||||
test_string_literals
|
||||
test_special_matcher_cases
|
||||
test_generic
|
||||
test_rewrite_rule
|
||||
test_server
|
||||
test_substring_disabled)
|
||||
(inline_tests)
|
||||
(preprocess (pps ppx_expect ppx_sexp_message ppx_deriving_yojson ppx_deriving_yojson.runtime))
|
||||
(libraries
|
||||
comby
|
||||
cohttp-lwt-unix
|
||||
core
|
||||
camlzip))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (source_tree example) (source_tree example/src/.ignore-me)))
|
1
test/alpha/example
Symbolic link
1
test/alpha/example
Symbolic link
@ -0,0 +1 @@
|
||||
../example
|
944
test/alpha/test_cli.ml
Normal file
944
test/alpha/test_cli.ml
Normal file
@ -0,0 +1,944 @@
|
||||
open Core
|
||||
|
||||
module Time = Core_kernel.Time_ns.Span
|
||||
|
||||
let binary_path = "../../../../comby"
|
||||
|
||||
let read_with_timeout read_from_channels =
|
||||
let read_from_fds = List.map ~f:Unix.descr_of_in_channel read_from_channels in
|
||||
let read_from_channels =
|
||||
Unix.select
|
||||
~restart:true
|
||||
~read:read_from_fds
|
||||
~write:[]
|
||||
~except:[]
|
||||
~timeout:(`After (Time.of_int_sec 1))
|
||||
()
|
||||
|> (fun { Unix.Select_fds.read; _ } -> read)
|
||||
|> List.map ~f:Unix.in_channel_of_descr
|
||||
in
|
||||
List.map read_from_channels ~f:In_channel.input_all
|
||||
|> String.concat ~sep:"\n"
|
||||
|
||||
let read_output command =
|
||||
let open Unix.Process_channels in
|
||||
let { stdout; stderr; _ } =
|
||||
Unix.open_process_full ~env:(Array.of_list ["COMBY_TEST=1"]) command
|
||||
in
|
||||
let stdout_result = In_channel.input_all stdout in
|
||||
let stderr_result = In_channel.input_all stderr in
|
||||
stdout_result ^ stderr_result
|
||||
|
||||
let read_expect_stdin_and_stdout command source =
|
||||
let open Unix.Process_channels in
|
||||
let { stdin; stdout; stderr } =
|
||||
Unix.open_process_full ~env:(Array.of_list ["COMBY_TEST=1"]) command
|
||||
in
|
||||
Out_channel.output_string stdin source;
|
||||
Out_channel.flush stdin;
|
||||
Out_channel.close stdin;
|
||||
let stdout_result = In_channel.input_all stdout in
|
||||
let stderr_result = In_channel.input_all stderr in
|
||||
stdout_result ^ stderr_result
|
||||
|
||||
let read_expect_stderr command source =
|
||||
let open Unix.Process_channels in
|
||||
let { stdin; stdout; stderr } =
|
||||
Unix.open_process_full ~env:(Array.of_list ["COMBY_TEST=1"]) command
|
||||
in
|
||||
Out_channel.output_string stdin source;
|
||||
Out_channel.flush stdin;
|
||||
Out_channel.close stdin;
|
||||
let _ = In_channel.input_all stdout in
|
||||
let stderr_result = In_channel.input_all stderr in
|
||||
stderr_result
|
||||
|
||||
let%expect_test "json_lines_separates_by_line" =
|
||||
let source = "hello world" in
|
||||
let match_template = "o" in
|
||||
let rewrite_template = "i" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -json-lines" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|{"uri":null,"rewritten_source":"helli wirld","in_place_substitutions":[{"range":{"start":{"offset":7,"line":-1,"column":-1},"end":{"offset":8,"line":-1,"column":-1}},"replacement_content":"i","environment":[]},{"range":{"start":{"offset":4,"line":-1,"column":-1},"end":{"offset":5,"line":-1,"column":-1}},"replacement_content":"i","environment":[]}],"diff":"--- /dev/null\n+++ /dev/null\n@@ -1,1 +1,1 @@\n-hello world\n+helli wirld"}
|
||||
|}]
|
||||
|
||||
let%expect_test "json_lines_json_pretty_do_not_output_when_diff_null" =
|
||||
let source = "hello world" in
|
||||
let match_template = "asdf" in
|
||||
let rewrite_template = "asdf" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -json-lines" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{| |}]
|
||||
|
||||
let%expect_test "json_lines_do_not_output_when_diff_null" =
|
||||
let source = "hello world" in
|
||||
let match_template = "asdf" in
|
||||
let rewrite_template = "asdf" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -json-lines" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{| |}]
|
||||
|
||||
let%expect_test "error_on_zip_and_stdin" =
|
||||
let command_args = "-zip x -stdin" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command "none" in
|
||||
print_string result;
|
||||
[%expect_exact {|No templates specified. See -h to specify on the command line, or use -templates <directory-containing-templates>.
|
||||
Next error: -zip may not be used with -stdin.
|
||||
|}]
|
||||
|
||||
let%expect_test "error_on_stdout_and_diff" =
|
||||
let command_args = "'' '' -stdout -diff" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command "none" in
|
||||
print_string result;
|
||||
[%expect_exact {|-stdout may not be used with -diff. Note: -stdout outputs the changed file contents and -diff outputs a unified diff. Choose one of these.
|
||||
|}]
|
||||
|
||||
let%expect_test "error_on_invalid_templates_dir" =
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -templates nonexistent" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|One or more directories specified with -templates is not a directory.
|
||||
|}]
|
||||
|
||||
let%expect_test "warn_on_anonymous_and_templates_flag" =
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -templates example/templates/identity" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|WARNING: Templates specified on the command line AND using -templates. Ignoring match
|
||||
and rewrite templates on the command line and only using those in directories.
|
||||
|}]
|
||||
|
||||
|
||||
let%expect_test "stdin_command" =
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;43;30m!|[0m[0;31mhello [0mworld
|
||||
|}]
|
||||
|
||||
let%expect_test "with_match_rule" =
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let rule = {|where :[1] == "world"|} in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -rule '%s' -f .c "
|
||||
match_template rewrite_template rule
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;43;30m!|[0m[0;31mhello [0mworld
|
||||
|}];
|
||||
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let rule = {|where :[1] != "world"|} in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -rule '%s' -f .c -stdout"
|
||||
match_template rewrite_template rule
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
hello world |}]
|
||||
|
||||
let%expect_test "with_rewrite_rule" =
|
||||
let source = "hello world" in
|
||||
let match_template = ":[2] :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let rule = {|where rewrite :[1] { ":[_]" -> ":[2]" }|} in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -rule '%s' -f .c "
|
||||
match_template rewrite_template rule
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;43;30m!|[0mhello[0;31m world[0m
|
||||
|}]
|
||||
|
||||
let%expect_test "with_rewrite_rule_stdin_default_no_extension" =
|
||||
let source = "hello world" in
|
||||
let match_template = ":[2] :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let rule = {|where rewrite :[1] { ":[_]" -> ":[2]" }|} in
|
||||
let command_args =
|
||||
Format.sprintf "-sequential '%s' '%s' -rule '%s' -stdin" match_template rewrite_template rule
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;43;30m!|[0mhello[0;31m world[0m
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning.
|
||||
|}]
|
||||
|
||||
let%expect_test "generic_matcher" =
|
||||
let source = {|\footnote{\small \url{https://github.com}}|} in
|
||||
let match_template = {|\footnote{\small :[1]}|} in
|
||||
let rewrite_template = {|\footnote{\scriptsize :[1]}|} in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .generic" match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;41;30m-|[0m[0m[0;2m\footnote{[0m[0;31m\small[0m[0;2m \url{https://github.com}}[0m[0m
|
||||
[0;42;30m+|[0m[0m\footnote{[0;32m\scriptsize[0m \url{https://github.com}}[0m
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning.
|
||||
|}]
|
||||
|
||||
|
||||
let%expect_test "json_output_option" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential -json-lines '%s' '%s' -f .c "
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|{"uri":null,"rewritten_source":"c X a c Y a","in_place_substitutions":[{"range":{"start":{"offset":6,"line":-1,"column":-1},"end":{"offset":11,"line":-1,"column":-1}},"replacement_content":"c Y a","environment":[{"variable":"1","value":"Y","range":{"start":{"offset":2,"line":-1,"column":-1},"end":{"offset":3,"line":-1,"column":-1}}}]},{"range":{"start":{"offset":0,"line":-1,"column":-1},"end":{"offset":5,"line":-1,"column":-1}},"replacement_content":"c X a","environment":[{"variable":"1","value":"X","range":{"start":{"offset":2,"line":-1,"column":-1},"end":{"offset":3,"line":-1,"column":-1}}}]}],"diff":"--- /dev/null\n+++ /dev/null\n@@ -1,1 +1,1 @@\n-a X c a Y c\n+c X a c Y a"}
|
||||
|}];
|
||||
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential -json-lines -match-only '%s' '%s' -f .c "
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|{"uri":null,"matches":[{"range":{"start":{"offset":0,"line":1,"column":1},"end":{"offset":5,"line":1,"column":6}},"environment":[{"variable":"1","value":"X","range":{"start":{"offset":2,"line":1,"column":3},"end":{"offset":3,"line":1,"column":4}}}],"matched":"a X c"},{"range":{"start":{"offset":6,"line":1,"column":7},"end":{"offset":11,"line":1,"column":12}},"environment":[{"variable":"1","value":"Y","range":{"start":{"offset":8,"line":1,"column":9},"end":{"offset":9,"line":1,"column":10}}}],"matched":"a Y c"}]}|}]
|
||||
|
||||
let with_zip f =
|
||||
let file = Filename.temp_file "comby_" ".zip" in
|
||||
let zip = Zip.open_out file in
|
||||
let entry_name = "main.ml" in
|
||||
let entry_content = "hello world" in
|
||||
Zip.add_entry entry_content zip entry_name;
|
||||
Zip.close_out zip;
|
||||
f file;
|
||||
Unix.remove file
|
||||
|
||||
let%expect_test "list_languages" =
|
||||
let command_args = "-list" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_output command in
|
||||
print_string result;
|
||||
[%expect_exact {|Option Language
|
||||
-matcher .s Assembly
|
||||
-matcher .sh Bash
|
||||
-matcher .c C
|
||||
-matcher .cs C#
|
||||
-matcher .css CSS
|
||||
-matcher .dart Dart
|
||||
-matcher .dyck Dyck
|
||||
-matcher .clj Clojure
|
||||
-matcher .elm Elm
|
||||
-matcher .erl Erlang
|
||||
-matcher .ex Elixir
|
||||
-matcher .f Fortran
|
||||
-matcher .fsx F#
|
||||
-matcher .go Go
|
||||
-matcher .html HTML
|
||||
-matcher .hs Haskell
|
||||
-matcher .java Java
|
||||
-matcher .js Javascript/Typescript
|
||||
-matcher .json JSON
|
||||
-matcher .jl Julia
|
||||
-matcher .kt Kotlin
|
||||
-matcher .tex LaTeX
|
||||
-matcher .lisp Lisp
|
||||
-matcher .nim Nim
|
||||
-matcher .ml OCaml
|
||||
-matcher .paren Paren
|
||||
-matcher .pas Pascal
|
||||
-matcher .php PHP
|
||||
-matcher .py Python
|
||||
-matcher .re Reason
|
||||
-matcher .rb Ruby
|
||||
-matcher .rs Rust
|
||||
-matcher .scala Scala
|
||||
-matcher .sql SQL
|
||||
-matcher .swift Swift
|
||||
-matcher .txt Text
|
||||
-matcher .xml XML
|
||||
-matcher .generic Generic
|
||||
|}]
|
||||
|
||||
|
||||
let%expect_test "patdiff_and_zip" =
|
||||
with_zip (fun file ->
|
||||
let match_template = ":[2] :[1]" in
|
||||
let rewrite_template = ":[1]" in
|
||||
let command_args =
|
||||
Format.sprintf "'%s' '%s' .ml -sequential -json-lines -zip %s"
|
||||
match_template rewrite_template file
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_output command in
|
||||
print_string result;
|
||||
[%expect_exact {|{"uri":"main.ml","rewritten_source":"world","in_place_substitutions":[{"range":{"start":{"offset":0,"line":-1,"column":-1},"end":{"offset":5,"line":-1,"column":-1}},"replacement_content":"world","environment":[{"variable":"1","value":"world","range":{"start":{"offset":0,"line":-1,"column":-1},"end":{"offset":5,"line":-1,"column":-1}}}]}],"diff":"--- main.ml\n+++ main.ml\n@@ -1,1 +1,1 @@\n-hello world\n+world"}
|
||||
|}]
|
||||
)
|
||||
|
||||
let%expect_test "template_parsing_no_match_template" =
|
||||
let source = "hello world" in
|
||||
let template_dir = "example" ^/ "templates" ^/ "parse-no-match-template" in
|
||||
let command_args = Format.sprintf "-stdin -sequential -f .c -templates %s" template_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|WARNING: Could not read required match file in example/templates/parse-no-match-template
|
||||
|}]
|
||||
|
||||
let%expect_test "template_parsing_with_trailing_newline" =
|
||||
let source = "hello world" in
|
||||
let template_dir = "example" ^/ "templates" ^/ "parse-template-no-trailing-newline" in
|
||||
let command_args = Format.sprintf "-stdin -sequential -f .c -templates %s -stdout" template_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
hello world |}]
|
||||
|
||||
let%expect_test "template_parsing_with_trailing_newline" =
|
||||
let source = "hello world" in
|
||||
let template_dir = "example" ^/ "templates" ^/ "parse-template-with-trailing-newline" in
|
||||
let command_args = Format.sprintf "-stdin -sequential -f .c -templates %s -stdout" template_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
hello world |}]
|
||||
|
||||
let%expect_test "nested_templates" =
|
||||
let source = "1 2 3" in
|
||||
let template_dir = "example" ^/ "multiple-nested-templates" in
|
||||
let command_args = Format.sprintf "-stdin -sequential -f .c -templates %s -stdout" template_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
+1 +2 +3WARNING: Could not read required match file in example/multiple-nested-templates/invalid-subdir |}]
|
||||
|
||||
let%expect_test "diff_is_default" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;41;30m-|[0m[0m[0;31ma[0m[0;2m X [0m[0;31mc a[0m[0;2m Y [0m[0;31mc[0m[0m
|
||||
[0;42;30m+|[0m[0m[0;32mc[0m X [0;32ma c[0m Y [0;32ma[0m[0m
|
||||
|}]
|
||||
|
||||
let%expect_test "diff_option" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential -diff '%s' '%s' -f .c"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|--- /dev/null
|
||||
+++ /dev/null
|
||||
@@ -1,1 +1,1 @@
|
||||
-a X c a Y c
|
||||
+c X a c Y a
|
||||
|}]
|
||||
|
||||
let%expect_test "stdout_option" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential -stdout '%s' '%s' -f .c"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|c X a c Y a|}]
|
||||
|
||||
let%expect_test "only_color_prints_colored_diff" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -color"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;41;30m-|[0m[0m[0;31ma[0m[0;2m X [0m[0;31mc a[0m[0;2m Y [0m[0;31mc[0m[0m
|
||||
[0;42;30m+|[0m[0m[0;32mc[0m X [0;32ma c[0m Y [0;32ma[0m[0m
|
||||
|}]
|
||||
|
||||
let%expect_test "diff_explicit_color" =
|
||||
let source = "a X c a Y c" in
|
||||
let match_template = "a :[1] c" in
|
||||
let rewrite_template = "c :[1] a" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential '%s' '%s' -f .c -diff -color"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;41;30m-|[0m[0m[0;31ma[0m[0;2m X [0m[0;31mc a[0m[0;2m Y [0m[0;31mc[0m[0m
|
||||
[0;42;30m+|[0m[0m[0;32mc[0m X [0;32ma c[0m Y [0;32ma[0m[0m
|
||||
|}]
|
||||
|
||||
let%expect_test "is_real_directory" =
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" ^/ "main.c" in
|
||||
let command_args = Format.sprintf "'main' 'pain' -sequential -d %s -exclude-dir 'ignore' -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
Directory specified with -d or -directory is not a directory. |}]
|
||||
|
||||
let%expect_test "exclude_dir_option" =
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'main' 'pain' -sequential -d %s -exclude-dir 'ignore' -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/honor-file-extensions/honor.pb.generic
|
||||
+++ example/src/honor-file-extensions/honor.pb.generic
|
||||
@@ -1,3 +1,3 @@
|
||||
-func main() {
|
||||
+func pain() {
|
||||
// foo()
|
||||
}
|
||||
--- example/src/honor-file-extensions/honor.pb.go
|
||||
+++ example/src/honor-file-extensions/honor.pb.go
|
||||
@@ -1,4 +1,4 @@
|
||||
-func main() {
|
||||
+func pain() {
|
||||
// in a comment foo()
|
||||
foo()
|
||||
}
|
||||
--- example/src/main.c
|
||||
+++ example/src/main.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int main() {}
|
||||
+int pain() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}];
|
||||
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'main' 'pain' -sequential -d %s -exclude-dir 'nonexist' -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/honor-file-extensions/honor.pb.generic
|
||||
+++ example/src/honor-file-extensions/honor.pb.generic
|
||||
@@ -1,3 +1,3 @@
|
||||
-func main() {
|
||||
+func pain() {
|
||||
// foo()
|
||||
}
|
||||
--- example/src/honor-file-extensions/honor.pb.go
|
||||
+++ example/src/honor-file-extensions/honor.pb.go
|
||||
@@ -1,4 +1,4 @@
|
||||
-func main() {
|
||||
+func pain() {
|
||||
// in a comment foo()
|
||||
foo()
|
||||
}
|
||||
--- example/src/ignore-me/main.c
|
||||
+++ example/src/ignore-me/main.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int main() {}
|
||||
+int pain() {}
|
||||
--- example/src/main.c
|
||||
+++ example/src/main.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int main() {}
|
||||
+int pain() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}]
|
||||
|
||||
let%expect_test "dir_depth_option" =
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'depth_' 'correct_depth_' -sequential -directory %s -depth %d -diff" src_dir (-1) in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{| -depth must be 0 or greater. |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'depth_' 'correct_depth_' -sequential -directory %s -depth %d -diff" src_dir 0 in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/depth-0.c
|
||||
+++ example/src/depth-0.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_0() {}
|
||||
+int correct_depth_0() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'depth_' 'correct_depth_' -sequential -directory %s -depth %d -diff" src_dir 1 in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/depth-0.c
|
||||
+++ example/src/depth-0.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_0() {}
|
||||
+int correct_depth_0() {}
|
||||
--- example/src/depth-1/depth-1.c
|
||||
+++ example/src/depth-1/depth-1.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_1() {}
|
||||
+int correct_depth_1() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'depth_' 'correct_depth_' -sequential -directory %s -depth %d -diff" src_dir 2 in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/depth-0.c
|
||||
+++ example/src/depth-0.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_0() {}
|
||||
+int correct_depth_0() {}
|
||||
--- example/src/depth-1/depth-1.c
|
||||
+++ example/src/depth-1/depth-1.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_1() {}
|
||||
+int correct_depth_1() {}
|
||||
--- example/src/depth-1/depth-2/depth-2.c
|
||||
+++ example/src/depth-1/depth-2/depth-2.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_2() {}
|
||||
+int correct_depth_2() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'depth_' 'correct_depth_' -sequential -directory %s -depth %d -diff" src_dir 1000 in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/depth-0.c
|
||||
+++ example/src/depth-0.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_0() {}
|
||||
+int correct_depth_0() {}
|
||||
--- example/src/depth-1/depth-1.c
|
||||
+++ example/src/depth-1/depth-1.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_1() {}
|
||||
+int correct_depth_1() {}
|
||||
--- example/src/depth-1/depth-2/depth-2.c
|
||||
+++ example/src/depth-1/depth-2/depth-2.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int depth_2() {}
|
||||
+int correct_depth_2() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}]
|
||||
|
||||
let%expect_test "matcher_override" =
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'(' '_unbalanced_match_' main.c -sequential -d %s -matcher .txt -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/ignore-me/main.c
|
||||
+++ example/src/ignore-me/main.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int main() {}
|
||||
+int main_unbalanced_match_) {}
|
||||
--- example/src/main.c
|
||||
+++ example/src/main.c
|
||||
@@ -1,1 +1,1 @@
|
||||
-int main() {}
|
||||
+int main_unbalanced_match_) {} |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let src_dir = "example" ^/ "src" in
|
||||
let command_args = Format.sprintf "'(' '_unbalanced_match_' main.c -sequential -d %s -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{| |}]
|
||||
|
||||
let%expect_test "infer_and_honor_extensions" =
|
||||
let source = "doesn't matter" in
|
||||
let src_dir = "example" ^/ "src" ^/ "honor-file-extensions" in
|
||||
let command_args = Format.sprintf "'foo()' 'bar()' .go -sequential -d %s -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/honor-file-extensions/honor.pb.go
|
||||
+++ example/src/honor-file-extensions/honor.pb.go
|
||||
@@ -1,4 +1,4 @@
|
||||
func main() {
|
||||
// in a comment foo()
|
||||
-foo()
|
||||
+bar()
|
||||
} |}];
|
||||
|
||||
let source = "doesn't matter" in
|
||||
let src_dir = "example" ^/ "src" ^/ "honor-file-extensions" in
|
||||
let command_args = Format.sprintf "'foo()' 'bar()' .generic -sequential -d %s -diff" src_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- example/src/honor-file-extensions/honor.pb.generic
|
||||
+++ example/src/honor-file-extensions/honor.pb.generic
|
||||
@@ -1,3 +1,3 @@
|
||||
func main() {
|
||||
-// foo()
|
||||
+// bar()
|
||||
}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}]
|
||||
|
||||
let%expect_test "diff_only" =
|
||||
let source = "hello world" in
|
||||
let command_args = Format.sprintf "'hello' 'world' -stdin -sequential -json-lines -json-only-diff" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
{"uri":null,"diff":"--- /dev/null\n+++ /dev/null\n@@ -1,1 +1,1 @@\n-hello world\n+world world"}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}];
|
||||
|
||||
let source = "hello world" in
|
||||
let command_args = Format.sprintf "'hello' 'world' -stdin -sequential -json-only-diff" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
-json-only-diff can only be supplied with -json-lines. |}]
|
||||
|
||||
let%expect_test "zip_exclude_dir_with_extension" =
|
||||
let source = "doesn't matter" in
|
||||
let zip = "example" ^/ "zip-test" ^/ "sample-repo.zip" in
|
||||
let exclude_dir = "sample-repo/vendor" in
|
||||
let command_args = Format.sprintf "'main' 'pain' .go -zip %s -sequential -diff -exclude-dir %s" zip exclude_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- sample-repo/src/main.go
|
||||
+++ sample-repo/src/main.go
|
||||
@@ -1,2 +1,2 @@
|
||||
// src
|
||||
-func main() {}
|
||||
+func pain() {} |}]
|
||||
|
||||
let%expect_test "zip_exclude_dir_no_extension" =
|
||||
let source = "doesn't matter" in
|
||||
let zip = "example" ^/ "zip-test" ^/ "sample-repo.zip" in
|
||||
let exclude_dir = "sample-repo/vendor" in
|
||||
let command_args = Format.sprintf "'main' 'pain' -zip %s -sequential -diff -exclude-dir %s" zip exclude_dir in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
--- sample-repo/src/main.go
|
||||
+++ sample-repo/src/main.go
|
||||
@@ -1,2 +1,2 @@
|
||||
// src
|
||||
-func main() {}
|
||||
+func pain() {}
|
||||
|
||||
WARNING: the GENERIC matcher was used, because a language could not be inferred from the file extension(s). The GENERIC matcher may miss matches. See '-list' to set a matcher for a specific language and to remove this warning. |}]
|
||||
|
||||
let%expect_test "invalid_path_with_error_message" =
|
||||
let source = "doesn't matter" in
|
||||
let command_args = Format.sprintf "'a' 'b' ./invalid/path" in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect{|
|
||||
No such file or directory: ./invalid/path. Comby interprets patterns containing '/' as file paths. If a pattern does not contain '/' (like '.ml'), it is considered a pattern where file endings must match the pattern. Please supply only valid file paths or patterns. |}]
|
||||
|
||||
let%expect_test "newline_separated_output"=
|
||||
let source = "a b c" in
|
||||
let match_template = ":[[1]]" in
|
||||
let rewrite_template = ":[[1]]" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential -stdout '%s' '%s' -n -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|a
|
||||
b
|
||||
c
|
||||
|}]
|
||||
|
||||
let%expect_test "warn_on_stdin_and_in_place_flags" =
|
||||
let source = "a b c" in
|
||||
let match_template = ":[[1]]" in
|
||||
let rewrite_template = ":[[1]]" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -in-place '%s' '%s' -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|WARNING: -in-place has no effect when -stdin is used. Ignoring -in-place.
|
||||
|}]
|
||||
|
||||
let%expect_test "print_single_line_matches" =
|
||||
let source = {|
|
||||
let () = x in
|
||||
let () = y in
|
||||
|}
|
||||
in
|
||||
let match_template = "let ()" in
|
||||
let rewrite_template = "dont care" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -match-only -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|let ()
|
||||
let ()
|
||||
|}]
|
||||
|
||||
let%expect_test "print_multi_line_matches" =
|
||||
let source = {|
|
||||
let () = x in
|
||||
let
|
||||
|
||||
()
|
||||
in
|
||||
let () = y in
|
||||
|}
|
||||
in
|
||||
let match_template = "let ()" in
|
||||
let rewrite_template = "dont care" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -match-only -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|let ()
|
||||
let\n\n ()
|
||||
let ()
|
||||
|}];
|
||||
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -match-only -count -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|3 matches
|
||||
|}];
|
||||
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -match-only -count -json-lines -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|{"uri":null,"matches":[{"range":{"start":{"offset":5,"line":1,"column":6},"end":{"offset":11,"line":1,"column":12}},"environment":[],"matched":"let ()"},{"range":{"start":{"offset":23,"line":1,"column":24},"end":{"offset":34,"line":3,"column":7}},"environment":[],"matched":"let\n\n ()"},{"range":{"start":{"offset":42,"line":1,"column":43},"end":{"offset":48,"line":1,"column":49}},"environment":[],"matched":"let ()"}]}WARNING: -count and -json-lines is specified. Ignoring -count.
|
||||
|}];
|
||||
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -count -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|3 matches
|
||||
WARNING: -count only works with -match-only. Performing -match-only -count.
|
||||
|}]
|
||||
|
||||
let%expect_test "unrecognized_matcher" =
|
||||
let source = {|dont care|} in
|
||||
let match_template = "dont care" in
|
||||
let rewrite_template = "dont care" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -matcher invalid"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|The matcher "invalid" is not supported. See -list for supported matchers
|
||||
|}]
|
||||
|
||||
let%expect_test "generic_matcher_ok" =
|
||||
let source = {|dont care|} in
|
||||
let match_template = "dont care" in
|
||||
let rewrite_template = "blah" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin '%s' '%s' -matcher .generic"
|
||||
match_template rewrite_template
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|[0;31m------ [0m[0;1m/dev/null[0m
|
||||
[0;32m++++++ [0m[0;1m/dev/null[0m
|
||||
[0;100;30m@|[0m[0;1m-1,1 +1,1[0m ============================================================
|
||||
[0;41;30m-|[0m[0m[0;31mdont care[0m[0m
|
||||
[0;42;30m+|[0m[0m[0;32mblah[0m[0m
|
||||
|}]
|
||||
|
||||
let%expect_test "warn_on_anonymous_and_templates_flag" =
|
||||
let source = "(fun i -> j) (fun x -> x)" in
|
||||
let command_args =
|
||||
Format.sprintf "-stdin -sequential 'ignore' 'ignore' -templates example/templates/implicit-equals -matcher .ml -stdout"
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let result = read_expect_stdin_and_stdout command source in
|
||||
print_string result;
|
||||
[%expect_exact {|(fun i -> j) identWARNING: Templates specified on the command line AND using -templates. Ignoring match
|
||||
and rewrite templates on the command line and only using those in directories.
|
||||
|}]
|
||||
|
||||
let%expect_test "dump_stats" =
|
||||
let source = {|dont care|} in
|
||||
let match_template = "care" in
|
||||
let rewrite_template = "realy care" in
|
||||
let command_args = Format.sprintf "-stdin '%s' '%s' -stats -matcher .txt" match_template rewrite_template in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
let stats_json = read_expect_stderr command source in
|
||||
(match Statistics.of_yojson (Yojson.Safe.from_string stats_json) with
|
||||
| Ok { number_of_files; lines_of_code; number_of_matches; _ } ->
|
||||
Format.printf "number_of_files: %d, lines_of_code: %d, number_of_matches: %d"
|
||||
number_of_files lines_of_code number_of_matches
|
||||
| Error _ -> print_string "Unexpected error");
|
||||
[%expect_exact {|number_of_files: 1, lines_of_code: 1, number_of_matches: 1|}]
|
||||
|
||||
let%expect_test "substitute_bad_parse" =
|
||||
let source = "dont care" in
|
||||
let match_template = "dont care" in
|
||||
let rewrite_template = "dont care" in
|
||||
let command_args = Format.sprintf "%s %s -substitute 'json'" match_template rewrite_template in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|Error, could not parse JSON to environment: Line 1, bytes 0-4:
|
||||
Invalid token 'json'
|
||||
|}]
|
||||
|
||||
let%expect_test "substitute_ok" =
|
||||
let source = "a match1 c d a match2 c d" in
|
||||
let match_template = "ignored" in
|
||||
let rewrite_template = ":[1] :[2]" in
|
||||
let environment = {|[{"variable":"1","value":"hole_1"},{"variable":"2","value":"hole_2"}]|} in
|
||||
let command_args =
|
||||
Format.sprintf "'%s' '%s' -stdin -match-only -matcher .txt -substitute '%s'" match_template rewrite_template environment
|
||||
in
|
||||
let command = Format.sprintf "%s %s" binary_path command_args in
|
||||
read_expect_stdin_and_stdout command source
|
||||
|> print_string;
|
||||
[%expect_exact {|hole_1 hole_2
|
||||
|}]
|
204
test/alpha/test_server.ml
Normal file
204
test/alpha/test_server.ml
Normal file
@ -0,0 +1,204 @@
|
||||
open Core
|
||||
|
||||
open Lwt.Infix
|
||||
|
||||
open Match
|
||||
open Server_types
|
||||
|
||||
let binary_path = "../../../../comby-server"
|
||||
|
||||
let port = "9991"
|
||||
|
||||
let pid' = ref None
|
||||
|
||||
let launch port =
|
||||
Unix.create_process ~prog:binary_path ~args:["-p"; port]
|
||||
|> fun { pid; _ } -> pid' := Some pid
|
||||
|
||||
let post endpoint json =
|
||||
let uri =
|
||||
let uri endpoint =
|
||||
Uri.of_string ("http://127.0.0.1:" ^ port ^ "/" ^ endpoint)
|
||||
in
|
||||
match endpoint with
|
||||
| `Match -> uri "match"
|
||||
| `Rewrite -> uri "rewrite"
|
||||
| `Substitute -> uri "substitute"
|
||||
in
|
||||
let thread =
|
||||
Cohttp_lwt_unix.Client.post ~body:(`String json) uri >>= fun (_, response) ->
|
||||
match response with
|
||||
| `Stream response -> Lwt_stream.get response >>= fun result -> Lwt.return result
|
||||
| _ -> Lwt.return None
|
||||
in
|
||||
match Lwt_unix.run thread with
|
||||
| None -> "FAIL"
|
||||
| Some result -> result
|
||||
|
||||
(* FIXME(RVT) use wait *)
|
||||
let launch () =
|
||||
launch port;
|
||||
Unix.sleep 2
|
||||
|
||||
let kill () =
|
||||
match !pid' with
|
||||
| None -> ()
|
||||
| Some pid ->
|
||||
match Signal.send Signal.kill (`Pid pid) with
|
||||
| `Ok -> ()
|
||||
| `No_such_process -> ()
|
||||
|
||||
let () = launch ()
|
||||
|
||||
let%expect_test "post_request" =
|
||||
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rule = Some {|where :[1] == "world"|} in
|
||||
let language = "generic" in
|
||||
|
||||
In.{ source; match_template; rule; language; id = 0 }
|
||||
|> In.match_request_to_yojson
|
||||
|> Yojson.Safe.to_string
|
||||
|> post `Match
|
||||
|> print_string;
|
||||
|
||||
[%expect {|
|
||||
{
|
||||
"matches": [
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 11, "line": 1, "column": 12 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "world",
|
||||
"range": {
|
||||
"start": { "offset": 6, "line": 1, "column": 7 },
|
||||
"end": { "offset": 11, "line": 1, "column": 12 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "hello world"
|
||||
}
|
||||
],
|
||||
"source": "hello world",
|
||||
"id": 0
|
||||
} |}];
|
||||
|
||||
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rule = Some {|where :[1] = "world"|} in
|
||||
let language = "generic" in
|
||||
|
||||
In.{ source; match_template; rule; language; id = 0 }
|
||||
|> In.match_request_to_yojson
|
||||
|> Yojson.Safe.to_string
|
||||
|> post `Match
|
||||
|> print_string;
|
||||
|
||||
[%expect {|
|
||||
Error in line 1, column 7:
|
||||
where :[1] = "world"
|
||||
^
|
||||
Expecting "false", "match", "rewrite" or "true"
|
||||
Backtracking occurred after:
|
||||
Error in line 1, column 12:
|
||||
where :[1] = "world"
|
||||
^
|
||||
Expecting "!=" or "==" |}];
|
||||
|
||||
let substitution_kind = "in_place" in
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rule = Some {|where :[1] == "world"|} in
|
||||
let rewrite_template = ":[1], hello" in
|
||||
let language = "generic" in
|
||||
|
||||
In.{ source; match_template; rewrite_template; rule; language; substitution_kind; id = 0}
|
||||
|> In.rewrite_request_to_yojson
|
||||
|> Yojson.Safe.to_string
|
||||
|> post `Rewrite
|
||||
|> print_string;
|
||||
|
||||
[%expect {|
|
||||
{
|
||||
"rewritten_source": "world, hello",
|
||||
"in_place_substitutions": [
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": -1, "column": -1 },
|
||||
"end": { "offset": 12, "line": -1, "column": -1 }
|
||||
},
|
||||
"replacement_content": "world, hello",
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "world",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": -1, "column": -1 },
|
||||
"end": { "offset": 5, "line": -1, "column": -1 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"id": 0
|
||||
} |}];
|
||||
|
||||
let substitution_kind = "newline_separated" in
|
||||
let source = "hello world {} hello world" in
|
||||
let match_template = "hello :[[1]]" in
|
||||
let rule = Some {|where :[1] == "world"|} in
|
||||
let rewrite_template = ":[1], hello" in
|
||||
let language = "generic" in
|
||||
|
||||
In.{ source; match_template; rewrite_template; rule; language; substitution_kind; id = 0}
|
||||
|> In.rewrite_request_to_yojson
|
||||
|> Yojson.Safe.to_string
|
||||
|> post `Rewrite
|
||||
|> print_string;
|
||||
|
||||
[%expect {|
|
||||
{
|
||||
"rewritten_source": "world, hello\nworld, hello",
|
||||
"in_place_substitutions": [],
|
||||
"id": 0
|
||||
} |}];
|
||||
|
||||
(* test there must be at least one predicate in a rule *)
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rule = Some {|where |} in
|
||||
let language = "generic" in
|
||||
|
||||
let request = In.{ source; match_template; rule; language; id = 0 } in
|
||||
let json = In.match_request_to_yojson request |> Yojson.Safe.to_string in
|
||||
let result = post `Match json in
|
||||
|
||||
print_string result;
|
||||
[%expect {|
|
||||
Error in line 1, column 7:
|
||||
where
|
||||
^
|
||||
Expecting ":[", "false", "match", "rewrite", "true" or string literal |}]
|
||||
|
||||
let%expect_test "post_substitute" =
|
||||
|
||||
let rewrite_template = ":[1] hi :[2]" in
|
||||
let environment = Environment.create () in
|
||||
let environment = Environment.add environment "1" "oh" in
|
||||
let environment = Environment.add environment "2" "there" in
|
||||
|
||||
In.{ rewrite_template; environment; id = 0 }
|
||||
|> In.substitution_request_to_yojson
|
||||
|> Yojson.Safe.to_string
|
||||
|> post `Substitute
|
||||
|> print_string;
|
||||
|
||||
[%expect {| { "result": "oh hi there", "id": 0 } |}]
|
||||
|
||||
let () = kill ()
|
22
test/common/dune
Normal file
22
test/common/dune
Normal file
@ -0,0 +1,22 @@
|
||||
(library
|
||||
(name common_test_integration)
|
||||
(modules
|
||||
test_nested_comments
|
||||
test_c
|
||||
test_bash
|
||||
test_go
|
||||
test_c_separators
|
||||
test_pipeline
|
||||
test_rewrite_parts
|
||||
test_user_defined_language)
|
||||
(inline_tests)
|
||||
(preprocess (pps ppx_expect ppx_sexp_message ppx_deriving_yojson ppx_deriving_yojson.runtime))
|
||||
(libraries
|
||||
comby
|
||||
cohttp-lwt-unix
|
||||
core
|
||||
camlzip))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (source_tree example) (source_tree example/src/.ignore-me)))
|
37
test/dune
37
test/dune
@ -1,35 +1,2 @@
|
||||
(library
|
||||
(name test_integration)
|
||||
(modules
|
||||
test_match_rule
|
||||
test_hole_extensions
|
||||
test_python_string_literals
|
||||
test_nested_comments
|
||||
test_integration
|
||||
test_statistics
|
||||
test_c
|
||||
test_cli
|
||||
test_bash
|
||||
test_go
|
||||
test_c_style_comments
|
||||
test_c_separators
|
||||
test_string_literals
|
||||
test_special_matcher_cases
|
||||
test_generic
|
||||
test_pipeline
|
||||
test_rewrite_parts
|
||||
test_rewrite_rule
|
||||
test_server
|
||||
test_substring_disabled
|
||||
test_user_defined_language)
|
||||
(inline_tests)
|
||||
(preprocess (pps ppx_expect ppx_sexp_message ppx_deriving_yojson ppx_deriving_yojson.runtime))
|
||||
(libraries
|
||||
comby
|
||||
cohttp-lwt-unix
|
||||
core
|
||||
camlzip))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (source_tree example) (source_tree example/src/.ignore-me)))
|
||||
(dirs common alpha)
|
||||
; (dirs common omega)
|
||||
|
31
test/omega/dune
Normal file
31
test/omega/dune
Normal file
@ -0,0 +1,31 @@
|
||||
(library
|
||||
(name omega_test_integration)
|
||||
(modules
|
||||
;
|
||||
; TODO
|
||||
;
|
||||
test_generic
|
||||
test_match_rule
|
||||
test_hole_extensions
|
||||
test_python_string_literals
|
||||
test_integration
|
||||
test_statistics
|
||||
test_cli
|
||||
test_c_style_comments
|
||||
test_string_literals
|
||||
test_special_matcher_cases
|
||||
test_generic
|
||||
test_rewrite_rule
|
||||
test_server
|
||||
test_substring_disabled)
|
||||
(inline_tests)
|
||||
(preprocess (pps ppx_expect ppx_sexp_message ppx_deriving_yojson ppx_deriving_yojson.runtime))
|
||||
(libraries
|
||||
comby
|
||||
cohttp-lwt-unix
|
||||
core
|
||||
camlzip))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (source_tree example) (source_tree example/src/.ignore-me)))
|
1
test/omega/example
Symbolic link
1
test/omega/example
Symbolic link
@ -0,0 +1 @@
|
||||
../example
|
222
test/omega/test_c_style_comments.ml
Normal file
222
test/omega/test_c_style_comments.ml
Normal file
@ -0,0 +1,222 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let all ?(configuration = configuration) template source =
|
||||
C.all ~configuration ~template ~source
|
||||
|
||||
let print_matches matches =
|
||||
List.map matches ~f:Match.to_yojson
|
||||
|> (fun matches -> `List matches)
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string
|
||||
|
||||
let%expect_test "rewrite_comments_1" =
|
||||
let template = "replace this :[1] end" in
|
||||
let source = "/* don't replace this () end */ do replace this () end" in
|
||||
let rewrite_template = "X" in
|
||||
|
||||
all template source
|
||||
|> (fun matches ->
|
||||
Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "/* don't replace this () end */ do X"]
|
||||
|
||||
let%expect_test "rewrite_comments_2" =
|
||||
let template =
|
||||
{|
|
||||
if (:[1]) { :[2] }
|
||||
|}
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
/* if (fake_condition_body_must_be_non_empty) { fake_body; } */
|
||||
// if (fake_condition_body_must_be_non_empty) { fake_body; }
|
||||
if (real_condition_body_must_be_empty) {
|
||||
int i;
|
||||
int j;
|
||||
}
|
||||
|}
|
||||
in
|
||||
|
||||
let rewrite_template =
|
||||
{|
|
||||
if (:[1]) {}
|
||||
|}
|
||||
in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact
|
||||
{|
|
||||
/* if (fake_condition_body_must_be_non_empty) { fake_body; } */
|
||||
if (real_condition_body_must_be_empty) {}
|
||||
|}]
|
||||
|
||||
let%expect_test "capture_comments" =
|
||||
let template = {|if (:[1]) { :[2] }|} in
|
||||
let source = {|if (true) { /* some comment */ console.log(z); }|} in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 48, "line": 1, "column": 49 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "true",
|
||||
"range": {
|
||||
"start": { "offset": 4, "line": 1, "column": 5 },
|
||||
"end": { "offset": 8, "line": 1, "column": 9 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"variable": "2",
|
||||
"value": "console.log(z);",
|
||||
"range": {
|
||||
"start": { "offset": 31, "line": 1, "column": 32 },
|
||||
"end": { "offset": 46, "line": 1, "column": 47 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "if (true) { /* some comment */ console.log(z); }"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "single_quote_in_comment" =
|
||||
let template =
|
||||
{| {:[1]} |}
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
/*'*/
|
||||
{test}
|
||||
|}
|
||||
in
|
||||
|
||||
let rewrite_template =
|
||||
{|
|
||||
{:[1]}
|
||||
|}
|
||||
in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact
|
||||
{|
|
||||
{test}
|
||||
|}]
|
||||
|
||||
let%expect_test "single_quote_in_comment" =
|
||||
let template =
|
||||
{| {:[1]} |}
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
{
|
||||
a = 1;
|
||||
/* Events with mask == AE_NONE are not set. So let's initiaize the
|
||||
* vector with it. */
|
||||
for (i = 0; i < setsize; i++)
|
||||
}
|
||||
|}
|
||||
in
|
||||
|
||||
let rewrite_template =
|
||||
{|
|
||||
{:[1]}
|
||||
|}
|
||||
in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact
|
||||
{|
|
||||
{
|
||||
a = 1;
|
||||
/* Events with mask == AE_NONE are not set. So let's initiaize the
|
||||
* vector with it. */
|
||||
for (i = 0; i < setsize; i++)
|
||||
}
|
||||
|}]
|
||||
|
||||
let%expect_test "single_quote_in_comment" =
|
||||
let template =
|
||||
{| {:[1]} |}
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
{
|
||||
a = 1;
|
||||
/* ' */
|
||||
for (i = 0; i < setsize; i++)
|
||||
}
|
||||
|}
|
||||
in
|
||||
|
||||
let rewrite_template =
|
||||
{|
|
||||
{:[1]}
|
||||
|}
|
||||
in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact
|
||||
{|
|
||||
{
|
||||
a = 1;
|
||||
/* ' */
|
||||
for (i = 0; i < setsize; i++)
|
||||
}
|
||||
|}]
|
||||
|
||||
let%expect_test "give_back_the_comment_characters_for_newline_comments_too" =
|
||||
let template =
|
||||
{| {:[1]} |}
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
{
|
||||
// a comment
|
||||
}
|
||||
|}
|
||||
in
|
||||
|
||||
let rewrite_template =
|
||||
{|
|
||||
{:[1]}
|
||||
|}
|
||||
in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact
|
||||
{|
|
||||
{
|
||||
// a comment
|
||||
}
|
||||
|}]
|
||||
*)
|
@ -1,4 +1,4 @@
|
||||
open Core
|
||||
(*open Core
|
||||
|
||||
module Time = Core_kernel.Time_ns.Span
|
||||
|
||||
@ -942,3 +942,4 @@ let%expect_test "substitute_ok" =
|
||||
|> print_string;
|
||||
[%expect_exact {|hole_1 hole_2
|
||||
|}]
|
||||
*)
|
434
test/omega/test_generic.ml
Normal file
434
test/omega/test_generic.ml
Normal file
@ -0,0 +1,434 @@
|
||||
open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let format s =
|
||||
let s = String.chop_prefix_exn ~prefix:"\n" s in
|
||||
let leading_indentation = Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
let run ?(configuration = configuration) source match_template rewrite_template =
|
||||
Generic.first ~configuration match_template source
|
||||
|> function
|
||||
| Ok result ->
|
||||
Rewrite.all ~source ~rewrite_template [result]
|
||||
|> (fun x -> Option.value_exn x)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
| Error _ ->
|
||||
(* this is too annoying to fix everytime the grammar changes. *)
|
||||
print_string ""
|
||||
|
||||
let run_all ?(configuration = configuration) source match_template rewrite_template =
|
||||
Generic.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| results ->
|
||||
Option.value_exn (Rewrite.all ~source ~rewrite_template results)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
|
||||
|
||||
let%expect_test "basic" =
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c d|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1] c d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1] d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b c|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b c d|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1] c d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (b c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[2] :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (b c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] :[1] d|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (c)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] c :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (d)|}];
|
||||
|
||||
let source = {|x:|} in
|
||||
let match_template = {|:[1]:|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|x|}]
|
||||
|
||||
let%expect_test "basic_failures" =
|
||||
let source = {|a x b bbq|} in
|
||||
let match_template = {|a :[1] b c|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] d :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact
|
||||
{||}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] b :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}]
|
||||
|
||||
let%expect_test "delimiter_matching" =
|
||||
let source = {|(a b c) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c|}];
|
||||
|
||||
let source = {|(a b c) d|} in
|
||||
let match_template = {|(:[1] b :[2]) d|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (c)|}];
|
||||
|
||||
let source = {|q(a b c) d|} in
|
||||
let match_template = {|q(:[1] b :[2]) d|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (c)|}];
|
||||
|
||||
let source = {|((a) b)|} in
|
||||
let match_template = {|(:[1] b)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a)|}];
|
||||
|
||||
let source = {|((a b c)) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a b c)|}];
|
||||
|
||||
let source = {|((a b c)) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a b c)|}];
|
||||
|
||||
let source = {|((a b c) q) d|} in
|
||||
let match_template = {|((:[1]) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c|}];
|
||||
|
||||
let source = {|((a b c) q) d|} in
|
||||
let match_template = {|((:[1] c) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|((a b () c) q) d|} in
|
||||
let match_template = {|((:[1] () c) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|((a ((x) d) b c)) d|} in
|
||||
let match_template = {|((a :[1] :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((x) d)|}];
|
||||
|
||||
let source = {|((a ((x) d) b c)) d|} in
|
||||
let match_template = {|((a (:[1]) :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(x) d b|}];
|
||||
|
||||
let source = {|(b (c) d)|} in
|
||||
let match_template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c) d|}];
|
||||
|
||||
let source = {|(b (c) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c) d|}];
|
||||
|
||||
let source = {|(b (c.) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c.) d|}];
|
||||
|
||||
let source = {|(b. (c) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b. (c) d|}];
|
||||
|
||||
let source = {|(b (c) d.)|} in
|
||||
let match_template = {|(b :[1] d.)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(c)|}];
|
||||
|
||||
let source = {|outer(inner(dst,src),src)|} in
|
||||
let match_template = {|outer(:[1],src)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|inner(dst,src)|}];
|
||||
|
||||
let source = {|(b ((c)) d.)|} in
|
||||
let match_template = {|(b :[1] d.)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((c))|}];
|
||||
|
||||
let source = {|a b c|} in
|
||||
let match_template = {|a :[1] c|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b|}];
|
||||
|
||||
let source = {|x = foo;|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|foo|}];
|
||||
|
||||
let source = {|((a {{x} d} b c)) d|} in
|
||||
let match_template = {|((a {:[1] d} :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{x} b|}];
|
||||
|
||||
let source = {|((a {([{x}]) d} b c)) d|} in
|
||||
let match_template = {|((a {:[1] d} :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|([{x}]) b|}];
|
||||
|
||||
let source = {|(((((x)))))|} in
|
||||
let match_template = {|(((:[1])))|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((x))|}];
|
||||
|
||||
let source = {|((((y(x)z))))|} in
|
||||
let match_template = {|(((:[1])))|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(y(x)z)|}];
|
||||
|
||||
let source = {|((((y(x)z))))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(y(x)z) |}];
|
||||
|
||||
let source = {|(((x)z))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|x z|}];
|
||||
|
||||
let source = {|((((x))z))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(x) z|}];
|
||||
|
||||
let source = {|lolwtfbbq|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|wtf|}];
|
||||
|
||||
let source = {|x = foo; x = bar;|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|foo x = bar;|}];
|
||||
|
||||
let source = {|[ no match prefix ] x = foo; [ no match suffix ]|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|[ no match prefix ] foo [ no match suffix ]|}];
|
||||
|
||||
let source = {|x = a; x = b; x = c|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a x = b; x = c|}];
|
||||
|
||||
let source = {|x = ( x = x; );|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|( x = x; )|}];
|
||||
|
||||
let source = {|( x = x = x; )|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|( x = x )|}];
|
||||
|
||||
let source = {|xxx a b d c 1 2 3 b d d blah|} in
|
||||
let match_template = {|a :[1] c :[2] d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|xxx b d 1 2 3 b d blah|}];
|
||||
|
||||
let source = {|howevenlolwtfbbqispossible|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|howevenwtfispossible|}];
|
||||
|
||||
let source = {|lolhowevenlolwtfbbqispossiblebbq|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|howevenlolwtfispossiblebbq|}];
|
||||
|
||||
let source = {|hello my name is bob the builder|} in
|
||||
let match_template = {|:[alongidentifiername] :[2] :[3] :[xyz] :[5] :[6]|} in
|
||||
let rewrite_template = {|:[alongidentifiername] :[2] :[3] :[xyz] :[5] :[6]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|hello my name is bob the builder|}];
|
||||
|
||||
let source = {|www.testdofooname.com/picsinsideit/stunningpictureofkays1381737242g8k4n-280x428.jpg|} in
|
||||
let match_template = {|www.:[1]-:[2].jpg|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|testdofooname.com/picsinsideit/stunningpictureofkays1381737242g8k4n 280x428|}];
|
||||
|
||||
let source = {|https://api.github.com/repos/dmjacobsen/slurm/commits/716c1499695c68afcab848a1b49653574b4fc167|} in
|
||||
let match_template = {|:[1]api.:[2]/repos/:[3]s/:[4]|} in
|
||||
let rewrite_template = {|:[1] :[2] :[3] :[4]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|https:// github.com dmjacobsen/slurm/commit 716c1499695c68afcab848a1b49653574b4fc167|}];
|
||||
|
||||
let source =
|
||||
{|
|
||||
assert(stream->md_len + md_len -
|
||||
si.foo_data_begin <= MAD_BUFFER_MDLEN);
|
||||
memcpy(*stream->foo_data + stream->md_len,
|
||||
mad_bit_nextbyte(&stream->ptr),
|
||||
frame_used = md_len - si.foo_data_begin);
|
||||
stream->md_len += frame_used;
|
||||
|} |> format
|
||||
in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3]);|} in
|
||||
let rewrite_template = {|:[1], :[2], :[3]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|assert(stream->md_len + md_len -
|
||||
si.foo_data_begin <= MAD_BUFFER_MDLEN);
|
||||
*stream->foo_data + stream->md_len, mad_bit_nextbyte(&stream->ptr), frame_used = md_len - si.foo_data_begin
|
||||
stream->md_len += frame_used;|}]
|
||||
|
||||
let%expect_test "significant_whitespace" =
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ~significant_whitespace:true () in
|
||||
let run = run ~configuration in
|
||||
|
||||
let source = {|two spaces|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|two spaces|}];
|
||||
|
||||
(* FIXME: this should fail. also test case where separators do or do not need
|
||||
whitespace. e.g., strict about strcpy(src,dst) matching a template
|
||||
strcpy(:[1],:[2]) versus strcpy(:[1], :[2]) *)
|
||||
let source = {|two spaces|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|two spaces|}]
|
||||
|
||||
let%expect_test "contextual_matching" =
|
||||
let run = run_all in
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}];
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}]
|
||||
|
||||
let%expect_test "contextual_matching_with_short_hole_syntax" =
|
||||
let run = run_all in
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[[1]], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[[1]]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}]
|
||||
|
||||
(*
|
||||
let%expect_test "trivial_empty_case" =
|
||||
let source = "" in
|
||||
let match_template = "" in
|
||||
begin
|
||||
Generic.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| hd :: _ ->
|
||||
print_string (Yojson.Safe.to_string (Match.to_yojson hd))
|
||||
end;
|
||||
[%expect_exact {|{"range":{"start":{"offset":0,"line":1,"column":1},"end":{"offset":0,"line":1,"column":1}},"environment":[],"matched":""}|}]
|
||||
*)
|
144
test/omega/test_hole_extensions.ml
Normal file
144
test/omega/test_hole_extensions.ml
Normal file
@ -0,0 +1,144 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let run_all ?(configuration = configuration) source match_template rewrite_template =
|
||||
Generic.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| results ->
|
||||
Option.value_exn (Rewrite.all ~source ~rewrite_template results)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
|
||||
let%expect_test "non_space" =
|
||||
let run = run_all in
|
||||
let source = {| foo. foo.bar.quux derp|} in
|
||||
let match_template = {|:[x.]|} in
|
||||
let rewrite_template = {|{:[x]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {| {foo.} {foo.bar.quux} {derp}|}]
|
||||
|
||||
let%expect_test "only_space" =
|
||||
let run = run_all in
|
||||
let source = {| foo. foo.bar.quux derp|} in
|
||||
let match_template = {|:[ x]|} in
|
||||
let rewrite_template = {|{:[x]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{ }foo.{ }foo.bar.quux{ }derp|}]
|
||||
|
||||
let%expect_test "up_to_newline" =
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|
|
||||
foo.
|
||||
foo.bar.quux
|
||||
derp
|
||||
|} in
|
||||
let match_template = {|:[x\n]|} in
|
||||
let rewrite_template = {|{:[x]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{
|
||||
}{foo.
|
||||
}{foo.bar.quux
|
||||
}{derp
|
||||
}|}]
|
||||
|
||||
let%expect_test "match_empty_in_newline_hole" =
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|stuff
|
||||
after
|
||||
|} in
|
||||
let match_template = {|stuff:[x\n]|} in
|
||||
let rewrite_template = {|{->:[x]<-}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{->
|
||||
<-}after
|
||||
|}]
|
||||
|
||||
let%expect_test "leading_indentation" =
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|
|
||||
foo. bar bazz
|
||||
foo.bar.quux
|
||||
derp
|
||||
|} in
|
||||
let match_template = {|:[ leading_indentation]:[rest\n]|} in
|
||||
let rewrite_template = {|{:[leading_indentation]}:[rest]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|
|
||||
{ }foo. bar bazz
|
||||
{ }foo.bar.quux
|
||||
{ }derp
|
||||
|}]
|
||||
|
||||
let%expect_test "non_space_partial_match" =
|
||||
let run = run_all in
|
||||
let source = {| foo. foo.bar.quux derp|} in
|
||||
let match_template = {|foo.:[x.]ux|} in
|
||||
let rewrite_template = {|{:[x]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {| foo. {bar.qu} derp|}]
|
||||
|
||||
let%expect_test "non_space_does_not_match_reserved_delimiters" =
|
||||
let run = run_all in
|
||||
let source = {|fo.o(x)|} in
|
||||
let match_template = {|:[f.]|} in
|
||||
let rewrite_template = {|{:[f]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{fo.o}({x})|}]
|
||||
|
||||
let%expect_test "alphanum_partial_match" =
|
||||
let run = run_all in
|
||||
let source = {| foo. foo.bar.quux derp|} in
|
||||
let match_template = {|foo.b:[x]r.quux|} in
|
||||
let rewrite_template = {|{:[x]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {| foo. {a} derp|}]
|
||||
|
||||
let%expect_test "newline_matcher_should_not_be_sat_on_space" =
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|a b c d
|
||||
e f g h|} in
|
||||
let match_template = {|:[line\n] |} in
|
||||
let rewrite_template = {|{:[line]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{a b c d
|
||||
}e f g h|}];
|
||||
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|a b c d
|
||||
e f g h|} in
|
||||
let match_template = {|:[line\n]:[next]|} in
|
||||
let rewrite_template = {|{:[line]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{a b c d
|
||||
}|}];
|
||||
|
||||
let run = run_all in
|
||||
let source =
|
||||
{|a b c d
|
||||
e f g h
|
||||
|} in
|
||||
let match_template = {|:[line1\n]:[next\n]|} in
|
||||
let rewrite_template = {|{:[line1]|:[next]}|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{a b c d
|
||||
|e f g h
|
||||
}|}]
|
||||
|
||||
let%expect_test "implicit_equals" =
|
||||
let run = run_all in
|
||||
let source = {|a b a|} in
|
||||
let match_template = {|:[[x]] :[[m]] :[[x]]|} in
|
||||
let rewrite_template = {|:[m]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b|}]
|
||||
*)
|
323
test/omega/test_integration.ml
Normal file
323
test/omega/test_integration.ml
Normal file
@ -0,0 +1,323 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let all ?(configuration = configuration) template source =
|
||||
Generic.all ~configuration ~template ~source
|
||||
|
||||
let print_matches matches =
|
||||
List.map matches ~f:Match.to_yojson
|
||||
|> (fun matches -> `List matches)
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string
|
||||
|
||||
let%expect_test "dont_get_stuck" =
|
||||
let template = "" in
|
||||
let source = "a" in
|
||||
let matches = all ~configuration template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[]|}]
|
||||
|
||||
let%expect_test "dont_get_stuck" =
|
||||
let template = "a" in
|
||||
let source = "a" in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 1, "line": 1, "column": 2 }
|
||||
},
|
||||
"environment": [],
|
||||
"matched": "a"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "dont_get_stuck" =
|
||||
let template = "a" in
|
||||
let source = "aaa" in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 1, "line": 1, "column": 2 }
|
||||
},
|
||||
"environment": [],
|
||||
"matched": "a"
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 2, "line": 1, "column": 3 }
|
||||
},
|
||||
"environment": [],
|
||||
"matched": "a"
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 2, "line": 1, "column": 3 },
|
||||
"end": { "offset": 3, "line": 1, "column": 4 }
|
||||
},
|
||||
"environment": [],
|
||||
"matched": "a"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "rewrite_awesome_1" =
|
||||
let template = "replace this :[1] end" in
|
||||
let source = "xreplace this () end" in
|
||||
let rewrite_template = "X" in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "xX"]
|
||||
|
||||
let%expect_test "rewrite_whole_template_matches" =
|
||||
let template = {|rewrite :[1] <- this string|} in
|
||||
let source = {|rewrite hello world <- this string|} in
|
||||
let rewrite_template = "?" in
|
||||
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "?"]
|
||||
|
||||
let%expect_test "single_token" =
|
||||
let template = {|:[[1]] this|} in
|
||||
let source = {|the problem is this|} in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 12, "line": 1, "column": 13 },
|
||||
"end": { "offset": 19, "line": 1, "column": 20 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "is",
|
||||
"range": {
|
||||
"start": { "offset": 12, "line": 1, "column": 13 },
|
||||
"end": { "offset": 14, "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "is this"
|
||||
}
|
||||
]|}]
|
||||
|
||||
|
||||
let%expect_test "single_token_with_preceding_whitespace" =
|
||||
let template = {| :[[1]] this|} in
|
||||
let source = {|the problem is this|} in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 11, "line": 1, "column": 12 },
|
||||
"end": { "offset": 19, "line": 1, "column": 20 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "is",
|
||||
"range": {
|
||||
"start": { "offset": 12, "line": 1, "column": 13 },
|
||||
"end": { "offset": 14, "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": " is this"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "single_token_rewrite" =
|
||||
let template = {| :[[1]] this|} in
|
||||
let source = {|the problem is this|} in
|
||||
let rewrite_template = ":[1]" in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "the problemis"]
|
||||
|
||||
let%expect_test "single_token_match_inside_paren_no_succeeding_whitespace" =
|
||||
let template = {|:[[1]](:[[2]])|} in
|
||||
let source = {|foo(bar)|} in
|
||||
let rewrite_template = ":[1] : :[2]" in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "foo : bar"]
|
||||
|
||||
let%expect_test "whitespace_hole_rewrite" =
|
||||
let template = {|:[ w]this|} in
|
||||
let rewrite_template = "space:[ w]here" in
|
||||
let source = {| this|} in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "space here"]
|
||||
|
||||
let%expect_test "punctuation_hole_rewrite" =
|
||||
let template = {|:[x.]|} in
|
||||
let rewrite_template = "->:[x.]<-" in
|
||||
let source = {|now.this. is,pod|racing|} in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "->now.this.<- ->is,pod|racing<-"]
|
||||
|
||||
let%expect_test "newline_hole_rewrite" =
|
||||
let template = {|:[x\n]|} in
|
||||
let rewrite_template = {|->:[x\n]<-|} in
|
||||
let source = {|now.this.
|
||||
is,pod|racing
|
||||
|} in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact "->now.this.
|
||||
<-->is,pod|racing
|
||||
<-"]
|
||||
|
||||
|
||||
|
||||
let%expect_test "shift_or_at_least_dont_get_stuck" =
|
||||
let template = ":[1]" in
|
||||
let source = "a" in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 1, "line": 1, "column": 2 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "a",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 1, "line": 1, "column": 2 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "a"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "shift_or_at_least_dont_get_stuck" =
|
||||
let template = ":[1]" in
|
||||
let source = "aa" in
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 2, "line": 1, "column": 3 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "aa",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 2, "line": 1, "column": 3 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "aa"
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "nested_rewrite1" =
|
||||
let source =
|
||||
{|
|
||||
x x y strcpy(strcpy(dst1, src1), src2); blah blah XXX
|
||||
|}
|
||||
in
|
||||
|
||||
let template =
|
||||
{|
|
||||
strcpy(:[1], :[2])
|
||||
|}
|
||||
in
|
||||
|
||||
let matches = all template source in
|
||||
print_matches matches;
|
||||
[%expect_exact "[]"]
|
||||
|
||||
(* FIXME(RVT) nested rewrites *)
|
||||
let%expect_test "nested_rewrite2" =
|
||||
let template =
|
||||
{|
|
||||
if :[var_check] != nil {
|
||||
for :[defines] := range :[var_use] {:[inner_body]}
|
||||
}
|
||||
|}
|
||||
in
|
||||
let source =
|
||||
{|
|
||||
if fields.List != nil {
|
||||
for _, field := range fields.List {
|
||||
if field.Names != nil {
|
||||
for _, fieldName := range field.Names {
|
||||
stuff with fields and things
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|}
|
||||
in
|
||||
let rewrite_template = "for :[defines] := range :[var_use] {:[inner_body]}" in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|for _, field := range fields.List {
|
||||
if field.Names != nil {
|
||||
for _, fieldName := range field.Names {
|
||||
stuff with fields and things
|
||||
}
|
||||
}
|
||||
}|}]
|
||||
|
||||
let%expect_test "match_:[[1]]" =
|
||||
let template =
|
||||
{|
|
||||
:[[1]].next()
|
||||
|}
|
||||
in
|
||||
let source =
|
||||
{|
|
||||
col_names = reader.next()
|
||||
}
|
||||
|}
|
||||
in
|
||||
let rewrite_template = "next(:[1])" in
|
||||
all template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|
|
||||
col_names =next(reader)}
|
||||
|}]
|
||||
*)
|
698
test/omega/test_match_rule.ml
Normal file
698
test/omega/test_match_rule.ml
Normal file
@ -0,0 +1,698 @@
|
||||
(*open Core
|
||||
|
||||
open Language
|
||||
open Matchers
|
||||
open Match
|
||||
|
||||
let rule_parses rule =
|
||||
match Rule.create rule with
|
||||
| Ok _ -> "true"
|
||||
| Error _ -> "false"
|
||||
|
||||
let print_matches matches =
|
||||
List.map matches ~f:Match.to_yojson
|
||||
|> (fun matches -> `List matches)
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string
|
||||
|
||||
let%expect_test "parse_rule" =
|
||||
let rule = {| where :[1] == :[2], :[3] == "y" |} in
|
||||
rule_parses rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where :[1] == :[2], :[3] != "x" |} in
|
||||
rule_parses rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where :[1] != :[3] |} in
|
||||
rule_parses rule |> print_string;
|
||||
[%expect_exact {|true|}]
|
||||
|
||||
let%expect_test "parse_basic" =
|
||||
Rule.create {|where "a" == "a"|}
|
||||
|> Or_error.ok_exn
|
||||
|> fun rule -> print_s [%message (rule : Ast.expression list)];
|
||||
[%expect_exact {|(rule ((Equal (String a) (String a))))
|
||||
|}]
|
||||
|
||||
let%expect_test "parse_match_one_case" =
|
||||
Rule.create {|where match "match_me" { | "case_one" -> true }|}
|
||||
|> Or_error.ok_exn
|
||||
|> fun rule -> print_s [%message (rule : Ast.expression list)];
|
||||
[%expect_exact "(rule ((Match (String match_me) (((String case_one) (True))))))
|
||||
"]
|
||||
|
||||
let%expect_test "parse_match_multi_case" =
|
||||
Rule.create
|
||||
{| where
|
||||
match "match_me" {
|
||||
| "case_one" -> true
|
||||
| "case_two" -> false
|
||||
}
|
||||
|}
|
||||
|> Or_error.ok_exn
|
||||
|> fun rule -> print_s [%message (rule : Ast.expression list)];
|
||||
[%expect_exact "(rule
|
||||
((Match (String match_me)
|
||||
(((String case_one) (True)) ((String case_two) (False))))))
|
||||
"]
|
||||
|
||||
let sat ?(env = Environment.create ()) rule =
|
||||
let rule = Rule.create rule |> Or_error.ok_exn in
|
||||
Format.sprintf "%b" (Rule.(sat @@ apply rule env))
|
||||
|
||||
let make_env bindings =
|
||||
List.fold bindings
|
||||
~init:(Environment.create ())
|
||||
~f:(fun env (var, value) -> Environment.add env var value)
|
||||
|
||||
let%expect_test "rule_sat" =
|
||||
let rule = {| where "x" != "y" |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where "x" != "x" |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|false|}];
|
||||
|
||||
let rule = {| where "x" == "x" |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where "x" == "y" |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|false|}];
|
||||
|
||||
let rule = {| where :[x] == "y" |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|false|}];
|
||||
|
||||
let rule = {| where :[x] == :[x] |} in
|
||||
sat rule |> print_string;
|
||||
[%expect_exact {|false|}]
|
||||
|
||||
let%expect_test "rule_sat_with_env" =
|
||||
let env = make_env ["1", "x"; "2", "y"; "3", "x"] in
|
||||
|
||||
let rule = {| where :[1] == :[3], :[1] != :[2] |} in
|
||||
sat ~env rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where :[1] == :[3], :[1] != "y" |} in
|
||||
sat ~env rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where :[1] == :[3], :[1] == "x" |} in
|
||||
sat ~env rule |> print_string;
|
||||
[%expect_exact {|true|}];
|
||||
|
||||
let rule = {| where :[1] == :[2], :[1] != :[2] |} in
|
||||
sat ~env rule |> print_string;
|
||||
[%expect_exact {|false|}]
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let format s =
|
||||
let s = s |> String.chop_prefix_exn ~prefix:"\n" in
|
||||
let leading_indentation =
|
||||
Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
|
||||
let%expect_test "where_true" =
|
||||
let template =
|
||||
{|
|
||||
(:[1]) => {}
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
(b,c) => {}
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let rule =
|
||||
{| where true
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 11, "line": 1, "column": 12 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "b,c",
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 4, "line": 1, "column": 5 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "(b,c) => {}"
|
||||
}
|
||||
] |}]
|
||||
|
||||
let%expect_test "match_sat" =
|
||||
let template =
|
||||
{|
|
||||
(:[1]) => {}
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
(b,c) => {}
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let rule =
|
||||
{| where
|
||||
match :[1] {
|
||||
| ":[_],:[_]" -> false
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}];
|
||||
|
||||
let rule =
|
||||
{| where
|
||||
match :[1] {
|
||||
| ":[_],:[_]" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 11, "line": 1, "column": 12 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "b,c",
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 4, "line": 1, "column": 5 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "(b,c) => {}"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let source =
|
||||
{|
|
||||
(a) => {}
|
||||
(b,c) => {}
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let rule =
|
||||
{| where
|
||||
match :[1] {
|
||||
| ":[_],:[_]" -> false
|
||||
| ":[_]" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 9, "line": 1, "column": 10 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "a",
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 2, "line": 1, "column": 3 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "(a) => {}"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where
|
||||
match :[1] {
|
||||
| ":[_],:[_]" -> false
|
||||
| ":[_]" -> :[1] == "a"
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 9, "line": 1, "column": 10 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "a",
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 2, "line": 1, "column": 3 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "(a) => {}"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let rule =
|
||||
{| where
|
||||
match :[1] {
|
||||
| ":[_],:[_]" -> false
|
||||
| ":[_]" -> :[1] == "b"
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}]
|
||||
|
||||
|
||||
let%expect_test "match_s_suffix" =
|
||||
let template = ":[1]s" in
|
||||
|
||||
let source = "names" in
|
||||
|
||||
let rule =
|
||||
{| where true
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 5, "line": 1, "column": 6 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "name",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 4, "line": 1, "column": 5 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "names"
|
||||
}
|
||||
] |}]
|
||||
|
||||
let%expect_test "match_s_suffix" =
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "names" in
|
||||
|
||||
let rule =
|
||||
{| where true
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 5, "line": 1, "column": 6 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "names",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 5, "line": 1, "column": 6 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "names"
|
||||
}
|
||||
] |}]
|
||||
|
||||
let%expect_test "configuration_choice_based_on_case" =
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "names" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] {
|
||||
| "ame" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}];
|
||||
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "names" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] {
|
||||
| "names" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 5, "line": 1, "column": 6 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "names",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 5, "line": 1, "column": 6 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "names"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "namesXXXXX" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] {
|
||||
| "names" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}]
|
||||
|
||||
|
||||
|
||||
|
||||
let%expect_test "match_using_environment_merge" =
|
||||
let template = "{:[1]}" in
|
||||
|
||||
let source = "{{ a : a } { a : a }}" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] { | "{ :[x] : :[y] }" -> :[x] == :[y] }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 21, "line": 1, "column": 22 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "{ a : a } { a : a }",
|
||||
"range": {
|
||||
"start": { "offset": 1, "line": 1, "column": 2 },
|
||||
"end": { "offset": 20, "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "{{ a : a } { a : a }}"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let template = "{:[1]}" in
|
||||
|
||||
let source = "{{ a : a } { a : b }}" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] { | "{ :[x] : :[y] }" -> :[x] == :[y] }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}]
|
||||
|
||||
|
||||
let%expect_test "nested_matches" =
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "{ { foo : { bar : { baz : qux } } } }" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] {
|
||||
| "{ :[foo] : :[tail1] }" -> match :[tail1] {
|
||||
| "{ :[bar] : :[tail2] }" -> match :[tail2] {
|
||||
| "{ baz : :[qux] }" -> :[qux] == "qux", :[bar] == "bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 37, "line": 1, "column": 38 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "{ { foo : { bar : { baz : qux } } } }",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 37, "line": 1, "column": 38 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "{ { foo : { bar : { baz : qux } } } }"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "{ { foo : { bar : { baz : qux } } } }" in
|
||||
|
||||
let rule =
|
||||
{| where match :[1] {
|
||||
| "{ :[foo] : :[tail1] }" -> match :[tail1] {
|
||||
| "{ :[bar] : :[tail2] }" -> match :[tail2] {
|
||||
| "{ baz : :[qux] }" -> :[qux] == "fail"
|
||||
}
|
||||
}
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}]
|
||||
|
||||
|
||||
let%expect_test "match_on_template" =
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "oodles" in
|
||||
|
||||
let rule =
|
||||
{| where match "p:[1]" {
|
||||
| "poodles" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 6, "line": 1, "column": 7 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "oodles",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 6, "line": 1, "column": 7 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "oodles"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "poodle" in
|
||||
|
||||
let rule =
|
||||
{| where match ":[1]s" {
|
||||
| "poodles" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 6, "line": 1, "column": 7 }
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"variable": "1",
|
||||
"value": "poodle",
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 6, "line": 1, "column": 7 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"matched": "poodle"
|
||||
}
|
||||
] |}];
|
||||
|
||||
let template = ":[1]" in
|
||||
|
||||
let source = "poodle" in
|
||||
|
||||
let rule =
|
||||
{| where match ":[1]," {
|
||||
| "poodle" -> true
|
||||
}
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
Generic.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } -> Rule.(sat @@ apply rule environment))
|
||||
|> print_matches;
|
||||
[%expect {|
|
||||
[] |}];
|
||||
*)
|
55
test/omega/test_python_string_literals.ml
Normal file
55
test/omega/test_python_string_literals.ml
Normal file
@ -0,0 +1,55 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let print_matches matches =
|
||||
List.map matches ~f:(fun matched -> `String matched.Match.matched)
|
||||
|> (fun matches -> `List matches)
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string
|
||||
|
||||
|
||||
let%expect_test "matched_contains_raw_literal_quotes" =
|
||||
let source = {|"""blah"""|} in
|
||||
let template = {|""":[[1]]"""|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"\"\"blah\"\"\"" ]|}]
|
||||
|
||||
let%expect_test "interpreted_string_does_not_match_raw_literal" =
|
||||
let source = {|"""blah""" "blah"|} in
|
||||
let template = {|":[[1]]"|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"blah\"" ]|}]
|
||||
|
||||
let%expect_test "interpreted_string_does_not_match_raw_literal_containing_quote" =
|
||||
let source = {|"""blah""" """bl"ah""" "blah"|} in
|
||||
let template = {|":[[1]]"|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"blah\"" ]|}]
|
||||
|
||||
let%expect_test "raw_string_matches_string_containing_quote" =
|
||||
let source = {|"""bl"ah"""|} in
|
||||
let template = {|""":[1]"""|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"\"\"bl\"ah\"\"\"" ]|}]
|
||||
|
||||
let%expect_test "invalid_raw_string_in_python_but_matches_because_ignores_after" =
|
||||
let source = {|"""""""|} in
|
||||
let template = {|""":[1]"""|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"\"\"\"\"\"" ]|}]
|
||||
|
||||
let%expect_test "raw_string_captures_escape_sequences" =
|
||||
let source = {|"""\""""|} in
|
||||
let template = {|""":[1]"""|} in
|
||||
let matches = Python.all ~configuration ~template ~source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"\"\"\\\"\"\"" ]|}]
|
||||
*)
|
127
test/omega/test_rewrite_rule.ml
Normal file
127
test/omega/test_rewrite_rule.ml
Normal file
@ -0,0 +1,127 @@
|
||||
(*open Core
|
||||
|
||||
open Language
|
||||
open Matchers
|
||||
open Match
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let format s =
|
||||
let s = String.chop_prefix_exn ~prefix:"\n" s in
|
||||
let leading_indentation = Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
let run_rule source match_template rewrite_template rule =
|
||||
Generic.first ~configuration match_template source
|
||||
|> function
|
||||
| Error _ -> print_string "bad"
|
||||
| Ok result ->
|
||||
match result with
|
||||
| ({ environment; _ } as m) ->
|
||||
let e = Rule.(result_env @@ apply rule environment) in
|
||||
match e with
|
||||
| None -> print_string "bad bad"
|
||||
| Some e ->
|
||||
{ m with environment = e }
|
||||
|> List.return
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (fun x -> Option.value_exn x)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
|
||||
let%expect_test "rewrite_rule" =
|
||||
let source = {|int|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where rewrite :[1] { "int" -> "expect" }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
run_rule source match_template rewrite_template rule;
|
||||
[%expect_exact {|expect|}]
|
||||
|
||||
let%expect_test "sequenced_rewrite_rule" =
|
||||
let source = {|{ { a : { b : { c : d } } } }|} in
|
||||
let match_template = {|{ :[a] : :[rest] }|} in
|
||||
let rewrite_template = {|{ :[a] : :[rest] }|} in
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where
|
||||
rewrite :[a] { "a" -> "qqq" },
|
||||
rewrite :[rest] { "{ b : { :[other] } }" -> "{ :[other] }" }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
run_rule source match_template rewrite_template rule;
|
||||
[%expect_exact {|{ { qqq : { c : d } } }|}]
|
||||
|
||||
let%expect_test "rewrite_rule_for_list" =
|
||||
let source = {|[1, 2, 3, 4,]|} in
|
||||
let match_template = {|[:[contents]]|} in
|
||||
let rewrite_template = {|[:[contents]]|} in
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where rewrite :[contents] { ":[[x]]," -> ":[[x]];" }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
run_rule source match_template rewrite_template rule;
|
||||
[%expect_exact {|[1; 2; 3; 4;]|}]
|
||||
|
||||
let%expect_test "rewrite_rule_for_list_strip_last" =
|
||||
let source = {|[1, 2, 3, 4]|} in
|
||||
let match_template = {|[:[contents]]|} in
|
||||
let rewrite_template = {|[:[contents]]|} in
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where rewrite :[contents] { ":[x], " -> ":[x]; " }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
run_rule source match_template rewrite_template rule;
|
||||
[%expect_exact {|[1; 2; 3; 4]|}]
|
||||
|
||||
let%expect_test "haskell_example" =
|
||||
let source = {|
|
||||
(concat
|
||||
[ "blah blah blah"
|
||||
, "blah"
|
||||
])
|
||||
|} in
|
||||
let match_template = {|(concat [:[contents]])|} in
|
||||
let rewrite_template = {|(:[contents])|} in
|
||||
|
||||
let rule =
|
||||
{|
|
||||
where rewrite :[contents] { "," -> "++" }
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
|
||||
run_rule source match_template rewrite_template rule;
|
||||
[%expect_exact {|
|
||||
( "blah blah blah"
|
||||
++ "blah"
|
||||
)
|
||||
|}]
|
||||
*)
|
@ -1,4 +1,4 @@
|
||||
open Core
|
||||
(*open Core
|
||||
|
||||
open Lwt.Infix
|
||||
|
||||
@ -202,3 +202,4 @@ let%expect_test "post_substitute" =
|
||||
[%expect {| { "result": "oh hi there", "id": 0 } |}]
|
||||
|
||||
let () = kill ()
|
||||
*)
|
459
test/omega/test_special_matcher_cases.ml
Normal file
459
test/omega/test_special_matcher_cases.ml
Normal file
@ -0,0 +1,459 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
|
||||
let run ?(configuration = configuration) (module M : Matchers.Matcher) source match_template rewrite_template =
|
||||
M.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| results ->
|
||||
Option.value_exn (Rewrite.all ~source ~rewrite_template results)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
|
||||
let%expect_test "parse_rust_apostrophe_ok" =
|
||||
let source = {|width="1280"|} in
|
||||
let match_template = {|width=":[1]"|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
run (module Matchers.Generic) source match_template rewrite_template;
|
||||
[%expect_exact {|1280|}]
|
||||
|
||||
let%expect_test "parse_rust_apostrophe_ok" =
|
||||
let source = {|pub struct GlobBuilder<'a> {}|} in
|
||||
let match_template = {|{}|} in
|
||||
let rewrite_template = {|{} // success|} in
|
||||
|
||||
run (module Matchers.Rust) source match_template rewrite_template;
|
||||
[%expect_exact {|pub struct GlobBuilder<'a> {} // success|}]
|
||||
|
||||
let%expect_test "parse_ocaml_apostrophe_ok" =
|
||||
let source = {|type 'a t = Poly of 'a | Int of int |} in
|
||||
let match_template = {|type :[v] t = :[_] Int of :[i]|} in
|
||||
let rewrite_template = {|:[v], :[i]|} in
|
||||
|
||||
run (module Matchers.OCaml) source match_template rewrite_template;
|
||||
[%expect_exact {|'a, int |}]
|
||||
|
||||
let%expect_test "strict_nested_matching" =
|
||||
let source = {|({})|} in
|
||||
let match_template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
run (module Matchers.Dyck) source match_template rewrite_template;
|
||||
[%expect_exact {|{}|}]
|
||||
|
||||
let%expect_test "strict_nested_matching" =
|
||||
let source = {|(})|} in
|
||||
let match_template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
run (module Matchers.Dyck) source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}]
|
||||
|
||||
|
||||
|
||||
let%expect_test "ocaml_blocks" =
|
||||
let source = {|
|
||||
module M : sig
|
||||
type t
|
||||
end = struct
|
||||
type t = int
|
||||
|
||||
module Nested_M = struct
|
||||
type r = int
|
||||
end
|
||||
end
|
||||
|}
|
||||
in
|
||||
let match_template = {|struct :[1] end|} in
|
||||
let rewrite_template = {|struct <deleted> end|} in
|
||||
|
||||
run (module Matchers.OCaml) source match_template rewrite_template;
|
||||
[%expect_exact {|
|
||||
module M : sig
|
||||
type t
|
||||
end = struct <deleted> end
|
||||
|}]
|
||||
|
||||
let%expect_test "ocaml_complex_blocks_with_same_end" =
|
||||
let source = {|
|
||||
begin
|
||||
match x with
|
||||
| _ ->
|
||||
let module M = struct type t end
|
||||
begin
|
||||
begin
|
||||
match y with
|
||||
| _ -> ()
|
||||
end
|
||||
end
|
||||
end
|
||||
|}
|
||||
in
|
||||
let match_template = {|begin :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.OCaml) source match_template rewrite_template;
|
||||
[%expect_exact {|
|
||||
<1>match x with
|
||||
| _ ->
|
||||
let module M = struct type t end
|
||||
begin
|
||||
begin
|
||||
match y with
|
||||
| _ -> ()
|
||||
end
|
||||
end</1>
|
||||
|}]
|
||||
|
||||
let%expect_test "ruby_blocks" =
|
||||
let source = {|
|
||||
class ActionController::Base
|
||||
before_filter :generate_css_from_less
|
||||
|
||||
def generate_css_from_less
|
||||
Less::More.generate_all
|
||||
end
|
||||
end
|
||||
|}
|
||||
in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|
|
||||
<1>ActionController::Base
|
||||
before_filter :generate_css_from_less
|
||||
|
||||
def generate_css_from_less
|
||||
Less::More.generate_all
|
||||
end</1>
|
||||
|}]
|
||||
|
||||
let%expect_test "erlang_blocks" =
|
||||
let source = {|Big = fun(X) -> if X > 10 -> true; true -> false end end.|} in
|
||||
let match_template = {|fun(:[1]) :[rest] end|} in
|
||||
let rewrite_template = {|<rest>:[rest]</rest>|} in
|
||||
|
||||
run (module Matchers.Erlang) source match_template rewrite_template;
|
||||
[%expect_exact {|Big = <rest>-> if X > 10 -> true; true -> false end</rest>.|}]
|
||||
|
||||
let%expect_test "ruby_blocks" =
|
||||
let source = {|class x end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>x</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_1" =
|
||||
let source = {|class class def body1 end def body2 end end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>class def body1 end def body2 end end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_2" =
|
||||
let source = {|class class (def body1 end) (def body2 end) end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>class (def body1 end) (def body2 end) end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_3" =
|
||||
let source = {| def (def b end)(def b end) end |} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {| <1>(def b end)(def b end)</1> |}]
|
||||
|
||||
let%expect_test "ruby_blocks_4" =
|
||||
let source = {| def (def a end) f (def b end)end |} in
|
||||
let match_template = {|def :[1]end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {| <1>(def a end) f (def b end)</1> |}]
|
||||
|
||||
(* this is correct: there's no space in the source 'end', so it matches the inner def/end blocks *)
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {| def (def a end) f (def b end) end |} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {| <1>(def a end) f (def b end)</1> |}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {| def(df b ed) (df b ed)end |} in
|
||||
let match_template = {|def:[1]end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {| <1>(df b ed) (df b ed)</1> |}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class class ((def (x) end) f (def body end)) end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>class ((def (x) end) f (def body end)) end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class class (def body1 end) (def body2 end) end end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|class class (<1>body1</1>) (<1>body2</1>) end end|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class class (def body1 end) (def body2 end) end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>class (def body1 end) (def body2 end) end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class class def (def body1 end) (def body2 end) end end end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|class class <1>(def body1 end) (def body2 end)</1> end end|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class class def () (def body2 end) end end end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|class class <1>() (def body2 end)</1> end end|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (def end) (def end) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(def end) (def end)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (def end) a (def end) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(def end) a (def end)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (defa aend) (adef aend) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(defa aend) (adef aend)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (defa aend) a (adef aend) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(defa aend) a (adef aend)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (adef a endq) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(adef a endq)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def adef a endq end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>adef a endq</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def def foo end end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def foo end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def def end endq|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def adef a endq end |} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>adef a endq</1> |}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def fadef a qendq end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>fadef a qendq</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def defa aend end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>defa aend</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|(adef a endq)|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def adef a endq end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>adef a endq</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def (adef a endq) end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(adef a endq)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class (def ( body )end) end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(def ( body )end)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class def ( body )end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def ( body )end</1>|}]
|
||||
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class def( body ) end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def( body ) end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class def() end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def() end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class def () end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def () end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class def( body )end end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>def( body )end</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class ( def( body )end) end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>( def( body )end)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|class (def( body )end) end|} in
|
||||
let match_template = {|class :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>(def( body )end)</1>|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|(def a endq)|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|def end|} in
|
||||
let match_template = {|def :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}]
|
||||
|
||||
let%expect_test "ruby_blocks_5" =
|
||||
let source = {|(def foo end)|} in
|
||||
let match_template = {|(def :[1] end)|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.Ruby) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>foo</1>|}]
|
||||
|
||||
let%expect_test "ocaml_struct_end" =
|
||||
let source = {|= struct Something end|} in
|
||||
let match_template = {|= struct :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.OCaml) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>Something</1>|}]
|
||||
|
||||
let%expect_test "ocaml_struct_end_2" =
|
||||
let source = {|= struct include Something end|} in
|
||||
let match_template = {|= struct :[1] end|} in
|
||||
let rewrite_template = {|<1>:[1]</1>|} in
|
||||
|
||||
run (module Matchers.OCaml) source match_template rewrite_template;
|
||||
[%expect_exact {|<1>include Something</1>|}]
|
||||
*)
|
88
test/omega/test_statistics.ml
Normal file
88
test/omega/test_statistics.ml
Normal file
@ -0,0 +1,88 @@
|
||||
(*open Core
|
||||
|
||||
open Language
|
||||
open Matchers
|
||||
open Match
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let format s =
|
||||
let s = s |> String.chop_prefix_exn ~prefix:"\n" in
|
||||
let leading_indentation =
|
||||
Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
let %expect_test "statistics" =
|
||||
let template =
|
||||
{|
|
||||
def :[fn_name](:[fn_params])
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let source =
|
||||
{|
|
||||
def foo(bar):
|
||||
pass
|
||||
|
||||
def bar(bazz):
|
||||
pass
|
||||
|}
|
||||
|> format
|
||||
in
|
||||
|
||||
let rule =
|
||||
{| where true
|
||||
|}
|
||||
|> Rule.create
|
||||
|> Or_error.ok_exn
|
||||
in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> List.filter ~f:(fun { environment; _ } ->
|
||||
Rule.(sat @@ apply rule environment))
|
||||
|> fun matches ->
|
||||
let statistics =
|
||||
Statistics.
|
||||
{ number_of_files = 1
|
||||
; lines_of_code = 5
|
||||
; number_of_matches = List.length matches
|
||||
; total_time = 0.0
|
||||
}
|
||||
in
|
||||
statistics
|
||||
|> Statistics.to_yojson
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string;
|
||||
[%expect {|
|
||||
{
|
||||
"number_of_files": 1,
|
||||
"lines_of_code": 5,
|
||||
"number_of_matches": 2,
|
||||
"total_time": 0.0
|
||||
} |}];
|
||||
|
||||
let statistics' =
|
||||
Statistics.merge
|
||||
{ number_of_files = 1
|
||||
; lines_of_code = 10
|
||||
; number_of_matches = 1
|
||||
; total_time = 1.5
|
||||
}
|
||||
statistics
|
||||
in
|
||||
statistics'
|
||||
|> Statistics.to_yojson
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string;
|
||||
[%expect {|
|
||||
{
|
||||
"number_of_files": 2,
|
||||
"lines_of_code": 15,
|
||||
"number_of_matches": 3,
|
||||
"total_time": 1.5
|
||||
} |}]
|
||||
*)
|
413
test/omega/test_string_literals.ml
Normal file
413
test/omega/test_string_literals.ml
Normal file
@ -0,0 +1,413 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let format s =
|
||||
let s = String.chop_prefix_exn ~prefix:"\n" s in
|
||||
let leading_indentation = Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let all ?(configuration = configuration) template source =
|
||||
C.all ~configuration ~template ~source
|
||||
|
||||
let print_matches matches =
|
||||
List.map matches ~f:Match.to_yojson
|
||||
|> (fun matches -> `List matches)
|
||||
|> Yojson.Safe.pretty_to_string
|
||||
|> print_string
|
||||
|
||||
let%expect_test "comments_in_string_literals_should_not_be_treated_as_comments_by_fuzzy" =
|
||||
let source = {|"/*"(x)|} in
|
||||
let template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all template source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "BROKEN EXPECT");
|
||||
[%expect_exact {|"/*"x|}]
|
||||
|
||||
let%expect_test "comments_in_string_literals_should_not_be_treated_as_comments_by_fuzzy_go_raw" =
|
||||
let source = {|`//`(x)|} in
|
||||
let template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "BROKEN EXPECT");
|
||||
[%expect_exact {|`//`x|}]
|
||||
|
||||
let%expect_test "tolerate_unbalanced_stuff_in_string_literals" =
|
||||
let template = {|"("|} in
|
||||
let source = {|"("|} in
|
||||
let matches = all ~configuration template source in
|
||||
print_matches matches;
|
||||
[%expect_exact {|[
|
||||
{
|
||||
"range": {
|
||||
"start": { "offset": 0, "line": 1, "column": 1 },
|
||||
"end": { "offset": 3, "line": 1, "column": 4 }
|
||||
},
|
||||
"environment": [],
|
||||
"matched": "\"(\""
|
||||
}
|
||||
]|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|"hello"|} in
|
||||
let match_template = {|":[1]"|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|hello|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|rewrite ("hello") this string|} in
|
||||
let match_template = {|rewrite (":[1]") this string|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|hello|}]
|
||||
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|rewrite (".") this string|} in
|
||||
let match_template = {|rewrite (":[1]") this string|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|.|}]
|
||||
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|rewrite ("") this string|} in
|
||||
let match_template = {|rewrite (":[1]") this string|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {||}]
|
||||
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|"(" match "a""a" this "(" |} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|"(" "a""a" "(" |}]
|
||||
|
||||
(* this tests special functionality in non-literal hole parser
|
||||
but which must still ignore unbalanced delims within strings *)
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|"(" match "(""(" this "(" |} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|"(" "(""(" "(" |}]
|
||||
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|rewrite ("") this string|} in
|
||||
let match_template = {|rewrite (:[1]) this string|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|""|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|"("|} in
|
||||
let match_template = {|":[1]"|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|(|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|"(""("|} in
|
||||
let match_template = {|":[1]"|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|((|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|"(""("|} in
|
||||
let match_template = {|":[1]"|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|((|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|"hello world"|} in
|
||||
let match_template = {|":[x] :[y]"|} in
|
||||
let rewrite_template = {|:[x] :[y]|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|hello world|}]
|
||||
|
||||
(* complex test: basically, we are checking that the inside of this literal is only matched by the val b part *)
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|val a = "class = ${String::class}" val b = "not $a"|} in
|
||||
let match_template = {|":[x]$:[[y]]"|} in
|
||||
let rewrite_template = {|(rewritten part: (:[x]) ([y]))|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|val a = "class = ${String::class}" val b = (rewritten part: (not ) ([y]))|}]
|
||||
|
||||
let%expect_test "base_literal_matching" =
|
||||
let source = {|get("type") rekt ("enabled", True)|} in
|
||||
let match_template = {|(":[1]", :[[3]])|} in
|
||||
let rewrite_template = {|(rewritten part: (:[1]) (:[3]))|} in
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|get("type") rekt (rewritten part: (enabled) (True))|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match "\"" this|} in
|
||||
let match_template = {|match "\"" this|} in
|
||||
let rewrite_template = "" in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {||}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match "\"" this|} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = ":[1]" in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|"\""|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match "\"\"" this|} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = ":[1]" in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|"\"\""|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match "\"(\"" "(\"" this|} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = ":[1]" in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|"\"(\"" "(\""|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match "\"(\"" "(\"" this|} in
|
||||
let match_template = {|match ":[1]" ":[2]" this|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|\"(\" (\"|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match 'sin(gle' 'quo(tes' this|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|match 'sin(gle' 'quo(tes' this|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match '\''|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|match '\''|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match 'asdf'|} in
|
||||
let match_template = {|':[1]'|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|match asdf|}]
|
||||
|
||||
let%expect_test "rewrite_string_literals_8" =
|
||||
let source = {|match '\''|} in
|
||||
let match_template = {|':[1]'|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
all match_template source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|match \'|}]
|
||||
|
||||
|
||||
let%expect_test "go_raw_string_literals" =
|
||||
let source =
|
||||
{|
|
||||
x = x
|
||||
y = `multi-line
|
||||
raw str(ing literal`
|
||||
z = `other multi-line
|
||||
raw stri(ng literal`
|
||||
|}
|
||||
in
|
||||
let match_template = {|`:[1]`|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
Go.all ~configuration ~source ~template:match_template
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|
|
||||
x = x
|
||||
y = multi-line
|
||||
raw str(ing literal
|
||||
z = other multi-line
|
||||
raw stri(ng literal
|
||||
|}]
|
||||
|
||||
let%expect_test "go_raw_string_literals" =
|
||||
let source = {|blah `(` quux|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
Go.all ~configuration ~source ~template:match_template
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|blah `(` quux|}]
|
||||
|
||||
let%expect_test "match_string_literals" =
|
||||
let source = {|`(` match `(``(` this `(` |} in
|
||||
let match_template = {|match :[1] this|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template:match_template ~source
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|`(` `(``(` `(` |}]
|
||||
|
||||
|
||||
let%expect_test "go_raw_string_literals" =
|
||||
let source =
|
||||
{|
|
||||
x = x
|
||||
y = `multi-line
|
||||
raw "str"(ing literal`
|
||||
z = `other multi-line
|
||||
raw '"'\"\\s\\\\\tr\ni(ng literal`
|
||||
|}
|
||||
in
|
||||
let match_template = {|`:[1]`|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
|
||||
Go.all ~configuration ~source ~template:match_template
|
||||
|> (fun matches -> Option.value_exn (Rewrite.all ~source ~rewrite_template matches))
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string;
|
||||
[%expect_exact {|
|
||||
x = x
|
||||
y = multi-line
|
||||
raw "str"(ing literal
|
||||
z = other multi-line
|
||||
raw '"'\"\\s\\\\\tr\ni(ng literal
|
||||
|}]
|
||||
|
||||
let%expect_test "regression_matching_kubernetes" =
|
||||
let source = {|"\n" y = 5|} in
|
||||
let template = {|y = :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "BROKEN EXPECT");
|
||||
[%expect_exact {|"\n" 5|}]
|
||||
|
||||
|
||||
let%expect_test "match_escaped_any_char" =
|
||||
let source = {|printf("hello world\n");|} in
|
||||
let template = {|printf(":[1]");|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "BROKEN EXPECT");
|
||||
[%expect_exact {|hello world\n|}]
|
||||
|
||||
let%expect_test "match_escaped_escaped" =
|
||||
let source = {|printf("hello world\n\\");|} in
|
||||
let template = {|printf(":[1]");|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "BROKEN EXPECT");
|
||||
[%expect_exact {|hello world\n\\|}]
|
||||
|
||||
let%expect_test "match_escaped_escaped" =
|
||||
let source = {|printf("hello world\n\");|} in
|
||||
let template = {|printf(":[1]");|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
Go.all ~configuration ~template ~source
|
||||
|> Rewrite.all ~source ~rewrite_template
|
||||
|> (function
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "EXPECT SUCCESS");
|
||||
[%expect_exact {|EXPECT SUCCESS|}]
|
||||
*)
|
433
test/omega/test_substring_disabled.ml
Normal file
433
test/omega/test_substring_disabled.ml
Normal file
@ -0,0 +1,433 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~disable_substring_matching:true ~match_kind:Fuzzy ()
|
||||
|
||||
let format s =
|
||||
let s = String.chop_prefix_exn ~prefix:"\n" s in
|
||||
let leading_indentation = Option.value_exn (String.lfindi s ~f:(fun _ c -> c <> ' ')) in
|
||||
s
|
||||
|> String.split ~on:'\n'
|
||||
|> List.map ~f:(Fn.flip String.drop_prefix leading_indentation)
|
||||
|> String.concat ~sep:"\n"
|
||||
|> String.chop_suffix_exn ~suffix:"\n"
|
||||
|
||||
let run ?(configuration = configuration) source match_template rewrite_template =
|
||||
Generic.first ~configuration match_template source
|
||||
|> function
|
||||
| Ok result ->
|
||||
Rewrite.all ~source ~rewrite_template [result]
|
||||
|> (fun x -> Option.value_exn x)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
| Error _ ->
|
||||
(* this is too annoying to fix everytime the grammar changes. *)
|
||||
print_string ""
|
||||
|
||||
let run_all ?(configuration = configuration) source match_template rewrite_template =
|
||||
Generic.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| results ->
|
||||
Option.value_exn (Rewrite.all ~source ~rewrite_template results)
|
||||
|> (fun { rewritten_source; _ } -> rewritten_source)
|
||||
|> print_string
|
||||
|
||||
|
||||
let%expect_test "basic" =
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c d|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1] c d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1] d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b c|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b c d|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1] c d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (b c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|:[2] :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (b c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] :[1] d|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (c)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (c d)|}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] c :[1]|} in
|
||||
let rewrite_template = {|(:[2]) (:[1])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(b) (d)|}];
|
||||
|
||||
let source = {|x:|} in
|
||||
let match_template = {|:[1]:|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|x|}]
|
||||
|
||||
let%expect_test "basic_failures" =
|
||||
let source = {|a x b bbq|} in
|
||||
let match_template = {|a :[1] b c|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] d :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact
|
||||
{||}];
|
||||
|
||||
let source = {|a b c d|} in
|
||||
let match_template = {|a :[2] b :[1]|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}]
|
||||
|
||||
let%expect_test "delimiter_matching" =
|
||||
let source = {|(a b c) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c|}];
|
||||
|
||||
let source = {|(a b c) d|} in
|
||||
let match_template = {|(:[1] b :[2]) d|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (c)|}];
|
||||
|
||||
let source = {|q(a b c) d|} in
|
||||
let match_template = {|q(:[1] b :[2]) d|} in
|
||||
let rewrite_template = {|(:[1]) (:[2])|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a) (c)|}];
|
||||
|
||||
let source = {|((a) b)|} in
|
||||
let match_template = {|(:[1] b)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a)|}];
|
||||
|
||||
let source = {|((a b c)) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a b c)|}];
|
||||
|
||||
let source = {|((a b c)) d|} in
|
||||
let match_template = {|(:[1]) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(a b c)|}];
|
||||
|
||||
let source = {|((a b c) q) d|} in
|
||||
let match_template = {|((:[1]) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b c|}];
|
||||
|
||||
let source = {|((a b c) q) d|} in
|
||||
let match_template = {|((:[1] c) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|((a b () c) q) d|} in
|
||||
let match_template = {|((:[1] () c) q) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a b|}];
|
||||
|
||||
let source = {|((a ((x) d) b c)) d|} in
|
||||
let match_template = {|((a :[1] :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((x) d)|}];
|
||||
|
||||
let source = {|((a ((x) d) b c)) d|} in
|
||||
let match_template = {|((a (:[1]) :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(x) d b|}];
|
||||
|
||||
let source = {|(b (c) d)|} in
|
||||
let match_template = {|(:[1])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c) d|}];
|
||||
|
||||
let source = {|(b (c) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c) d|}];
|
||||
|
||||
let source = {|(b (c.) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b (c.) d|}];
|
||||
|
||||
let source = {|(b. (c) d.)|} in
|
||||
let match_template = {|(:[1].)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b. (c) d|}];
|
||||
|
||||
let source = {|(b (c) d.)|} in
|
||||
let match_template = {|(b :[1] d.)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(c)|}];
|
||||
|
||||
let source = {|outer(inner(dst,src),src)|} in
|
||||
let match_template = {|outer(:[1],src)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|inner(dst,src)|}];
|
||||
|
||||
let source = {|(b ((c)) d.)|} in
|
||||
let match_template = {|(b :[1] d.)|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((c))|}];
|
||||
|
||||
let source = {|a b c|} in
|
||||
let match_template = {|a :[1] c|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|b|}];
|
||||
|
||||
let source = {|x = foo;|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|foo|}];
|
||||
|
||||
let source = {|((a {{x} d} b c)) d|} in
|
||||
let match_template = {|((a {:[1] d} :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|{x} b|}];
|
||||
|
||||
let source = {|((a {([{x}]) d} b c)) d|} in
|
||||
let match_template = {|((a {:[1] d} :[2] c)) d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|([{x}]) b|}];
|
||||
|
||||
let source = {|(((((x)))))|} in
|
||||
let match_template = {|(((:[1])))|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|((x))|}];
|
||||
|
||||
let source = {|((((y(x)z))))|} in
|
||||
let match_template = {|(((:[1])))|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(y(x)z)|}];
|
||||
|
||||
let source = {|((((y(x)z))))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(y(x)z) |}];
|
||||
|
||||
let source = {|(((x)z))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|x z|}];
|
||||
|
||||
let source = {|((((x))z))|} in
|
||||
let match_template = {|(((:[1]):[2]))|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|(x) z|}];
|
||||
|
||||
let source = {|lolwtfbbq|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source = {|x = foo; x = bar;|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|foo x = bar;|}];
|
||||
|
||||
let source = {|[ no match prefix ] x = foo; [ no match suffix ]|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|[ no match prefix ] foo [ no match suffix ]|}];
|
||||
|
||||
let source = {|x = a; x = b; x = c|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a x = b; x = c|}];
|
||||
|
||||
let source = {|x = ( x = x; );|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|( x = x; )|}];
|
||||
|
||||
let source = {|( x = x = x; )|} in
|
||||
let match_template = {|x = :[1];|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|( x = x )|}];
|
||||
|
||||
let source = {|xxx a b d c 1 2 3 b d d blah|} in
|
||||
let match_template = {|a :[1] c :[2] d|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|xxx b d 1 2 3 b d blah|}];
|
||||
|
||||
let source = {|howevenlolwtfbbqispossible|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source = {|lolhowevenlolwtfbbqispossiblebbq|} in
|
||||
let match_template = {|lol:[1]bbq|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source = {|hello my name is bob the builder|} in
|
||||
let match_template = {|:[alongidentifiername] :[2] :[3] :[xyz] :[5] :[6]|} in
|
||||
let rewrite_template = {|:[alongidentifiername] :[2] :[3] :[xyz] :[5] :[6]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|hello my name is bob the builder|}];
|
||||
|
||||
let source = {|www.testdofooname.com/picsinsideit/stunningpictureofkays1381737242g8k4n-280x428.jpg|} in
|
||||
let match_template = {|www.:[1]-:[2].jpg|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|testdofooname.com/picsinsideit/stunningpictureofkays1381737242g8k4n 280x428|}];
|
||||
|
||||
let source = {|https://api.github.com/repos/dmjacobsen/slurm/commits/716c1499695c68afcab848a1b49653574b4fc167|} in
|
||||
let match_template = {|:[1]api.:[2]/repos/:[3]s/:[4]|} in
|
||||
let rewrite_template = {|:[1] :[2] :[3] :[4]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {||}];
|
||||
|
||||
let source =
|
||||
{|
|
||||
assert(stream->md_len + md_len -
|
||||
si.foo_data_begin <= MAD_BUFFER_MDLEN);
|
||||
memcpy(*stream->foo_data + stream->md_len,
|
||||
mad_bit_nextbyte(&stream->ptr),
|
||||
frame_used = md_len - si.foo_data_begin);
|
||||
stream->md_len += frame_used;
|
||||
|} |> format
|
||||
in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3]);|} in
|
||||
let rewrite_template = {|:[1], :[2], :[3]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|assert(stream->md_len + md_len -
|
||||
si.foo_data_begin <= MAD_BUFFER_MDLEN);
|
||||
*stream->foo_data + stream->md_len, mad_bit_nextbyte(&stream->ptr), frame_used = md_len - si.foo_data_begin
|
||||
stream->md_len += frame_used;|}]
|
||||
|
||||
let%expect_test "significant_whitespace" =
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ~significant_whitespace:true () in
|
||||
let run = run ~configuration in
|
||||
|
||||
let source = {|two spaces|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|two spaces|}];
|
||||
|
||||
(* FIXME: this should fail. also test case where separators do or do not need
|
||||
whitespace. e.g., strict about strcpy(src,dst) matching a template
|
||||
strcpy(:[1],:[2]) versus strcpy(:[1], :[2]) *)
|
||||
let source = {|two spaces|} in
|
||||
let match_template = {|:[1] :[2]|} in
|
||||
let rewrite_template = {|:[1] :[2]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|two spaces|}]
|
||||
|
||||
let%expect_test "contextual_matching" =
|
||||
let run = run_all in
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}];
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[1], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[1]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}]
|
||||
|
||||
let%expect_test "contextual_matching_with_short_hole_syntax" =
|
||||
let run = run_all in
|
||||
|
||||
let source = {|memcpy(dst1, src1, 1); memcpy(dst2, src2, 2);|} in
|
||||
let match_template = {|memcpy(:[[1]], :[2], :[3])|} in
|
||||
let rewrite_template = {|:[[1]]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|dst1; dst2;|}]
|
||||
|
||||
let%expect_test "trivial_empty_case" =
|
||||
let source = "" in
|
||||
let match_template = "" in
|
||||
begin
|
||||
Generic.all ~configuration ~template:match_template ~source
|
||||
|> function
|
||||
| [] -> print_string "No matches."
|
||||
| hd :: _ ->
|
||||
print_string (Yojson.Safe.to_string (Match.to_yojson hd))
|
||||
end;
|
||||
[%expect_exact {|{"range":{"start":{"offset":0,"line":1,"column":1},"end":{"offset":0,"line":1,"column":1}},"environment":[],"matched":""}|}]
|
||||
*)
|
Loading…
Reference in New Issue
Block a user