hetu-script icon indicating copy to clipboard operation
hetu-script copied to clipboard

Weird issue with extern fun and hetu_script_dev_tools

Open juh9870 opened this issue 2 years ago • 4 comments

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

juh9870 avatar Apr 04 '22 12:04 juh9870

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: image So it looks like, calling my custom eval function, erases the identifier from scope, but only if ran via evalFile

juh9870 avatar Apr 04 '22 12:04 juh9870

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();

image

juh9870 avatar Apr 04 '22 12:04 juh9870

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.

hythl0day avatar Apr 06 '22 02:04 hythl0day

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.

hythl0day avatar Apr 06 '22 03:04 hythl0day