summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--src/s2wasm-main.cpp50
-rw-r--r--src/support/command-line.cpp148
-rw-r--r--src/support/command-line.h50
-rwxr-xr-x[-rw-r--r--]test/__init__.py0
m---------test/experimental0
6 files changed, 188 insertions, 65 deletions
diff --git a/README.md b/README.md
index 3a8c2ba8e..af030cdcf 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,11 @@ Usage instructions for each are below.
```
$ ./build.sh
```
+or
+```
+cmake && make
+```
+Note that you can also use `ninja` as your generator: `cmake -G ninja && ninja`.
* `binaryen-shell` and `asm2wasm` require a C++11 compiler.
* If you also want to compile C/C++ to WebAssembly (and not just asm.js to WebAssembly), you'll need Emscripten. You'll need the `incoming` branch there (which you can get via [the SDK](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html)).
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index 00b71ab16..a7060dd6e 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -25,24 +25,33 @@ using namespace cashew;
using namespace wasm;
int main(int argc, const char *argv[]) {
- Options options;
- processCommandLine(argc, argv, &options,
- "s2wasm INFILE\n\n"
- "Link .s file into .wast\n\n"
- "Optional arguments:\n"
- " -n, --help Show this help message and exit\n"
- " -d, --debug Print debug information to stderr\n"
- " -o, --output Output file (stdout if not specified)\n"
- " --global-base=N Where to start to place globals\n");
+ Options options("s2wasm", "Link .s file into .wast");
+ options.add("--output", "-o", "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options *o, const std::string &argument) {
+ o->extra["output"] = argument;
+ })
+ .add("--global-base", "-g", "Where to start to place globals",
+ Options::Arguments::One,
+ [](Options *o, const std::string &argument) {
+ o->extra["global-base"] = argument;
+ })
+ .add_positional("INFILE", Options::Arguments::One,
+ [](Options *o, const std::string &argument) {
+ o->extra["infile"] = argument;
+ });
+ options.parse(argc, argv);
std::string input;
{
if (options.debug) {
- std::cerr << "Loading '" << options.infile << "'..." << std::endl;
+ std::cerr << "Loading '" << options.extra["infile"] << "'..."
+ << std::endl;
}
- std::ifstream infile(options.infile);
+ std::ifstream infile(options.extra["infile"]);
if (!infile.is_open()) {
- std::cerr << "Failed opening '" << options.infile << "'" << std::endl;
+ std::cerr << "Failed opening '" << options.extra["infile"] << "'"
+ << std::endl;
exit(EXIT_FAILURE);
}
infile.seekg(0, std::ios::end);
@@ -54,11 +63,15 @@ int main(int argc, const char *argv[]) {
std::streambuf *buffer;
std::ofstream outfile;
- if (options.outfile.size()) {
- if (options.debug) std::cerr << "Opening '" << options.outfile << std::endl;
- outfile.open(options.outfile, std::ofstream::out | std::ofstream::trunc);
+ if (options.extra["output"].size()) {
+ if (options.debug) {
+ std::cerr << "Opening '" << options.extra["output"] << std::endl;
+ }
+ outfile.open(options.extra["output"],
+ std::ofstream::out | std::ofstream::trunc);
if (!outfile.is_open()) {
- std::cerr << "Failed opening '" << options.outfile << "'" << std::endl;
+ std::cerr << "Failed opening '" << options.extra["output"] << "'"
+ << std::endl;
exit(EXIT_FAILURE);
}
buffer = outfile.rdbuf();
@@ -69,7 +82,10 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "Parsing and wasming..." << std::endl;
AllocatingModule wasm;
- size_t globalBase = options.extra["global-base"] ? atoi(options.extra["global-base"]) : 1;
+ size_t globalBase = options.extra.find("global-base") != options.extra.end()
+ ? std::stoull(options.extra["global-base"])
+ : 1;
+ if (options.debug) std::cerr << "Global base " << globalBase << '\n';
S2WasmBuilder s2wasm(wasm, input.c_str(), options.debug, globalBase);
if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
diff --git a/src/support/command-line.cpp b/src/support/command-line.cpp
index 3c03d48f4..40e11f60a 100644
--- a/src/support/command-line.cpp
+++ b/src/support/command-line.cpp
@@ -16,50 +16,122 @@
#include "support/command-line.h"
-namespace {
-bool optionIs(const char *arg, const char *LongOpt, const char *ShortOpt) {
- return strcmp(arg, LongOpt) == 0 || strcmp(arg, ShortOpt) == 0;
+using namespace wasm;
+
+Options::Options(const std::string &command, const std::string &description)
+ : debug(false), positional(Arguments::Zero) {
+ add("--help", "-h", "Show this help message and exit", Arguments::Zero,
+ [this, command, description](Options *o, const std::string &) {
+ std::cerr << command;
+ if (positional != Arguments::Zero) std::cerr << ' ' << positionalName;
+ std::cerr << "\n\n" << description << "\n\nOptions:\n";
+ size_t optionWidth = 0;
+ for (const auto &o : options) {
+ optionWidth =
+ std::max(optionWidth, o.longName.size() + o.shortName.size());
+ }
+ // TODO: line-wrap description.
+ for (const auto &o : options) {
+ size_t pad = 1 + optionWidth - o.longName.size() - o.shortName.size();
+ std::cerr << " " << o.longName << ',' << o.shortName
+ << std::string(pad, ' ') << o.description << '\n';
+ }
+ std::cerr << '\n';
+ exit(EXIT_SUCCESS);
+ });
+ add("--debug", "-d", "Print debug information to stderr", Arguments::Zero,
+ [](Options *o, const std::string &) { o->debug = true; });
}
-bool startsWith(const char *str, const char *prefix) {
- return strncmp(str, prefix, strlen(prefix)) == 0;
+
+Options::~Options() {}
+
+Options &Options::add(const std::string &longName, const std::string &shortName,
+ const std::string &description, Arguments arguments,
+ const Action &action) {
+ options.push_back({longName, shortName, description, arguments, action, 0});
+ return *this;
}
-} // anonymous namespace
-void wasm::processCommandLine(int argc, const char *argv[], Options *options,
- const char *help) {
+Options &Options::add_positional(const std::string &name, Arguments arguments,
+ const Action &action) {
+ positional = arguments;
+ positionalName = name;
+ positionalAction = action;
+ return *this;
+}
+
+void Options::parse(int argc, const char *argv[]) {
assert(argc > 0 && "expect at least program name as an argument");
+ size_t positionalsSeen = 0;
+ auto dashes = [](const std::string &s) {
+ for (size_t i = 0;; ++i) {
+ if (s[i] != '-') return i;
+ }
+ };
for (size_t i = 1, e = argc; i != e; ++i) {
- if (optionIs(argv[i], "--help", "-h")) {
- std::cerr << help;
- exit(EXIT_SUCCESS);
- } else if (optionIs(argv[i], "--debug", "-d")) {
- options->debug = true;
- } else if (optionIs(argv[i], "--output", "-o")) {
- if (i + 1 == e) {
- std::cerr << "No output file" << std::endl;
- exit(EXIT_FAILURE);
- }
- if (options->outfile.size()) {
- std::cerr << "Expected only one output file, got '" << options->outfile
- << "' and '" << argv[i] << "'" << std::endl;
- exit(EXIT_FAILURE);
- }
- options->outfile = argv[++i];
- } else if (startsWith(argv[i], "--")) {
- size_t j = 2;
- std::string name;
- while (argv[i][j] && argv[i][j] != '=') {
- name += argv[i][j];
- j++;
- }
- options->extra[name] = argv[i][j] == '=' ? &argv[i][j + 1] : "(no value)";
- } else {
- if (options->infile.size()) {
- std::cerr << "Expected only one input file, got '" << options->infile
- << "' and '" << argv[i] << "'" << std::endl;
- exit(EXIT_FAILURE);
+ std::string currentOption = argv[i];
+
+ if (dashes(currentOption) == 0) {
+ // Positional.
+ switch (positional) {
+ case Arguments::Zero:
+ std::cerr << "Unexpected positional argument '" << currentOption
+ << "'\n";
+ exit(EXIT_FAILURE);
+ case Arguments::One:
+ if (positionalsSeen) {
+ std::cerr << "Unexpected second positional argument '"
+ << currentOption << "' for " << positionalName << '\n';
+ exit(EXIT_FAILURE);
+ }
+ // Fallthrough.
+ case Arguments::N:
+ positionalAction(this, currentOption);
+ ++positionalsSeen;
}
- options->infile = argv[i];
+ continue;
+ }
+
+ // Non-positional.
+ std::string argument;
+ auto equal = currentOption.find_first_of('=');
+ if (equal != std::string::npos) {
+ argument = currentOption.substr(equal + 1);
+ currentOption = currentOption.substr(0, equal - 1);
+ }
+ Option *option = nullptr;
+ for (auto &o : options)
+ if (o.longName == currentOption || o.shortName == currentOption)
+ option = &o;
+ if (!option) {
+ std::cerr << "Unknown option '" << currentOption << "'\n";
+ exit(EXIT_FAILURE);
+ }
+ switch (option->arguments) {
+ case Arguments::Zero:
+ if (argument.size()) {
+ std::cerr << "Unexpected argument '" << argument
+ << "' for option '" << currentOption << "'\n";
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case Arguments::One:
+ if (option->seen) {
+ std::cerr << "Unexpected second argument '" << argument << "' for '"
+ << currentOption << "'\n";
+ exit(EXIT_FAILURE);
+ }
+ // Fallthrough.
+ case Arguments::N:
+ if (!argument.size()) {
+ if (i + 1 == e) {
+ std::cerr << "Couldn't find expected argument for '" << currentOption << "'\n";
+ exit(EXIT_FAILURE);
+ }
+ argument = argv[++i];
+ }
}
+ option->action(this, argument);
+ ++option->seen;
}
}
diff --git a/src/support/command-line.h b/src/support/command-line.h
index f57929b6b..14dbce57f 100644
--- a/src/support/command-line.h
+++ b/src/support/command-line.h
@@ -21,22 +21,52 @@
#ifndef wasm_support_command_line_h
#define wasm_support_command_line_h
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
#include "wasm.h"
+
namespace wasm {
-struct Options {
- // standard options
+class Options {
+ public:
+ typedef std::function<void(Options *, const std::string &)> Action;
+ enum class Arguments { Zero, One, N };
+
bool debug;
- std::string infile;
- std::string outfile;
- // extra options
- std::map<std::string, const char *> extra;
- Options() : debug(false) {}
-};
+ std::map<std::string, std::string> extra;
-void processCommandLine(int argc, const char *argv[], Options *options,
- const char *help);
+ Options(const std::string &command, const std::string &description);
+ ~Options();
+ Options &add(const std::string &longName, const std::string &shortName,
+ const std::string &description, Arguments arguments,
+ const Action &action);
+ Options &add_positional(const std::string &name, Arguments arguments,
+ const Action &action);
+ void parse(int argc, const char *argv[]);
+
+ private:
+ Options() = delete;
+ Options(const Options &) = delete;
+ Options &operator=(const Options &) = delete;
+
+ struct Option {
+ std::string longName;
+ std::string shortName;
+ std::string description;
+ Arguments arguments;
+ Action action;
+ size_t seen;
+ };
+ std::vector<Option> options;
+ Arguments positional;
+ std::string positionalName;
+ Action positionalAction;
+};
} // namespace wasm
diff --git a/test/__init__.py b/test/__init__.py
index 8db5bb0bf..8db5bb0bf 100644..100755
--- a/test/__init__.py
+++ b/test/__init__.py
diff --git a/test/experimental b/test/experimental
-Subproject e7c05d099669c7f5c117be569f1f920ff0d5966
+Subproject 3ad542d797a5b7c3a51a85429fdb8917e7bea8a