package comby
A tool for structural code search and replace that supports ~every language
Install
Dune Dependency
Authors
Maintainers
Sources
1.3.0.tar.gz
md5=617a80e8673c3f811403f09701c08a25
sha512=2f8f82c119210ae0efd7f3eefdd992d6b52655575233dfab74662d9a9854ce4aafcd4fe01dad17ba310e38f28ee1437be2f3c4af4f6952a97bb19e1400fc709a
doc/src/comby.rewriter/rewrite.ml.html
Source file rewrite.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
open Core open Match open Replacement let debug = Sys.getenv "DEBUG_COMBY" |> Option.is_some let substitute_match_contexts ?sequential ?metasyntax (matches: Match.t list) source replacements = if debug then Format.printf "Matches: %d | Replacements: %d@." (List.length matches) (List.length replacements); let rewrite_template, environment = List.fold2_exn matches replacements ~init:(source, Environment.create ()) ~f:(fun (rewrite_template, accumulator_environment) ({ environment = _match_environment; _ } as match_) { replacement_content; _ } -> (* create a hole in the rewrite template based on this match context *) let hole_id, rewrite_template = Rewrite_template.of_match_context ?metasyntax match_ ~source:rewrite_template in if debug then Format.printf "Hole: %s in %s@." hole_id rewrite_template; (* add this match context replacement to the environment *) let accumulator_environment = Environment.add accumulator_environment hole_id replacement_content in (* update match context replacements offset *) rewrite_template, accumulator_environment) in if debug then Format.printf "Env:@.%s" (Environment.to_string environment); if debug then Format.printf "Rewrite in:@.%s@." rewrite_template; let rewritten_source = Rewrite_template.substitute ?metasyntax ?sequential rewrite_template environment |> fst in let offsets = Rewrite_template.get_offsets_for_holes ?metasyntax rewrite_template (Environment.vars environment) in if debug then Format.printf "Replacements: %d | Offsets 1: %d@." (List.length replacements) (List.length offsets); let offsets = Rewrite_template.get_offsets_after_substitution offsets environment in if debug then Format.printf "Replacements: %d | Offsets 2: %d@." (List.length replacements) (List.length offsets); let in_place_substitutions = List.map2_exn replacements offsets ~f:(fun replacement (_uid, offset) -> let match_start = { Location.default with offset } in let offset = offset + String.length replacement.replacement_content in let match_end = { Location.default with offset } in let range = Range.{ match_start; match_end } in { replacement with range }) in { rewritten_source ; in_place_substitutions } (* store range information for this match_context replacement: (a) its offset in the original source (b) its replacement context (to calculate the range) (c) an environment of values that are updated to reflect their relative offset in the rewrite template *) let substitute_in_rewrite_template ?sequential ?metasyntax rewrite_template ({ environment; _ } : Match.t) = let replacement_content, vars_substituted_for = Rewrite_template.substitute ?metasyntax ?sequential rewrite_template environment in let offsets = Rewrite_template.get_offsets_for_holes ?metasyntax rewrite_template (Environment.vars environment) in let offsets = Rewrite_template.get_offsets_after_substitution offsets environment in let environment = List.fold offsets ~init:(Environment.create ()) ~f:(fun acc (var, relative_offset) -> if List.mem vars_substituted_for var ~equal:String.equal then let value = Option.value_exn (Environment.lookup environment var) in (* FIXME(RVT): Location does not update row/column here *) let start_location = Location.{ default with offset = relative_offset } in let end_location = let offset = relative_offset + String.length value in Location.{ default with offset } in let range = Range. { match_start = start_location ; match_end = end_location } in Environment.add ~range acc var value else acc) in { replacement_content ; environment ; range = { match_start = { Location.default with offset = 0 } ; match_end = Location.default } } let all ?source ?metasyntax ?sequential ~rewrite_template matches : result option = if List.is_empty matches then None else match source with (* in-place substitution *) | Some source -> let matches : Match.t list = List.rev matches in matches |> List.map ~f:(substitute_in_rewrite_template ?metasyntax ?sequential rewrite_template) |> substitute_match_contexts ?metasyntax ?sequential matches source |> Option.some (* no in place substitution, emit result separated by newlines *) | None -> matches |> List.map ~f:(substitute_in_rewrite_template ?metasyntax ?sequential rewrite_template) |> List.map ~f:(fun { replacement_content; _ } -> replacement_content) |> String.concat ~sep:"\n" |> (fun rewritten_source -> { rewritten_source; in_place_substitutions = [] }) |> Option.some
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>