从函数和“闭包”中构造“词法环境”的操作顺序是什么?

问题描述

这是对What does the call stack look like in a system of nested functions,functions passed as arguments,and returned functions?

的改进/阐述

这是一些组成代码,演示2个模块和一些嵌套函数调用

// module_1.js

// global variables
var CONST = 6541

function add(a,b) {
  return CONST + a + b
}

function sub(a,b) {
  return CONST - a - b
}

function mul(a,b) {
  return CONST * a * b
}

// module_2.js

// global variables
var a = 11
var b = 5
var c = 2

main()

function main() {
  var v = foo_1()
  var w = foo_2()

  var t = v(1,2,3)
  var u = w(4)
  var k = add(t,u)

  // OUTPUT
  console.log(k)

  // nested functions
  function foo_1() {
    var d = bar_1(2,3)
    var e = bar_2(10)

    // returning functions as results.
    return bar_3

    // super nested functions.
    function bar_1(x,y) {
      var m = mul(x,a)
      var n = sub(m,y)
      var o = mul(n,c)
      return o
    }

    function bar_2(x) {
      var m = mul(x,x)
      var n = add(m,3)
      var o = mul(n,a)
      return n
    }

    function bar_3(x,y,z) {
      var m = mul(x,y)
      var o = add(n,b)
      var p = mul(o,z)
      var q = sub(p,c)
      var r = mul(q,d)
      var s = add(r,e)
      return s
    }
  }

  function foo_2() {
    return bar_2

    function bar_1(x,y) {
      var p = add(y,a)
      var q = add(x,p)
      return q
    }

    function bar_2(x) {
      var p = bar_1(x,2)
      var q = bar_1(x,4)
      var r = mul(p,a)
      var s = add(q,c)
      return r * s
    }
  }
}

因此,基本上,有2个模块,每个模块在其功能中使用全局变量。第二个模块具有一系列嵌套函数,并在某些点返回函数

要做的是拼凑编译器将要执行的操作顺序。这是我几个小时后到目前为止得到的:

main.closure = createClosure(a,b,c)
main.foo_1.closure = createClosure(parent: main.closure,d,e)
main.foo_1.bar_1.closure = createClosure(parent: main.foo_1.closure,x,m,n,o)
mul.closure = createClosure(CONST,a,b)

也就是说,每个函数都使用(包装在)闭包中进行初始化。

然后您开始调用函数

-> call(main)
  -> main.env = createEnvironment({
      closure: main.closure,a: 11,b: 5,c: 2
    })
    -> call(foo_1)
      -> main.foo_1.env = createEnvironment({
          closure: main.foo_1.closure,// with parent environment
          parent: main.env,d: null,e: null
        })
        -> call(bar_1,3)
          -> main.foo_1.bar_1.env = createEnvironment({
              closure: main.foo_1.bar_1.closure,// with parent environment
              parent: main.foo_1.env,x: 2,y: 3,m: null,n: null,o: null
            })
            -> call(mul,main.foo_1.bar_1.env.x,main.foo_1.bar_1.env.parent.parent.a)
              -> mul.env = createEnvironment({
                  closure: mul.closure,// no parent environment
                  CONST: 6541,a: main.foo_1.bar_1.env.x,b: main.foo_1.bar_1.env.y
                })

或者按照实际情况变平:

-> call(main) =
  -> main.env = createEnvironment({
      closure: main.closure,c: 2
    })
-> call(foo_1) =
  -> main.foo_1.env = createEnvironment({
      closure: main.foo_1.closure,// with parent environment
      parent: main.env,e: null
    })
-> call(bar_1,3) =
  -> main.foo_1.bar_1.env = createEnvironment({
      closure: main.foo_1.bar_1.closure,// with parent environment
      parent: main.foo_1.env,o: null
    })
-> call(mul,main.foo_1.bar_1.env.parent.parent.a) =
  -> mul.env = createEnvironment({
      closure: mul.closure,// no parent environment
      CONST: 6541,b: main.foo_1.bar_1.env.y
    })

所以基本上:

  1. 为每个函数创建一个闭包(在调用任何函数之前)。它基本上会创建一个可以在函数中访问的所有变量的列表。
  2. 每个函数调用都会创建一个新的 environment ,该环境是基于闭包创建的。这将获取闭包中定义的所有变量,以供在函数中使用。
  3. 环境将其所有变量设置为当前值。也许它具有指向父环境值或参数的指针?

我仍然不太了解整个图片。如果有人可以为操作顺序写出伪代码,那将是我想要的全部。基本上,一系列嵌套函数(以及在其他模块中定义的具有其他“全局变量”的函数)是如何实现为一系列原始调用(以创建环境或其他方式)实现的。

基本上,我正在努力实现支持这些功能的编译器。我需要获取函数定义(作为AST),并将其编译为类似于原始程序集的指令块。每个指令“块”或“标签”都是指令序列(按照程序集定义)。因此,它将类似于以下程序集伪代码

data a,11
data a,5
data a,2

main:
  call foo_1
  call foo_2
  ...
foo_1:
  push 2
  push 3
  call bar_1
  ...
foo_1_bar_1:
  ...
...
  ...
foo_2:
  ...
foo_3:
  ...

但是,它将包含更多,并且还将包含每个通话的环境。像这样:

main:
  // create main environment
  push a
  push b
  push c
  // some other stuff perhaps for constructing the environment.
  call foo_1
  ...

因此,基本上,我陷入了如何想象将面向语言语法的“嵌套函数和模块”转换为类似汇编的“指令序列”的步骤。尤其是与创建环境关闭有关。

用伪代码编写的环境并不一定比我的优雅,

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)