예제 #1
0
파일: JSYNC.cs 프로젝트: renesugar/niecza
    Variable GetFromHash()
    {
        SkipCharWS('{');
        // we can't make any assumptions about ordering here, as JSON
        // emitters can blindly reorder hashes
        string h_tag    = null;
        string h_anchor = null;
        Dictionary <string, string> h_key_ind = null;
        VarHash h_val_ind = null;
        VarHash zyg       = new VarHash();
        bool    comma     = false;

        while (true)
        {
            if (SkipWhite(true) == '}')
            {
                break;
            }
            if (comma)
            {
                SkipChar(',');
            }
            comma = true;
            SkipWhite(false);
            GetString();
            if (s_content_type == NONE && s_anchor == null && s_tag == "")
            {
                if (h_tag != null)
                {
                    Err("Tag specified twice");
                }
                h_tag = GetSimpleStringValue();
            }
            else if (s_content_type == NONE && s_tag == null && s_anchor == "")
            {
                if (h_anchor != null)
                {
                    Err("Anchor specified twice");
                }
                h_anchor = GetSimpleStringValue();
            }
            else if (s_content_type == NONE)
            {
                if (s_anchor == null || s_tag != null)
                {
                    Err("Invalid hash key form");
                }
                string k1 = s_anchor;
                if (h_key_ind == null)
                {
                    h_key_ind = new Dictionary <string, string>();
                }
                if (h_key_ind.ContainsKey(k1))
                {
                    Err("Key alias &" + k1 + " specified twice");
                }
                SkipCharWS(':');
                if (SkipWhite(true) != '"')
                {
                    Err("Non-scalar hash keys NYI in Niecza Perl 6");
                }
                GetString();
                if (s_tag != null || s_anchor != null || s_content_type != SCALAR)
                {
                    Err("Typed hash keys NYI in Niecza Perl 6");
                }
                h_key_ind[k1] = s_content;
            }
            else if (s_content_type == ALIAS)
            {
                string k1 = s_content;
                if (h_val_ind == null)
                {
                    h_val_ind = new VarHash();
                }
                if (h_val_ind.ContainsKey(k1))
                {
                    Err("Key alias *" + k1 + " used twice");
                }
                SkipCharWS(':');
                h_val_ind[k1] = GetObj();
            }
            else if (s_content_type == DIRECTIVE)
            {
                Err("Got directive in hash key position");
            }
            else
            {
                if (s_tag != null || s_anchor != null)
                {
                    Err("Typed hash keys NYI in Niecza Perl 6");
                }
                string k1 = s_content;
                SkipCharWS(':');
                zyg[k1] = GetObj();
            }
        }

        SkipChar('}');

        if (h_key_ind != null || h_val_ind != null)
        {
            h_key_ind = h_key_ind ?? new Dictionary <string, string>();
            h_val_ind = h_val_ind ?? new VarHash();

            foreach (KeyValuePair <string, string> kv in h_key_ind)
            {
                if (!h_val_ind.ContainsKey(kv.Key))
                {
                    Err("No value provided for indirect key *" + kv.Key);
                }
                Variable val = h_val_ind[kv.Key];
                h_val_ind.Remove(kv.Key);
                if (zyg.ContainsKey(kv.Value))
                {
                    Err("Indirect key &" + kv.Value + " collides with non-indirect key");
                }
                zyg[kv.Value] = val;
            }

            foreach (string k in h_val_ind.Keys)
            {
                Err("Indirect key &" + k + " is unused");
            }
        }

        Variable obj;

        if (h_tag != null)
        {
            if (!Utils.StartsWithInvariant("!perl6/", h_tag))
            {
                Err("Unsupported hash tag " + h_tag);
            }
            string s2  = "::GLOBAL::" + h_tag.Substring(7);
            int    cut = s2.LastIndexOf("::");

            Variable v_cursor = setting.GetVar(s2.Substring(0, cut),
                                               s2.Substring(cut + 2)).v;

            if (v_cursor.Rw)
            {
                Err(s2.Substring(2) + " does not name a loaded global class");
            }
            P6any p_cursor = v_cursor.Fetch();

            if (p_cursor.Isa(setting.HashMO))
            {
                if (p_cursor.mo.nslots != 0)
                {
                    Err("Cannot thaw Hash subclass " + p_cursor.mo.name + "; it has attributes");
                }
                obj = BoxRW <VarHash>(zyg, p_cursor.mo);
            }
            else
            {
                P6opaque dyo = new P6opaque(p_cursor.mo);
                for (int i = 0; i < dyo.mo.nslots; i++)
                {
                    string sn = dyo.mo.all_slot[i];
                    if (!zyg.ContainsKey(sn))
                    {
                        Err("No value for attribute " + sn + " in thawed value of class " + dyo.mo.name);
                    }
                    dyo.slots[i] = zyg[sn];
                    zyg.Remove(sn);
                }
                foreach (string key in zyg.Keys)
                {
                    Err("Attribute " + key + " not present in " + dyo.mo.name);
                }
                obj = Kernel.NewMuScalar(dyo);
            }
        }
        else
        {
            obj = BoxRW <VarHash>(zyg, setting.HashMO);
        }
        if (h_anchor != null)
        {
            AddAnchor(h_anchor, obj.Fetch());
        }
        return(obj);
    }