package org.jruby.ir;

import java.util.EnumSet;

public enum IRFlags {
    // Does this scope require a binding to be materialized?
    // Yes if any of the following holds true:
    // - calls 'Proc.new'
    // - calls 'eval'
    // - calls 'call' (could be a call on a stored block which could be local!)
    // - calls 'send' and we cannot resolve the message (method name) that is being sent!
    // - calls methods that can access the caller's binding
    // - calls a method which we cannot resolve now!
    // - has a call whose closure requires a binding
    BINDING_HAS_ESCAPED,
    // Does this execution scope (applicable only to methods) receive a block and use it in such a way that
    // all of the caller's local variables need to be materialized into a heap binding?
    // Ex:
    //   def foo(&b)
    //      eval 'puts a', b
    //    end
    //
    //    def bar
    //      a = 1
    //      foo {} # prints out '1'
    //    end
    //
    // Here, 'foo' can access all of bar's variables because it captures the caller's closure.
    //
    // There are 2 scenarios when this can happen (even this is conservative -- but, good enough for now)
    // 1. This method receives an explicit block argument (in this case, the block can be stored, passed around,
    //   eval'ed against, called, etc.).
    //    CAVEAT: This is conservative ... it may not actually be stored & passed around, evaled, called, ...
    // 2. This method has a 'super' call (ZSuper AST node -- ZSuperInstr IR instruction)
    //    In this case, the parent (in the inheritance hierarchy) can access the block and store it, etc.  So, in reality,
    //    rather than assume that the parent will always do this, we can query the parent, if we can precisely identify
    //    the parent method (which in the face of Ruby's dynamic hierarchy, we cannot).  So, be pessimistic.
    //
    // This logic was extracted from an email thread on the JRuby mailing list -- Yehuda Katz & Charles Nutter
    // contributed this analysis above.
    HAS_END_BLOCKS,               // has an end block. big de-opt flag
    REQUIRES_DYNSCOPE,            // does this scope require a dynamic scope?

    REQUIRES_LASTLINE,
    REQUIRES_BACKREF,
    REQUIRES_VISIBILITY,          // callee may read/write caller's visibility
    REQUIRES_BLOCK,
    REQUIRES_SELF,
    REQUIRES_METHODNAME,
    REQUIRES_LINE,
    REQUIRES_CLASS,
    REQUIRES_FILENAME,
    REQUIRES_SCOPE,
    FLAGS_COMPUTED;               // Have these flags been computed yet?

    public static final EnumSet<IRFlags> REQUIRE_ALL_FRAME_FIELDS =
            EnumSet.of(
                    REQUIRES_LASTLINE,
                    REQUIRES_BACKREF,
                    REQUIRES_VISIBILITY,
                    REQUIRES_BLOCK,
                    REQUIRES_SELF,
                    REQUIRES_METHODNAME,
                    REQUIRES_LINE,
                    REQUIRES_CLASS,
                    REQUIRES_FILENAME,
                    REQUIRES_SCOPE);


    public static final EnumSet<IRFlags> REQUIRE_ALL_FRAME_EXCEPT_SCOPE =
            EnumSet.of(
                    REQUIRES_LASTLINE,
                    REQUIRES_BACKREF,
                    REQUIRES_VISIBILITY,
                    REQUIRES_BLOCK,
                    REQUIRES_SELF,
                    REQUIRES_METHODNAME,
                    REQUIRES_LINE,
                    REQUIRES_CLASS,
                    REQUIRES_FILENAME,
                    REQUIRES_SCOPE);
}