#!/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..."] 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 "lib/os.nom" use "lib/consolecolor.nom" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ((#$(COMMAND LINE ARGS).extras) < 2): fail (" Usage: nomsu -t replace [--literal="$v1 $v2..."] file1 file2... ") $pattern = $(COMMAND LINE ARGS).extras.1 $replacement = $(COMMAND LINE ARGS).extras.2 $pattern_tree = ($pattern parsed) $replacement_tree = ($replacement parsed) $literal_vars = {} if $(COMMAND LINE ARGS).literal: for $var in ($(COMMAND LINE 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 = ($(COMMAND LINE 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 $(COMMAND LINE ARGS).q: unless $(COMMAND LINE 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 ($(COMMAND LINE ARGS).i and (not $(COMMAND LINE 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 $(COMMAND LINE 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)