diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 125 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | src/emscripten-exported.json | 45 | ||||
-rw-r--r-- | src/wasm-allocator.c | 4 | ||||
-rw-r--r-- | src/wasm-allocator.h | 2 | ||||
-rw-r--r-- | src/wasm-emscripten-helpers.c | 94 | ||||
-rw-r--r-- | src/wasm.js | 278 |
8 files changed, 519 insertions, 38 deletions
@@ -2,6 +2,7 @@ /out /third_party/v8/depot_tools /fuzz-out +/emscripten *.pyc #Visual Studio Products diff --git a/CMakeLists.txt b/CMakeLists.txt index f1bfd83c..35fb4e58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,17 +37,26 @@ endif () include(CheckIncludeFile) include(CheckSymbolExists) -include(CheckTypeSize) check_include_file("alloca.h" HAVE_ALLOCA_H) check_include_file("unistd.h" HAVE_UNISTD_H) check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) check_symbol_exists(sysconf "unistd.h" HAVE_SYSCONF) -check_type_size(ssize_t SSIZE_T) -check_type_size(size_t SIZEOF_SIZE_T) -check_type_size(int SIZEOF_INT BUILTIN_TYPES_ONLY) -check_type_size(long SIZEOF_LONG BUILTIN_TYPES_ONLY) -check_type_size("long long" SIZEOF_LONG_LONG BUILTIN_TYPES_ONLY) + +if (EMSCRIPTEN) + set(SIZEOF_SSIZE_T 4) + set(SIZEOF_SIZE_T 4) + set(SIZEOF_INT 4) + set(SIZEOF_LONG 4) + set(SIZEOF_LONG_LONG 8) +else () + include(CheckTypeSize) + check_type_size(ssize_t SSIZE_T) + check_type_size(size_t SIZEOF_SIZE_T) + check_type_size(int SIZEOF_INT BUILTIN_TYPES_ONLY) + check_type_size(long SIZEOF_LONG BUILTIN_TYPES_ONLY) + check_type_size("long long" SIZEOF_LONG_LONG BUILTIN_TYPES_ONLY) +endif () configure_file( ${SEXPR_WASM_SOURCE_DIR}/src/wasm-config.h.in @@ -75,43 +84,45 @@ else () add_definitions(-Wno-clobbered) endif () - # try to get the target architecture by compiling a dummy.c file and checking - # the architecture using the file command. - file(WRITE ${SEXPR_WASM_BINARY_DIR}/dummy.c "main(){}") - try_compile( - COMPILE_OK - ${SEXPR_WASM_BINARY_DIR} - ${SEXPR_WASM_BINARY_DIR}/dummy.c - COPY_FILE ${SEXPR_WASM_BINARY_DIR}/dummy - ) - if (COMPILE_OK) - execute_process( - COMMAND file ${SEXPR_WASM_BINARY_DIR}/dummy - RESULT_VARIABLE FILE_RESULT - OUTPUT_VARIABLE FILE_OUTPUT - ERROR_QUIET + if (NOT EMSCRIPTEN) + # try to get the target architecture by compiling a dummy.c file and + # checking the architecture using the file command. + file(WRITE ${SEXPR_WASM_BINARY_DIR}/dummy.c "main(){}") + try_compile( + COMPILE_OK + ${SEXPR_WASM_BINARY_DIR} + ${SEXPR_WASM_BINARY_DIR}/dummy.c + COPY_FILE ${SEXPR_WASM_BINARY_DIR}/dummy ) + if (COMPILE_OK) + execute_process( + COMMAND file ${SEXPR_WASM_BINARY_DIR}/dummy + RESULT_VARIABLE FILE_RESULT + OUTPUT_VARIABLE FILE_OUTPUT + ERROR_QUIET + ) - if (FILE_RESULT EQUAL 0) - if (${FILE_OUTPUT} MATCHES "x86-64") - set(TARGET_ARCH "x86-64") - elseif (${FILE_OUTPUT} MATCHES "Intel 80386") - set(TARGET_ARCH "i386") - elseif (${FILE_OUTPUT} MATCHES "ARM") - set(TARGET_ARCH "ARM") + if (FILE_RESULT EQUAL 0) + if (${FILE_OUTPUT} MATCHES "x86-64") + set(TARGET_ARCH "x86-64") + elseif (${FILE_OUTPUT} MATCHES "Intel 80386") + set(TARGET_ARCH "i386") + elseif (${FILE_OUTPUT} MATCHES "ARM") + set(TARGET_ARCH "ARM") + else () + message(WARNING "Unknown target architecture!") + endif () else () - message(WARNING "Unknown target architecture!") + message(WARNING "Error running file on dummy executable") endif () else () - message(WARNING "Error running file on dummy executable") + message(WARNING "Error compiling dummy.c file") endif () - else () - message(WARNING "Error compiling dummy.c file") - endif () - if (TARGET_ARCH STREQUAL "i386") - # wasm doesn't allow for x87 floating point math - add_definitions(-msse2 -mfpmath=sse) + if (TARGET_ARCH STREQUAL "i386") + # wasm doesn't allow for x87 floating point math + add_definitions(-msse2 -mfpmath=sse) + endif () endif () endif () @@ -248,6 +259,48 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/squirrel/squirrel) endif () +# emscripten stuff +if (EMSCRIPTEN) + # just dump everything into one binary so we can reference it from JavaScript + add_executable(libwasm + src/wasm-apply-names.c + src/wasm-ast.c + src/wasm-ast-checker.c + src/wasm-ast-writer.c + src/wasm-binary-reader-ast.c + src/wasm-binary-reader.c + src/wasm-binary-writer.c + src/wasm-binary-writer-spec.c + src/wasm-emscripten-helpers.c + src/wasm-generate-names.c + src/wasm-literal.c + src/wasm-mark-used-blocks.c + src/wasm-parser-lexer-shared.c + ${BISON_PARSER_C} + ${FLEX_LEXER_C} + ) + add_dependencies(everything libwasm) + target_link_libraries(libwasm wasm-interp-common wasm-common) + + set(WASM_JS ${SEXPR_WASM_SOURCE_DIR}/src/wasm.js) + set(EMSCRIPTEN_EXPORTED_JSON + ${SEXPR_WASM_SOURCE_DIR}/src/emscripten-exported.json) + + set(LIBWASM_LINK_FLAGS + --post-js ${WASM_JS} + -s EXPORTED_FUNCTIONS=\"@${EMSCRIPTEN_EXPORTED_JSON}\" + -s RESERVED_FUNCTION_POINTERS=10 + ) + string(REPLACE ";" " " LIBWASM_LINK_FLAGS_STR "${LIBWASM_LINK_FLAGS}") + + set_target_properties(libwasm + PROPERTIES + LINK_FLAGS "${LIBWASM_LINK_FLAGS_STR}" + LINK_DEPENDS "${WASM_JS};${EMSCRIPTEN_EXPORTED_JSON}" + ) +endif () + + # hexfloat-test option(BUILD_TESTS "Build GTest-based tests" ON) find_package(Threads) @@ -20,14 +20,15 @@ MAKEFILE_NAME := $(lastword $(MAKEFILE_LIST)) ROOT_DIR := $(dir $(abspath $(MAKEFILE_NAME))) USE_NINJA ?= 0 -FUZZ_BIN_DIR ?= afl-fuzz +FUZZ_BIN_DIR ?= ${ROOT_DIR}/afl-fuzz GCC_FUZZ_CC := ${FUZZ_BIN_DIR}/afl-gcc GCC_FUZZ_CXX := ${FUZZ_BIN_DIR}/afl-g++ +EMSCRIPTEN_DIR ?= ${ROOT_DIR}/emscripten DEFAULT_COMPILER = CLANG DEFAULT_BUILD_TYPE = DEBUG -COMPILERS := GCC GCC_I686 GCC_FUZZ CLANG +COMPILERS := GCC GCC_I686 GCC_FUZZ CLANG EMSCRIPTEN BUILD_TYPES := DEBUG RELEASE SANITIZERS := ASAN MSAN LSAN CONFIGS := NORMAL ASAN MSAN LSAN NO_FLEX_BISON NO_TESTS @@ -38,6 +39,7 @@ GCC_DIR := gcc/ GCC_I686_DIR := gcc-i686/ GCC_FUZZ_DIR := gcc-fuzz/ CLANG_DIR := clang/ +EMSCRIPTEN_DIR := emscripten/ DEBUG_DIR := Debug/ RELEASE_DIR := Release/ NORMAL_DIR := @@ -53,6 +55,7 @@ GCC_I686_FLAG := -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ \ -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 GCC_FUZZ_FLAG := -DCMAKE_C_COMPILER=${GCC_FUZZ_CC} -DCMAKE_CXX_COMPILER=${GCC_FUZZ_CXX} CLANG_FLAG := -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ +EMSCRIPTEN_FLAG := -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_DIR}/cmake/Modules/Platform/Emscripten.cmake DEBUG_FLAG := -DCMAKE_BUILD_TYPE=Debug RELEASE_FLAG := -DCMAKE_BUILD_TYPE=Release NORMAL_FLAG := @@ -67,6 +70,7 @@ GCC_PREFIX := gcc GCC_I686_PREFIX := gcc-i686 GCC_FUZZ_PREFIX := gcc-fuzz CLANG_PREFIX := clang +EMSCRIPTEN_PREFIX := emscripten DEBUG_PREFIX := -debug RELEASE_PREFIX := -release NORMAL_PREFIX := diff --git a/src/emscripten-exported.json b/src/emscripten-exported.json new file mode 100644 index 00000000..3e7b04df --- /dev/null +++ b/src/emscripten-exported.json @@ -0,0 +1,45 @@ +[ +"_wasm_check_assert_invalid", +"_wasm_check_ast", +"_wasm_close_mem_writer", +"_wasm_default_assert_invalid_source_error_callback", +"_wasm_default_source_error_callback", +"_wasm_destroy_lexer", +"_wasm_destroy_script", +"_wasm_destroy_stack_allocator", +"_wasm_get_libc_allocator", +"_wasm_init_mem_writer", +"_wasm_init_stack_allocator", +"_wasm_mark_used_blocks", +"_wasm_new_buffer_lexer", +"_wasm_new_file_lexer", +"_wasm_offsetof_allocator_alloc", +"_wasm_offsetof_allocator_destroy", +"_wasm_offsetof_allocator_free", +"_wasm_offsetof_allocator_mark", +"_wasm_offsetof_allocator_print_stats", +"_wasm_offsetof_allocator_realloc", +"_wasm_offsetof_allocator_reset_to_mark", +"_wasm_offsetof_binary_error_handler_on_error", +"_wasm_offsetof_binary_error_handler_user_data", +"_wasm_offsetof_location_filename", +"_wasm_offsetof_location_first_column", +"_wasm_offsetof_location_last_column", +"_wasm_offsetof_location_line", +"_wasm_offsetof_source_error_handler_on_error", +"_wasm_offsetof_source_error_handler_source_line_max_length", +"_wasm_offsetof_source_error_handler_user_data", +"_wasm_offsetof_stack_allocator_allocator", +"_wasm_offsetof_string_slice_length", +"_wasm_offsetof_string_slice_start", +"_wasm_parse", +"_wasm_sizeof_allocator", +"_wasm_sizeof_binary_error_handler", +"_wasm_sizeof_location", +"_wasm_sizeof_script", +"_wasm_sizeof_source_error_handler", +"_wasm_sizeof_stack_allocator", +"_wasm_sizeof_string_slice", +"_wasm_write_binary_script", +"_wasm_write_binary_spec_script" +] diff --git a/src/wasm-allocator.c b/src/wasm-allocator.c index 0c4a0d0b..8be4b222 100644 --- a/src/wasm-allocator.c +++ b/src/wasm-allocator.c @@ -110,3 +110,7 @@ static void libc_print_stats(WasmAllocator* allocator) { WasmAllocator g_wasm_libc_allocator = { libc_alloc, libc_realloc, libc_free, libc_destroy, libc_mark, libc_reset_to_mark, libc_print_stats}; + +WasmAllocator* wasm_get_libc_allocator(void) { + return &g_wasm_libc_allocator; +} diff --git a/src/wasm-allocator.h b/src/wasm-allocator.h index 9c9deb18..6425cdad 100644 --- a/src/wasm-allocator.h +++ b/src/wasm-allocator.h @@ -78,6 +78,8 @@ extern WasmAllocator g_wasm_libc_allocator; WASM_EXTERN_C_BEGIN +WasmAllocator* wasm_get_libc_allocator(void); + static WASM_INLINE void* wasm_alloc_zero_(WasmAllocator* allocator, size_t size, size_t align, diff --git a/src/wasm-emscripten-helpers.c b/src/wasm-emscripten-helpers.c new file mode 100644 index 00000000..04fb5a84 --- /dev/null +++ b/src/wasm-emscripten-helpers.c @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef WASM_EMSCRIPTEN_HELPERS_H_ +#define WASM_EMSCRIPTEN_HELPERS_H_ + +#include <stddef.h> + +#include "wasm-allocator.h" +#include "wasm-ast.h" +#include "wasm-common.h" +#include "wasm-stack-allocator.h" + +/* TODO(binji): it would be nicer to generate this as static data, but it's not + * currently easy to do. Maybe use LLVM's python bindings for this? */ + +#define WASM_DEFINE_SIZEOF(Name, name) \ + size_t wasm_sizeof_##name(void) { return sizeof(Name); } + +#define WASM_DEFINE_OFFSETOF(Name, name, member) \ + size_t wasm_offsetof_##name##_##member(void) { \ + return offsetof(Name, member); \ + } + +/* See http://stackoverflow.com/a/1872506 */ +#define CONCAT(a, b) CONCAT_(a, b) +#define CONCAT_(a, b) CONCAT__(a, b) +#define CONCAT__(a, b) a##b +#define FOREACH_1(m, S, s, x, ...) m(S, s, x) +#define FOREACH_2(m, S, s, x, ...) m(S, s, x) FOREACH_1(m, S, s, __VA_ARGS__) +#define FOREACH_3(m, S, s, x, ...) m(S, s, x) FOREACH_2(m, S, s, __VA_ARGS__) +#define FOREACH_4(m, S, s, x, ...) m(S, s, x) FOREACH_3(m, S, s, __VA_ARGS__) +#define FOREACH_5(m, S, s, x, ...) m(S, s, x) FOREACH_4(m, S, s, __VA_ARGS__) +#define FOREACH_6(m, S, s, x, ...) m(S, s, x) FOREACH_5(m, S, s, __VA_ARGS__) +#define FOREACH_7(m, S, s, x, ...) m(S, s, x) FOREACH_6(m, S, s, __VA_ARGS__) +#define FOREACH_8(m, S, s, x, ...) m(S, s, x) FOREACH_7(m, S, s, __VA_ARGS__) +#define NARG(...) NARG_(__VA_ARGS__, RSEQ_N()) +#define NARG_(...) ARG_N(__VA_ARGS__) +#define ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N +#define RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define FOREACH(m, S, s, ...) FOREACH_(NARG(__VA_ARGS__), m, S, s, __VA_ARGS__) +#define FOREACH_(N, m, S, s, ...) CONCAT(FOREACH_, N)(m, S, s, __VA_ARGS__) +#define WASM_DEFINE_STRUCT0(Name, name) WASM_DEFINE_SIZEOF(Name, name) +#define WASM_DEFINE_STRUCT(Name, name, ...) \ + WASM_DEFINE_SIZEOF(Name, name) \ + FOREACH(WASM_DEFINE_OFFSETOF, Name, name, __VA_ARGS__) + +WASM_EXTERN_C_BEGIN + +/* clang-format off */ +WASM_DEFINE_STRUCT( + WasmAllocator, allocator, + alloc, realloc, free, destroy, mark, reset_to_mark, print_stats) + +WASM_DEFINE_STRUCT( + WasmBinaryErrorHandler, binary_error_handler, + on_error, user_data) + +WASM_DEFINE_STRUCT( + WasmLocation, location, + filename, line, first_column, last_column) + +WASM_DEFINE_STRUCT0( + WasmScript, script) + +WASM_DEFINE_STRUCT( + WasmSourceErrorHandler, source_error_handler, + on_error, source_line_max_length, user_data) + +WASM_DEFINE_STRUCT( + WasmStackAllocator, stack_allocator, + allocator); + +WASM_DEFINE_STRUCT( + WasmStringSlice, string_slice, + start, length) +/* clang-format on */ + +WASM_EXTERN_C_END + +#endif /* WASM_EMSCRIPTEN_HELPERS_H_ */ diff --git a/src/wasm.js b/src/wasm.js new file mode 100644 index 00000000..98e1dbe6 --- /dev/null +++ b/src/wasm.js @@ -0,0 +1,278 @@ +/* + * 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. + */ + +var wasm = (function() { + +var OK = 0; +var ERROR = 1; + +// Helpers ///////////////////////////////////////////////////////////////////// +function malloc(size) { + var addr = Module._malloc(size); + if (addr == 0) + throw "malloc failed"; + return addr; +} + +function mallocz(size) { + var addr = malloc(size); + HEAP8.fill(0, addr, addr + size); + return addr; +} + +function free(p) { Module._free(p); } + +function decorateStruct(struct, structName, members) { + struct.prototype = Object.create(Object.prototype); + struct.$size = Module['_wasm_sizeof_' + structName](); + struct.$allocate = function() { return mallocz(this.$size); }; + struct.prototype.$free = function() { return free(this.$addr); }; + struct.prototype.$destroy = function() { return this.$free(); }; + struct.$newAt = function(addr) { + var this_ = Object.create(this.prototype); + var args = Array.prototype.slice.call(arguments, 1); + this_.$addr = addr; + this_.$init.apply(this_, args); + return this_; + }; + defineOffsets(struct.prototype, structName, members); +} + +function defineOffsets(proto, structName, members) { + for (var i = 0; i < members.length; ++i) { + var offsetName = '$offsetof_' + members[i]; + var funcName = '_wasm_offsetof_' + structName + '_' + members[i]; + proto[offsetName] = Module[funcName](); + } +} + +function loadi8(addr) { return HEAP8[addr]; } +function loadu8(addr) { return HEAPU8[addr]; } +function loadi16(addr) { return HEAP16[addr >> 1]; } +function loadu16(addr) { return HEAPU16[addr >> 1]; } +function loadi32(addr) { return HEAP32[addr >> 2]; } +function loadu32(addr) { return HEAPU32[addr >> 2]; } + +function storei8(addr, value) { HEAP8[addr] = value; } +function storeu8(addr, value) { HEAPU8[addr] = value; } +function storei16(addr, value) { HEAP16[addr >> 1] = value; } +function storeu16(addr, value) { HEAPU16[addr >> 1] = value; } +function storei32(addr, value) { HEAP32[addr >> 2] = value; } +function storeu32(addr, value) { HEAPU32[addr >> 2] = value; } + +function allocateString(str) { + var len = str.length + 1; + var mem = malloc(len); + Module.writeAsciiToMemory(str, mem); + return mem; +} + +function freeString(mem) { + free(mem); +} + +// Allocator /////////////////////////////////////////////////////////////////// +Allocator = function() { + throw "Allocator is an abstract base class"; +}; +decorateStruct(Allocator, 'allocator', + ['alloc', 'realloc', 'free', 'destroy', 'mark', 'reset_to_mark', + 'print_stats']); +Allocator.prototype.$init = function() { + this.$alloc = loadu32(this.$addr + this.$offsetof_alloc); + this.$realloc = loadu32(this.$addr + this.$offsetof_realloc); + this.$free = loadu32(this.$addr + this.$offsetof_free); + this.$destroy = loadu32(this.$addr + this.$offsetof_destroy); + this.$mark = loadu32(this.$addr + this.$offsetof_mark); + this.$reset_to_mark = loadu32(this.$addr + this.$offsetof_reset_to_mark); + this.$print_stats = loadu32(this.$addr + this.$offsetof_print_stats); +}; +Allocator.prototype.alloc = function(size, align) { + return Runtime.dynCall('iiiiii', this.$alloc, + [this.$addr, size, align, 0, 0]); +}; +Allocator.prototype.realloc = function(p, size, align) { + return Runtime.dynCall('iiiiiii', this.$realloc, + [this.$addr, p, size, align, 0, 0]); +}; +Allocator.prototype.free = function(p) { + Runtime.dynCall('viiii', this.$free, [this.$addr, p, 0, 0]); +}; +Allocator.prototype.destroy = function() { + Runtime.dynCall('vi', this.$destroy, [this.$addr]); +}; +Allocator.prototype.mark = function() { + Runtime.dynCall('ii', this.$mark, [this.$addr]); +}; +Allocator.prototype.resetToMark = function(mark) { + Runtime.dynCall('vii', this.$reset_to_mark, [this.$addr, mark]); +}; +Allocator.prototype.printStats = function() { + Runtime.dynCall('vi', this.$print_stats, [this.$addr]); +}; + +LibcAllocator = Allocator.$newAt(Module._wasm_get_libc_allocator()); + +// Buffer ////////////////////////////////////////////////////////////////////// +Buffer = function(size) { + this.$addr = mallocz(size); + this.$size = size; +}; +Buffer.prototype = Object.create(Object.prototype); +Buffer.fromString = function(str) { + var this_ = Object.create(Buffer.prototype); + this_.$size = str.length; + this_.$addr = malloc(this_.$size); + Module.writeAsciiToMemory(str, this_.$addr, true); // don't null-terminate + return this_; +}; +Buffer.prototype.$free = function() { free(this.$addr); }; +Buffer.prototype.$destroy = function() { this.$free(); }; + +// Lexer /////////////////////////////////////////////////////////////////////// +Lexer = function() { + throw "Lexer must be created with $fromFile or $fromBuffer"; +}; +Lexer.prototype = Object.create(Object.prototype); +Lexer.fromFile = function(allocator, filename) { + var $filename = allocateString(filename); + var addr = Module._wasm_new_file_lexer(allocator.$addr, $filename); + if (addr == 0) + throw "Lexer.fromFile failed"; + var this_ = Object.create(Lexer.prototype); + this_.$addr = addr; + this_.$filename = $filename; + return this_; +}; +Lexer.fromBuffer = function(allocator, filename, buffer) { + var $filename = allocateString(filename); + var addr = Module._wasm_new_buffer_lexer(allocator.$addr, $filename, + buffer.$addr, buffer.$size); + if (addr == 0) + throw "Lexer.fromBuffer failed"; + var this_ = Object.create(Lexer.prototype); + this_.$addr = addr; + this_.$filename = $filename; + return this_; +}; +Lexer.prototype.$destroy = function() { + Module._wasm_destroy_lexer(this.$addr); + freeString(this.$filename); +}; + +// Location //////////////////////////////////////////////////////////////////// +Location = function() { + this.$addr = Location.$allocate(); + this.$init(); +}; +decorateStruct(Location, 'location', + ['filename', 'line', 'first_column', 'last_column']); +Location.prototype.$init = function() { + this.filename = + Module.AsciiToString(loadu32(this.$addr + this.$offsetof_filename)); + this.line = loadu32(this.$addr + this.$offsetof_line); + this.firstColumn = loadu32(this.$addr + this.$offsetof_first_column); + this.lastColumn = loadu32(this.$addr + this.$offsetof_last_column); +}; + +// Script ////////////////////////////////////////////////////////////////////// +Script = function() { + this.$addr = Script.$allocate(); + this.$init(); +}; +decorateStruct(Script, 'script', []); +Script.prototype.$init = function() {}; + +// SourceErrorHandler ////////////////////////////////////////////////////////// +SourceErrorHandler = function(callback, sourceLineMaxLength) { + this.$addr = SourceErrorHandler.$allocate(); + this.$init(callback, sourceLineMaxLength); +} +decorateStruct(SourceErrorHandler, 'source_error_handler', + ['on_error', 'source_line_max_length', 'user_data']); +SourceErrorHandler.prototype.$init = + function(onError, sourceLineMaxLength) { + var f; + if (onError) { + f = function(loc, error, sourceLine, sourceLineLength, + sourceLineColumnOffset, userData) { + loc = Location.$newAt(loc); + error = Module.AsciiToString(error); + sourceLine = Module.Pointer_stringify(sourceLine, sourceLineLength); + onError(loc, error, sourceLine, sourceLineColumnOffset); + }; + } else { + f = function() { + Module._wasm_default_source_error_callback.apply(null, arguments); + }; + } + this.index = Runtime.addFunction(f); + storeu32(this.$addr + this.$offsetof_on_error, this.index); + storeu32(this.$addr + this.$offsetof_source_line_max_length, + sourceLineMaxLength); +}; +SourceErrorHandler.prototype.$destroy = function() { + Runtime.removeFunction(this.index); + this.$free(); +}; + +// StackAllocator ////////////////////////////////////////////////////////////// +StackAllocator = function(fallback) { + this.$addr = StackAllocator.$allocate(); + this.$init(fallback); +} +decorateStruct(StackAllocator, 'stack_allocator', ['allocator']); +StackAllocator.prototype.$init = function(fallback) { + Module._wasm_init_stack_allocator(this.$addr, fallback.$addr); + this.allocator = Allocator.$newAt(this.$addr + this.$offsetof_allocator); +}; +StackAllocator.prototype.$destroy = function() { + Module._wasm_destroy_stack_allocator(this.$addr); +}; + +// Free functions ////////////////////////////////////////////////////////////// +parse = function(lexer, errorHandler) { + var script = new Script(); + var result = + Module._wasm_parse(lexer.$addr, script.$addr, errorHandler.$addr); + if (result != OK) + throw "parse failed"; + return script; +}; + +checkAst = function(lexer, script, errorHandler) { + var result = + Module._wasm_check_ast(lexer.$addr, script.$addr, errorHandler.$addr); + if (result != OK) + throw "check failed"; +}; + +return { + OK: OK, + ERROR: ERROR, + Allocator: Allocator, + Buffer: Buffer, + Lexer: Lexer, + LibcAllocator: LibcAllocator, + Location: Location, + Script: Script, + SourceErrorHandler: SourceErrorHandler, + StackAllocator: StackAllocator, + parse: parse, + checkAst: checkAst, +}; + +})(); |