diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/interp/ops.c | 2 | ||||
| -rw-r--r-- | src/op/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/op/select.c | 119 |
3 files changed, 121 insertions, 1 deletions
diff --git a/src/interp/ops.c b/src/interp/ops.c index 4366a49..7c0d911 100644 --- a/src/interp/ops.c +++ b/src/interp/ops.c @@ -41,7 +41,7 @@ static void (*const ops[])(struct nw_interp *) = NULL, NULL, nwp_op_drop, /* OP_DROP */ - NULL, /* OP_SELECT */ + nwp_op_select, /* OP_SELECT */ NULL, NULL, NULL, diff --git a/src/op/CMakeLists.txt b/src/op/CMakeLists.txt index 7cc6ff8..90ce763 100644 --- a/src/op/CMakeLists.txt +++ b/src/op/CMakeLists.txt @@ -49,6 +49,7 @@ target_sources(${PROJECT_NAME} PRIVATE loop.c nop.c return.c + select.c set_global.c set_local.c tee_local.c diff --git a/src/op/select.c b/src/op/select.c new file mode 100644 index 0000000..7705af9 --- /dev/null +++ b/src/op/select.c @@ -0,0 +1,119 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/opcodes.h> +#include <nw/ops.h> +#include <nw/stack.h> +#include <nw/types.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_select *const s = &i->sm.select; + const enum nw_state n = nwp_stack_push(i, &s->io); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state pop_left(struct nw_interp *const i) +{ + struct nw_i_sm_select *const s = &i->sm.select; + const enum nw_state n = nwp_stack_pop(i, &s->io); + struct nw_sm_io io = {0}; + + if (n) + return n; + + io.buf = s->condition ? &s->left : &s->right; + io.n = s->sz; + s->io = io; + i->next = push; + return NW_AGAIN; +} + +static enum nw_state pop_right(struct nw_interp *const i) +{ + struct nw_i_sm_select *const s = &i->sm.select; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &s->left; + io.n = s->sz; + s->io = io; + } + + i->next = pop_left; + return NW_AGAIN; +} + +static enum nw_state pop_condition(struct nw_interp *const i) +{ + struct nw_i_sm_select *const s = &i->sm.select; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &s->right; + io.n = s->sz; + s->io = io; + } + + i->next = pop_right; + return NW_AGAIN; +} + +static enum nw_state check(struct nw_interp *const i) +{ + struct nw_i_sm_select *const s = &i->sm.select; + + if (nwp_type_sz(i->push_type, &s->sz)) + { + static const char *const exc = "invalid type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)i->push_type); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &s->condition; + io.n = sizeof s->condition; + s->io = io; + } + + i->next = pop_condition; + return NW_AGAIN; +} + +void nwp_op_select(struct nw_interp *const i) +{ + const struct nw_i_sm_select s = {0}; + + i->sm.select = s; + i->next = check; +} |
