• 跳转到 … +
    browser.coffee cake.coffee coffeescript.coffee command.coffee grammar.coffee helpers.coffee index.coffee lexer.coffee nodes.coffee optparse.coffee register.coffee repl.coffee rewriter.coffee scope.litcoffee sourcemap.litcoffee
  • scope.litcoffee

  • §

    Scope 类在 CoffeeScript 中管理词法作用域。在生成代码时,您会创建一个与嵌套函数体形状相同的范围树。每个范围都知道在其内声明的变量,并具有对其父封闭范围的引用。通过这种方式,我们知道哪些变量是新的,需要使用 var 声明,哪些变量与外部范围共享。

    exports.Scope = class Scope
  • §

    使用其父级初始化范围,以便向上查找链,以及对它所属的 Block 节点的引用,它应该在其中声明其变量,对它所属的函数的引用,以及源代码中引用的变量列表,因此在生成变量时应避免这些变量。还要跟踪应作为变量声明的一部分输出的注释。

      constructor: (@parent, @expressions, @method, @referencedVars) ->
        @variables = [{name: 'arguments', type: 'arguments'}]
        @comments  = {}
        @positions = {}
        @utilities = {} unless @parent
  • §

    @root 是给定文件的顶级 Scope 对象。

        @root = @parent?.root ? this
  • §

    添加一个新变量或覆盖现有变量。

      add: (name, type, immediate) ->
        return @parent.add name, type, immediate if @shared and not immediate
        if Object::hasOwnProperty.call @positions, name
          @variables[@positions[name]].type = type
        else
          @positions[name] = @variables.push({name, type}) - 1
  • §

    当调用 super 时,我们需要找到当前方法的名称,以便知道如何调用父类的相同方法。如果从内部函数调用 super,这可能会变得很复杂。namedMethod 将向上遍历范围树,直到找到第一个具有填充名称的函数对象,或者到底部。

      namedMethod: ->
        return @method if @method?.name or !@parent
        @parent.namedMethod()
  • §

    在词法作用域中查找变量名称,如果它不存在,则声明它。

      find: (name, type = 'var') ->
        return yes if @check name
        @add name, type
        no
  • §

    将变量名称保留为来自此范围的函数参数。内部引用不需要 var。

      parameter: (name) ->
        return if @shared and @parent.check name, yes
        @add name, 'param'
  • §

    只需检查变量是否已声明,不保留,向上遍历到根范围。

      check: (name) ->
        !!(@type(name) or @parent?.check(name))
  • §

    在给定索引处生成一个临时变量名称。

      temporary: (name, index, single=false) ->
        if single
          startCode = name.charCodeAt(0)
          endCode = 'z'.charCodeAt(0)
          diff = endCode - startCode
          newCode = startCode + index % (diff + 1)
          letter = String.fromCharCode(newCode)
          num = index // (diff + 1)
          "#{letter}#{num or ''}"
        else
          "#{name}#{index or ''}"
  • §

    获取变量的类型。

      type: (name) ->
        return v.type for v in @variables when v.name is name
        null
  • §

    如果我们需要存储中间结果,请找到编译器生成的变量的可用名称。_var、_var2 等…

      freeVariable: (name, options={}) ->
        index = 0
        loop
          temp = @temporary name, index, options.single
          break unless @check(temp) or temp in @root.referencedVars
          index++
        @add temp, 'var', yes if options.reserve ? true
        temp
  • §

    确保在此范围的顶部(或在请求的顶级范围)进行赋值。

      assign: (name, value) ->
        @add name, {value, assigned: yes}, yes
        @hasAssignments = yes
  • §

    此范围是否有任何声明的变量?

      hasDeclarations: ->
        !!@declaredVariables().length
  • §

    返回在此范围中首次声明的变量列表。

      declaredVariables: ->
        (v.name for v in @variables when v.type is 'var').sort()
  • §

    返回应该在此范围的顶部进行的赋值列表。

      assignedVariables: ->
        "#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned