• ジャンプ先… +
    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
  • スコープ 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'
  • ¶

    変数がすでに宣言されているかどうかをチェックしますが、予約はせず、root スコープまで移動します。

      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