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); }