diff options
Diffstat (limited to 'lib/tools/replace.nom')
| -rwxr-xr-x | lib/tools/replace.nom | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/lib/tools/replace.nom b/lib/tools/replace.nom new file mode 100755 index 0000000..fdb8e38 --- /dev/null +++ b/lib/tools/replace.nom @@ -0,0 +1,147 @@ +#!/usr/bin/env nomsu -V6.14 +# + This is a tool to replace syntax trees with something new. + + Usage: + nomsu -t replace [-i] [-f] [-q] [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2... + + Example: + nomsu -t replace "($1 and $2) and $3" "all of [$1, $2, $3]" my_file.nom + + If the "-i" flag is used, the file(s) will be edited in-place. + When editing in-place, if the "-f" flag is not used, each change will be + run past the user first. + If the "-q" flag is used and a file fails to parse, the original file + contents will be output. + If no files are passed in, this will read from stdin. + +use "filesystem" +use "consolecolor" +use "commandline" + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +command line program with $args: + if ((#$args.extras) < 2): + fail (" + Usage: nomsu -t replace [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2... + ") + $pattern = $args.extras.1 + $replacement = $args.extras.2 + $pattern_tree = ($pattern parsed) + $replacement_tree = ($replacement parsed) + $literal_vars = {} + if $args.literal: + for $var in ($args.literal, all matches of "$([^ ]*)"): + $literal_vars.$var = (yes) + + if (($pattern_tree.type == "Var") and (not $literal_vars.($pattern_tree.1))): + fail "Pattern matches every part of the file." + + $pattern_vars = { + : for $ in recursive $pattern_tree: + if (($.type == "Var") and (not $literal_vars.($.1))): add $.1 + for $child in $: + if ($child is a "Syntax Tree"): + recurse $ on $child + } + + # TODO: support wildcards and unpacking + e.g. nomsu -t replace "test(: $test; *$more_tests)" "*$more_tests; *$test" + ($tree matches $patt with $substitution_values) means: + # TODO: optimize + $substitution_values = {: for $k = $v in $substitution_values: add $k = $v} + when: + (not ($tree is syntax tree)): return (no) + (($patt.type == "Var") and $pattern_vars.($patt.1)): + if $substitution_values.($patt.1): + if ($tree == $substitution_values.($patt.1)): + return $substitution_values + ..else: + return (nil) + ..else: + $substitution_values.($patt.1) = $tree + return $substitution_values + ($tree.type != $patt.type): return (nil) + ($tree.type == "Action"): + if (($tree, get stub) != ($patt, get stub)): return (nil) + + for $ in 1 to (#$patt): + if ($patt.$ is syntax tree): + $new_values = ($tree.$ matches $patt.$ with $substitution_values) + unless $new_values: + return (nil) + + for $k = $v in $new_values: + $substitution_values.$k = $v + ..else: + unless ($tree.$ == $patt.$): return (nil) + + if ((#$tree) != (#$patt)): return (nil) + return $substitution_values + $filenames = ($args.extras, from 3 to -1) + if ((#$filenames) == 0): + say (" + Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find - + ") + $filenames = ["stdin"] + + for $filename in $filenames: + $file = (read file $filename) + unless $file: + fail "File does not exist: \$filename" + $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file) + try: + $tree = ($code parsed) + ..if it fails $msg: + if $args.q: + unless $args.i: say $code + ..else: + say $msg + + unless $tree: + do next $filename + + $replaced = {} + $matched = {} + $user_answers = {} + ($tree with replacements) means + $tree, map + for $t: + $values = ($t matches $pattern_tree with {}) + if $values: + $matched.$t = (yes) + for $k = $v in $values: + $values.$k = ($v with replacements) + $ret = ($replacement_tree with vars $values) + if ($args.i and (not $args.f)): + if ($user_answers.$t == (nil)): + if ((#$user_answers) > 0): say "" + $user_answers.$t = "n" + say "\(bright)Should this:" + say (" + \(bright)\(yellow)\("\(($t with replacements) as nomsu)", with "\n" -> "\n ")\ + ..\(reset color) + ") + say "\(bright)..be replaced with:" + + say (" + \(bright)\(blue)\("\($ret as nomsu)", with "\n" -> "\n ")\(reset color) + ") + + $user_answers.$t = (ask "\(bright)..? [Y/n]\(reset color) ") + + if ($user_answers.$t == "n"): return (nil) + $replaced.$t = (yes) + return $ret + $tree2 = ($tree with replacements) + if $args.i: + if ((#$user_answers) > 0): say "" + say (" + \(#$replaced)/\(#$matched) replacement\("" if ((#$replaced) == 1) else "s") in \$filename + ") + + if ((#$replaced) > 0): + write "\($tree2 as nomsu)" to file $filename + ..else: + say ($tree2 as nomsu) |
