上下文保留评估

2024-04-27

我们正在构建一个小型 REPL 来评估(使用eval) 用户输入的 JavaScript 表达式。由于整个事情是事件驱动的,因此评估必须在单独的函数中进行,但必须在调用之间保留上下文(即所有声明的变量和函数)。我想出了以下解决方案:

function* _EVAL(s) {
    while (1) {
        try {
            s = yield eval(s)
        } catch(err) {
            s = yield err
        }
    }
}

let _eval = _EVAL()
_eval.next()

function evaluate(expr) {
    let result = _eval.next(expr).value
    if (result instanceof Error)
        console.log(expr, 'ERROR:', result.message)
    else
        console.log(expr, '===>', result)
}

evaluate('var ten = 10')
evaluate('function cube(x) { return x ** 3 }')
evaluate('ten + cube(3)')
evaluate('console.log("SIDE EFFECT")')
evaluate('let twenty = 20')
evaluate('twenty + 40') // PROBLEM

正如您所看到的,它可以很好地处理函数范围的变量(var and function),但在块作用域上失败(let).

我怎样才能写一个上下文保留eval包装器也将保留块范围的变量?

代码在浏览器中运行,DOM 和 Workers 完全可用。

应该提到的是,所需的函数必须正确处理副作用,即每一行代码,或者至少每个副作用,应该只执行一次。

Links:

JavaScript:在一台虚拟机中进行所有评估 https://stackoverflow.com/questions/67173347/javascript-do-all-evaluations-in-one-vm | https://vane.life/2016/04/03/eval-locally-with-persistent-context/ https://vane.life/2016/04/03/eval-locally-with-persistent-context/


The 您链接的文章 https://vane.life/2016/04/03/eval-locally-with-persistent-context/包含一个实际上有效的疯狂方法:在每个eval()调用,我们在其中创建一个新的闭包eval作用域并导出它,以便我们可以使用它来评估下一个语句。

var __EVAL = s => eval(`void (__EVAL = ${__EVAL.toString()}); ${s}`);

function evaluate(expr) {
    try {
        const result = __EVAL(expr);
        console.log(expr, '===>', result)
    } catch(err) {
        console.log(expr, 'ERROR:', err.message)
    }
}

evaluate('var ten = 10')
evaluate('function cube(x) { return x ** 3 }')
evaluate('ten + cube(3)')
evaluate('console.log("SIDE EFFECT")')
evaluate('let twenty = 20')
evaluate('twenty + 40') // NO PROBLEM :D
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

上下文保留评估 的相关文章