diff options
-rw-r--r-- | README.md | 5 | ||||
-rwxr-xr-x | check.py | 15 | ||||
-rw-r--r-- | src/s2wasm-main.cpp | 50 | ||||
-rw-r--r-- | src/support/command-line.cpp | 148 | ||||
-rw-r--r-- | src/support/command-line.h | 50 | ||||
-rwxr-xr-x[-rw-r--r--] | test/__init__.py | 0 | ||||
m--------- | test/experimental | 0 |
7 files changed, 202 insertions, 66 deletions
@@ -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)). @@ -1,5 +1,19 @@ #!/usr/bin/env python +# Copyright 2015 WebAssembly Community Group participants +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import os, sys, subprocess, difflib, json, time interpreter = None @@ -366,4 +380,3 @@ if has_emcc: fail(out, expected) print '\n[ success! ]' - 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 |