Extended and early detection of errors in scripts


#1

Hi,

When we ‘eval’ a script from c++, it reports the syntax errors (such as missing parentheses, …), but not report about reference to functions or objects that are not declared.

I know that this is the normal behaviour of interpreted language, but if we could have the best of the two worlds…

Imagine the following script:

def f(int i)
{
    if (i > 1000) {
        missing_function();
    }
    …
}

From C++, we call:

engine.eval(script); // No error reported
std::function<void (int)> fScript = engine.eval<std::function<void (int)> >("f");

for (int i = 0; i < 150; i++) {
    fScript(i);  // The error will only be reported on the 100th iterations
}

How to validate that all functions/objects referenced in the script are existing without invoking it ?

Philippe Leuba


#2

I appreciate what you’re asking for, but it would be a large breaking change for ChaiScript, semantically.

For example, what exactly is missing_function()?

It could be a function:

def missing_function() {}

Or it could be a global variable:

GLOBAL missing_function = fun(){ };

Or maybe it’s both. For example, it’s currently possible to override the built in print function:

GLOBAL print = fun(x) { `print`("You printed: ${x}!"); };

The main real problem I see is that we’d now need a way to forward declare functions, if for some reason you needed two functions that referenced each other. But even that wouldn’t fully give you what you want. Take for example this performance test code I run:

https://github.com/ChaiScript/ChaiScript/blob/develop/contrib/codeanalysis/heterogenous_array_loop.chai

What if there was an object inside of the vector that did not have a matching to_string function? You could still get a no matching function to dispatch to error even after doing a lookup of the function name.


So, after all that, I’d say it’d be possible to write an analysis function that generates a warning or error in the case that an identifier cannot be found. I’ve been meaning to do something like this as a performance optimization, so that I can limit the search / lookup for an identifier at script execution time.

-Jason


#3

Hi Jason,

Thanks for your quick answer.

I agree that it will not be possible to check all errors, but the more we catch early, the better it is…

My idea was to do this check not automaticslly during the eval but later just before the script invocation, with an explicit call. This prevents the need to forward declare functions and allow functions to be added to the engine in multiples steps.

Is it already possible to browse the internal data to do such kind of checks, for example iterates the AST tree of a function and verify that the called functions name exist? Or that the used variables exist?

Thanks for this awesome library for the c++ world.

Philippe


#4

Oh sure, that’s certainly possible.

You can see an example of how we walk the AST currently to do some minor optimizations at parse time:

It’s possible to get the base AST_Node of any ChaiScript parsed function with:

So, it wouldn’t be a simple task to get started on, but it is possible. If you’re interested in working on a validator, I could help you get started.

The main question would be: when would you want to run this? Immediately after parsing? At some arbitrary time, some validate_all_functions() call, or something else?

-Jason


#5

Hi Jason,

My idea is to have a kind of validate() function, independent of the evaluation, that we can call just before executing a script function.

Do you think that I could implement this on my code, without modifying the chai script source files?

I would really appreciate if you can help me to get started on this.

Have a nice day.

Philippe


#6

I know it’s been a long time, but I think if you look at this thread, and use the ability to parse/eval separately you could do the validation you want to do.

parse, then walk the AST tree (validate), then eval

-Jason