• 跳至… +
    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