• 跳到… +
    browser.coffee cake.coffee coffee-script.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'}]
        @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