WIP: filter wasm-dis to only disassemble certain specified functions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 51c7e9f..5d277f8 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -423,11 +423,16 @@
   const char *maybeSpace;
   const char *maybeNewLine;
 
-  bool full = false; // whether to not elide nodes in output when possible
-                     // (like implicit blocks) and to emit types
-  bool printStackIR = false; // whether to print stack IR if it is present
-                             // (if false, and Stack IR is there, we just
-                             // note it exists)
+  // whether to not elide nodes in output when possible
+  // (like implicit blocks) and to emit types
+  bool full = false;
+  // whether to print stack IR if it is present
+  // (if false, and Stack IR is there, we just
+  // note it exists)
+  bool printStackIR = false;
+  // if null, print the entire module, otherwise print only
+  // the single function with this name
+  Name singleFunctionName;
 
   Module* currModule = nullptr;
   Function* currFunction = nullptr;
@@ -474,6 +479,8 @@
 
   void setFull(bool full_) { full = full_; }
 
+  void setSingleFunction(Name const& name) { singleFunctionName = name; }
+
   void incIndent() {
     if (minify) return;
     o << '\n';
@@ -1059,53 +1066,59 @@
     o << '(';
     printMajor(o, "module");
     incIndent();
-    for (auto& child : curr->functionTypes) {
-      doIndent(o, indent);
-      o << '(';
-      printMedium(o, "type") << ' ';
-      printName(child->name, o) << ' ';
-      visitFunctionType(child.get());
-      o << ")" << maybeNewLine;
-    }
-    ModuleUtils::iterImportedMemories(*curr, [&](Memory* memory) {
-      visitMemory(memory);
-    });
-    ModuleUtils::iterImportedTables(*curr, [&](Table* table) {
-      visitTable(table);
-    });
-    ModuleUtils::iterImportedGlobals(*curr, [&](Global* global) {
-      visitGlobal(global);
-    });
-    ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
-      visitFunction(func);
-    });
-    ModuleUtils::iterDefinedMemories(*curr, [&](Memory* memory) {
-      visitMemory(memory);
-    });
-    ModuleUtils::iterDefinedTables(*curr, [&](Table* table) {
-      visitTable(table);
-    });
-    ModuleUtils::iterDefinedGlobals(*curr, [&](Global* global) {
-      visitGlobal(global);
-    });
-    for (auto& child : curr->exports) {
-      doIndent(o, indent);
-      visitExport(child.get());
-      o << maybeNewLine;
-    }
-    if (curr->start.is()) {
-      doIndent(o, indent);
-      o << '(';
-      printMedium(o, "start") << ' ' << curr->start << ')';
-      o << maybeNewLine;
+    if (singleFunctionName.isNull()) {
+      for (auto& child : curr->functionTypes) {
+        doIndent(o, indent);
+        o << '(';
+        printMedium(o, "type") << ' ';
+        printName(child->name, o) << ' ';
+        visitFunctionType(child.get());
+        o << ")" << maybeNewLine;
+      }
+      ModuleUtils::iterImportedMemories(*curr, [&](Memory* memory) {
+        visitMemory(memory);
+      });
+      ModuleUtils::iterImportedTables(*curr, [&](Table* table) {
+        visitTable(table);
+      });
+      ModuleUtils::iterImportedGlobals(*curr, [&](Global* global) {
+        visitGlobal(global);
+      });
+      ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
+          visitFunction(func);
+      });
+      ModuleUtils::iterDefinedMemories(*curr, [&](Memory* memory) {
+        visitMemory(memory);
+      });
+      ModuleUtils::iterDefinedTables(*curr, [&](Table* table) {
+        visitTable(table);
+      });
+      ModuleUtils::iterDefinedGlobals(*curr, [&](Global* global) {
+        visitGlobal(global);
+      });
+      for (auto& child : curr->exports) {
+        doIndent(o, indent);
+        visitExport(child.get());
+        o << maybeNewLine;
+      }
+      if (curr->start.is()) {
+        doIndent(o, indent);
+        o << '(';
+        printMedium(o, "start") << ' ' << curr->start << ')';
+        o << maybeNewLine;
+      }
     }
     ModuleUtils::iterDefinedFunctions(*curr, [&](Function* func) {
-      visitFunction(func);
+      if (singleFunctionName.is() && func->name.hasSubstring(singleFunctionName)) {
+        visitFunction(func);
+      }
     });
-    for (auto& section : curr->userSections) {
-      doIndent(o, indent);
-      o << ";; custom section \"" << section.name << "\", size " << section.data.size();
-      o << maybeNewLine;
+    if (singleFunctionName.isNull()) {
+      for (auto& section : curr->userSections) {
+        doIndent(o, indent);
+        o << ";; custom section \"" << section.name << "\", size " << section.data.size();
+        o << maybeNewLine;
+      }
     }
     decIndent();
     o << maybeNewLine;
@@ -1203,6 +1216,14 @@
   return printModule(module, std::cout);
 }
 
+std::ostream& WasmPrinter::printSingleFunction(Module* module, Name const& name, std::ostream& o) {
+  PrintSExpression print(o);
+  print.setMinify(false);
+  print.setSingleFunction(name);
+  print.visitModule(module);
+  return o;
+}
+
 std::ostream& WasmPrinter::printExpression(Expression* expression, std::ostream& o, bool minify, bool full) {
   if (!expression) {
     o << "(null expression)";
diff --git a/src/tools/wasm-dis.cpp b/src/tools/wasm-dis.cpp
index 3ff6819..22fd125 100644
--- a/src/tools/wasm-dis.cpp
+++ b/src/tools/wasm-dis.cpp
@@ -29,6 +29,7 @@
 
 int main(int argc, const char *argv[]) {
   std::string sourceMapFilename;
+  std::string singleFunctionName;
   Options options("wasm-dis", "Un-assemble a .wasm (WebAssembly binary format) into a .wast (WebAssembly text format)");
   options.add("--output", "-o", "Output file (stdout if not specified)",
               Options::Arguments::One,
@@ -39,6 +40,11 @@
       .add("--source-map", "-sm", "Consume source map from the specified file to add location information",
            Options::Arguments::One,
            [&sourceMapFilename](Options *o, const std::string& argument) { sourceMapFilename = argument; })
+      .add("--func", "-f", "Only disassemble a single function",
+           Options::Arguments::One,
+           [&singleFunctionName](Options *o, const std::string& argument) {
+             singleFunctionName = argument;
+           })
       .add_positional("INFILE", Options::Arguments::One,
                       [](Options *o, const std::string& argument) {
                         o->extra["infile"] = argument;
@@ -61,7 +67,11 @@
 
   if (options.debug) std::cerr << "Printing..." << std::endl;
   Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
-  WasmPrinter::printModule(&wasm, output.getStream());
+  if (singleFunctionName == "") {
+    WasmPrinter::printModule(&wasm, output.getStream());
+  } else {
+    WasmPrinter::printSingleFunction(&wasm, Name(singleFunctionName.c_str()), output.getStream());
+  }
   output << '\n';
 
   if (options.debug) std::cerr << "Done." << std::endl;
diff --git a/src/wasm-printing.h b/src/wasm-printing.h
index d3327aa..ae61659 100644
--- a/src/wasm-printing.h
+++ b/src/wasm-printing.h
@@ -21,6 +21,7 @@
 
 #include "wasm.h"
 #include "pass.h"
+#include "support/name.h"
 
 namespace wasm {
 
@@ -29,6 +30,8 @@
 
   static std::ostream& printModule(Module* module);
 
+  static std::ostream& printSingleFunction(Module* module, Name const& name, std::ostream& o);
+
   static std::ostream& printExpression(Expression* expression, std::ostream& o, bool minify = false, bool full = false);
 
   static std::ostream& printStackInst(StackInst* inst, std::ostream& o, Function* func=nullptr);