hetu-script
hetu-script copied to clipboard
Weird issue with extern fun and hetu_script_dev_tools
When I defined my custom "eval" function, it behaves in weird way, so I have a series of issues with it, so I had to split them into multiple github issues.
Name | Value |
---|---|
Dart source | https://pastebin.com/8zkJhyUJ |
Dart version | Dart SDK version: 2.16.1 (stable) (Tue Feb 8 12:02:33 2022 +0100) on "windows_x64" |
hetu_script version | 0.3.12 |
hetu_script_dev_tools version | 0.0.9 |
hetu file:
external fun my_eval;
var a = my_eval("3");
a;
This hetu code evaluates fine when I use hetu.eval
to run it from string, but if I try to run it via hetu.evalFile
, then I get following error:
error: File: [D:/EH/hetu/script/index.hts]()
Line: 4, Column: 1
Runtime error: undefined
Message: Undefined identifier [a].
sourceContext is provided via HTFileSystemResourceContext
from hetu_script_dev_tools
Additional info:
If I change index.hts
to
external fun my_eval;
var a = 9;
print("Pre-eval: ${a}");
a = my_eval("3");
a;
then I get this log:
So it looks like, calling my custom eval function, erases the identifier from scope, but only if ran via
evalFile
While testing code for another issue, I found out that default eval
function also behaves in the same way.
Code to replicate
var meaning;
fun global(){
eval("meaning = 'hello from a deeper dream!'");
meaning;
}
global();
In current design, eval will use Global namespace as it's namespace.
This is for clarity and safe, for example, if you are evaling a string variable rather than a literal string, and you changed the variable within the context, it will be very confusing.
It will not use the context you called it within, so you cannot access variable defined outside of the literal string code.
And a code file like *.hts or *.ht will create it's own namespace when running, so the context of the running code is the file so eval cannot use any variable defined in that file either.
And in general, just don't use this method, I am pretty sure your need can be achieve by other means other than use this evil method.
As for the eval returns null bug, I think it is due to the reason that interpreter's eval method is called within another eval process. So the stackframe information is changed and is not restored properly.
I have changed the builtin eval method implementation to fix this.
(HTEntity entity,
{List<dynamic> positionalArgs = const [],
Map<String, dynamic> namedArgs = const {},
List<HTType> typeArgs = const []}) {
final code = positionalArgs.first as String;
final savedFileName = interpreter.currentFileName;
final savedModuleName = interpreter.bytecodeModule.id;
final savedNamespace = interpreter.currentNamespace;
final savedIp = interpreter.bytecodeModule.ip;
final result = interpreter.eval(code);
interpreter.restoreStackFrame(
clearStack: false,
savedFileName: savedFileName,
savedModuleName: savedModuleName,
savedNamespace: savedNamespace,
savedIp: savedIp,
);
return result;
};
The fix will be commited to the main branch.