package comby-kernel
A match engine for structural code search and replace that supports ~every language
Install
Dune Dependency
Authors
Maintainers
Sources
1.4.1.tar.gz
md5=cd732f90664bc686eaa1134f42c8f7cd
sha512=81c7cd1d70cddee4d1679710a95c50d22f8dc60e48f24554009a5f944eb23e9124ca9aa99357b9879a5a60ca2dbcf976011f53afb442a7f15642e509255a0326
doc/src/comby-kernel.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 113
open Core_kernel open Match open Replacement let debug = match Sys.getenv "DEBUG_COMBY" with | exception Not_found -> false | _ -> true let substitute_match_contexts ?fresh ?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 sub_fresh = Option.map fresh ~f:(fun f -> fun () -> ("sub_" ^ f ())) in (* ensure custom fresh function is unique for substition. *) let hole_id, rewrite_template = Rewrite_template.of_match_context ?metasyntax ?fresh:sub_fresh 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 ?fresh 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 ?fresh ?metasyntax rewrite_template ({ environment; _ } : Match.t) = let replacement_content, vars_substituted_for = Rewrite_template.substitute ?metasyntax ?fresh 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 ?fresh ~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 ?fresh rewrite_template) |> substitute_match_contexts ?metasyntax ?fresh matches source |> Option.some (* no in place substitution, emit result separated by newlines *) | None -> matches |> List.map ~f:(substitute_in_rewrite_template ?metasyntax ?fresh 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)"
>