diff options
Diffstat (limited to 'src/ast.cc')
-rw-r--r-- | src/ast.cc | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/src/ast.cc b/src/ast.cc new file mode 100644 index 00000000..80d41f53 --- /dev/null +++ b/src/ast.cc @@ -0,0 +1,716 @@ +/* + * 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 "ast.h" + +#include <assert.h> +#include <stddef.h> + +int wabt_get_index_from_var(const WabtBindingHash* hash, const WabtVar* var) { + if (var->type == WABT_VAR_TYPE_NAME) + return wabt_find_binding_index_by_name(hash, &var->name); + return (int)var->index; +} + +WabtExportPtr wabt_get_export_by_name(const WabtModule* module, + const WabtStringSlice* name) { + int index = wabt_find_binding_index_by_name(&module->export_bindings, name); + if (index == -1) + return NULL; + return module->exports.data[index]; +} + +int wabt_get_func_index_by_var(const WabtModule* module, const WabtVar* var) { + return wabt_get_index_from_var(&module->func_bindings, var); +} + +int wabt_get_global_index_by_var(const WabtModule* module, const WabtVar* var) { + return wabt_get_index_from_var(&module->global_bindings, var); +} + +int wabt_get_table_index_by_var(const WabtModule* module, const WabtVar* var) { + return wabt_get_index_from_var(&module->table_bindings, var); +} + +int wabt_get_memory_index_by_var(const WabtModule* module, const WabtVar* var) { + return wabt_get_index_from_var(&module->memory_bindings, var); +} + +int wabt_get_func_type_index_by_var(const WabtModule* module, + const WabtVar* var) { + return wabt_get_index_from_var(&module->func_type_bindings, var); +} + +int wabt_get_local_index_by_var(const WabtFunc* func, const WabtVar* var) { + if (var->type == WABT_VAR_TYPE_INDEX) + return (int)var->index; + + int result = + wabt_find_binding_index_by_name(&func->param_bindings, &var->name); + if (result != -1) + return result; + + result = wabt_find_binding_index_by_name(&func->local_bindings, &var->name); + if (result == -1) + return result; + + /* the locals start after all the params */ + return func->decl.sig.param_types.size + result; +} + +int wabt_get_module_index_by_var(const WabtScript* script, const WabtVar* var) { + return wabt_get_index_from_var(&script->module_bindings, var); +} + +WabtFuncPtr wabt_get_func_by_var(const WabtModule* module, const WabtVar* var) { + int index = wabt_get_index_from_var(&module->func_bindings, var); + if (index < 0 || (size_t)index >= module->funcs.size) + return NULL; + return module->funcs.data[index]; +} + +WabtGlobalPtr wabt_get_global_by_var(const WabtModule* module, + const WabtVar* var) { + int index = wabt_get_index_from_var(&module->global_bindings, var); + if (index < 0 || (size_t)index >= module->globals.size) + return NULL; + return module->globals.data[index]; +} + +WabtTablePtr wabt_get_table_by_var(const WabtModule* module, + const WabtVar* var) { + int index = wabt_get_index_from_var(&module->table_bindings, var); + if (index < 0 || (size_t)index >= module->tables.size) + return NULL; + return module->tables.data[index]; +} + +WabtMemoryPtr wabt_get_memory_by_var(const WabtModule* module, + const WabtVar* var) { + int index = wabt_get_index_from_var(&module->memory_bindings, var); + if (index < 0 || (size_t)index >= module->memories.size) + return NULL; + return module->memories.data[index]; +} + +WabtFuncTypePtr wabt_get_func_type_by_var(const WabtModule* module, + const WabtVar* var) { + int index = wabt_get_index_from_var(&module->func_type_bindings, var); + if (index < 0 || (size_t)index >= module->func_types.size) + return NULL; + return module->func_types.data[index]; +} + +int wabt_get_func_type_index_by_sig(const WabtModule* module, + const WabtFuncSignature* sig) { + size_t i; + for (i = 0; i < module->func_types.size; ++i) + if (wabt_signatures_are_equal(&module->func_types.data[i]->sig, sig)) + return i; + return -1; +} + +int wabt_get_func_type_index_by_decl(const WabtModule* module, + const WabtFuncDeclaration* decl) { + if (wabt_decl_has_func_type(decl)) { + return wabt_get_func_type_index_by_var(module, &decl->type_var); + } else { + return wabt_get_func_type_index_by_sig(module, &decl->sig); + } +} + +WabtModule* wabt_get_first_module(const WabtScript* script) { + size_t i; + for (i = 0; i < script->commands.size; ++i) { + WabtCommand* command = &script->commands.data[i]; + if (command->type == WABT_COMMAND_TYPE_MODULE) + return &command->module; + } + return NULL; +} + +WabtModule* wabt_get_module_by_var(const WabtScript* script, + const WabtVar* var) { + int index = wabt_get_index_from_var(&script->module_bindings, var); + if (index < 0 || (size_t)index >= script->commands.size) + return NULL; + WabtCommand* command = &script->commands.data[index]; + assert(command->type == WABT_COMMAND_TYPE_MODULE); + return &command->module; +} + +void wabt_make_type_binding_reverse_mapping( + const WabtTypeVector* types, + const WabtBindingHash* bindings, + WabtStringSliceVector* out_reverse_mapping) { + uint32_t num_names = types->size; + wabt_reserve_string_slices(out_reverse_mapping, num_names); + out_reverse_mapping->size = num_names; + memset(out_reverse_mapping->data, 0, num_names * sizeof(WabtStringSlice)); + + /* map index to name */ + size_t i; + for (i = 0; i < bindings->entries.capacity; ++i) { + const WabtBindingHashEntry* entry = &bindings->entries.data[i]; + if (wabt_hash_entry_is_free(entry)) + continue; + + uint32_t index = entry->binding.index; + assert(index < out_reverse_mapping->size); + out_reverse_mapping->data[index] = entry->binding.name; + } +} + +void wabt_find_duplicate_bindings(const WabtBindingHash* bindings, + WabtDuplicateBindingCallback callback, + void* user_data) { + size_t i; + for (i = 0; i < bindings->entries.capacity; ++i) { + WabtBindingHashEntry* entry = &bindings->entries.data[i]; + if (wabt_hash_entry_is_free(entry)) + continue; + + /* only follow the chain if this is the first entry in the chain */ + if (entry->prev != NULL) + continue; + + WabtBindingHashEntry* a = entry; + for (; a; a = a->next) { + WabtBindingHashEntry* b = a->next; + for (; b; b = b->next) { + if (wabt_string_slices_are_equal(&a->binding.name, &b->binding.name)) + callback(a, b, user_data); + } + } + } +} + +WabtModuleField* wabt_append_module_field(WabtModule* module) { + WabtModuleField* result = + (WabtModuleField*)wabt_alloc_zero(sizeof(WabtModuleField)); + if (!module->first_field) + module->first_field = result; + else if (module->last_field) + module->last_field->next = result; + module->last_field = result; + return result; +} + +WabtFuncType* wabt_append_implicit_func_type(WabtLocation* loc, + WabtModule* module, + WabtFuncSignature* sig) { + WabtModuleField* field = wabt_append_module_field(module); + field->loc = *loc; + field->type = WABT_MODULE_FIELD_TYPE_FUNC_TYPE; + field->func_type.sig = *sig; + + WabtFuncType* func_type_ptr = &field->func_type; + wabt_append_func_type_ptr_value(&module->func_types, &func_type_ptr); + return func_type_ptr; +} + +#define FOREACH_EXPR_TYPE(V) \ + V(WABT_EXPR_TYPE_BINARY, binary) \ + V(WABT_EXPR_TYPE_BLOCK, block) \ + V(WABT_EXPR_TYPE_BR, br) \ + V(WABT_EXPR_TYPE_BR_IF, br_if) \ + V(WABT_EXPR_TYPE_BR_TABLE, br_table) \ + V(WABT_EXPR_TYPE_CALL, call) \ + V(WABT_EXPR_TYPE_CALL_INDIRECT, call_indirect) \ + V(WABT_EXPR_TYPE_COMPARE, compare) \ + V(WABT_EXPR_TYPE_CONST, const) \ + V(WABT_EXPR_TYPE_CONVERT, convert) \ + V(WABT_EXPR_TYPE_GET_GLOBAL, get_global) \ + V(WABT_EXPR_TYPE_GET_LOCAL, get_local) \ + V(WABT_EXPR_TYPE_IF, if) \ + V(WABT_EXPR_TYPE_LOAD, load) \ + V(WABT_EXPR_TYPE_LOOP, loop) \ + V(WABT_EXPR_TYPE_SET_GLOBAL, set_global) \ + V(WABT_EXPR_TYPE_SET_LOCAL, set_local) \ + V(WABT_EXPR_TYPE_STORE, store) \ + V(WABT_EXPR_TYPE_TEE_LOCAL, tee_local) \ + V(WABT_EXPR_TYPE_UNARY, unary) \ + V(WABT_EXPR_TYPE_CURRENT_MEMORY, current_memory) \ + V(WABT_EXPR_TYPE_DROP, drop) \ + V(WABT_EXPR_TYPE_GROW_MEMORY, grow_memory) \ + V(WABT_EXPR_TYPE_NOP, nop) \ + V(WABT_EXPR_TYPE_RETURN, return ) \ + V(WABT_EXPR_TYPE_SELECT, select) \ + V(WABT_EXPR_TYPE_UNREACHABLE, unreachable) + +#define DEFINE_NEW_EXPR(type_, name) \ + WabtExpr* wabt_new_##name##_expr(void) { \ + WabtExpr* result = (WabtExpr*)wabt_alloc_zero(sizeof(WabtExpr)); \ + result->type = type_; \ + return result; \ + } +FOREACH_EXPR_TYPE(DEFINE_NEW_EXPR) +#undef DEFINE_NEW_EXPR + +void wabt_destroy_var(WabtVar* var) { + if (var->type == WABT_VAR_TYPE_NAME) + wabt_destroy_string_slice(&var->name); +} + +void wabt_destroy_var_vector_and_elements(WabtVarVector* vars) { + WABT_DESTROY_VECTOR_AND_ELEMENTS(*vars, var); +} + +void wabt_destroy_func_signature(WabtFuncSignature* sig) { + wabt_destroy_type_vector(&sig->param_types); + wabt_destroy_type_vector(&sig->result_types); +} + +void wabt_destroy_expr_list(WabtExpr* first) { + WabtExpr* expr = first; + while (expr) { + WabtExpr* next = expr->next; + wabt_destroy_expr(expr); + expr = next; + } +} + +void wabt_destroy_block(WabtBlock* block) { + wabt_destroy_string_slice(&block->label); + wabt_destroy_type_vector(&block->sig); + wabt_destroy_expr_list(block->first); +} + +void wabt_destroy_expr(WabtExpr* expr) { + switch (expr->type) { + case WABT_EXPR_TYPE_BLOCK: + wabt_destroy_block(&expr->block); + break; + case WABT_EXPR_TYPE_BR: + wabt_destroy_var(&expr->br.var); + break; + case WABT_EXPR_TYPE_BR_IF: + wabt_destroy_var(&expr->br_if.var); + break; + case WABT_EXPR_TYPE_BR_TABLE: + WABT_DESTROY_VECTOR_AND_ELEMENTS(expr->br_table.targets, var); + wabt_destroy_var(&expr->br_table.default_target); + break; + case WABT_EXPR_TYPE_CALL: + wabt_destroy_var(&expr->call.var); + break; + case WABT_EXPR_TYPE_CALL_INDIRECT: + wabt_destroy_var(&expr->call_indirect.var); + break; + case WABT_EXPR_TYPE_GET_GLOBAL: + wabt_destroy_var(&expr->get_global.var); + break; + case WABT_EXPR_TYPE_GET_LOCAL: + wabt_destroy_var(&expr->get_local.var); + break; + case WABT_EXPR_TYPE_IF: + wabt_destroy_block(&expr->if_.true_); + wabt_destroy_expr_list(expr->if_.false_); + break; + case WABT_EXPR_TYPE_LOOP: + wabt_destroy_block(&expr->loop); + break; + case WABT_EXPR_TYPE_SET_GLOBAL: + wabt_destroy_var(&expr->set_global.var); + break; + case WABT_EXPR_TYPE_SET_LOCAL: + wabt_destroy_var(&expr->set_local.var); + break; + case WABT_EXPR_TYPE_TEE_LOCAL: + wabt_destroy_var(&expr->tee_local.var); + break; + + case WABT_EXPR_TYPE_BINARY: + case WABT_EXPR_TYPE_COMPARE: + case WABT_EXPR_TYPE_CONST: + case WABT_EXPR_TYPE_CONVERT: + case WABT_EXPR_TYPE_DROP: + case WABT_EXPR_TYPE_CURRENT_MEMORY: + case WABT_EXPR_TYPE_GROW_MEMORY: + case WABT_EXPR_TYPE_LOAD: + case WABT_EXPR_TYPE_NOP: + case WABT_EXPR_TYPE_RETURN: + case WABT_EXPR_TYPE_SELECT: + case WABT_EXPR_TYPE_STORE: + case WABT_EXPR_TYPE_UNARY: + case WABT_EXPR_TYPE_UNREACHABLE: + break; + } + wabt_free(expr); +} + +void wabt_destroy_func_declaration(WabtFuncDeclaration* decl) { + wabt_destroy_var(&decl->type_var); + if (!(decl->flags & WABT_FUNC_DECLARATION_FLAG_SHARED_SIGNATURE)) + wabt_destroy_func_signature(&decl->sig); +} + +void wabt_destroy_func(WabtFunc* func) { + wabt_destroy_string_slice(&func->name); + wabt_destroy_func_declaration(&func->decl); + wabt_destroy_type_vector(&func->local_types); + wabt_destroy_binding_hash(&func->param_bindings); + wabt_destroy_binding_hash(&func->local_bindings); + wabt_destroy_expr_list(func->first_expr); +} + +void wabt_destroy_global(WabtGlobal* global) { + wabt_destroy_string_slice(&global->name); + wabt_destroy_expr_list(global->init_expr); +} + +void wabt_destroy_import(WabtImport* import) { + wabt_destroy_string_slice(&import->module_name); + wabt_destroy_string_slice(&import->field_name); + switch (import->kind) { + case WABT_EXTERNAL_KIND_FUNC: + wabt_destroy_func(&import->func); + break; + case WABT_EXTERNAL_KIND_TABLE: + wabt_destroy_table(&import->table); + break; + case WABT_EXTERNAL_KIND_MEMORY: + wabt_destroy_memory(&import->memory); + break; + case WABT_EXTERNAL_KIND_GLOBAL: + wabt_destroy_global(&import->global); + break; + case WABT_NUM_EXTERNAL_KINDS: + assert(0); + break; + } +} + +void wabt_destroy_export(WabtExport* export_) { + wabt_destroy_string_slice(&export_->name); + wabt_destroy_var(&export_->var); +} + +void wabt_destroy_func_type(WabtFuncType* func_type) { + wabt_destroy_string_slice(&func_type->name); + wabt_destroy_func_signature(&func_type->sig); +} + +void wabt_destroy_data_segment(WabtDataSegment* data) { + wabt_destroy_var(&data->memory_var); + wabt_destroy_expr_list(data->offset); + wabt_free(data->data); +} + +void wabt_destroy_memory(WabtMemory* memory) { + wabt_destroy_string_slice(&memory->name); +} + +void wabt_destroy_table(WabtTable* table) { + wabt_destroy_string_slice(&table->name); +} + +static void destroy_module_field(WabtModuleField* field) { + switch (field->type) { + case WABT_MODULE_FIELD_TYPE_FUNC: + wabt_destroy_func(&field->func); + break; + case WABT_MODULE_FIELD_TYPE_GLOBAL: + wabt_destroy_global(&field->global); + break; + case WABT_MODULE_FIELD_TYPE_IMPORT: + wabt_destroy_import(&field->import); + break; + case WABT_MODULE_FIELD_TYPE_EXPORT: + wabt_destroy_export(&field->export_); + break; + case WABT_MODULE_FIELD_TYPE_FUNC_TYPE: + wabt_destroy_func_type(&field->func_type); + break; + case WABT_MODULE_FIELD_TYPE_TABLE: + wabt_destroy_table(&field->table); + break; + case WABT_MODULE_FIELD_TYPE_ELEM_SEGMENT: + wabt_destroy_elem_segment(&field->elem_segment); + break; + case WABT_MODULE_FIELD_TYPE_MEMORY: + wabt_destroy_memory(&field->memory); + break; + case WABT_MODULE_FIELD_TYPE_DATA_SEGMENT: + wabt_destroy_data_segment(&field->data_segment); + break; + case WABT_MODULE_FIELD_TYPE_START: + wabt_destroy_var(&field->start); + break; + } +} + +void wabt_destroy_module(WabtModule* module) { + wabt_destroy_string_slice(&module->name); + + WabtModuleField* field = module->first_field; + while (field != NULL) { + WabtModuleField* next_field = field->next; + destroy_module_field(field); + wabt_free(field); + field = next_field; + } + + /* everything that follows shares data with the module fields above, so we + only need to destroy the containing vectors */ + wabt_destroy_func_ptr_vector(&module->funcs); + wabt_destroy_global_ptr_vector(&module->globals); + wabt_destroy_import_ptr_vector(&module->imports); + wabt_destroy_export_ptr_vector(&module->exports); + wabt_destroy_func_type_ptr_vector(&module->func_types); + wabt_destroy_table_ptr_vector(&module->tables); + wabt_destroy_elem_segment_ptr_vector(&module->elem_segments); + wabt_destroy_memory_ptr_vector(&module->memories); + wabt_destroy_data_segment_ptr_vector(&module->data_segments); + wabt_destroy_binding_hash_entry_vector(&module->func_bindings.entries); + wabt_destroy_binding_hash_entry_vector(&module->global_bindings.entries); + wabt_destroy_binding_hash_entry_vector(&module->export_bindings.entries); + wabt_destroy_binding_hash_entry_vector(&module->func_type_bindings.entries); + wabt_destroy_binding_hash_entry_vector(&module->table_bindings.entries); + wabt_destroy_binding_hash_entry_vector(&module->memory_bindings.entries); +} + +void wabt_destroy_raw_module(WabtRawModule* raw) { + if (raw->type == WABT_RAW_MODULE_TYPE_TEXT) { + wabt_destroy_module(raw->text); + wabt_free(raw->text); + } else { + wabt_destroy_string_slice(&raw->binary.name); + wabt_free(raw->binary.data); + } +} + +void wabt_destroy_action(WabtAction* action) { + wabt_destroy_var(&action->module_var); + switch (action->type) { + case WABT_ACTION_TYPE_INVOKE: + wabt_destroy_string_slice(&action->invoke.name); + wabt_destroy_const_vector(&action->invoke.args); + break; + case WABT_ACTION_TYPE_GET: + wabt_destroy_string_slice(&action->get.name); + break; + } +} + +void wabt_destroy_command(WabtCommand* command) { + switch (command->type) { + case WABT_COMMAND_TYPE_MODULE: + wabt_destroy_module(&command->module); + break; + case WABT_COMMAND_TYPE_ACTION: + wabt_destroy_action(&command->action); + break; + case WABT_COMMAND_TYPE_REGISTER: + wabt_destroy_string_slice(&command->register_.module_name); + wabt_destroy_var(&command->register_.var); + break; + case WABT_COMMAND_TYPE_ASSERT_MALFORMED: + wabt_destroy_raw_module(&command->assert_malformed.module); + wabt_destroy_string_slice(&command->assert_malformed.text); + break; + case WABT_COMMAND_TYPE_ASSERT_INVALID: + case WABT_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY: + wabt_destroy_raw_module(&command->assert_invalid.module); + wabt_destroy_string_slice(&command->assert_invalid.text); + break; + case WABT_COMMAND_TYPE_ASSERT_UNLINKABLE: + wabt_destroy_raw_module(&command->assert_unlinkable.module); + wabt_destroy_string_slice(&command->assert_unlinkable.text); + break; + case WABT_COMMAND_TYPE_ASSERT_UNINSTANTIABLE: + wabt_destroy_raw_module(&command->assert_uninstantiable.module); + wabt_destroy_string_slice(&command->assert_uninstantiable.text); + break; + case WABT_COMMAND_TYPE_ASSERT_RETURN: + wabt_destroy_action(&command->assert_return.action); + wabt_destroy_const_vector(&command->assert_return.expected); + break; + case WABT_COMMAND_TYPE_ASSERT_RETURN_NAN: + wabt_destroy_action(&command->assert_return_nan.action); + break; + case WABT_COMMAND_TYPE_ASSERT_TRAP: + case WABT_COMMAND_TYPE_ASSERT_EXHAUSTION: + wabt_destroy_action(&command->assert_trap.action); + wabt_destroy_string_slice(&command->assert_trap.text); + break; + case WABT_NUM_COMMAND_TYPES: + assert(0); + break; + } +} + +void wabt_destroy_command_vector_and_elements(WabtCommandVector* commands) { + WABT_DESTROY_VECTOR_AND_ELEMENTS(*commands, command); +} + +void wabt_destroy_elem_segment(WabtElemSegment* elem) { + wabt_destroy_var(&elem->table_var); + wabt_destroy_expr_list(elem->offset); + WABT_DESTROY_VECTOR_AND_ELEMENTS(elem->vars, var); +} + +void wabt_destroy_script(WabtScript* script) { + WABT_DESTROY_VECTOR_AND_ELEMENTS(script->commands, command); + wabt_destroy_binding_hash(&script->module_bindings); +} + +#define CHECK_RESULT(expr) \ + do { \ + if (WABT_FAILED((expr))) \ + return WABT_ERROR; \ + } while (0) + +#define CALLBACK(member) \ + CHECK_RESULT((visitor)->member \ + ? (visitor)->member(expr, (visitor)->user_data) \ + : WABT_OK) + +static WabtResult visit_expr(WabtExpr* expr, WabtExprVisitor* visitor); + +WabtResult wabt_visit_expr_list(WabtExpr* first, WabtExprVisitor* visitor) { + WabtExpr* expr; + for (expr = first; expr; expr = expr->next) + CHECK_RESULT(visit_expr(expr, visitor)); + return WABT_OK; +} + +static WabtResult visit_expr(WabtExpr* expr, WabtExprVisitor* visitor) { + switch (expr->type) { + case WABT_EXPR_TYPE_BINARY: + CALLBACK(on_binary_expr); + break; + + case WABT_EXPR_TYPE_BLOCK: + CALLBACK(begin_block_expr); + CHECK_RESULT(wabt_visit_expr_list(expr->block.first, visitor)); + CALLBACK(end_block_expr); + break; + + case WABT_EXPR_TYPE_BR: + CALLBACK(on_br_expr); + break; + + case WABT_EXPR_TYPE_BR_IF: + CALLBACK(on_br_if_expr); + break; + + case WABT_EXPR_TYPE_BR_TABLE: + CALLBACK(on_br_table_expr); + break; + + case WABT_EXPR_TYPE_CALL: + CALLBACK(on_call_expr); + break; + + case WABT_EXPR_TYPE_CALL_INDIRECT: + CALLBACK(on_call_indirect_expr); + break; + + case WABT_EXPR_TYPE_COMPARE: + CALLBACK(on_compare_expr); + break; + + case WABT_EXPR_TYPE_CONST: + CALLBACK(on_const_expr); + break; + + case WABT_EXPR_TYPE_CONVERT: + CALLBACK(on_convert_expr); + break; + + case WABT_EXPR_TYPE_CURRENT_MEMORY: + CALLBACK(on_current_memory_expr); + break; + + case WABT_EXPR_TYPE_DROP: + CALLBACK(on_drop_expr); + break; + + case WABT_EXPR_TYPE_GET_GLOBAL: + CALLBACK(on_get_global_expr); + break; + + case WABT_EXPR_TYPE_GET_LOCAL: + CALLBACK(on_get_local_expr); + break; + + case WABT_EXPR_TYPE_GROW_MEMORY: + CALLBACK(on_grow_memory_expr); + break; + + case WABT_EXPR_TYPE_IF: + CALLBACK(begin_if_expr); + CHECK_RESULT(wabt_visit_expr_list(expr->if_.true_.first, visitor)); + CALLBACK(after_if_true_expr); + CHECK_RESULT(wabt_visit_expr_list(expr->if_.false_, visitor)); + CALLBACK(end_if_expr); + break; + + case WABT_EXPR_TYPE_LOAD: + CALLBACK(on_load_expr); + break; + + case WABT_EXPR_TYPE_LOOP: + CALLBACK(begin_loop_expr); + CHECK_RESULT(wabt_visit_expr_list(expr->loop.first, visitor)); + CALLBACK(end_loop_expr); + break; + + case WABT_EXPR_TYPE_NOP: + CALLBACK(on_nop_expr); + break; + + case WABT_EXPR_TYPE_RETURN: + CALLBACK(on_return_expr); + break; + + case WABT_EXPR_TYPE_SELECT: + CALLBACK(on_select_expr); + break; + + case WABT_EXPR_TYPE_SET_GLOBAL: + CALLBACK(on_set_global_expr); + break; + + case WABT_EXPR_TYPE_SET_LOCAL: + CALLBACK(on_set_local_expr); + break; + + case WABT_EXPR_TYPE_STORE: + CALLBACK(on_store_expr); + break; + + case WABT_EXPR_TYPE_TEE_LOCAL: + CALLBACK(on_tee_local_expr); + break; + + case WABT_EXPR_TYPE_UNARY: + CALLBACK(on_unary_expr); + break; + + case WABT_EXPR_TYPE_UNREACHABLE: + CALLBACK(on_unreachable_expr); + break; + } + + return WABT_OK; +} + +/* TODO(binji): make the visitor non-recursive */ +WabtResult wabt_visit_func(WabtFunc* func, WabtExprVisitor* visitor) { + return wabt_visit_expr_list(func->first_expr, visitor); +} |