package comby
A tool for structural code search and replace that supports ~every language
Install
Dune Dependency
Authors
Maintainers
Sources
1.2.2.tar.gz
md5=86fd3dcdaa792a5d871f695a082ad9b5
sha512=63af340d65f4ca37f00bee2a67c7a87822ef15c86051e6486c6eeb5d7fe310c845d4fff15625a72b48ceea89e14aff52dc678da1d43d2029f58b435885d568d8
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
open Core open Match open Replacement let debug = Sys.getenv "DEBUG_COMBY" |> Option.is_some let substitute_match_contexts ?sequential (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 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 ?sequential rewrite_template environment |> fst in let offsets = Rewrite_template.get_offsets_for_holes rewrite_template (Environment.vars environment) in if debug then Format.printf "Replacements: %d | Offsets 1: %d@." (List.length replacements) (List.length offsets); let offsets = Rewrite_template.get_offsets_after_substitution offsets environment in if debug then Format.printf "Replacements: %d | Offsets 2: %d@." (List.length replacements) (List.length offsets); let in_place_substitutions = List.map2_exn replacements offsets ~f:(fun replacement (_uid, offset) -> let match_start = { Location.default with offset } in 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 rewrite_template ({ environment; _ } : Match.t) = let replacement_content, vars_substituted_for = Rewrite_template.substitute ?sequential rewrite_template environment in let offsets = Rewrite_template.get_offsets_for_holes 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 ?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 ?sequential rewrite_template) |> substitute_match_contexts ?sequential matches source |> Option.some (* no in place substitution, emit result separated by newlines *) | None -> matches |> List.map ~f:(substitute_in_rewrite_template ?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)"
>