(149 lines)
1 #!/usr/bin/env nomsu -V7.0.02 ###3 This is a tool to replace syntax trees with something new.5 Usage:6 nomsu -t replace [-i] [-f] [-q] [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...8 Example:9 nomsu -t replace "($1 and $2) and $3" "all of [$1, $2, $3]" my_file.nom11 If the "-i" flag is used, the file(s) will be edited in-place.12 When editing in-place, if the "-f" flag is not used, each change will be13 run past the user first.14 If the "-q" flag is used and a file fails to parse, the original file15 contents will be output.16 If no files are passed in, this will read from stdin.18 use "filesystem"19 use "consolecolor"20 use "commandline"22 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~24 command line program with $args:25 if (#$args.extras < 2):26 fail ("27 Usage: nomsu -t replace [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...28 ")29 $pattern = $args.extras.130 $replacement = $args.extras.231 $pattern_tree = ($pattern parsed)32 $replacement_tree = ($replacement parsed)33 $literal_vars = {}34 if $args.literal:35 for $var in ($args.literal, all matches of "$([^ ]*)"):36 $literal_vars.$var = (yes)38 if (($pattern_tree.type == "Var") and (not $literal_vars.($pattern_tree.1))):39 fail "Pattern matches every part of the file."41 $pattern_vars = {:42 for $ in recursive $pattern_tree:43 if (($.type == "Var") and (not $literal_vars.($.1))): add $.144 for $child in $:45 if ($child is "a Syntax Tree"):46 recurse $ on $child47 }49 ### TODO: support wildcards and unpacking50 e.g. nomsu -t replace "test(: $test; *$more_tests)" "*$more_tests; *$test"51 ($tree matches $patt with $substitution_values) means:52 ### TODO: optimize53 $substitution_values = {: for ($k = $v) in $substitution_values: add $k = $v}54 when:55 (not ($tree is syntax tree)): return (no)56 (($patt.type == "Var") and $pattern_vars.($patt.1)):57 if $substitution_values.($patt.1):58 if ($tree == $substitution_values.($patt.1)):59 return $substitution_values60 ..else:61 return (nil)62 ..else:63 $substitution_values.($patt.1) = $tree64 return $substitution_values66 ($tree.type != $patt.type): return (nil)67 ($tree.type == "Action"):68 if (($tree, get stub) != ($patt, get stub)): return (nil)70 for $ in (1 to #$patt):71 if ($patt.$ is syntax tree):72 $new_values = ($tree.$ matches $patt.$ with $substitution_values)73 unless $new_values:74 return (nil)76 for ($k = $v) in $new_values:77 $substitution_values.$k = $v78 ..else:79 unless ($tree.$ == $patt.$): return (nil)81 if (#$tree != #$patt):82 return (nil)84 return $substitution_values85 $filenames = ($args.extras, from 3 to -1)86 if (#$filenames == 0):87 say ("88 Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find -89 ")90 $filenames = ["stdin"]92 for $filename in $filenames:93 $file = (read file $filename)94 unless $file:95 fail "File does not exist: \$filename"96 $code = (NomsuCode from ($Source $filename 1 #$file) $file)97 try:98 $tree = ($code parsed)99 ..if it fails with $msg:100 if $args.q:101 unless $args.i:102 say $code103 ..else:104 say $msg106 unless $tree:107 do next $filename109 $replaced = {}110 $matched = {}111 $user_answers = {}112 ($tree with replacements) means113 $tree, with114 for $t:115 $values = ($t matches $pattern_tree with {})116 if $values:117 $matched.$t = (yes)118 for ($k = $v) in $values:119 $values.$k = ($v with replacements)120 $ret = ($replacement_tree, with $values)121 if ($args.i and (not $args.f)):122 if ($user_answers.$t == (nil)):123 if (#$user_answers > 0): say ""124 $user_answers.$t = "n"125 say "\(bright)Should this:"126 say ("127 \(bright)\(yellow)\("\(($t with replacements) as nomsu)", with "\n" -> "\n ")\128 ..\(reset color)129 ")130 say "\(bright)..be replaced with:"131 say ("132 \(bright)\(blue)\("\($ret as nomsu)", with "\n" -> "\n ")\(reset color)133 ")134 $user_answers.$t = (ask "\(bright)..? [Y/n]\(reset color) ")135 if ($user_answers.$t == "n"): return (nil)136 $replaced.$t = (yes)137 return $ret139 $tree2 = ($tree with replacements)140 if $args.i:141 if (#$user_answers > 0): say ""142 say ("143 \(#$replaced)/\(#$matched) replacement\("" if (#$replaced == 1) else "s") in \$filename144 ")146 if (#$replaced > 0):147 write "\($tree2 as nomsu)" to file $filename148 ..else:149 say ($tree2 as nomsu)