I think this is a toy problem, but here is a possible approach to this problem. Convert the function to a string, then for all instances of a valid return statement anywhere in the string replace them with confederate return statements. Execute this modified function using eval()
and observe what is returned.
For example,
function foo(){ return; }
function bar(){ if(0) return; }
becomes
function foo(){ return 'return;'; } // "return;"
function bar(){ if(0) return 'return'; } // undefined
This way whatever path the logic follows in the function, if something is explicitly returned, we can know what form it takes. If nothing is returned, due to design or logic flow, then 'undefined' is returned. Consider the following function:
function inspectReturn(fcn) {
var str = fcn.toString();
// Anytime we see a 'return something' we replace it with return 'something'
str = str.replace(/(\b)return \s*(\S[^\n;}]+)/mg, "$1return '$2'");
// Anywhere we see a lone 'return' we replace it with return 'return'
str = str.replace(/(\b)return\s*([\n;}])/mg, "$1return 'return;'$2");
eval("fcn="+str);
return fcn();
}
We can then observe the return values from the the below sample functions:
function noReturn(){ } // undefined
function useReturn(){ return } // "return;"
function useReturn2(){ return; } // "return;"
function useReturn3(){ return true; } // "true"
function useReturn4(){ if(0) return; } // undefined
function useReturn5(){ return undefined } // "undefined "
function useReturn6(){ var _return = " return "; return _return; } // "_return"
Demo: JSBin
Note: Voice your opinion about how the regex can be improved all you wish. You might be able to break it (and congratulations to you), but there are simple and concrete JavaScript parsing rules for validating return statements, so on such a toy problem it's up to the reader to properly implement them. Also, if something is thrown
, then catch
blocks exist for that. However, this is a sufficient demo IMHO.