aboutsummaryrefslogtreecommitdiff
path: root/lib/tools/replace.nom
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tools/replace.nom')
-rwxr-xr-xlib/tools/replace.nom147
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)