package org.perl6.rakudo;

import org.perl6.nqp.runtime.*;
import org.perl6.nqp.sixmodel.*;

public class RakudoContainerSpec extends ContainerSpec {
    /* Container related hints. */
    public static final int HINT_descriptor = 0;
    public static final int HINT_value = 1;
    public static final int HINT_whence = 2;
    
    /* Callsite descriptor for WHENCEs. */
    private static final CallSiteDescriptor WHENCE = new CallSiteDescriptor(
        new byte[] { }, null);
    
    /* Fetches a value out of a container. Used for decontainerization. */
    public SixModelObject fetch(ThreadContext tc, SixModelObject cont) {
        return cont.get_attribute_boxed(tc, RakOps.key.getGC(tc).Scalar, "$!value", HINT_value);
    }
    
    /* Stores a value in a container. Used for assignment. */
    private static final CallSiteDescriptor storeThrower = new CallSiteDescriptor(
        new byte[] { CallSiteDescriptor.ARG_STR, CallSiteDescriptor.ARG_OBJ, CallSiteDescriptor.ARG_OBJ }, null);
    public void store(ThreadContext tc, SixModelObject cont, SixModelObject value) {
        RakOps.GlobalExt gcx = RakOps.key.getGC(tc);

        long rw = 0;
        SixModelObject desc = cont.get_attribute_boxed(tc, gcx.Scalar,
            "$!descriptor", HINT_descriptor);
        if (desc != null) {
            desc.get_attribute_native(tc, gcx.ContainerDescriptor, "$!rw", RakOps.HINT_CD_RW);
            rw = tc.native_i;
        }
        if (rw == 0)
            throw ExceptionHandling.dieInternal(tc,
                "Cannot assign to a readonly variable or a value");

        if (value.st.WHAT == gcx.Nil)
            value = desc.get_attribute_boxed(tc,
                gcx.ContainerDescriptor, "$!default", RakOps.HINT_CD_DEFAULT);
                
        SixModelObject of = desc.get_attribute_boxed(tc,
            gcx.ContainerDescriptor, "$!of", RakOps.HINT_CD_OF);
        long ok = Ops.istype(value, of, tc);
        if (ok == 0) {
            desc.get_attribute_native(tc, gcx.ContainerDescriptor, "$!name", RakOps.HINT_CD_NAME);
            String name = tc.native_s;
            SixModelObject thrower = RakOps.getThrower(tc, "X::TypeCheck::Assignment");
            if (thrower == null)
                throw ExceptionHandling.dieInternal(tc,
                    "Type check failed in assignment to '" + name + "'");
            else
                Ops.invokeDirect(tc, thrower,
                    storeThrower, new Object[] { name, value, of });
        }
        
        SixModelObject whence = cont.get_attribute_boxed(tc, gcx.Scalar, "$!whence", HINT_whence);
        if (whence != null)
            Ops.invokeDirect(tc, whence,
                WHENCE, new Object[] { });
        
        cont.bind_attribute_boxed(tc, gcx.Scalar, "$!value", HINT_value, value);
    }
    
    /* Stores a value in a container, without any checking of it (this
     * assumes an optimizer or something else already did it). Used for
     * assignment. */
    public void storeUnchecked(ThreadContext tc, SixModelObject cont, SixModelObject obj) {
        SixModelObject Scalar = RakOps.key.getGC(tc).Scalar;
        SixModelObject whence = cont.get_attribute_boxed(tc, Scalar, "$!whence", HINT_whence);
        if (whence != null)
            Ops.invokeDirect(tc, whence,
                WHENCE, new Object[] { });
        
        cont.bind_attribute_boxed(tc, Scalar, "$!value", HINT_value, obj);
    }
    
    /* Name of this container specification. */
    public String name() {
        return "rakudo_scalar";
    }
    
    /* Serializes the container data, if any. */
    public void serialize(ThreadContext tc, STable st, SerializationWriter writer) {
        /* No data to serialize. */
    }
    
    /* Deserializes the container data, if any. */
    public void deserialize(ThreadContext tc, STable st, SerializationReader reader) {
        /* No data to deserialize. */
    }
}

@@ -1611,17 +1611,19 @@
 gcx.Nil)
+ %7B
 %0A
-
         
@@ -1750,24 +1750,26 @@
         
+%7D%0A
         
 %0A       
@@ -1756,33 +1756,41 @@
   %7D%0A        
-%0A
+else %7B%0A  
         
 SixModelObje
@@ -1769,32 +1769,34 @@
 lse %7B%0A          
+  
 SixModelObject o
@@ -1820,32 +1820,36 @@
 ibute_boxed(tc,%0A
+    
             gcx.
@@ -1901,24 +1901,28 @@
 F);%0A        
+   
+ 
 long ok = Op
@@ -1950,24 +1950,28 @@
 c);%0A        
+    
 if (ok == 0)
@@ -1969,24 +1969,28 @@
 (ok == 0) %7B%0A
+    
             
@@ -2088,16 +2088,20 @@
         
+    
 String n
@@ -2119,16 +2119,20 @@
 tive_s;%0A
+    
         
@@ -2219,24 +2219,28 @@
             
+ 
+   
 if (thrower 
@@ -2240,32 +2240,36 @@
 hrower == null)%0A
+    
                 
@@ -2328,16 +2328,20 @@
         
+   
+ 
 %22Type ch
@@ -2402,13 +2402,21 @@
     
+    
 else%0A
+    
     
@@ -2477,16 +2477,20 @@
         
+    
 storeThr
@@ -2526,24 +2526,38 @@
 lue, of %7D);%0A
+            %7D%0A
         %7D%0A  
@@ -2554,24 +2554,16 @@
       %7D%0A
-        
 %0A       

Correct Nil handling on JVM.