Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
11 changes: 4 additions & 7 deletions src/common/blib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2881,13 +2881,10 @@ void cmd_call_vfunc() {
rt_raise(ERR_NO_FUNC);
}
} else {
if (code_peek() == kwTYPE_LEVEL_BEGIN) {
code_skipnext();
}
v_func->v.fn.cb(map, NULL);
if (code_peek() == kwTYPE_LEVEL_END) {
code_skipnext();
}
var_t result;
v_init(&result);
v_eval_func(map, v_func, &result);
v_free(&result);
}
}

Expand Down
148 changes: 71 additions & 77 deletions src/common/plugins.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand All @@ -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;
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
}
12 changes: 11 additions & 1 deletion src/common/plugins.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand All @@ -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
Expand Down
9 changes: 9 additions & 0 deletions src/common/var.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,5 +800,14 @@ 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;
}

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;
}
61 changes: 55 additions & 6 deletions src/common/var_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -14,6 +14,55 @@
#include "common/smbas.h"
#include "common/var.h"
#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
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
Expand Down Expand Up @@ -147,18 +196,18 @@ 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;
}
}
} else if (field->type == V_ARRAY) {
result = code_getvarptr_arridx(field);
} else if (field->type == V_FUNC) {
result = v_get_tmp(map);
v_init(result);
v_eval_func(map, field, result);
} else {
code_skipnext();
var_t var;
Expand Down
7 changes: 7 additions & 0 deletions src/common/var_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 0 additions & 8 deletions src/include/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
Loading