From 2844d7db698bcafa835beba937c9ee7a2eb3d5a9 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 6 Jan 2024 12:31:36 +1030 Subject: [PATCH 1/3] COMMON: Allow modules to return objects with methods that take arguments --- ChangeLog | 3 + src/common/blib.c | 18 +++- src/common/eval.c | 2 +- src/common/plugins.c | 148 ++++++++++++++++----------------- src/common/plugins.h | 12 ++- src/include/module.h | 8 -- src/include/var.h | 12 ++- src/platform/console/image.cpp | 30 ++++--- src/ui/form.cpp | 21 ++--- src/ui/image.cpp | 42 +++++----- src/ui/window.cpp | 77 ++++++++++------- 11 files changed, 202 insertions(+), 171 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d857ee3..7eb7e802 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2024-01-06 (12.27) + COMMON: Allow modules to return objects with methods that take arguments + 2023-08-27 (12.27) COMMON: Fix parameter number error when calling a unit sub/func COMMON: Show a runtime error if a module calls exit() diff --git a/src/common/blib.c b/src/common/blib.c index 6902ab94..b24c9625 100644 --- a/src/common/blib.c +++ b/src/common/blib.c @@ -12,6 +12,7 @@ #include "common/fmt.h" #include "common/keymap.h" #include "common/messages.h" +#include "common/plugins.h" #define STR_INIT_SIZE 256 #define PKG_INIT_SIZE 5 @@ -2881,12 +2882,21 @@ void cmd_call_vfunc() { rt_raise(ERR_NO_FUNC); } } else { + slib_par_t *ptable; + int pcount; if (code_peek() == kwTYPE_LEVEL_BEGIN) { - code_skipnext(); + ptable = (slib_par_t *)malloc(sizeof(slib_par_t) * MAX_PARAMS); + pcount = plugin_build_ptable(ptable, MAX_PARAMS); + } else { + ptable = NULL; + pcount = 0; } - v_func->v.fn.cb(map, NULL); - if (code_peek() == kwTYPE_LEVEL_END) { - code_skipnext(); + if (!prog_error) { + v_func->v.fn.cb(map, pcount, ptable, NULL); + } + if (ptable) { + plugin_free_ptable(ptable, pcount); + free(ptable); } } } diff --git a/src/common/eval.c b/src/common/eval.c index 52fe12d0..dab6c3ce 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -786,7 +786,7 @@ static inline void eval_var(var_t *r, var_t *var_p) { v_set(r, var_p); break; case V_FUNC: - var_p->v.fn.cb(var_p, r); + var_p->v.fn.cb(var_p, 0, NULL, r); break; case V_NIL: r->type = V_NIL; diff --git a/src/common/plugins.c b/src/common/plugins.c index 0e5159b3..cd5c4b5a 100644 --- a/src/common/plugins.c +++ b/src/common/plugins.c @@ -358,80 +358,6 @@ static void slib_import_routines(slib_t *lib, int comp) { } } -// -// build parameter table -// -static int slib_build_ptable(slib_par_t *ptable) { - int pcount = 0; - var_t *arg; - bcip_t ofs; - - if (code_peek() == kwTYPE_LEVEL_BEGIN) { - code_skipnext(); - byte ready = 0; - do { - byte code = code_peek(); - switch (code) { - case kwTYPE_EOC: - code_skipnext(); - break; - case kwTYPE_SEP: - code_skipsep(); - break; - case kwTYPE_LEVEL_END: - ready = 1; - break; - case kwTYPE_VAR: - // variable - ofs = prog_ip; - if (code_isvar()) { - // push parameter - ptable[pcount].var_p = code_getvarptr(); - ptable[pcount].byref = 1; - pcount++; - break; - } - - // restore IP - prog_ip = ofs; - // no 'break' here - default: - // default --- expression (BYVAL ONLY) - arg = v_new(); - eval(arg); - if (!prog_error) { - // push parameter - ptable[pcount].var_p = arg; - ptable[pcount].byref = 0; - pcount++; - } else { - v_free(arg); - v_detach(arg); - return pcount; - } - } - if (pcount == MAX_PARAM) { - err_parm_limit(MAX_PARAM); - } - } while (!ready && !prog_error); - // kwTYPE_LEVEL_END - code_skipnext(); - } - return pcount; -} - -// -// free parameter table -// -static void slib_free_ptable(slib_par_t *ptable, int pcount) { - for (int i = 0; i < pcount; i++) { - if (ptable[i].byref == 0) { - v_free(ptable[i].var_p); - v_detach(ptable[i].var_p); - } - } -} - // // execute a function or procedure // @@ -440,13 +366,13 @@ static int slib_exec(slib_t *lib, var_t *ret, int index, int proc) { int pcount; if (code_peek() == kwTYPE_LEVEL_BEGIN) { ptable = (slib_par_t *)malloc(sizeof(slib_par_t) * MAX_PARAM); - pcount = slib_build_ptable(ptable); + pcount = plugin_build_ptable(ptable, MAX_PARAM); } else { ptable = NULL; pcount = 0; } if (prog_error) { - slib_free_ptable(ptable, pcount); + plugin_free_ptable(ptable, pcount); free(ptable); return 0; } @@ -470,7 +396,7 @@ static int slib_exec(slib_t *lib, var_t *ret, int index, int proc) { // clean-up if (ptable) { - slib_free_ptable(ptable, pcount); + plugin_free_ptable(ptable, pcount); free(ptable); } @@ -643,3 +569,71 @@ int plugin_funcexec(int lib_id, int index, var_t *ret) { return -1; } void plugin_free(int lib_id, int cls_id, int id) {} void plugin_close() {} #endif + +int plugin_build_ptable(slib_par_t *ptable, int size) { + int pcount = 0; + var_t *arg; + bcip_t ofs; + + if (code_peek() == kwTYPE_LEVEL_BEGIN) { + code_skipnext(); + byte ready = 0; + do { + byte code = code_peek(); + switch (code) { + case kwTYPE_EOC: + code_skipnext(); + break; + case kwTYPE_SEP: + code_skipsep(); + break; + case kwTYPE_LEVEL_END: + ready = 1; + break; + case kwTYPE_VAR: + // variable + ofs = prog_ip; + if (code_isvar()) { + // push parameter + ptable[pcount].var_p = code_getvarptr(); + ptable[pcount].byref = 1; + pcount++; + break; + } + + // restore IP + prog_ip = ofs; + // no 'break' here + default: + // default --- expression (BYVAL ONLY) + arg = v_new(); + eval(arg); + if (!prog_error) { + // push parameter + ptable[pcount].var_p = arg; + ptable[pcount].byref = 0; + pcount++; + } else { + v_free(arg); + v_detach(arg); + return pcount; + } + } + if (pcount == size) { + err_parm_limit(size); + } + } while (!ready && !prog_error); + // kwTYPE_LEVEL_END + code_skipnext(); + } + return pcount; +} + +void plugin_free_ptable(slib_par_t *ptable, int pcount) { + for (int i = 0; i < pcount; i++) { + if (ptable[i].byref == 0) { + v_free(ptable[i].var_p); + v_detach(ptable[i].var_p); + } + } +} diff --git a/src/common/plugins.h b/src/common/plugins.h index a4dd16bd..ceac683c 100644 --- a/src/common/plugins.h +++ b/src/common/plugins.h @@ -44,7 +44,7 @@ int plugin_get_kid(int lib_id, const char *keyword); // returns the function pointer for the given function name // void *plugin_get_func(const char *name); - + // // executes the plugin procedure at the given index // @@ -65,6 +65,16 @@ void plugin_free(int lib_id, int cls_id, int id); // void plugin_close(); +// +// build parameter table +// +int plugin_build_ptable(slib_par_t *ptable, int size); + +// +// free parameter table +// +void plugin_free_ptable(slib_par_t *ptable, int pcount); + #if defined(__cplusplus) } #endif diff --git a/src/include/module.h b/src/include/module.h index 451e24e2..d27ea522 100644 --- a/src/include/module.h +++ b/src/include/module.h @@ -16,14 +16,6 @@ extern "C" { #endif -typedef struct { - // the parameter - var_t *var_p; - - // whether the parameter can be used by reference - uint8_t byref; -} slib_par_t; - /** * @ingroup modstd * diff --git a/src/include/var.h b/src/include/var.h index 003e7949..eb347c2e 100644 --- a/src/include/var.h +++ b/src/include/var.h @@ -47,7 +47,17 @@ extern "C" { #endif struct var_s; -typedef void (*method) (struct var_s *self, struct var_s *retval); + +typedef struct { + // the parameter + struct var_s *var_p; + + // whether the parameter can be used by reference + uint8_t byref; +} slib_par_t; + +// object method signature +typedef void (*method) (struct var_s *self, int param_count, slib_par_t *params, struct var_s *retval); typedef struct var_s { union { diff --git a/src/platform/console/image.cpp b/src/platform/console/image.cpp index 527a539d..b5837fff 100644 --- a/src/platform/console/image.cpp +++ b/src/platform/console/image.cpp @@ -245,10 +245,15 @@ ImageBuffer *load_xpm_image(char **data) { // // png.clip(10, 10, 10, 10) // -void cmd_image_clip(var_s *self, var_s *) { - var_int_t left, top, right, bottom; +void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageBuffer *image = load_image(self); - if (par_massget("iiii", &left, &top, &right, &bottom) == 4) { + if (param_count != 4) { + err_parm_num(param_count, 4); + } else { + var_int_t left = v_getint(params[0].var_p); + var_int_t top = v_getint(params[1].var_p); + var_int_t right = v_getint(params[2].var_p); + var_int_t bottom = v_getint(params[3].var_p); int w = image->_width - (right + left); int h = image->_height - (bottom + top); int size = w * h * 4; @@ -277,8 +282,6 @@ void cmd_image_clip(var_s *self, var_s *) { map_set_int(self, IMG_WIDTH, w); map_set_int(self, IMG_HEIGHT, h); } - } else { - err_throw(ERR_PARAM); } } @@ -290,7 +293,7 @@ void cmd_image_clip(var_s *self, var_s *) { // end // png.filter(use colorToAlpha(x)) // -void cmd_image_filter(var_s *self, var_s *) { +void cmd_image_filter(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageBuffer *image_buffer = load_image(self); if (code_peek() == kwUSE && image_buffer != nullptr) { code_skipnext(); @@ -326,19 +329,22 @@ void cmd_image_filter(var_s *self, var_s *) { // png2 = image(w, h) // png2.paste(png1, 0, 0) // -void cmd_image_paste(var_s *self, var_s *) { - var_int_t x, y; - var_t *var; +void cmd_image_paste(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageBuffer *image = load_image(self); - int count = par_massget("Piiii", &var, &x, &y); - if (image != nullptr && (count == 1 || count == 3)) { + if (image != nullptr && (param_count == 1 || param_count == 3)) { + var_t *var = params[0].var_p; ImageBuffer *srcImage = load_image(var); if (srcImage == nullptr) { err_throw(ERR_PARAM); } else { + var_int_t x; + var_int_t y; if (count == 1) { x = 0; y = 0; + } else { + x = v_getint(params[1].var_p); + y = v_getint(params[2].var_p); } int dw = image->_width; int dh = image->_height; @@ -370,7 +376,7 @@ void cmd_image_paste(var_s *self, var_s *) { // png.save("horse1.png") // png.save(#1) // -void cmd_image_save(var_s *self, var_s *) { +void cmd_image_save(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageBuffer *image = load_image(self); dev_file_t *filep = nullptr; byte code = code_peek(); diff --git a/src/ui/form.cpp b/src/ui/form.cpp index 8cd9a85f..444fad94 100644 --- a/src/ui/form.cpp +++ b/src/ui/form.cpp @@ -116,29 +116,20 @@ void FormLink::clicked(int x, int y, bool pressed) { } } -void cmd_form_close(var_s *self, var_s *) { +void cmd_form_close(var_s *self, int param_count, slib_par_t *params, var_s *) { g_system->getOutput()->removeInputs(); g_system->getOutput()->resetScroll(); - - var_t arg; - v_init(&arg); - eval(&arg); - if (arg.type == V_STR) { - g_system->setLoadBreak(arg.v.p.ptr); + if (param_count == 1 && params[0].var_p->type == V_STR) { + g_system->setLoadBreak(params[0].var_p->v.p.ptr); } - v_free(&arg); } -void cmd_form_refresh(var_s *self, var_s *) { - var_t arg; - v_init(&arg); - eval(&arg); - bool setVars = v_getint(&arg) != 0; - v_free(&arg); +void cmd_form_refresh(var_s *self, int param_count, slib_par_t *params, var_s *) { + bool setVars = param_count == 1 && v_getint(params[0].var_p) != 0; g_system->getOutput()->updateInputs(self, setVars); } -void cmd_form_do_events(var_s *self, var_s *) { +void cmd_form_do_events(var_s *self, int param_count, slib_par_t *params, var_s *) { // apply any variable changes onto attached widgets if (g_system->isRunning()) { AnsiWidget *out = g_system->getOutput(); diff --git a/src/ui/image.cpp b/src/ui/image.cpp index b0797ceb..1cb4fbbc 100644 --- a/src/ui/image.cpp +++ b/src/ui/image.cpp @@ -370,7 +370,7 @@ ImageBuffer *load_xpm_image(char **data) { return result; } -void get_image_display(var_s *self, ImageDisplay *image) { +void get_image_display(var_s *self, int param_count, slib_par_t *params, ImageDisplay *image) { image->_bid = map_get_int(self, IMG_BID, -1); List_each(ImageBuffer *, it, buffers) { @@ -381,14 +381,13 @@ void get_image_display(var_s *self, ImageDisplay *image) { } } - var_int_t x, y, z, op; - int count = par_massget("iiii", &x, &y, &z, &op); - - if (prog_error || image->_buffer == nullptr || count == 1 || count > 4) { + if (prog_error || image->_buffer == nullptr || param_count == 1 || param_count > 4) { err_throw(ERR_PARAM); } else { // 0, 2, 3, 4 arguments accepted - if (count >= 2) { + if (param_count >= 2) { + var_int_t x = v_getint(params[0].var_p); + var_int_t y = v_getint(params[1].var_p); image->_x = x; image->_y = y; map_set_int(self, IMG_X, x); @@ -397,13 +396,15 @@ void get_image_display(var_s *self, ImageDisplay *image) { image->_x = map_get_int(self, IMG_X, -1); image->_y = map_get_int(self, IMG_Y, -1); } - if (count >= 3) { + if (param_count >= 3) { + var_int_t z = v_getint(params[2].var_p); image->_zIndex = z; map_set_int(self, IMG_ZINDEX, z); } else { image->_zIndex = map_get_int(self, IMG_ZINDEX, -1); } - if (count == 4) { + if (param_count == 4) { + var_int_t op = v_getint(params[3].var_p); image->_opacity = op; map_set_int(self, IMG_OPACITY, op); } else { @@ -421,9 +422,9 @@ void get_image_display(var_s *self, ImageDisplay *image) { // // png.show(x, y, zindex, opacity) // -void cmd_image_show(var_s *self, var_s *) { +void cmd_image_show(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageDisplay image; - get_image_display(self, &image); + get_image_display(self, param_count, params, &image); if (!prog_error) { g_system->getOutput()->addImage(image); } @@ -432,9 +433,9 @@ void cmd_image_show(var_s *self, var_s *) { // // png.draw(x, y, opacity) // -void cmd_image_draw(var_s *self, var_s *) { +void cmd_image_draw(var_s *self, int param_count, slib_par_t *params, var_s *) { ImageDisplay image; - get_image_display(self, &image); + get_image_display(self, param_count, params, &image); if (!prog_error) { image._opacity = image._zIndex; g_system->getOutput()->drawImage(image); @@ -444,7 +445,7 @@ void cmd_image_draw(var_s *self, var_s *) { // // png.hide() // -void cmd_image_hide(var_s *self, var_s *) { +void cmd_image_hide(var_s *self, int param_count, slib_par_t *params, var_s *) { int id = map_get_int(self, IMG_ID, -1); g_system->getOutput()->removeImage(id); } @@ -455,7 +456,7 @@ void cmd_image_hide(var_s *self, var_s *) { // png.save("horse1.png") // png.save(#1) // -void cmd_image_save(var_s *self, var_s *) { +void cmd_image_save(var_s *self, int param_count, slib_par_t *params, var_s *) { unsigned id = map_get_int(self, IMG_BID, -1); ImageBuffer *image = get_image(id); dev_file_t *file; @@ -516,17 +517,16 @@ void cmd_image_save(var_s *self, var_s *) { // // png.clip(10, 10, 10, 10) // -void cmd_image_clip(var_s *self, var_s *) { +void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { if (self->type == V_MAP) { int bid = map_get_int(self, IMG_BID, -1); if (bid != -1) { ImageBuffer *image = get_image((unsigned)bid); - var_int_t left, top, right, bottom; - if (image != nullptr && par_massget("iiii", &left, &top, &right, &bottom)) { - map_set_int(self, IMG_OFFSET_LEFT, left); - map_set_int(self, IMG_OFFSET_TOP, top); - map_set_int(self, IMG_WIDTH, right); - map_set_int(self, IMG_HEIGHT, bottom); + if (image != nullptr && param_count == 4) { + map_set_int(self, IMG_OFFSET_LEFT, v_getint(params[0].var_p)); + map_set_int(self, IMG_OFFSET_TOP, v_getint(params[1].var_p)); + map_set_int(self, IMG_WIDTH, v_getint(params[2].var_p)); + map_set_int(self, IMG_HEIGHT, v_getint(params[3].var_p)); } } } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 7f31b125..2bebe619 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -62,30 +62,34 @@ StringList *get_items() { return items; } -void cmd_window_select_screen1(var_s *self, var_s *) { +void cmd_window_select_screen1(var_s *self, int param_count, slib_par_t *params, var_s *) { g_system->getOutput()->selectScreen(USER_SCREEN1); } -void cmd_window_select_screen2(var_s *self, var_s *) { +void cmd_window_select_screen2(var_s *self, int param_count, slib_par_t *params, var_s *) { g_system->getOutput()->selectScreen(USER_SCREEN2); } -void cmd_window_select_screen3(var_s *self, var_s *) { +void cmd_window_select_screen3(var_s *self, int param_count, slib_par_t *params, var_s *) { g_system->getOutput()->selectScreen(TEXT_SCREEN); } -void cmd_window_show_keypad(var_s *self, var_s *) { +void cmd_window_show_keypad(var_s *self, int param_count, slib_par_t *params, var_s *) { maShowVirtualKeyboard(); } -void cmd_window_hide_keypad(var_s *self, var_s *) { +void cmd_window_hide_keypad(var_s *self, int param_count, slib_par_t *params, var_s *) { maHideVirtualKeyboard(); } -void cmd_window_inset(var_s *self, var_s *) { - var_int_t x, y, w, h; - par_massget("IIII", &x, &y, &w, &h); - if (!prog_error) { +void cmd_window_inset(var_s *self, int param_count, slib_par_t *params, var_s *) { + if (param_count != 4) { + err_parm_num(param_count, 4); + } else { + var_int_t x = v_getint(params[0].var_p); + var_int_t y = v_getint(params[1].var_p); + var_int_t w = v_getint(params[2].var_p); + var_int_t h = v_getint(params[3].var_p); if (x < 0 || x > 100 || y < 0 || y > 100 || w < 1 || x + w > 100 || @@ -97,31 +101,42 @@ void cmd_window_inset(var_s *self, var_s *) { } } -void cmd_window_set_font(var_s *self, var_s *) { - var_num_t size; - var_int_t bold, italic; - char *unit = nullptr; - par_massget("FSII", &size, &unit, &bold, &italic); - if (unit != nullptr && strcmp(unit, "em") == 0) { - size *= g_system->getOutput()->getFontSize(); +void cmd_window_set_font(var_s *self, int param_count, slib_par_t *params, var_s *) { + if (param_count != 4) { + err_parm_num(param_count, 4); + } else { + var_num_t size = v_getreal(params[0].var_p); + const char *unit = v_getstr(params[1].var_p); + var_int_t bold = v_getint(params[2].var_p); + var_int_t italic = v_getint(params[3].var_p); + if (unit != nullptr && strcmp(unit, "em") == 0) { + size *= g_system->getOutput()->getFontSize(); + } + g_system->getOutput()->setFont(size, bold, italic); } - g_system->getOutput()->setFont(size, bold, italic); - pfree(unit); } -void cmd_window_set_size(var_s *self, var_s *) { - var_int_t width, height; - par_massget("II", &width, &height); - g_system->setWindowRect(-1, -1, width, height); +void cmd_window_set_size(var_s *self, int param_count, slib_par_t *params, var_s *) { + if (param_count != 2) { + err_parm_num(param_count, 2); + } else { + var_int_t width = v_getint(params[0].var_p); + var_int_t height = v_getint(params[1].var_p); + g_system->setWindowRect(-1, -1, width, height); + } } -void cmd_window_set_location(var_s *self, var_s *) { - var_int_t x, y; - par_massget("II", &x, &y); - g_system->setWindowRect(x, y, -1, -1); +void cmd_window_set_location(var_s *self, int param_count, slib_par_t *params, var_s *) { + if (param_count != 2) { + err_parm_num(param_count, 2); + } else { + var_int_t x = v_getint(params[0].var_p); + var_int_t y = v_getint(params[1].var_p); + g_system->setWindowRect(x, y, -1, -1); + } } -void cmd_window_get_theme(var_s *, var_s *retval) { +void cmd_window_get_theme(var_s *self, int param_count, slib_par_t *params, var_s *retval) { if (retval != nullptr) { EditTheme theme; theme.setId(g_themeId); @@ -137,7 +152,7 @@ void cmd_window_get_theme(var_s *, var_s *retval) { } } -void cmd_window_alert(var_s *self, var_s *) { +void cmd_window_alert(var_s *self, int param_count, slib_par_t *params, var_s *) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { const char *message = items->size() > 0 ? (*items)[0]->c_str() : ""; @@ -147,7 +162,7 @@ void cmd_window_alert(var_s *self, var_s *) { delete items; } -void cmd_window_ask(var_s *self, var_s *retval) { +void cmd_window_ask(var_s *self, int param_count, slib_par_t *params, var_s *retval) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { const char *message = items->size() > 0 ? (*items)[0]->c_str() : ""; @@ -161,7 +176,7 @@ void cmd_window_ask(var_s *self, var_s *retval) { delete items; } -void cmd_window_menu(var_s *self, var_s *) { +void cmd_window_menu(var_s *self, int param_count, slib_par_t *params, var_s *) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { g_system->optionsBox(items); @@ -169,7 +184,7 @@ void cmd_window_menu(var_s *self, var_s *) { delete items; } -void cmd_window_message(var_s *self, var_s *) { +void cmd_window_message(var_s *self, int param_count, slib_par_t *params, var_s *) { var_t arg; v_init(&arg); eval(&arg); From 5adc663b3a5103b83ea3b50487fba5c3b8231306 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 6 Jan 2024 20:49:10 +1030 Subject: [PATCH 2/3] COMMON: Allow modules to return objects with methods that take arguments --- src/common/blib.c | 21 ++-------- src/common/eval.c | 2 +- src/common/var.c | 1 + src/common/var_eval.c | 47 ++++++++++++++++++++- src/common/var_eval.h | 7 ++++ src/include/var.h | 8 +++- src/platform/console/image.cpp | 30 ++++++------- src/ui/form.cpp | 21 +++++++--- src/ui/image.cpp | 42 +++++++++---------- src/ui/window.cpp | 77 ++++++++++++++-------------------- 10 files changed, 144 insertions(+), 112 deletions(-) diff --git a/src/common/blib.c b/src/common/blib.c index b24c9625..d3e10fcc 100644 --- a/src/common/blib.c +++ b/src/common/blib.c @@ -12,7 +12,6 @@ #include "common/fmt.h" #include "common/keymap.h" #include "common/messages.h" -#include "common/plugins.h" #define STR_INIT_SIZE 256 #define PKG_INIT_SIZE 5 @@ -2882,22 +2881,10 @@ void cmd_call_vfunc() { rt_raise(ERR_NO_FUNC); } } else { - slib_par_t *ptable; - int pcount; - if (code_peek() == kwTYPE_LEVEL_BEGIN) { - ptable = (slib_par_t *)malloc(sizeof(slib_par_t) * MAX_PARAMS); - pcount = plugin_build_ptable(ptable, MAX_PARAMS); - } else { - ptable = NULL; - pcount = 0; - } - if (!prog_error) { - v_func->v.fn.cb(map, pcount, ptable, NULL); - } - if (ptable) { - plugin_free_ptable(ptable, pcount); - free(ptable); - } + var_t result; + v_init(&result); + v_eval_func(map, v_func, &result); + v_free(&result); } } diff --git a/src/common/eval.c b/src/common/eval.c index dab6c3ce..52fe12d0 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -786,7 +786,7 @@ static inline void eval_var(var_t *r, var_t *var_p) { v_set(r, var_p); break; case V_FUNC: - var_p->v.fn.cb(var_p, 0, NULL, r); + var_p->v.fn.cb(var_p, r); break; case V_NIL: r->type = V_NIL; diff --git a/src/common/var.c b/src/common/var.c index 05017773..3574840d 100644 --- a/src/common/var.c +++ b/src/common/var.c @@ -800,5 +800,6 @@ void v_create_func(var_p_t map, const char *name, method cb) { var_p_t v_func = map_add_var(map, name, 0); v_func->type = V_FUNC; v_func->v.fn.cb = cb; + v_func->v.fn.mcb = NULL; v_func->v.fn.id = 0; } diff --git a/src/common/var_eval.c b/src/common/var_eval.c index 4509fef9..aa6912ed 100644 --- a/src/common/var_eval.c +++ b/src/common/var_eval.c @@ -5,7 +5,7 @@ // This program is distributed under the terms of the GPL v2.0 or later // Download the GNU Public License (GPL) from www.gnu.org // -// Copyright(C) 2010-2014 Chris Warren-Smith. [http://tinyurl.com/ja2ss] +// Copyright(C) 2010-2024 Chris Warren-Smith. [http://tinyurl.com/ja2ss] #include "common/sys.h" #include "common/kw.h" @@ -14,6 +14,44 @@ #include "common/smbas.h" #include "common/var.h" #include "common/var_eval.h" +#include "common/plugins.h" + +void v_eval_func(var_p_t self, var_p_t v_func, var_p_t result) { + if (v_func->v.fn.cb != NULL) { + // internal object method + if (code_peek() == kwTYPE_LEVEL_BEGIN) { + code_skipnext(); + } + v_func->v.fn.cb(self, NULL); + if (code_peek() == kwTYPE_LEVEL_END) { + code_skipnext(); + } + } else { + // module callback + slib_par_t *ptable; + int pcount; + if (code_peek() == kwTYPE_LEVEL_BEGIN) { + ptable = (slib_par_t *)malloc(sizeof(slib_par_t) * MAX_PARAMS); + pcount = plugin_build_ptable(ptable, MAX_PARAMS); + } else { + ptable = NULL; + pcount = 0; + } + if (!prog_error) { + if (!v_func->v.fn.mcb(self, pcount, ptable, result)) { + if (result->type == V_STR) { + err_throw(result->v.p.ptr); + } else { + err_throw("Undefined"); + } + } + } + if (ptable) { + plugin_free_ptable(ptable, pcount); + free(ptable); + } + } +} /** * Convert multi-dim index to one-dim index @@ -159,6 +197,13 @@ var_t *code_get_map_element(var_t *map, var_t *field) { } } else if (field->type == V_ARRAY) { result = code_getvarptr_arridx(field); + } else if (field->type == V_FUNC) { + result = map_get(map, MAP_TMP_FIELD); + if (result == NULL) { + result = map_add_var(map, MAP_TMP_FIELD, 0); + } + v_init(result); + v_eval_func(map, field, result); } else { code_skipnext(); var_t var; diff --git a/src/common/var_eval.h b/src/common/var_eval.h index 9ba681ef..6daee18a 100644 --- a/src/common/var_eval.h +++ b/src/common/var_eval.h @@ -67,6 +67,13 @@ int code_isvar(void); */ void v_eval_str(var_p_t v); +/** + * @ingroup var + * + * invokes the virtual function + */ +void v_eval_func(var_p_t self, var_p_t v_func, var_p_t result); + #if defined(__cplusplus) } #endif diff --git a/src/include/var.h b/src/include/var.h index eb347c2e..8ea30f90 100644 --- a/src/include/var.h +++ b/src/include/var.h @@ -56,8 +56,11 @@ typedef struct { uint8_t byref; } slib_par_t; -// object method signature -typedef void (*method) (struct var_s *self, int param_count, slib_par_t *params, struct var_s *retval); +// signature for module callback/virtual functions +typedef int (*callback) (struct var_s *self, int param_count, slib_par_t *params, struct var_s *retval); + +// signature for internal v_funcs +typedef void (*method) (struct var_s *self, struct var_s *retval); typedef struct var_s { union { @@ -93,6 +96,7 @@ typedef struct var_s { // object method struct { method cb; + callback mcb; uint32_t id; } fn; diff --git a/src/platform/console/image.cpp b/src/platform/console/image.cpp index b5837fff..527a539d 100644 --- a/src/platform/console/image.cpp +++ b/src/platform/console/image.cpp @@ -245,15 +245,10 @@ ImageBuffer *load_xpm_image(char **data) { // // png.clip(10, 10, 10, 10) // -void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_clip(var_s *self, var_s *) { + var_int_t left, top, right, bottom; ImageBuffer *image = load_image(self); - if (param_count != 4) { - err_parm_num(param_count, 4); - } else { - var_int_t left = v_getint(params[0].var_p); - var_int_t top = v_getint(params[1].var_p); - var_int_t right = v_getint(params[2].var_p); - var_int_t bottom = v_getint(params[3].var_p); + if (par_massget("iiii", &left, &top, &right, &bottom) == 4) { int w = image->_width - (right + left); int h = image->_height - (bottom + top); int size = w * h * 4; @@ -282,6 +277,8 @@ void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { map_set_int(self, IMG_WIDTH, w); map_set_int(self, IMG_HEIGHT, h); } + } else { + err_throw(ERR_PARAM); } } @@ -293,7 +290,7 @@ void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { // end // png.filter(use colorToAlpha(x)) // -void cmd_image_filter(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_filter(var_s *self, var_s *) { ImageBuffer *image_buffer = load_image(self); if (code_peek() == kwUSE && image_buffer != nullptr) { code_skipnext(); @@ -329,22 +326,19 @@ void cmd_image_filter(var_s *self, int param_count, slib_par_t *params, var_s *) // png2 = image(w, h) // png2.paste(png1, 0, 0) // -void cmd_image_paste(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_paste(var_s *self, var_s *) { + var_int_t x, y; + var_t *var; ImageBuffer *image = load_image(self); - if (image != nullptr && (param_count == 1 || param_count == 3)) { - var_t *var = params[0].var_p; + int count = par_massget("Piiii", &var, &x, &y); + if (image != nullptr && (count == 1 || count == 3)) { ImageBuffer *srcImage = load_image(var); if (srcImage == nullptr) { err_throw(ERR_PARAM); } else { - var_int_t x; - var_int_t y; if (count == 1) { x = 0; y = 0; - } else { - x = v_getint(params[1].var_p); - y = v_getint(params[2].var_p); } int dw = image->_width; int dh = image->_height; @@ -376,7 +370,7 @@ void cmd_image_paste(var_s *self, int param_count, slib_par_t *params, var_s *) // png.save("horse1.png") // png.save(#1) // -void cmd_image_save(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_save(var_s *self, var_s *) { ImageBuffer *image = load_image(self); dev_file_t *filep = nullptr; byte code = code_peek(); diff --git a/src/ui/form.cpp b/src/ui/form.cpp index 444fad94..8cd9a85f 100644 --- a/src/ui/form.cpp +++ b/src/ui/form.cpp @@ -116,20 +116,29 @@ void FormLink::clicked(int x, int y, bool pressed) { } } -void cmd_form_close(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_form_close(var_s *self, var_s *) { g_system->getOutput()->removeInputs(); g_system->getOutput()->resetScroll(); - if (param_count == 1 && params[0].var_p->type == V_STR) { - g_system->setLoadBreak(params[0].var_p->v.p.ptr); + + var_t arg; + v_init(&arg); + eval(&arg); + if (arg.type == V_STR) { + g_system->setLoadBreak(arg.v.p.ptr); } + v_free(&arg); } -void cmd_form_refresh(var_s *self, int param_count, slib_par_t *params, var_s *) { - bool setVars = param_count == 1 && v_getint(params[0].var_p) != 0; +void cmd_form_refresh(var_s *self, var_s *) { + var_t arg; + v_init(&arg); + eval(&arg); + bool setVars = v_getint(&arg) != 0; + v_free(&arg); g_system->getOutput()->updateInputs(self, setVars); } -void cmd_form_do_events(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_form_do_events(var_s *self, var_s *) { // apply any variable changes onto attached widgets if (g_system->isRunning()) { AnsiWidget *out = g_system->getOutput(); diff --git a/src/ui/image.cpp b/src/ui/image.cpp index 1cb4fbbc..b0797ceb 100644 --- a/src/ui/image.cpp +++ b/src/ui/image.cpp @@ -370,7 +370,7 @@ ImageBuffer *load_xpm_image(char **data) { return result; } -void get_image_display(var_s *self, int param_count, slib_par_t *params, ImageDisplay *image) { +void get_image_display(var_s *self, ImageDisplay *image) { image->_bid = map_get_int(self, IMG_BID, -1); List_each(ImageBuffer *, it, buffers) { @@ -381,13 +381,14 @@ void get_image_display(var_s *self, int param_count, slib_par_t *params, ImageDi } } - if (prog_error || image->_buffer == nullptr || param_count == 1 || param_count > 4) { + var_int_t x, y, z, op; + int count = par_massget("iiii", &x, &y, &z, &op); + + if (prog_error || image->_buffer == nullptr || count == 1 || count > 4) { err_throw(ERR_PARAM); } else { // 0, 2, 3, 4 arguments accepted - if (param_count >= 2) { - var_int_t x = v_getint(params[0].var_p); - var_int_t y = v_getint(params[1].var_p); + if (count >= 2) { image->_x = x; image->_y = y; map_set_int(self, IMG_X, x); @@ -396,15 +397,13 @@ void get_image_display(var_s *self, int param_count, slib_par_t *params, ImageDi image->_x = map_get_int(self, IMG_X, -1); image->_y = map_get_int(self, IMG_Y, -1); } - if (param_count >= 3) { - var_int_t z = v_getint(params[2].var_p); + if (count >= 3) { image->_zIndex = z; map_set_int(self, IMG_ZINDEX, z); } else { image->_zIndex = map_get_int(self, IMG_ZINDEX, -1); } - if (param_count == 4) { - var_int_t op = v_getint(params[3].var_p); + if (count == 4) { image->_opacity = op; map_set_int(self, IMG_OPACITY, op); } else { @@ -422,9 +421,9 @@ void get_image_display(var_s *self, int param_count, slib_par_t *params, ImageDi // // png.show(x, y, zindex, opacity) // -void cmd_image_show(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_show(var_s *self, var_s *) { ImageDisplay image; - get_image_display(self, param_count, params, &image); + get_image_display(self, &image); if (!prog_error) { g_system->getOutput()->addImage(image); } @@ -433,9 +432,9 @@ void cmd_image_show(var_s *self, int param_count, slib_par_t *params, var_s *) { // // png.draw(x, y, opacity) // -void cmd_image_draw(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_draw(var_s *self, var_s *) { ImageDisplay image; - get_image_display(self, param_count, params, &image); + get_image_display(self, &image); if (!prog_error) { image._opacity = image._zIndex; g_system->getOutput()->drawImage(image); @@ -445,7 +444,7 @@ void cmd_image_draw(var_s *self, int param_count, slib_par_t *params, var_s *) { // // png.hide() // -void cmd_image_hide(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_hide(var_s *self, var_s *) { int id = map_get_int(self, IMG_ID, -1); g_system->getOutput()->removeImage(id); } @@ -456,7 +455,7 @@ void cmd_image_hide(var_s *self, int param_count, slib_par_t *params, var_s *) { // png.save("horse1.png") // png.save(#1) // -void cmd_image_save(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_save(var_s *self, var_s *) { unsigned id = map_get_int(self, IMG_BID, -1); ImageBuffer *image = get_image(id); dev_file_t *file; @@ -517,16 +516,17 @@ void cmd_image_save(var_s *self, int param_count, slib_par_t *params, var_s *) { // // png.clip(10, 10, 10, 10) // -void cmd_image_clip(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_image_clip(var_s *self, var_s *) { if (self->type == V_MAP) { int bid = map_get_int(self, IMG_BID, -1); if (bid != -1) { ImageBuffer *image = get_image((unsigned)bid); - if (image != nullptr && param_count == 4) { - map_set_int(self, IMG_OFFSET_LEFT, v_getint(params[0].var_p)); - map_set_int(self, IMG_OFFSET_TOP, v_getint(params[1].var_p)); - map_set_int(self, IMG_WIDTH, v_getint(params[2].var_p)); - map_set_int(self, IMG_HEIGHT, v_getint(params[3].var_p)); + var_int_t left, top, right, bottom; + if (image != nullptr && par_massget("iiii", &left, &top, &right, &bottom)) { + map_set_int(self, IMG_OFFSET_LEFT, left); + map_set_int(self, IMG_OFFSET_TOP, top); + map_set_int(self, IMG_WIDTH, right); + map_set_int(self, IMG_HEIGHT, bottom); } } } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 2bebe619..7f31b125 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -62,34 +62,30 @@ StringList *get_items() { return items; } -void cmd_window_select_screen1(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_select_screen1(var_s *self, var_s *) { g_system->getOutput()->selectScreen(USER_SCREEN1); } -void cmd_window_select_screen2(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_select_screen2(var_s *self, var_s *) { g_system->getOutput()->selectScreen(USER_SCREEN2); } -void cmd_window_select_screen3(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_select_screen3(var_s *self, var_s *) { g_system->getOutput()->selectScreen(TEXT_SCREEN); } -void cmd_window_show_keypad(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_show_keypad(var_s *self, var_s *) { maShowVirtualKeyboard(); } -void cmd_window_hide_keypad(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_hide_keypad(var_s *self, var_s *) { maHideVirtualKeyboard(); } -void cmd_window_inset(var_s *self, int param_count, slib_par_t *params, var_s *) { - if (param_count != 4) { - err_parm_num(param_count, 4); - } else { - var_int_t x = v_getint(params[0].var_p); - var_int_t y = v_getint(params[1].var_p); - var_int_t w = v_getint(params[2].var_p); - var_int_t h = v_getint(params[3].var_p); +void cmd_window_inset(var_s *self, var_s *) { + var_int_t x, y, w, h; + par_massget("IIII", &x, &y, &w, &h); + if (!prog_error) { if (x < 0 || x > 100 || y < 0 || y > 100 || w < 1 || x + w > 100 || @@ -101,42 +97,31 @@ void cmd_window_inset(var_s *self, int param_count, slib_par_t *params, var_s *) } } -void cmd_window_set_font(var_s *self, int param_count, slib_par_t *params, var_s *) { - if (param_count != 4) { - err_parm_num(param_count, 4); - } else { - var_num_t size = v_getreal(params[0].var_p); - const char *unit = v_getstr(params[1].var_p); - var_int_t bold = v_getint(params[2].var_p); - var_int_t italic = v_getint(params[3].var_p); - if (unit != nullptr && strcmp(unit, "em") == 0) { - size *= g_system->getOutput()->getFontSize(); - } - g_system->getOutput()->setFont(size, bold, italic); +void cmd_window_set_font(var_s *self, var_s *) { + var_num_t size; + var_int_t bold, italic; + char *unit = nullptr; + par_massget("FSII", &size, &unit, &bold, &italic); + if (unit != nullptr && strcmp(unit, "em") == 0) { + size *= g_system->getOutput()->getFontSize(); } + g_system->getOutput()->setFont(size, bold, italic); + pfree(unit); } -void cmd_window_set_size(var_s *self, int param_count, slib_par_t *params, var_s *) { - if (param_count != 2) { - err_parm_num(param_count, 2); - } else { - var_int_t width = v_getint(params[0].var_p); - var_int_t height = v_getint(params[1].var_p); - g_system->setWindowRect(-1, -1, width, height); - } +void cmd_window_set_size(var_s *self, var_s *) { + var_int_t width, height; + par_massget("II", &width, &height); + g_system->setWindowRect(-1, -1, width, height); } -void cmd_window_set_location(var_s *self, int param_count, slib_par_t *params, var_s *) { - if (param_count != 2) { - err_parm_num(param_count, 2); - } else { - var_int_t x = v_getint(params[0].var_p); - var_int_t y = v_getint(params[1].var_p); - g_system->setWindowRect(x, y, -1, -1); - } +void cmd_window_set_location(var_s *self, var_s *) { + var_int_t x, y; + par_massget("II", &x, &y); + g_system->setWindowRect(x, y, -1, -1); } -void cmd_window_get_theme(var_s *self, int param_count, slib_par_t *params, var_s *retval) { +void cmd_window_get_theme(var_s *, var_s *retval) { if (retval != nullptr) { EditTheme theme; theme.setId(g_themeId); @@ -152,7 +137,7 @@ void cmd_window_get_theme(var_s *self, int param_count, slib_par_t *params, var_ } } -void cmd_window_alert(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_alert(var_s *self, var_s *) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { const char *message = items->size() > 0 ? (*items)[0]->c_str() : ""; @@ -162,7 +147,7 @@ void cmd_window_alert(var_s *self, int param_count, slib_par_t *params, var_s *) delete items; } -void cmd_window_ask(var_s *self, int param_count, slib_par_t *params, var_s *retval) { +void cmd_window_ask(var_s *self, var_s *retval) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { const char *message = items->size() > 0 ? (*items)[0]->c_str() : ""; @@ -176,7 +161,7 @@ void cmd_window_ask(var_s *self, int param_count, slib_par_t *params, var_s *ret delete items; } -void cmd_window_menu(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_menu(var_s *self, var_s *) { StringList *items = get_items(); if (!prog_error && items->size() > 0) { g_system->optionsBox(items); @@ -184,7 +169,7 @@ void cmd_window_menu(var_s *self, int param_count, slib_par_t *params, var_s *) delete items; } -void cmd_window_message(var_s *self, int param_count, slib_par_t *params, var_s *) { +void cmd_window_message(var_s *self, var_s *) { var_t arg; v_init(&arg); eval(&arg); From 222d01439925be6b52cf8910ba2ae61600d621e5 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 7 Jan 2024 11:20:02 +1030 Subject: [PATCH 3/3] COMMON: Allow modules to return objects with methods that take arguments --- src/common/var.c | 8 ++++++++ src/common/var_eval.c | 22 +++++++++++++--------- src/include/var.h | 7 +++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/common/var.c b/src/common/var.c index 3574840d..6f46ca7b 100644 --- a/src/common/var.c +++ b/src/common/var.c @@ -803,3 +803,11 @@ void v_create_func(var_p_t map, const char *name, method cb) { v_func->v.fn.mcb = NULL; v_func->v.fn.id = 0; } + +void v_create_callback(var_p_t map, const char *name, callback cb) { + var_p_t v_func = map_add_var(map, name, 0); + v_func->type = V_FUNC; + v_func->v.fn.cb = NULL; + v_func->v.fn.mcb = cb; + v_func->v.fn.id = 0; +} diff --git a/src/common/var_eval.c b/src/common/var_eval.c index aa6912ed..7bcec5de 100644 --- a/src/common/var_eval.c +++ b/src/common/var_eval.c @@ -16,6 +16,17 @@ #include "common/var_eval.h" #include "common/plugins.h" +// +// returns a temporary var that can exist in the calling scope +// +var_p_t v_get_tmp(var_p_t map) { + var_p_t result = map_get(map, MAP_TMP_FIELD); + if (result == NULL) { + result = map_add_var(map, MAP_TMP_FIELD, 0); + } + return result; +} + void v_eval_func(var_p_t self, var_p_t v_func, var_p_t result) { if (v_func->v.fn.cb != NULL) { // internal object method @@ -185,11 +196,7 @@ var_t *code_get_map_element(var_t *map, var_t *field) { if (udf_rv.type != kwTYPE_RET) { err_stackmess(); } else { - // result must exist until processed in eval() - var_p_t var = map_get(map, MAP_TMP_FIELD); - if (var == NULL) { - var = map_add_var(map, MAP_TMP_FIELD, 0); - } + var_p_t var = v_get_tmp(map); v_move(var, udf_rv.x.vdvar.vptr); v_detach(udf_rv.x.vdvar.vptr); result = var; @@ -198,10 +205,7 @@ var_t *code_get_map_element(var_t *map, var_t *field) { } else if (field->type == V_ARRAY) { result = code_getvarptr_arridx(field); } else if (field->type == V_FUNC) { - result = map_get(map, MAP_TMP_FIELD); - if (result == NULL) { - result = map_add_var(map, MAP_TMP_FIELD, 0); - } + result = v_get_tmp(map); v_init(result); v_eval_func(map, field, result); } else { diff --git a/src/include/var.h b/src/include/var.h index 8ea30f90..16e0f4d2 100644 --- a/src/include/var.h +++ b/src/include/var.h @@ -503,6 +503,13 @@ int v_strlen(const var_t *v); */ void v_create_func(var_p_t map, const char *name, method cb); +/** + * @ingroup var + * + * creates a callback method + */ +void v_create_callback(var_p_t map, const char *name, callback cb); + #if defined(__cplusplus) } #endif