More detailed error from runbuf function in Dynamics AX - axapta

I try to build some kind of X++ script executor and therefore play around with the runbuf function.
It works as long as the X++ code I pass in is valid, but when I pass invalid code then it just throws an error that it is not able to compile the code but no further details.
For example when I try the following code
runbuf('void dynAdd(int lhs, int rhs) { return lhs + rhs; }');
it fails with the error
Unable to compile "void dynAdd(int lhs, int rhs) { return lhs + rhs;
}".
Is there a way to get more information about the error?
Thanks in advance

You can use XppCompiler for that like so
static void DynamicXppTest(Args _args)
{
str dynamicXpp;
int result;
XppCompiler xppCompiler;
;
dynamicXpp = 'void dynAdd(int lhs, int rhs) { return lhs + rhs; }';
// previous runbuf - style
//
// result = runbuf(dynamicXpp, 3, 4);
// info(strfmt("result = %1", result));
xppCompiler = new XppCompiler();
if (xppCompiler.compile(dynamicXpp))
{
result = xppCompiler.execute(3, 4);
info(strfmt("result = %1", result));
}
else
{
error(xppCompiler.errorText());
}
}
which will result in the below error in the infolog
*** Error: 82, The operand is not compatible with the type of the function.

Related

What is an async scope for a delegate in Vala?

I am trying the async examples from the GNOME project site. I get the follwoing warning which I don't under stand on how to fix.
async.vala:8.2-8.17: warning: delegates with scope="async" must be owned
Code
async double do_calc_in_bg(double val) throws ThreadError {
SourceFunc callback = do_calc_in_bg.callback;
double[] output = new double[1];
// Hold reference to closure to keep it from being freed whilst
// thread is active.
// WARNING HERE
ThreadFunc<bool> run = () => {
// Perform a dummy slow calculation.
// (Insert real-life time-consuming algorithm here.)
double result = 0;
for (int a = 0; a<100000000; a++)
result += val * a;
output[0] = result;
Idle.add((owned) callback);
return true;
};
new Thread<bool>("thread-example", run);
yield;
return output[0];
}
void main(string[] args) {
var loop = new MainLoop();
do_calc_in_bg.begin(0.001, (obj, res) => {
try {
double result = do_calc_in_bg.end(res);
stderr.printf(#"Result: $result\n");
} catch (ThreadError e) {
string msg = e.message;
stderr.printf(#"Thread error: $msg\n");
}
loop.quit();
});
loop.run();
}
The warning is pointing at the run variable inside the async function. Who or what needs to be owned? The reference to the closure?
The delegate needs to have a well defined owner all the time. The error message is a bit misleading.
To fix it you have to explicitly transfer the ownership from the delegate to the thread constructor:
new Thread<bool>("thread-example", (owned) run);
Instead of
new Thread<bool>("thread-example", run);
See also: https://wiki.gnome.org/Projects/Vala/Tutorial#Ownership
PS: The generated C code is fine in both cases. (at least with valac 0.46.6)

warning.expression prevents last.warning from update

I'm interested in trying to manipulate warnings on call without creating support infrastructure around a method. That is, I need to be able to catch the warning without resorting to wrapping code with:
tryCatch(..., warning = function() { action() } )
I believe I can do this using the warning.expression handler.
However, the issue I am running into is the last.warning when invoked during the warning dispatch of warning.expression fails to retrieve the latest warning.
For example:
warning_handler = function() {
if (exists("last.warning", baseenv()) &&
!is.null(last.warning)) {
warning_contents = names(last.warning)
} else {
warning_contents = NA
}
message(warning_contents)
}
options(warning.expression = quote({ warning_handler() }))
warning("test1")
# test1
warning("testing2")
# test1
warning("sampletest3")
# test1
If I revert to using the default handler, e.g. NULL, then the message is updated at the cost of not being able to interact with it.
options(warning.expression = NULL)
warning("test1")
# Warning message:
# test1
warning("testing2")
# Warning message:
# testing2
warning("sampletest3")
# Warning message:
# sampletest3
Am I missing something related to the handler or?
Adding a warning.expression almost certainly interferes with the warning collection mechanism. I'm not 100% certain about this, but if you look at (R.3.4.0, I have an old copy of the sources), you can see at errors.c#335:
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
{
int w;
SEXP names, s;
const char *dcall;
char buf[BUFSIZE];
RCNTXT *cptr;
RCNTXT cntxt;
if (inWarning)
return;
s = GetOption1(install("warning.expression"));
if( s != R_NilValue ) {
if( !isLanguage(s) && ! isExpression(s) )
error(_("invalid option \"warning.expression\""));
cptr = R_GlobalContext;
while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
cptr = cptr->nextcontext;
eval(s, cptr->cloenv);
return;
}
// ... snip ...
else if(w == 0) { /* collect them */
if(!R_CollectWarnings) setupwarnings();
if(R_CollectWarnings < R_nwarnings) {
SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
// ... snip ...
}
So the part after the return doesn't run.
And it looks like last.value is populated by printWarnings in errors.c#466, so this either happens after the warning.expressions handler, or more likely, not at all:
attribute_hidden
void PrintWarnings(void)
{
// ... snip to very end of fun ...
/* now truncate and install last.warning */
PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
names = CAR(ATTRIB(R_Warnings));
for(i = 0; i < R_CollectWarnings; i++) {
SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
SET_STRING_ELT(t, i, STRING_ELT(names, i));
}
setAttrib(s, R_NamesSymbol, t);
SET_SYMVALUE(install("last.warning"), s);
UNPROTECT(2);
endcontext(&cntxt);
inPrintWarnings = 0;
R_CollectWarnings = 0;
R_Warnings = R_NilValue;
return;
}
So it is likely that's what going on. I haven't worked through the flow patterns so it's possible I'm wrong. If I'm right it seems like there isn't a way to get the warning info from warning.expression.
Beyond that, note that last.warning is documented as being undocumented, FWIW.
Another answer courtesy of #lionel in chat was: to install a warning handler at top level, which you can do by calling into internal functions with .Internal()
handlers <- list(warning = function(cnd) cat("hello\n"))
classes <- names(handlers)
.Internal(.addCondHands(classes, handlers, globalenv(), NULL, TRUE))
warn("plop")
The only downside to this approach is CRAN would reject a package on submission due to the internal call.

Passing value by reference to Qore script function from C++ code

I need pass returnValue to a method as argument passed by reference and adjust original var value when function id done. So using ReferenceArgumentHelper class.
What's wrong in code bellow when returnValue is unintentionally deleted (when it is a node, i.e. string) and valgrind detects it. callMethod("onFunctionExit" calls an Qore script method and I can see there correct returnValue value. I suspect it's deleted when exiting onFunctionExit when ReferenceArgumentHelper is destroyed. rah.getArg() references reference variable, so it should not be deleted in callMethod.
DLLLOCAL ThreadDebugEnum callMethod(const char* name, const ThreadDebugEnum defaultResult, QoreProgram *pgm, int paramCount, AbstractQoreNode** params, ExceptionSink* xsink) {
int rv;
QoreListNode* l = new QoreListNode();
qore_program_to_object_map_t::iterator i = qore_program_to_object_map.find(pgm);
if (i == qore_program_to_object_map.end()) {
return defaultResult;
}
i->second->ref();
l->push(i->second);
for (int i=0; i<paramCount; i++) {
if (params[i])
params[i]->ref();
l->push(params[i]);
}
rv = qo->intEvalMethod(name, l, xsink);
l->deref(xsink);
return (ThreadDebugEnum) rv;
}
DLLLOCAL virtual ThreadDebugEnum onFunctionExit(QoreProgram *pgm, const StatementBlock *blockStatement, QoreValue& returnValue, ExceptionSink* xsink) {
AbstractQoreNode* params[2];
params[0] = getLocation(blockStatement);
ReferenceArgumentHelper rah(returnValue.takeNode(), xsink); // grab node from returnValue and pass to helper
params[1] = rah.getArg(); // caller owns ref
ThreadDebugEnum rv = callMethod("onFunctionExit", DBG_SB_RUN, pgm, 2, params, xsink);
AbstractQoreNode* rc = rah.getOutputValue(); // caller owns ref
returnValue.assign(rc); // takes reference
// returnValue.ref();
}
return rv;
}
When looking deeply I did not get why compiler is happy with code in /lib/ReferenceArgumentHelper.cpp:
struct lvih_intern {
LocalVar lv;
ExceptionSink* xsink;
ReferenceNode* ref;
DLLLOCAL lvih_intern(AbstractQoreNode* val, ExceptionSink* xs) : lv("ref_arg_helper", 0), xsink(xs) {
printd(5, "ReferenceArgumentHelper::ReferenceArgumentHelper() instantiating %p (val: %p type: '%s') \n", &lv, val, val ? val->getTypeName() : "n/a");
lv.instantiate(val); <--------------
VarRefNode* vr = new VarRefNode(strdup("ref_arg_helper"), VT_LOCAL);
vr->ref.id = &lv;
ref = new ReferenceNode(vr, 0, vr, 0);
}
class LocalVar {
....
DLLLOCAL void instantiate(QoreValue nval) const {
What is behind conversion AbstractQoreNode* to QoreValue in method call? I did not find an overloaded operator or so. I'm looking what exactly happens with references.
** EDIT **
To make a long story short, ReferenceArgumentHelper was buggy; it hadn't been used in years and was not up to date. The class has been fixed which should fix your issue I hope.
Thank you for pointing this out, and let me know if you have any further problems with this or the fix to the affected code.

QList to QQmlListProperty

I'm trying to pass QList into QML using QQmlListProperty, as official documentation says:
QQmlListProperty::QQmlListProperty(QObject *object, void *data, CountFunction count, AtFunction at)
My code is:
QQmlListProperty<TTimingDriver> TTiming::getDrivers()
{
return QQmlListProperty<TTimingDriver>(this, &m_drivers, &TTiming::count, &TTiming::driverAt);
}
int TTiming::count(QQmlListProperty<TTimingDriver> *property)
{
TTiming * timing = qobject_cast<TTiming *>(property->object);
return timing->m_drivers.count();
}
TTimingDriver * TTiming::driverAt(QQmlListProperty<TTimingDriver> *property, int i)
{
TTiming * timing = qobject_cast<TTiming *>(property->object);
return timing->m_drivers.at(i);
}
But I'm getting an error:
no matching function for call to 'QQmlListProperty<TTimingDriver>::QQmlListProperty(TTiming*, QList<TTimingDriver*>*, int (TTiming::*)(QQmlListProperty<TTimingDriver>*), TTimingDriver* (TTiming::*)(QQmlListProperty<TTimingDriver>*, int))'
return QQmlListProperty<TTimingDriver>(this, &m_drivers, &TTiming::count, &TTiming::driverAt);
I think <ou are mixing two of the QQmlListProperty constructor overloads.
The one that takes the QList<T*> does not need pointers to functions.
So this should be sufficient
QQmlListProperty<TTimingDriver> TTiming::getDrivers()
{
return QQmlListProperty<TTimingDriver>(this, &m_drivers);
}
Assuming that m_drivers is of type QList<TTimingDriver*>

Parallel Iterators in the D language

I am trying to implement a graph data structure in the D language which supports parallel iteration over the node and edge sets.
alias ulong index;
alias index node;
alias ulong count;
class Graph {
index z; // max node index
count n; // number of nodes
count m; // number of edges
node[][] adja; // adjacency list
count[] deg; // node degree
this(count n = 0) {
this.z = n;
this.n = n;
this.m = 0;
this.adja = new node[][](this.z, 0);
this.deg = new count[](this.z);
}
Here's a sequential node iterator method:
/**
* Iterate over all nodes of the graph and call handler (lambda closure).
*/
void forNodes(F)(F handle) {
foreach (node v; 0 .. z) {
// call here
handle(v);
}
}
Works like this, and seems to work fine:
ulong sum1 = 0;
G.forNodes((node v) {
sum1 += v;
});
Now I try a parallel version using the 'std.parallelism' module:
void parallelForNodes(F)(F handle) {
foreach (node v; taskPool.parallel(z)) {
// call here
handle(v);
}
}
But this gives me the a compiler error. What am I doing wrong here?
cls ~/workspace/Prototypes/PLPd $ ./main.d
/usr/local/Cellar/dmd/2.063/src/phobos/std/parallelism.d(3795): Error: cannot have parameter of type void
/usr/local/Cellar/dmd/2.063/src/phobos/std/parallelism.d(3796): Error: cannot have parameter of type void
/usr/local/Cellar/dmd/2.063/src/phobos/std/parallelism.d(1539): Error: template instance std.parallelism.ParallelForeach!(ulong) error instantiating
Graph.d(90): instantiated from here: parallel!(ulong)
./main.d(100): instantiated from here: parallelForNodes!(void delegate(ulong v) nothrow #safe)
Graph.d(90): Error: template instance std.parallelism.TaskPool.parallel!(ulong) error instantiating
./main.d(100): instantiated from here: parallelForNodes!(void delegate(ulong v) nothrow #safe)
./main.d(100): Error: template instance Graph.Graph.parallelForNodes!(void delegate(ulong v) nothrow #safe) error instantiating
Failed: 'dmd' '-v' '-o-' './main.d' '-I.'
parallel takes a range. Use std.range.iota to get the range equivalent of 0 .. z: foreach (v; parallel(iota(z))) {...}

Resources