【问题标题】:How to get all functions and top-level names from Javascript如何从 Javascript 中获取所有函数和顶级名称
【发布时间】:2014-01-22 10:42:55
【问题描述】:

我正在尝试编写一个在 Javascript 和另一种语言 (Elm) 之间自动生成 FFI 文件的程序。

我想知道,是否有任何工具可以采用 Javascript 模块并列出所有可用的函数,可能还有它们的参数数量?如果它只能做顶级功能,那没关系,我意识到这会因闭包和 thunk 等而变得复杂。

是否可以在 Javascript 中做类似的事情作为一种自省形式,还是我必须使用某种解析器/分析器?如果是这样,是否存在任何此类工具并且相当成熟/易于使用?

编辑:我意识到 JavaScript 是动态的。我的主要目标是为库和 API 生成 FFI 接口,因此那里的东西应该很容易静态推理,因为它们不会动态更改。如果它不完美,我没关系,我正在寻找一种工具来简化我编写样板的工作,而不是保证是防弹的东西。

【问题讨论】:

  • 您必须解析并执行代码才能真正知道它在做什么。 JavaScript 是一种动态语言,因此静态分析的功能是有限度的。
  • 即便如此,如果代码可以在未知的其他代码已经运行的上下文中“在野外”运行,你就不能真正知道你正在学习它在所有情况下的作用。
  • 好的,但是您不必执行代码来查看最初可以全局访问的函数名称。我愿意做出合理的假设,即我正在为其编写 FFI 的库不会从其全局函数中删除函数定义。就像我说的,我使用它来生成 FFI,所以我主要关心的是获取全局可访问的 API 函数名称,而不是可能由 JS 生成的每个函数。
  • 不,这不是真的。库通常有 no 声明为全局函数。相反,它们以编程方式将值动态绑定到全局符号。
  • 好的...然后会有一个工具可以进行库初始化然后遍历可用函数吗?

标签: javascript static static-analysis introspection ffi


【解决方案1】:

对您来说比较棘手的是,创建 Javascript 模块有许多不同的约定:将变量放在全局范围内,从文件返回表等。模块的创建也是非常动态的,所以它可能是更容易在 Javascript 中做事。

假设您可以获取与您的模块相对应的 javascript 对象,您可以使用 for in 循环对其进行检查:

var myModule = ...
for(var key in myModule){
  if( Object.hasOwnProperty.call(myModule, key) ){
    var func = myModule[key];
    ...
  }
}

要检查对象属性是否为函数,可以使用typeof 运算符:

if(typeod func == "function")

要查看参数的数量,您可以检查函数的长度属性:

func.length

请注意,如果函数是可变参数或以其他方式从 arguments 数组中获取参数,则参数的数量可能是错误的。但是检查源文本的东西也会出错......

【讨论】:

    【解决方案2】:

    可以在 node.js 中实现。由于安全原因,在运行脚本时: node script.js 在 nodejs 提供的 global 对象中看不到函数或变量,但是在使用 node -e "some script" 运行脚本时,可以从 global object 访问函数和变量。

    所以我写了 3 个脚本。

    1. 读取需要解析的文件(scriptThatNeedsToBeParsed.js)和解释文件(interpretFile.js)。组合它们并使用 node -e combinedFileContents 创建一个进程
    2. 需要解析的脚本
    3. 用于解释解析文件的脚本

    scriptThatNeedsToBeParsed.js:

    function A(a,b,c){}
    var abc;
    function T(){}
    

    readFile.js:

    我正在读取需要解析的文件并定义了 2 个变量: START_FROM_THIS_OBJECT 在文件内容之前,END_TO_THIS_OBJECT 在文件内容之后。所以以后我会知道从哪里到哪里搜索函数和变量。

    if(process.argv.length !=4 )
    {
        console.log("Usage %s <input-file> <interpret-file>",process.argv[0]);
        process.exit(0);
    }
    var input_file = process.argv[2];
    var interpret_file = process.argv[3];
    var fs = require('fs');
    var fileToParse = ";var START_FROM_THIS_OBJECT;";
    fileToParse += fs.readFileSync(input_file, "utf8");
    var interpretFile = fs.readFileSync(interpret_file, "utf8");
    fileToParse += ";var END_TO_THIS_OBJECT;";
    var script = fileToParse + interpretFile;
    var child = require('child_process').execFile('node', 
    [ 
        '-e', script, 
    ], function(err, stdout, stderr) { 
        console.log(stdout); 
    });
    

    解释文件.js: 我只在上面定义的 2 个控制变量“之间”搜索函数和变量

    var printObjects = false;
    for(var item in global)
    {
        if(item == "END_TO_THIS_OBJECT")
        {
            printObjects = false;
        }
        if(printObjects)
        {
    
            if(typeof(global[item]) == "function")
            {
                console.log("Function :%s with nr args: %d",item,global[item].length); 
            }
            else
            {
                console.log("Variable :%s with value: %d",item,global[item]); 
            }
        }
        if(item == "START_FROM_THIS_OBJECT")
        {
            printObjects = true;
        }
    }
    

    来自nodejs的global对象的最后一部分:console.log(global);

         module:
          { id: '[eval]',
            exports: {},
            parent: undefined,
            filename: 'E:\\LOCAL\\xampp\\htdocs\\nodejs\\[eval]',
            loaded: false,
            children: [],
            paths:
             [ 'E:\\LOCAL\\xampp\\htdocs\\nodejs\\node_modules',
               'E:\\LOCAL\\xampp\\htdocs\\node_modules',
               'E:\\LOCAL\\xampp\\node_modules',
               'E:\\LOCAL\\node_modules',
               'E:\\node_modules' ] },
         __dirname: '.',
         require:
          { [Function: require]
            resolve: [Function],
            main: undefined,
            extensions: { '.js': [Function], '.json': [Function], '.node': [Function] },
            registerExtension: [Function],
            cache: {} },
         START_FROM_THIS_OBJECT: undefined,<<<<<<<<<<<<<<
         A: [Function: A],
         abc: undefined,
         T: [Function: T],
         END_TO_THIS_OBJECT: undefined,<<<<<<<<<<<<<<<<
    

    我运行脚本:node readFile.js scriptThatNeedsToBeParsed.js interpretFile.js 这是输出:
    功能:A 带 nr 参数:3
    变量:abc,值为:NaN
    函数 :T with nr args: 0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-10
      • 1970-01-01
      • 1970-01-01
      • 2021-08-13
      • 2016-01-26
      • 1970-01-01
      • 2021-04-11
      相关资源
      最近更新 更多