summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt38
-rw-r--r--Makefile3
-rw-r--r--src/exe/wast-desugar.c193
-rw-r--r--src/wasm-ast.c10
-rw-r--r--src/wasm-ast.h1
-rw-r--r--test/desugar/basic.txt27
-rw-r--r--test/find_exe.py38
-rwxr-xr-xtest/run-tests.py47
8 files changed, 299 insertions, 58 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3d4a29b..763f64de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -245,17 +245,6 @@ if (NOT EMSCRIPTEN)
add_dependencies(everything wasmdump)
target_link_libraries(wasmdump libwasm)
- if (NOT WIN32)
- add_custom_command( TARGET wast2wasm
- POST_BUILD
- COMMAND ln -sf wast2wasm sexpr-wasm)
- add_custom_command( TARGET wasm2wast
- POST_BUILD
- COMMAND ln -sf wasm2wast wasm-wast)
-
- endif ()
- set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "wasm2wast" "wast2wasm")
-
# wasm-interp
add_executable(wasm-interp src/exe/wasm-interp.c)
add_dependencies(everything wasm-interp)
@@ -264,6 +253,28 @@ if (NOT EMSCRIPTEN)
target_link_libraries(wasm-interp m)
endif ()
+ # wast-desugar
+ add_executable(wast-desugar src/exe/wast-desugar.c)
+ add_dependencies(everything wast-desugar)
+ target_link_libraries(wast-desugar libwasm)
+
+ # symlinks for wast2wasm and wasm2wast
+ if (NOT WIN32)
+ add_custom_command(
+ TARGET wast2wasm
+ POST_BUILD
+ COMMAND ln -sf wast2wasm sexpr-wasm
+ )
+ add_custom_command(
+ TARGET wasm2wast
+ POST_BUILD
+ COMMAND ln -sf wasm2wast wasm-wast
+ )
+ endif ()
+ set_property(
+ DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+ "wasm2wast" "wast2wasm")
+
# hexfloat-test
find_package(Threads)
if (BUILD_TESTS AND CMAKE_USE_PTHREADS_INIT)
@@ -304,7 +315,10 @@ if (NOT EMSCRIPTEN)
)
# install
- install(TARGETS wast2wasm wasm2wast wasm-interp wasmopcodecnt wasmdump DESTINATION bin)
+ install(
+ TARGETS wast2wasm wasm2wast wasm-interp wasmopcodecnt wasmdump wast-desugar
+ DESTINATION bin
+ )
else ()
# emscripten stuff
diff --git a/Makefile b/Makefile
index be1edb17..0c6a158f 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,8 @@ COMPILERS := GCC GCC_I686 GCC_FUZZ CLANG EMSCRIPTEN
BUILD_TYPES := DEBUG RELEASE
SANITIZERS := ASAN MSAN LSAN UBSAN
CONFIGS := NORMAL $(SANITIZERS) NO_RE2C_BISON NO_TESTS
-EXECUTABLES := wast2wasm wasm2wast wasm-interp wasmopcodecnt hexfloat_test wasmdump
+EXECUTABLES := wast2wasm wasm2wast wasm-interp wasmopcodecnt hexfloat_test \
+ wasmdump wast-desugar
# directory names
GCC_DIR := gcc/
diff --git a/src/exe/wast-desugar.c b/src/exe/wast-desugar.c
new file mode 100644
index 00000000..8f49bbb7
--- /dev/null
+++ b/src/exe/wast-desugar.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "wasm-config.h"
+
+#include "wasm-apply-names.h"
+#include "wasm-ast.h"
+#include "wasm-ast-parser.h"
+#include "wasm-ast-writer.h"
+#include "wasm-common.h"
+#include "wasm-generate-names.h"
+#include "wasm-option-parser.h"
+#include "wasm-stack-allocator.h"
+#include "wasm-stream.h"
+#include "wasm-writer.h"
+
+#define PROGRAM_NAME "wast-desugar"
+
+static const char* s_infile;
+static const char* s_outfile;
+static WasmBool s_use_libc_allocator;
+static WasmBool s_generate_names;
+
+static WasmSourceErrorHandler s_error_handler =
+ WASM_SOURCE_ERROR_HANDLER_DEFAULT;
+
+enum {
+ FLAG_HELP,
+ FLAG_OUTPUT,
+ FLAG_USE_LIBC_ALLOCATOR,
+ FLAG_GENERATE_NAMES,
+ NUM_FLAGS
+};
+
+static const char s_description[] =
+ " read a file in the wasm s-expression format and format it.\n"
+ "\n"
+ "examples:\n"
+ " # write output to stdout\n"
+ " $ wast-desugar test.wast\n"
+ "\n"
+ " # write output to test2.wast\n"
+ " $ wast-desugar test.wast -o test2.wast\n"
+ "\n"
+ " # generate names for indexed variables\n"
+ " $ wast-desugar --generate-names test.wast\n";
+
+static WasmOption s_options[] = {
+ {FLAG_HELP, 'h', "help", NULL, WASM_OPTION_NO_ARGUMENT,
+ "print this help message"},
+ {FLAG_OUTPUT, 'o', "output", "FILE", WASM_OPTION_HAS_ARGUMENT,
+ "output file for the formatted file"},
+ {FLAG_USE_LIBC_ALLOCATOR, 0, "use-libc-allocator", NULL,
+ WASM_OPTION_NO_ARGUMENT,
+ "use malloc, free, etc. instead of stack allocator"},
+ {FLAG_GENERATE_NAMES, 0, "generate-names", NULL, WASM_OPTION_NO_ARGUMENT,
+ "Give auto-generated names to non-named functions, types, etc."},
+};
+WASM_STATIC_ASSERT(NUM_FLAGS == WASM_ARRAY_SIZE(s_options));
+
+static void on_option(struct WasmOptionParser* parser,
+ struct WasmOption* option,
+ const char* argument) {
+ switch (option->id) {
+ case FLAG_HELP:
+ wasm_print_help(parser, PROGRAM_NAME);
+ exit(0);
+ break;
+
+ case FLAG_OUTPUT:
+ s_outfile = argument;
+ break;
+
+ case FLAG_USE_LIBC_ALLOCATOR:
+ s_use_libc_allocator = WASM_TRUE;
+ break;
+
+ case FLAG_GENERATE_NAMES:
+ s_generate_names = WASM_TRUE;
+ break;
+ }
+}
+
+static void on_argument(struct WasmOptionParser* parser, const char* argument) {
+ s_infile = argument;
+}
+
+static void on_option_error(struct WasmOptionParser* parser,
+ const char* message) {
+ WASM_FATAL("%s\n", message);
+}
+
+static void parse_options(int argc, char** argv) {
+ WasmOptionParser parser;
+ WASM_ZERO_MEMORY(parser);
+ parser.description = s_description;
+ parser.options = s_options;
+ parser.num_options = WASM_ARRAY_SIZE(s_options);
+ parser.on_option = on_option;
+ parser.on_argument = on_argument;
+ parser.on_error = on_option_error;
+ wasm_parse_options(&parser, argc, argv);
+
+ if (!s_infile) {
+ wasm_print_help(&parser, PROGRAM_NAME);
+ WASM_FATAL("No filename given.\n");
+ }
+}
+
+typedef struct Context {
+ WasmAllocator* allocator;
+ WasmMemoryWriter json_writer;
+ WasmMemoryWriter module_writer;
+ WasmStream json_stream;
+ WasmStringSlice output_filename_noext;
+ char* module_filename;
+ WasmResult result;
+} Context;
+
+int main(int argc, char** argv) {
+ WasmStackAllocator stack_allocator;
+ WasmAllocator* allocator;
+
+ wasm_init_stdio();
+ parse_options(argc, argv);
+
+ if (s_use_libc_allocator) {
+ allocator = &g_wasm_libc_allocator;
+ } else {
+ wasm_init_stack_allocator(&stack_allocator, &g_wasm_libc_allocator);
+ allocator = &stack_allocator.allocator;
+ }
+
+ WasmAstLexer* lexer = wasm_new_ast_file_lexer(allocator, s_infile);
+ if (!lexer)
+ WASM_FATAL("unable to read %s\n", s_infile);
+
+ WasmScript script;
+ WasmResult result = wasm_parse_ast(lexer, &script, &s_error_handler);
+
+ if (WASM_SUCCEEDED(result)) {
+ WasmModule* module = wasm_get_first_module(&script);
+ if (!module)
+ WASM_FATAL("no module in file.\n");
+
+ if (s_generate_names)
+ result = wasm_generate_names(allocator, module);
+
+ if (WASM_SUCCEEDED(result))
+ result = wasm_apply_names(allocator, module);
+
+ if (WASM_SUCCEEDED(result)) {
+ WasmFileWriter file_writer;
+ if (s_outfile) {
+ result = wasm_init_file_writer(&file_writer, s_outfile);
+ } else {
+ wasm_init_file_writer_existing(&file_writer, stdout);
+ }
+
+ if (WASM_SUCCEEDED(result)) {
+ result = wasm_write_ast(allocator, &file_writer.base, module);
+ wasm_close_file_writer(&file_writer);
+ }
+ }
+ }
+
+ wasm_destroy_ast_lexer(lexer);
+
+ if (s_use_libc_allocator)
+ wasm_destroy_script(&script);
+ wasm_print_allocator_stats(allocator);
+ wasm_destroy_allocator(allocator);
+ return result;
+}
+
diff --git a/src/wasm-ast.c b/src/wasm-ast.c
index 39fe7039..a6c4fe8a 100644
--- a/src/wasm-ast.c
+++ b/src/wasm-ast.c
@@ -272,6 +272,16 @@ int wasm_get_func_type_index_by_decl(const WasmModule* module,
}
}
+WasmModule* wasm_get_first_module(const WasmScript* script) {
+ size_t i;
+ for (i = 0; i < script->commands.size; ++i) {
+ WasmCommand* command = &script->commands.data[i];
+ if (command->type == WASM_COMMAND_TYPE_MODULE)
+ return &command->module;
+ }
+ return NULL;
+}
+
void wasm_make_type_binding_reverse_mapping(
struct WasmAllocator* allocator,
const WasmTypeVector* types,
diff --git a/src/wasm-ast.h b/src/wasm-ast.h
index 63bfa4a9..244a1cb7 100644
--- a/src/wasm-ast.h
+++ b/src/wasm-ast.h
@@ -511,6 +511,7 @@ WasmImportPtr wasm_get_import_by_var(const WasmModule* module,
const WasmVar* var);
WasmExportPtr wasm_get_export_by_name(const WasmModule* module,
const WasmStringSlice* name);
+WasmModule* wasm_get_first_module(const WasmScript* script);
void wasm_make_type_binding_reverse_mapping(
struct WasmAllocator*,
diff --git a/test/desugar/basic.txt b/test/desugar/basic.txt
new file mode 100644
index 00000000..0fe702eb
--- /dev/null
+++ b/test/desugar/basic.txt
@@ -0,0 +1,27 @@
+;;; TOOL: wast-desugar
+(module
+ (import "foo" "bar" (func (result i32)))
+
+ (global i32 (i32.const 1))
+
+ (table anyfunc (elem 0))
+
+ (memory (data "hello"))
+
+ (func (result i32)
+ (i32.add (call 0) (i32.load8_s (i32.const 1)))))
+(;; STDOUT ;;;
+(module
+ (import "foo" "bar" (func (;0;) (result i32)))
+ (type (;0;) (func (result i32)))
+ (global (;0;) i32 (i32.const 1))
+ (table (;0;) 1 1 anyfunc)
+ (elem (i32.const 0) 0)
+ (memory (;0;) 1 1)
+ (data (i32.const 0) "hello")
+ (func (;1;) (result i32)
+ call 0
+ i32.const 1
+ i32.load8_s
+ i32.add))
+;;; STDOUT ;;)
diff --git a/test/find_exe.py b/test/find_exe.py
index 5c0b66eb..53d23ba9 100644
--- a/test/find_exe.py
+++ b/test/find_exe.py
@@ -23,18 +23,17 @@ from utils import Error
IS_WINDOWS = sys.platform == 'win32'
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT_DIR = os.path.dirname(SCRIPT_DIR)
-DEFAULT_WAST2WASM_EXE = os.path.join(REPO_ROOT_DIR, 'out', 'wast2wasm')
-DEFAULT_WASM2WAST_EXE = os.path.join(REPO_ROOT_DIR, 'out', 'wasm2wast')
-DEFAULT_WASMDUMP_EXE = os.path.join(REPO_ROOT_DIR, 'out', 'wasmdump')
-DEFAULT_WASM_INTERP_EXE = os.path.join(REPO_ROOT_DIR, 'out', 'wasm-interp')
-DEFAULT_WASMOPCODECNT_EXE = os.path.join(REPO_ROOT_DIR, 'out', 'wasmopcodecnt')
+EXECUTABLES = [
+ 'wast2wasm', 'wasm2wast', 'wasmdump', 'wasm-interp', 'wasmopcodecnt',
+ 'wast-desugar'
+]
-if IS_WINDOWS:
- DEFAULT_WAST2WASM_EXE += '.exe'
- DEFAULT_WASM2WAST_EXE += '.exe'
- DEFAULT_WASM_INTERP_EXE += '.exe'
- DEFAULT_WASMOPCODECNT_EXE += '.exe'
+def GetDefaultExe(basename):
+ result = os.path.join(REPO_ROOT_DIR, 'out', basename)
+ if IS_WINDOWS:
+ result += '.exe'
+ return result
def FindExeWithFallback(name, default_exe_list, override_exe=None):
@@ -55,22 +54,29 @@ def FindExeWithFallback(name, default_exe_list, override_exe=None):
'\n'.join('search path: %s' % path for path in default_exe_list)))
+def FindExecutable(basename, override=None):
+ return FindExeWithFallback(basename, [GetDefaultExe(basename)], override)
+
+
def GetWast2WasmExecutable(override=None):
- return FindExeWithFallback('wast2wasm', [DEFAULT_WAST2WASM_EXE], override)
+ return FindExecutable('wast2wasm', override)
def GetWasm2WastExecutable(override=None):
- return FindExeWithFallback('wasm2wast', [DEFAULT_WASM2WAST_EXE], override)
+ return FindExecutable('wasm2wast', override)
def GetWasmdumpExecutable(override=None):
- return FindExeWithFallback('wasmdump', [DEFAULT_WASMDUMP_EXE], override)
+ return FindExecutable('wasmdump', override)
def GetWasmInterpExecutable(override=None):
- return FindExeWithFallback('wasm-interp', [DEFAULT_WASM_INTERP_EXE], override)
+ return FindExecutable('wasm-interp', override)
def GetWasmOpcodeCntExecutable(override=None):
- return FindExeWithFallback('wasmopcodecnt', [DEFAULT_WASMOPCODECNT_EXE],
- override)
+ return FindExecutable('wasmopcodecnt', override)
+
+
+def GetWastDesugarExecutable(override=None):
+ return FindExecutable('wast-desugar', override)
diff --git a/test/run-tests.py b/test/run-tests.py
index 57099280..ba544d98 100755
--- a/test/run-tests.py
+++ b/test/run-tests.py
@@ -54,6 +54,9 @@ TOOLS = {
'EXE': '%(wast2wasm)s',
'VERBOSE-FLAGS': ['-v']
},
+ 'wast-desugar': {
+ 'EXE': '%(wast-desugar)s'
+ },
'run-wasmdump': {
'EXE': 'test/run-wasmdump.py',
'FLAGS': ' '.join([
@@ -688,16 +691,9 @@ def main(args):
help='directory to search for all executables. '
'This can be overridden by the other executable '
'flags.')
- parser.add_argument('--wast2wasm', metavar='PATH',
- help='override wast2wasm executable.')
- parser.add_argument('--wasm2wast', metavar='PATH',
- help='override wasm2wast executable.')
- parser.add_argument('--wasmdump', metavar='PATH',
- help='override wasmdump executable.')
- parser.add_argument('--wasm-interp', metavar='PATH',
- help='override wasm-interp executable.')
- parser.add_argument('--wasmopcodecnt', metavar='PATH',
- help='override wasmopcodecnt executable.')
+ for exe_basename in find_exe.EXECUTABLES:
+ parser.add_argument('--%s' % exe_basename, metavar='PATH',
+ help='override %s executable.' % exe_basename)
parser.add_argument('-v', '--verbose', help='print more diagnotic messages.',
action='store_true')
parser.add_argument('-f', '--fail-fast',
@@ -746,25 +742,18 @@ def main(args):
print('no tests match that filter')
return 1
- if options.exe_dir:
- if not options.wast2wasm:
- options.wast2wasm = os.path.join(options.exe_dir, 'wast2wasm')
- if not options.wasm2wast:
- options.wasm2wast = os.path.join(options.exe_dir, 'wasm2wast')
- if not options.wasm_interp:
- options.wasm_interp = os.path.join(options.exe_dir, 'wasm-interp')
- if not options.wasmopcodecnt:
- options.wasmopcodecnt = os.path.join(options.exe_dir, 'wasmopcodecnt')
- if not options.wasmdump:
- options.wasmdump = os.path.join(options.exe_dir, 'wasmdump')
-
- variables = {
- 'wast2wasm': find_exe.GetWast2WasmExecutable(options.wast2wasm),
- 'wasm2wast': find_exe.GetWasm2WastExecutable(options.wasm2wast),
- 'wasmdump': find_exe.GetWasmdumpExecutable(options.wasmdump),
- 'wasm-interp': find_exe.GetWasmInterpExecutable(options.wasm_interp),
- 'wasmopcodecnt': find_exe.GetWasmOpcodeCntExecutable(options.wasmopcodecnt),
- }
+ variables = {}
+
+ for exe_basename in find_exe.EXECUTABLES:
+ attr_name = exe_basename.replace('-', '_')
+ exe_override = getattr(options, attr_name)
+ if options.exe_dir:
+ if not exe_override:
+ exe_override = os.path.join(options.exe_dir, exe_basename)
+ setattr(options, attr_name, exe_override)
+
+ variables[exe_basename] = find_exe.FindExecutable(exe_basename,
+ exe_override)
status = Status(options.verbose)
infos = GetAllTestInfo(test_names, status)