mirror of
https://github.com/comby-tools/comby.git
synced 2024-09-11 13:25:36 +03:00
omega matcher progress
This commit is contained in:
parent
9c3bfa0468
commit
823b6005da
4
dune
4
dune
@ -1,6 +1,6 @@
|
||||
(env
|
||||
(dev
|
||||
(flags (:standard -w A-3-4-32-34-39-40-41-42-44-45-48-49-50-57)))
|
||||
(flags (:standard -w A-3-4-32-34-39-40-41-42-44-45-48-49-50-57-60)))
|
||||
(release
|
||||
(flags (:standard -w A-3-4-32-34-39-40-41-42-44-45-48-49-50-57))
|
||||
(flags (:standard -w A-3-4-32-34-39-40-41-42-44-45-48-49-50-57-60))
|
||||
(ocamlopt_flags (-O3))))
|
||||
|
@ -1,3 +1,6 @@
|
||||
(copy_files# alpha/*.ml{,i})
|
||||
; (copy_files# omega/*.ml{,i})
|
||||
|
||||
(library
|
||||
(name language)
|
||||
(public_name comby.language)
|
||||
|
47
lib/language/omega/parser.ml
Normal file
47
lib/language/omega/parser.ml
Normal file
@ -0,0 +1,47 @@
|
||||
open Core
|
||||
|
||||
open Angstrom
|
||||
|
||||
open Ast
|
||||
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let alphanum =
|
||||
satisfy (function
|
||||
| 'a' .. 'z'
|
||||
| 'A' .. 'Z'
|
||||
| '0' .. '9' -> true
|
||||
| _ -> false)
|
||||
|
||||
let variable_parser =
|
||||
(string Syntax.variable_left_delimiter
|
||||
*> (many (alphanum <|> char '_') |>> String.of_char_list)
|
||||
<* string Syntax.variable_right_delimiter)
|
||||
|
||||
let escaped_char_s =
|
||||
any_char
|
||||
|
||||
let char_token_s =
|
||||
(char '\\' *> escaped_char_s >>= fun c -> return (Format.sprintf {|\%c|} c))
|
||||
<|> (any_char |>> String.of_char)
|
||||
|
||||
let value_parser =
|
||||
(string {|"|}
|
||||
*> (many_till char_token_s (string {|"|})))
|
||||
|>> String.concat
|
||||
|
||||
let operator_parser =
|
||||
choice
|
||||
[ string Syntax.equal
|
||||
; string Syntax.not_equal
|
||||
]
|
||||
|
||||
let atom_parser =
|
||||
choice
|
||||
[ (variable_parser >>= fun variable -> return (Variable variable))
|
||||
; (value_parser >>= fun value -> return (String value))
|
||||
]
|
||||
|
||||
let rewrite_template_parser =
|
||||
value_parser >>= fun value -> return (RewriteTemplate value)
|
243
lib/language/omega/rule.ml
Normal file
243
lib/language/omega/rule.ml
Normal file
@ -0,0 +1,243 @@
|
||||
open Core
|
||||
open Angstrom
|
||||
|
||||
open Match
|
||||
open Rewriter
|
||||
|
||||
open Ast
|
||||
open Parser
|
||||
|
||||
module Configuration = Matchers.Configuration
|
||||
|
||||
type t = Ast.t
|
||||
|
||||
type result = bool * environment option
|
||||
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let sat = fst
|
||||
|
||||
let result_env = snd
|
||||
|
||||
let match_configuration_of_syntax template =
|
||||
(* decide match configuration based on whether there are holes *)
|
||||
let antecedent_contains_hole_syntax case =
|
||||
String.is_substring case ~substring:Syntax.variable_left_delimiter
|
||||
in
|
||||
if antecedent_contains_hole_syntax template then
|
||||
Configuration.create ~match_kind:Fuzzy ()
|
||||
else
|
||||
Configuration.create ~match_kind:Exact ()
|
||||
|
||||
let merge_match_environments matches environment' =
|
||||
List.map matches ~f:(fun { environment; _ } ->
|
||||
Environment.merge environment environment')
|
||||
|
||||
type rewrite_context =
|
||||
{ variable : string }
|
||||
|
||||
let rec apply
|
||||
?(matcher = (module Matchers.Generic : Matchers.Matcher))
|
||||
?(substitute_in_place = true)
|
||||
predicates
|
||||
env =
|
||||
let open Option in
|
||||
let module Matcher = (val matcher : Matchers.Matcher) in
|
||||
|
||||
let equal_in_environment var value env =
|
||||
match Environment.lookup env var with
|
||||
| None -> false, Some env
|
||||
| Some var_value -> String.equal var_value value, Some env
|
||||
in
|
||||
(* accepts only one expression *)
|
||||
let rec rule_match ?(rewrite_context : rewrite_context option) env =
|
||||
function
|
||||
| True -> true, Some env
|
||||
| False -> false, Some env
|
||||
| Equal (Variable var, String value)
|
||||
| Equal (String value, Variable var) ->
|
||||
equal_in_environment var value env
|
||||
| Equal (String left, String right) ->
|
||||
String.equal left right, Some env
|
||||
| Equal (Variable left, Variable right) ->
|
||||
let result =
|
||||
Environment.lookup env left >>= fun left ->
|
||||
Environment.lookup env right >>= fun right ->
|
||||
return (String.equal left right)
|
||||
in
|
||||
Option.value result ~default:false, Some env
|
||||
| Not_equal (left, right) ->
|
||||
let sat, env = rule_match env (Equal (left, right)) in
|
||||
not sat, env
|
||||
| Match (Variable variable, cases) ->
|
||||
let result =
|
||||
Environment.lookup env variable >>= fun source ->
|
||||
List.find_map cases ~f:(fun (template, case_expression) ->
|
||||
match template with
|
||||
| String template ->
|
||||
begin
|
||||
let configuration = match_configuration_of_syntax template in
|
||||
Matcher.all ~configuration ~template ~source |> function
|
||||
| [] -> None
|
||||
| matches ->
|
||||
(* merge environments. overwrite behavior is undefined *)
|
||||
let fold_matches (sat, out) { environment; _ } =
|
||||
let fold_cases (sat, out) predicate =
|
||||
if sat then
|
||||
let env' = Environment.merge env environment in
|
||||
rule_match ?rewrite_context env' predicate
|
||||
else
|
||||
(sat, out)
|
||||
in
|
||||
List.fold case_expression ~init:(sat, out) ~f:fold_cases
|
||||
in
|
||||
List.fold matches ~init:(true, None) ~f:fold_matches
|
||||
|> Option.some
|
||||
end
|
||||
| Variable _ ->
|
||||
failwith "| :[hole] is invalid. Maybe you meant to put quotes")
|
||||
in
|
||||
Option.value_map result ~f:ident ~default:(false, Some env)
|
||||
| Match (String template, cases) ->
|
||||
let source, _ = Rewriter.Rewrite_template.substitute template env in
|
||||
let fresh_var = Uuid_unix.(Fn.compose Uuid.to_string create ()) in
|
||||
let env = Environment.add env fresh_var source in
|
||||
rule_match env (Match (Variable fresh_var, cases))
|
||||
| RewriteTemplate rewrite_template ->
|
||||
begin
|
||||
match rewrite_context with
|
||||
| None -> false, None
|
||||
| Some { variable; _ } ->
|
||||
(* FIXME(RVT) assumes only contextual rewrite for now. *)
|
||||
let env =
|
||||
Rewrite_template.substitute rewrite_template env
|
||||
|> fst
|
||||
|> fun replacement' ->
|
||||
Environment.update env variable replacement'
|
||||
|> Option.some
|
||||
in
|
||||
true, env
|
||||
end
|
||||
| Rewrite (Variable variable, (match_template, rewrite_expression)) ->
|
||||
begin match rewrite_expression with
|
||||
| RewriteTemplate rewrite_template ->
|
||||
let template =
|
||||
match match_template with
|
||||
| Variable _ -> failwith "Invalid syntax in rewrite LHS"
|
||||
| String template -> template
|
||||
in
|
||||
let result =
|
||||
Environment.lookup env variable >>= fun source ->
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy () in
|
||||
let matches = Matcher.all ~configuration ~template ~source in
|
||||
let source = if substitute_in_place then Some source else None in
|
||||
let result = Rewrite.all ?source ~rewrite_template matches in
|
||||
match result with
|
||||
| Some { rewritten_source; _ } ->
|
||||
(* substitute for variables that are in the outside scope *)
|
||||
let rewritten_source, _ = Rewrite_template.substitute rewritten_source env in
|
||||
let env = Environment.update env variable rewritten_source in
|
||||
return (true, Some env)
|
||||
| None ->
|
||||
return (true, Some env)
|
||||
in
|
||||
Option.value_map result ~f:ident ~default:(false, Some env)
|
||||
| _ -> failwith "Not implemented yet"
|
||||
end
|
||||
| Rewrite _ -> failwith "TODO/Invalid: Have not decided whether rewrite \":[x]\" is useful."
|
||||
in
|
||||
List.fold predicates ~init:(true, None) ~f:(fun (sat, out) predicate ->
|
||||
if sat then
|
||||
let env =
|
||||
Option.value_map out
|
||||
~f:(fun out -> Environment.merge out env)
|
||||
~default:env
|
||||
in
|
||||
rule_match env predicate
|
||||
else
|
||||
(sat, out))
|
||||
|
||||
|
||||
let make_equality_expression operator left right =
|
||||
if String.equal operator Syntax.equal then
|
||||
return (Equal (left, right))
|
||||
else if
|
||||
String.equal operator Syntax.not_equal then
|
||||
return (Not_equal (left, right))
|
||||
else
|
||||
let message =
|
||||
Format.sprintf
|
||||
"Unhandled operator %s. Did you mean %s or %s?"
|
||||
operator
|
||||
Syntax.equal
|
||||
Syntax.not_equal in
|
||||
fail message
|
||||
|
||||
let is_whitespace = function
|
||||
| ' ' | '\t' | '\r' | '\n' -> true
|
||||
| _ -> false
|
||||
|
||||
let spaces =
|
||||
take_while is_whitespace >>= fun s ->
|
||||
return s
|
||||
|
||||
let spaces1 =
|
||||
satisfy is_whitespace >>= fun c ->
|
||||
take_while is_whitespace >>= fun s ->
|
||||
return (Format.sprintf "%c%s" c s)
|
||||
|
||||
let create rule =
|
||||
let operator_parser =
|
||||
spaces *> atom_parser >>= fun left ->
|
||||
spaces *> operator_parser >>= fun operator ->
|
||||
spaces *> atom_parser >>= fun right ->
|
||||
make_equality_expression operator left right <* spaces
|
||||
in
|
||||
let true' = spaces *> string Syntax.true' <* spaces |>> fun _ -> True in
|
||||
let false' = spaces *> string Syntax.false' <* spaces |>> fun _ -> False in
|
||||
let expression_parser =
|
||||
fix (fun expression_parser ->
|
||||
let match_pattern_parser =
|
||||
let case_parser =
|
||||
spaces *> string Syntax.pipe_operator *>
|
||||
spaces *> atom_parser <* spaces <* string Syntax.arrow <* spaces >>= fun antecedent ->
|
||||
spaces *> sep_by (char ',') expression_parser <* spaces |>> fun consequent ->
|
||||
antecedent, consequent
|
||||
in
|
||||
let pattern keyword =
|
||||
string keyword *> spaces *> atom_parser <* spaces <* char '{' <* spaces
|
||||
>>= fun atom ->
|
||||
many1 case_parser
|
||||
<* char '}' <* spaces
|
||||
>>= fun cases -> return (atom, cases)
|
||||
in
|
||||
pattern Syntax.start_match_pattern |>> fun (atom, cases) ->
|
||||
Match (atom, cases)
|
||||
in
|
||||
let rewrite_pattern_parser =
|
||||
string Syntax.start_rewrite_pattern *> spaces *> atom_parser <* spaces <* char '{' <* spaces
|
||||
>>= fun atom ->
|
||||
atom_parser <* spaces <* string Syntax.arrow <* spaces >>= fun match_template ->
|
||||
spaces *> rewrite_template_parser <* spaces <* char '}' <* spaces
|
||||
|>> fun rewrite_template ->
|
||||
Rewrite (atom, (match_template, rewrite_template))
|
||||
in
|
||||
choice
|
||||
[ match_pattern_parser
|
||||
; rewrite_pattern_parser
|
||||
; operator_parser
|
||||
; true'
|
||||
; false'
|
||||
])
|
||||
in
|
||||
let rule_parser =
|
||||
spaces
|
||||
*> string Syntax.rule_prefix
|
||||
*> spaces1
|
||||
*> sep_by1 (spaces *> char ',' <* spaces) expression_parser
|
||||
<* end_of_input
|
||||
in
|
||||
match parse_string rule_parser rule with
|
||||
| Ok rule -> Or_error.return rule
|
||||
| Error error -> Or_error.error_string error
|
@ -66,7 +66,7 @@ type t =
|
||||
}
|
||||
[@@deriving yojson]
|
||||
|
||||
val create : unit -> t
|
||||
val create : ?range:range -> unit -> t
|
||||
|
||||
val pp : Format.formatter -> string option * t list -> unit
|
||||
|
||||
|
@ -7,8 +7,8 @@ type t =
|
||||
}
|
||||
[@@deriving yojson]
|
||||
|
||||
let create () =
|
||||
{ range = Range.default
|
||||
let create ?(range = Range.default) () =
|
||||
{ range
|
||||
; environment = Environment.create ()
|
||||
; matched = ""
|
||||
}
|
||||
|
@ -922,4 +922,6 @@ module Make (Syntax : Syntax.S) (Info : Info.S) = struct
|
||||
let matches = compute_nested_matches matches in
|
||||
return matches
|
||||
end
|
||||
|
||||
let set_rewrite_template _ = () (* Unused in alpha matcher *)
|
||||
end
|
||||
|
@ -3,3 +3,6 @@ module Syntax = Types.Syntax
|
||||
module type Matcher = Types.Matcher.S
|
||||
|
||||
include Languages
|
||||
|
||||
(** Omega only *)
|
||||
module Template = Template
|
||||
|
@ -3,3 +3,6 @@ module Syntax = Types.Syntax
|
||||
module type Matcher = Types.Matcher.S
|
||||
|
||||
include module type of Languages
|
||||
|
||||
(** Omega only *)
|
||||
module Template = Template
|
||||
|
File diff suppressed because it is too large
Load Diff
140
lib/matchers/omega/parser.ml
Normal file
140
lib/matchers/omega/parser.ml
Normal file
@ -0,0 +1,140 @@
|
||||
open Core
|
||||
|
||||
open Angstrom
|
||||
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let between left right p =
|
||||
left *> p <* right
|
||||
|
||||
let zero =
|
||||
fail ""
|
||||
|
||||
let cons x xs = x :: xs
|
||||
|
||||
let debug = true
|
||||
|
||||
let dont_use_any_char_except_parser p =
|
||||
if debug then Format.printf "Entered@.";
|
||||
let stop = ref false in
|
||||
let set_stop v = stop := v in
|
||||
let get_stop () = !stop in
|
||||
let c =
|
||||
choice
|
||||
[ (p >>= fun reserved -> pos >>= fun po -> (if debug then Format.printf "1. stop @@ %s @@ %d@." reserved po; return (set_stop true)) >>= fun _ -> fail "stop")
|
||||
; (return () >>= fun _ -> Format.printf "X@."; if get_stop () then (if debug then Format.printf "2. stop@."; fail "stop") else any_char)
|
||||
]
|
||||
in
|
||||
c >>= fun c' -> if debug then Format.printf "Parsed: %c@." c'; if debug then Format.printf "Exit@."; return c'
|
||||
|
||||
let dont_use_is_not p =
|
||||
dont_use_any_char_except_parser p
|
||||
|
||||
let many_till_stop p t =
|
||||
let stop = ref false in
|
||||
let set_stop v = stop := v in
|
||||
let get_stop () = !stop in
|
||||
fix (fun m ->
|
||||
choice
|
||||
[ (t >>= fun _ -> (return (set_stop true)) >>= fun _ -> fail "stop")
|
||||
; (return () >>= fun _ -> if get_stop () then return [] else lift2 cons p m)
|
||||
])
|
||||
|
||||
let many1_till_stop p t =
|
||||
let stop = ref false in
|
||||
let set_stop v = stop := v in
|
||||
let get_stop () = !stop in
|
||||
(* one needs to fail if p isn't successful so that it doesn't consume and advance one char *)
|
||||
let one =
|
||||
choice
|
||||
[ (t >>= fun _ -> (return (set_stop true)) >>= fun _ -> fail "stop")
|
||||
; (return () >>= fun _ -> if get_stop () then fail "stop" else p)
|
||||
]
|
||||
in
|
||||
lift2 cons one (many_till_stop p t)
|
||||
|
||||
|
||||
(* use many1_till_stop instead of "many1 (any_allowed_except_parser allowed until" *)
|
||||
(*
|
||||
let any_allowed_except_parser allowed p =
|
||||
let rewind = ref false in
|
||||
let set_rewind v = rewind := v in
|
||||
let get_rewind () = !rewind in
|
||||
choice
|
||||
[ (p >>= fun _ -> (return (set_rewind true)) >>= fun _ -> fail "bad")
|
||||
; (return () >>= fun _ -> if get_rewind () then fail "rewind" else allowed)
|
||||
(* TODO this needs some kind of EOF condition to work for both template and match parsing *)
|
||||
]
|
||||
*)
|
||||
|
||||
let alphanum =
|
||||
satisfy (function
|
||||
| 'a' .. 'z'
|
||||
| 'A' .. 'Z'
|
||||
| '0' .. '9' -> true
|
||||
| _ -> false)
|
||||
|
||||
let is_whitespace = function
|
||||
| ' ' | '\t' | '\r' | '\n' -> true
|
||||
| _ -> false
|
||||
|
||||
let blank =
|
||||
choice
|
||||
[ char ' '
|
||||
; char '\t'
|
||||
]
|
||||
|
||||
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 skip_unit p =
|
||||
p |>> ignore
|
||||
|
||||
module Deprecate = struct
|
||||
(* 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"
|
||||
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
|
||||
|
||||
let identifier_parser () =
|
||||
many (alphanum <|> char '_')
|
||||
|>> String.of_char_list
|
||||
|
||||
let many1_till p t =
|
||||
let cons x xs = x::xs in
|
||||
lift2 cons p (many_till p t)
|
@ -81,10 +81,12 @@ module Omega = struct
|
||||
; identifier : string
|
||||
; text : string
|
||||
}
|
||||
[@@deriving yojson]
|
||||
|
||||
type production =
|
||||
| Unit
|
||||
| String of string
|
||||
| Template_string of string
|
||||
| Hole of hole
|
||||
| Match of omega_match_production
|
||||
end
|
||||
@ -105,6 +107,8 @@ module Matcher = struct
|
||||
-> string
|
||||
-> Match.t Or_error.t
|
||||
|
||||
val set_rewrite_template : string -> unit
|
||||
|
||||
val all
|
||||
: ?configuration:Configuration.t
|
||||
-> template:string
|
||||
|
@ -6,18 +6,30 @@ module Omega = struct
|
||||
let (|>>) p f =
|
||||
p >>= fun x -> return (f x)
|
||||
|
||||
let between left _right p =
|
||||
left *> p (*<* right*)
|
||||
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 between left right p =
|
||||
left *> p <* right
|
||||
|
||||
let to_string from until between : string =
|
||||
from ^ (String.of_char_list between) ^ until
|
||||
|
||||
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))
|
||||
many (any_char_except ~reserved:[until])
|
||||
|
||||
let anything_excluding_newlines () =
|
||||
anything_including_newlines ~until:"\n"
|
||||
@ -41,7 +53,8 @@ module Omega = struct
|
||||
end
|
||||
end
|
||||
|
||||
(* XXX consumes the newline *)
|
||||
(* Consumes the newline if we don't reintroduce it. This can be improved, we
|
||||
shouldn't need to reintroduce it.*)
|
||||
let until_newline start =
|
||||
(string start *> anything_excluding_newlines ()
|
||||
|>> fun l -> start^(String.of_char_list l))
|
||||
|
@ -22,13 +22,31 @@ module Omega = struct
|
||||
<|> (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 *)
|
||||
return (Format.sprintf {|%s%s%s|} M.delimiter result M.delimiter)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
module Raw = struct
|
||||
module type S = sig
|
||||
val left_delimiter : string
|
||||
val right_delimiter : string
|
||||
end
|
||||
|
||||
module Make (M : S) = struct
|
||||
let char_token_s =
|
||||
(any_char |>> String.of_char)
|
||||
|
||||
let base_string_literal =
|
||||
((
|
||||
string M.left_delimiter *> (many_till char_token_s (string M.right_delimiter))
|
||||
|>> String.concat)
|
||||
>>= fun result ->
|
||||
return (Format.sprintf {|%s%s%s|} M.left_delimiter result M.right_delimiter)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -119,8 +119,11 @@ let update_match f m =
|
||||
let environment = update_environment m.environment f in
|
||||
{ m with range; environment }
|
||||
|
||||
let timed_run matcher ?substitute_in_place ?rule ~configuration ~template ~source () =
|
||||
let timed_run matcher ?rewrite_template ?substitute_in_place ?rule ~configuration ~template ~source () =
|
||||
let module Matcher = (val matcher : Matchers.Matcher) in
|
||||
(match rewrite_template with
|
||||
| Some template -> Matcher.set_rewrite_template template;
|
||||
| None -> ());
|
||||
let matches = Matcher.all ~configuration ~template ~source in
|
||||
let rule = Option.value rule ~default:[Ast.True] in
|
||||
let matches = apply_rule ?substitute_in_place matcher rule matches in
|
||||
@ -171,7 +174,7 @@ let process_single_source
|
||||
in
|
||||
let matches =
|
||||
with_timeout timeout source ~f:(fun () ->
|
||||
timed_run matcher ?rule ~substitute_in_place ~configuration ~template ~source:input_text ())
|
||||
timed_run matcher ?rewrite_template ?rule ~substitute_in_place ~configuration ~template ~source:input_text ())
|
||||
in
|
||||
match rewrite_template with
|
||||
| None -> Matches (matches, List.length matches)
|
||||
|
@ -2,18 +2,7 @@
|
||||
(name alpha_test_integration)
|
||||
(modules
|
||||
test_optional_holes
|
||||
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))
|
||||
|
@ -1,6 +1,17 @@
|
||||
(library
|
||||
(name common_test_integration)
|
||||
(modules
|
||||
test_cli
|
||||
test_rewrite_rule
|
||||
test_server
|
||||
test_statistics
|
||||
test_integration
|
||||
test_match_rule
|
||||
test_python_string_literals
|
||||
test_hole_extensions
|
||||
test_generic
|
||||
test_string_literals
|
||||
test_c_style_comments
|
||||
test_nested_comments
|
||||
test_c
|
||||
test_bash
|
||||
|
@ -145,7 +145,7 @@ let%expect_test "implicit_equals" =
|
||||
let%expect_test "implicit_equals_does_not_apply_to_underscore" =
|
||||
let run = run_all in
|
||||
let source = {|a b c|} in
|
||||
let match_template = {|:[[_]] :[[_]] :[[_]]|} in
|
||||
let rewrite_template = {|:[_]|} in
|
||||
let match_template = {|:[[x]] :[[_]] :[[_]]|} in
|
||||
let rewrite_template = {|:[x]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|a|}]
|
@ -46,9 +46,12 @@ let%expect_test "invalid_raw_string_in_python_but_matches_because_ignores_after"
|
||||
print_matches matches;
|
||||
[%expect_exact {|[ "\"\"\"\"\"\"" ]|}]
|
||||
|
||||
(* Disabled: this works by luck in Alpha, but it shouldn't. It is empty list in Omega. Should be explicitly supported *)
|
||||
(*
|
||||
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 {|[ "\"\"\"\\\"\"\"" ]|}]
|
||||
*)
|
@ -88,28 +88,29 @@ let%expect_test "post_request" =
|
||||
"id": 0
|
||||
} |}];
|
||||
|
||||
(* Disabled: Angstrom does not output similarly useful parse errors.
|
||||
let source = "hello world" in
|
||||
let match_template = "hello :[1]" in
|
||||
let rule = Some {|where :[1] = "world"|} in
|
||||
let language = "generic" in
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
[%expect {|
|
||||
Error in line 1, column 7:
|
||||
where :[1] = "world"
|
||||
^
|
||||
Expecting "!=" or "==" |}];
|
||||
^
|
||||
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
|
||||
@ -167,24 +168,26 @@ let%expect_test "post_request" =
|
||||
"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
|
||||
(* Disabled: Angstrom does not output similarly useful parse errors.
|
||||
(* 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
|
||||
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 {|
|
||||
print_string result;
|
||||
[%expect {|
|
||||
Error in line 1, column 7:
|
||||
where
|
||||
^
|
||||
Expecting ":[", "false", "match", "rewrite", "true" or string literal |}]
|
||||
*)
|
||||
|
||||
let%expect_test "post_substitute" =
|
||||
|
@ -4,19 +4,8 @@
|
||||
;
|
||||
; 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_optional_holes
|
||||
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))
|
||||
|
@ -1 +0,0 @@
|
||||
../example
|
@ -1,222 +0,0 @@
|
||||
(*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,945 +0,0 @@
|
||||
(*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
|
||||
|}]
|
||||
*)
|
@ -1,434 +0,0 @@
|
||||
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":""}|}]
|
||||
*)
|
@ -1,144 +0,0 @@
|
||||
(*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|}]
|
||||
*)
|
@ -1,323 +0,0 @@
|
||||
(*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)}
|
||||
|}]
|
||||
*)
|
@ -1,698 +0,0 @@
|
||||
(*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 {|
|
||||
[] |}];
|
||||
*)
|
218
test/omega/test_optional_holes.ml
Normal file
218
test/omega/test_optional_holes.ml
Normal file
@ -0,0 +1,218 @@
|
||||
(*open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
|
||||
let configuration = Configuration.create ~match_kind:Fuzzy ()
|
||||
|
||||
let run ?(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 "optional_holes_basic_match" =
|
||||
let source = {||} in
|
||||
let match_template = {|:[[?x]]|} in
|
||||
let rewrite_template = {|/:[?x]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
let source = {||} in
|
||||
let match_template = {|:[[?x]]:[[?y]]|} in
|
||||
let rewrite_template = {|/:[?x]/:[?y]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|///|}];
|
||||
|
||||
let source = {|a |} in
|
||||
let match_template = {|:[[x]] :[[?y]]|} in
|
||||
let rewrite_template = {|/:[x]/:[?y]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/a//|}];
|
||||
|
||||
let source = {|a |} in
|
||||
let match_template = {|:[[x]] :[[?y]]|} in
|
||||
let rewrite_template = {|/:[x]/:[?y]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/a//|}];
|
||||
|
||||
let source = {|(foo )|} in
|
||||
let match_template = {|(:[[?x]] :[[?y]])|} in
|
||||
let rewrite_template = {|/:[?x]/:[?y]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/foo//|}];
|
||||
|
||||
let source = {|(foo)|} in
|
||||
let match_template = {|(:[[?x]]:[? w])|} in
|
||||
let rewrite_template = {|/:[?x]/:[?w]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/foo//|}];
|
||||
|
||||
let source = {|()|} in
|
||||
let match_template = {|(:[[?x]]:[? w]:[?y]:[?z.])|} in
|
||||
let rewrite_template = {|/:[?x]/:[?w]/:[?y]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|///|}];
|
||||
|
||||
let source = {|()|} in
|
||||
let match_template = {|(:[?s\n])|} in
|
||||
let rewrite_template = {|/:[?s]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}]
|
||||
|
||||
let%expect_test "optional_holes_match_over_coalesced_whitespace" =
|
||||
let source = {|a c|} in
|
||||
let match_template = {|:[[a]] :[[?b]] :[[c]]|} in
|
||||
let rewrite_template = {|/:[?a]/:[?b]/:[?c]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/a//c|}];
|
||||
|
||||
let source = {|a c|} in
|
||||
let match_template = {|:[[a]] :[[?b]]:[[c]]|} in
|
||||
let rewrite_template = {|/:[?a]/:[?b]/:[?c]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/a//c|}];
|
||||
|
||||
let source = {|a c|} in
|
||||
let match_template = {|:[[a]]:[[?b]]:[[c]]|} in
|
||||
let rewrite_template = {|/:[?a]/:[?b]/:[?c]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}];
|
||||
|
||||
let source = {|a c|} in
|
||||
let match_template = {|:[[a]]:[[?b]] :[[?c]]|} in
|
||||
let rewrite_template = {|/:[?a]/:[?b]/:[?c]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/a//c|}];
|
||||
|
||||
let source = {|a c|} in
|
||||
let match_template = {|a :[?b] c|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
let source = {|a c|} in
|
||||
let match_template = {|a :[?b] c|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
let source = {|
|
||||
|
||||
a
|
||||
|
||||
c
|
||||
|
||||
|} in
|
||||
let match_template = {| a :[?b] c |} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
let source = {|func foo(bar) {}|} in
|
||||
let match_template = {|func :[?receiver] foo(:[args])|} in
|
||||
let rewrite_template = {|/:[receiver]/:[args]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//bar/ {}|}];
|
||||
|
||||
let source = {|func foo(bar) {}|} in
|
||||
let match_template = {|func :[?receiver] foo(:[args])|} in
|
||||
let rewrite_template = {|/:[receiver]/:[args]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//bar/ {}|}];
|
||||
|
||||
let source = {|func (r *receiver) foo(bar) {}|} in
|
||||
let match_template = {|func :[?receiver] foo(:[args])|} in
|
||||
let rewrite_template = {|/:[receiver]/:[args]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/(r *receiver)/bar/ {}|}];
|
||||
|
||||
let source = {|func foo()|} in
|
||||
let match_template = {|func :[?receiver] foo()|} in
|
||||
let rewrite_template = {|/:[receiver]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
let source = {|a l|} in
|
||||
let match_template = {|a :[?b]asdfasdfsadf|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}];
|
||||
|
||||
let source = {|func foo (1, 3)|} in
|
||||
let match_template = {|func :[?receiver] foo (1, :[?args] 3)|} in
|
||||
let rewrite_template = {|/:[receiver]/:[args]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|///|}];
|
||||
|
||||
let source = {|
|
||||
try {
|
||||
foo()
|
||||
} catch (Exception e) {
|
||||
logger.error(e)
|
||||
hey
|
||||
}
|
||||
|} in
|
||||
let match_template = {|
|
||||
catch (:[type] :[var]) {
|
||||
:[?anything]
|
||||
logger.:[logMethod](:[var])
|
||||
:[?something]
|
||||
}
|
||||
|} in
|
||||
let rewrite_template = {|
|
||||
catch (:[type] :[var]) {
|
||||
:[anything]
|
||||
logger.:[logMethod]("", :[var])
|
||||
:[something]
|
||||
}
|
||||
|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|
|
||||
try {
|
||||
foo()
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
logger.error("", e)
|
||||
hey
|
||||
}
|
||||
|}];
|
||||
|
||||
let source = {|<p>content</p><p attr="attr">more content</p>|} in
|
||||
let match_template = {|<p:[?attrs]>|} in
|
||||
let rewrite_template = {|<p{:[?attrs]}>|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|<p{}>content</p><p{ attr="attr"}>more content</p>|}]
|
||||
|
||||
let%expect_test "optional_holes_match_over_coalesced_whitespace_in_strings" =
|
||||
let source = {|"a c"|} in
|
||||
let match_template = {|"a :[?b] c"|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|No matches.|}];
|
||||
|
||||
let source = {|"a c"|} in
|
||||
let match_template = {|"a :[?b] c"|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|//|}];
|
||||
|
||||
(* Uh, turns out whitespace is significant inside strings, so this is correct
|
||||
until it is decided otherwise *)
|
||||
let source = {|"a c"|} in
|
||||
let match_template = {|"a :[?b] c"|} in
|
||||
let rewrite_template = {|/:[?b]/|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|/ /|}]
|
||||
|
||||
let%expect_test "optional_holes_substitute" =
|
||||
let source = {|()|} in
|
||||
let match_template = {|(:[[?x]]:[? w]:[?y]:[?z.])|} in
|
||||
let rewrite_template = {|/:[x]/:[w]/:[y]/:[z]|} in
|
||||
run source match_template rewrite_template;
|
||||
[%expect_exact {|////|}]
|
||||
*)
|
@ -1,55 +0,0 @@
|
||||
(*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 {|[ "\"\"\"\\\"\"\"" ]|}]
|
||||
*)
|
@ -1,127 +0,0 @@
|
||||
(*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,205 +0,0 @@
|
||||
(*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 ()
|
||||
*)
|
@ -1,88 +0,0 @@
|
||||
(*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
|
||||
} |}]
|
||||
*)
|
@ -1,4 +1,4 @@
|
||||
(*open Core
|
||||
open Core
|
||||
|
||||
open Matchers
|
||||
open Rewriter
|
||||
@ -410,4 +410,3 @@ let%expect_test "match_escaped_escaped" =
|
||||
| Some { rewritten_source; _ } -> print_string rewritten_source
|
||||
| None -> print_string "EXPECT SUCCESS");
|
||||
[%expect_exact {|EXPECT SUCCESS|}]
|
||||
*)
|
||||
|
Loading…
Reference in New Issue
Block a user