metaes, JavaScript解释器,用于更好的工具,JavaScript

分享于 

19分钟阅读

GitHub

  繁體 雙語
JavaScript in JavaScript interpreter for better tools
  • 源代码名称:metaes
  • 源代码网址:http://www.github.com/metaes/metaes
  • metaes源代码文档
  • metaes源代码下载
  • Git URL:
    git://www.github.com/metaes/metaes.git
    Git Clone代码到本地:
    git clone http://www.github.com/metaes/metaes
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/metaes/metaes
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    MetaES ( 正在进行中)

    Build Status

    [Docs copied from legacy https://github.com/metaes/metaes-es5 ]

    MetaES是在 ECMAScript 5.1标准下编写的metacircular解释器( http://en.wikipedia.org/wiki/Meta-circular_evaluator ),所以它可以在任何支持 ES5.1,的环境中运行,例如现代浏览器的( 带移动设备)。nodejs。nashorn。和其他 ECMAScript 5.1解释器。

    MetaES当前处于alpha状态。

    链接

    安装

    使用 npm:

    
    npm install git+git@github.com:metaes/metaes.git
    
    
    
    

    然后在 .js file: 中写入

    var metaes =require('metaes');functioninterceptor(e, val, env, pause) {
     console.log('['+e.type+']', e.subProgram, val);
    }var c =1,
     map=function (x) {
     return x * x * c;
     },
     metacircularMap =metaes.evaluate(map, {c:10}, {interceptor: interceptor});// see the resultsconsole.log("map:", [1, 2, 3, 4, 5].map(map));console.log("metacircular map:", [1, 2, 3, 4, 5].map(metacircularMap));

    查看控制台中的输出。

    使用 bower:

    
    bower install git@github.com:metaes/metaes.git
    
    
    
    

    然后导入脚本:

    <scriptsrc="bower_components/esprima/esprima.js"></script>
    <scriptsrc="bower_components/metaes/metaes.js"></script>

    然后你可以写:

    metaes.evaluate('console.log("hello world!")', window);

    文档

    2阅读API文档。 API参考

    许可证

    
    The MIT License (MIT)
    
    
    
    
    table-内容

    1关于MetaES作为metacircular解释器

    就像在序曲中所说的,MetaES是一个metacircular解释器。 例如你可以了解更多关于这种解释器的信息,例如在免费在线 http://mitpress.mit.edu/sicp/full-text/sicp/book/node76.html 中可以获得的SICP。

    Picture 1. Gerald Jay Sussman showing how it works from the big picture

    [ 图 1.Gerald Jay展示了它是如何从大图片中展示

    Metacircular解释器基本上解释了它所写的语言,但解释过程更容易,因为基本解释器实现了很多功能。 对于 MetaES,这些功能在每个 ECMAScript 5.1解释器中都可用:

    • 二进制表达式运算符,比如: +-*/
    • 文字(。booleanStringNumber,对象- {...},数组- [...] )
    • functions,内部函数 [[Call]]bindapplycall
    • Prototype - MetaES不会重写它们
    • 使用 newObject.create 创建对象,
    • 标准全局对象,如 ObjectArrayStringDate

    等等。

    因此,metacircullar解释的主要部分就是重用原始解释器的功能。 但是,MetaES添加了一些可以供用户使用的信息,在正常执行中隐藏并且只能通过特定的调试器 API。 这些信息包括:

    • 作为JavaScript对象访问范围:

      var metaes =require('metaes');functioninterceptor(e, value, env, pause) {
       if (e.type==='CallExpression'&& value &&value.callee== getScopeVariablesNames) {
       pause()(Object.keys(env.names));
       }
      }functiongetScopeVariablesNames() {
       thrownewError("Direct call is not allowed.")
      }functionfn() {
       var a ="string", b =2, c =false, d = {};
       // let's call the special method constructed for this instance of interpreter.console.log(getScopeVariablesNames());
      }var metaFn =metaes.evaluate(fn, {
       console:console,
       getScopeVariablesNames: getScopeVariablesNames
       },
       {interceptor: interceptor});metaFn();// output:// [ 'this', 'fn', 'a', 'b', 'c', 'd' ]
    • 作为JavaScript对象访问堆栈:

      var metaes =require('metaes');functioninterceptor(e, value, env, pause) {
       if (e.type==='CallExpression'&& value &&value.callee== getStack) {
       var stack = [];
       do {
       stack.push(env)
       } while (env =env.prev);
       pause()(stack.map(function (env) {
       if (env.fn) {
       returnenv.fn.e.id.name;
       } else {
       return'global';
       }
       }));
       }
      }functiongetStack() {
       thrownewError("Direct call is not allowed.")
      }functionfn() {
       functiona() {
       // let's call the special method constructed for this instance of interpreter.console.log(getStack());
       }
       functionb() {
       a();
       }
       functionc() {
       b();
       }
       c();
      }var metaFn =metaes.evaluate(fn, {
       console:console,
       getStack: getStack
       },
       {interceptor: interceptor});metaFn();// output// [ 'a', 'b', 'c', 'fn', 'global' ]
    • 访问函数闭包:

      var metaes =require('metaes');functioninterceptor(e, value, env, pause) {
       if (e.type==='CallExpression'&& value &&value.callee== getCurrentFunctionClosure) {
       pause()(Object.keys(env.closure.names));
       }
      }functiongetCurrentFunctionClosure() {
       thrownewError("Direct call is not allowed.")
      }functionfn() {
       console.log("outer", getCurrentFunctionClosure());
       var a, b, c, d;
       (function () {
       console.log("inner", getCurrentFunctionClosure());
       }());
      }var metaFn =metaes.evaluate(fn, {
       console:console,
       getCurrentFunctionClosure: getCurrentFunctionClosure
       },
       {interceptor: interceptor});metaFn();// outer [ 'console', 'getCurrentFunctionClosure' ]// inner [ 'this', 'fn', 'a', 'b', 'c', 'd' ]
    • 停止/恢复执行

      var metaes =require('metaes');functioninterceptor(e, value, env, pause) {
       if (e.type==='CallExpression'&& value &&value.callee== sleep) {
       var ms =value.arguments[0];
       var resume =pause();
       setTimeout(resume, ms);
       }
      }functionsleep() {
      }functionfn() {
       console.log("before");
       var start =newDate().getTime();
       sleep(1000);
       console.log("after", newDate().getTime() - start +"ms");
      }var metaFn =metaes.evaluate(fn, {
       console:console,
       sleep: sleep,
       Date:Date },
       {interceptor: interceptor});metaFn();// before// after 1007ms
    • 支持ES6或者任何未来版本的版本

      像 Traceur/Babel/es6to5 这样的项目证明了在ES5中模拟ES6特性是可行的。 解释可以能更强大,因为解释器有机会使用前面的behind 实现新功能,就像 C++ 中的本机解释器。 因这里,有少量的工作是 ArrowFunctions

      [1,2,3].map((x) => {return x*x}) // [1, 4, 9]

    ArrayComprehension的( 在ES7中提出,但在 esprima#harmony 中实现):

    [for (let x in [1,2,3]) x*x]; // [1, 4, 9]

    它们基于 FunctionExpressionForStatement,在ES5中可用。

    classimportexport 也很简单,没有提到 yield,只是基于暂停和恢复执行来保存作用域。 ES7s await 也可能是一个实现的主题,如果underlaying解析器正确解析它的话。

    简而言之,在运行过程中,MetaES可能会通知每个令牌与它的值。源信息( 起始/停止行/列。索引范围。已经解析的AST node 值)。当前调用。

    附加特性或者这个解释器是有意的原生JavaScript互操作性。 让我们通过一个示例列表来了解更多的metacircullarity概念:

    • 你可以通过那些没有生成的函数调用MetaES解释器生成的函数,反之亦然。
    • 它甚至可以解释解释器 inside 以前的解释器实例,以便使一些更先进的introspections,
    • 你可以在MetaES虚拟机的不同实例之间共享 functions/objects/variables,也可以在本地JavaScript解释器之间共享,
    • 从metacircular函数外看只是一个函数,但是 inside 使用MetaES来执行它的主体,
    • 你可以创建metacircular拦截器,
    • 比如,你可以钩子任何评估和更改它的行为,例如你可以引入某种 Big Numbers 或者货币,并使用拦截器正确解释它们。 BinaryExpression 中的"1USD" +"2USD" 类似,+ 运算符将给出 "3USD"。 在运动场上找一个例子
    • 你可以注入特殊函数 inside VM并模拟不同的控制流,如 continuations。yield。synergy。 转到操场,用 ES7 await 查看示例。 前面显示的pause/sleep 也创建了不同的控制结构,
    • MetaES允许使用本机速度运行大多数应用程序,并使用metacircular解释在几个重要位置减慢。 例如库代码可以运行,但库客户端将以metacircular方式运行,但是可以在MetaES模式下运行性能。

    2.API参考

    有 TypeScript typings 。 你可以将它们视为这里引用的complemention。

    这是 metaes 对象中调用解释器的函数的签名:

    functionevaluate(text, rootEnvironment, cfg, c, cerr)

    参数包括:

    • text - JavaScript程序源或者函数引用
    • rootEnvironment ( 可选) - 包含将成为程序环境的key-value 对的对象。 例如我可以是 window/global,或者 {a: 1, b:2},或者具有以前( 外部) 环境的环境,以及应该具有以下属性的环境:
      • name - key值对象,如前面所示: {a: 1, b:2}
      • prev - 环境

    例如: js var outer = { names: window, prev: null }, env = { names: {foo:"bar"}, prev: outer }; metaes.evaluate("console.log(foo)", env); 或者 js metaes.evaluate("console.log(foo)", {foo:"bar", console:console});

    • cfg ( 可选) - 可能包含以下属性的对象:

      • 可以是文件名的name - NAME,也可以是任意任意的NAME。 在默认情况下,将它的保留为未定义将在默认情况下分配 NAME,其中 x 为下一个自然数。
      • interceptor - 签名的函数 (e, value, env, pause) 火警的警铃在哪里?
        • 来自esprima的e - AST node,
        • value - 一个JavaScript值
        • env - 与扩展 rootEnvironment 参数兼容的环境对象
        • pause - 函数一次调用停止执行MetaES并返回一个函数来恢复执行的参数。 更多示例。
    • c ( 可选) - 如果评估成功完成将调用的函数应具有签名

      function(ast, value)

      参数所在的位置:

      • 解析程序的ast - AST
      • value - 最后一个表达式的值
    • cerr ( 可选) - 如果评估完成时将调用的函数,则返回错误(。SyntaxError,任何异常类型的ReferenceError )。 函数应具有签名:

      function(ast, errorName, error);

      参数所在的位置:

      • 解析程序的ast - AST
      • errorName - 可以是 Error,它是本机错误,SyntaxError 或者 ReferenceError
      • Error - 错误对象

    evaluate 返回同步评估的结果。 让我们来比较一下 eval:

    metaes.evaluate("2+x", {x:2}) ===eval("2+2") // true

    或者:

    metaes.evaluate("var x = 1 + a, x;", {a:1});

    将返回 2,但:

    metaes.evaluate("var x = 1 + a, x;");

    将会引发 ReferenceError: a is not defined. 就像 eval

    如果你好奇的话

    metaes.evaluate("eval(1+2)"); // ReferenceError: eval is not defined.metaes.evaluate("eval(1+2)", {eval:eval}); // 3eval('metaes.evaluate("eval(1+2)", {eval:eval})'); // 3

    最有趣的特性是 interceptor。 所以你可以写

    functioninterceptor(e, value, env, pause) {
     console.log("["+e.type+"]: "+e.subProgram+" (line:"+e.loc.start.line+", col: "+e.loc.start.column+")");
    }var fn =metaes.evaluate(function(x){return x*x}, {}, {interceptor: interceptor});console.log([1,2,3].map(fn));

    你就可以进入你的控制台了:

    [ExpressionStatement]:undefined (line:1, col:0)VM1331:3 [FunctionExpression]:undefined (line:1, col:1)VM1331:3 [FunctionExpression]:function (x){return x*x} (line:1, col:1)VM1331:3 [ExpressionStatement]: (function (x){return x*x}) (line:1, col:0)VM1331:3 [Identifier]:undefined (line:1, col:11)VM1331:3 [BlockStatement]:undefined (line:1, col:13)VM1331:3 [ReturnStatement]:undefined (line:1, col:14)VM1331:3 [BinaryExpression]:undefined (line:1, col:21)VM1331:3 [Identifier]:undefined (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:21)VM1331:3 [Identifier]:undefined (line:1, col:23)VM1331:3 [Identifier]:x (line:1, col:23)VM1331:3 [BinaryExpression]: x*x (line:1, col:21)VM1331:3 [ReturnStatement]:return x*x (line:1, col:14)VM1331:3 [FunctionExpression]:function (x){return x*x} (line:1, col:1)VM1331:3 [Identifier]:undefined (line:1, col:11)VM1331:3 [BlockStatement]: {return x*x} (line:1, col:13)VM1331:3 [ReturnStatement]:return x*x (line:1, col:14)VM1331:3 [BinaryExpression]: x*x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:23)VM1331:3 [Identifier]:x (line:1, col:23)VM1331:3 [BinaryExpression]: x*x (line:1, col:21)VM1331:3 [ReturnStatement]:return x*x (line:1, col:14)VM1331:3 [FunctionExpression]:function (x){return x*x} (line:1, col:1)VM1331:3 [Identifier]:undefined (line:1, col:11)VM1331:3 [BlockStatement]: {return x*x} (line:1, col:13)VM1331:3 [ReturnStatement]:return x*x (line:1, col:14)VM1331:3 [BinaryExpression]: x*x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:21)VM1331:3 [Identifier]:x (line:1, col:23)VM1331:3 [Identifier]:x (line:1, col:23)VM1331:3 [BinaryExpression]: x*x (line:1, col:21)VM1331:3 [ReturnStatement]:return x*x (line:1, col:14)VM1331:3 [FunctionExpression]:function (x){return x*x} (line:1, col:1)VM1331:7 [1, 4, 9]

    调用metacircular函数实际上是这样的:

    >>Function.prototype.toString.call(fn);// outputs>>"function (x) {return MetaInvokerInner.apply(this,arguments)}"

    3。路线图

    MetaES仍处于实验模式和alpha状态,因此有两个目标要完成:

    • 清除源代码并更新内部命名给 MATCH 官方ECMAScript参考
    • 完成ES6的实现并为ES7和进一步版本创建一个实验空间
    • 使用tests262测试套件创建CI系统
    • 重写源代码以打印和实现源映射

    JAVA  INT  Javascript  tool  解释器  
    相关文章