public static int Extract(Dictionary <string, object> localVariables, PhpArray /*!*/ vars, ExtractType type, string prefix) { if (vars == null) { PhpException.ArgumentNull("vars"); return(0); } if (vars.Count == 0) { return(0); } // unfortunately, type contains flags are combined with enumeration: bool refs = (type & ExtractType.Refs) != 0; type &= ExtractType.NonFlags; // // construct the action used to set the variable into the locals/globals // Action <string /*name*/, object /*value*/> updateVariableFn; // function that writes the value to locals/globals Predicate <string /*name*/> containsFn; // function that checks if variable exists PhpArray globals = (localVariables != null) ? null : ScriptContext.CurrentContext.GlobalVariables; #region select function that writes the variable if (refs) { // makes a reference and writes it back (deep copy is not necessary, "no duplicate pointers" rule preserved): if (localVariables != null) { updateVariableFn = (name, value) => { localVariables[name] = vars[name] = PhpVariable.MakeReference(value); }; } else { updateVariableFn = (name, value) => { globals[name] = vars[name] = PhpVariable.MakeReference(value); }; } } else { if (localVariables != null) { updateVariableFn = (name, value) => { // deep copy the value value = PhpVariable.DeepCopy(PhpVariable.Dereference(value)); // put into locals object item; PhpReference ref_item; if (localVariables.TryGetValue(name, out item) && (ref_item = item as PhpReference) != null) { ref_item.Value = value; } else { localVariables[name] = value; } }; } else { updateVariableFn = (name, value) => { // deep copy the value value = PhpVariable.DeepCopy(PhpVariable.Dereference(value)); // set the value to globals object item; PhpReference ref_item; if (globals.TryGetValue(name, out item) && (ref_item = item as PhpReference) != null) { ref_item.Value = value; } else { globals[name] = value; } }; } } #endregion Debug.Assert(updateVariableFn != null); #region select function that checks if variable exists if (localVariables != null) { containsFn = (name) => localVariables.ContainsKey(name); } else { containsFn = (name) => globals.ContainsKey(name); } #endregion Debug.Assert(containsFn != null); // // // int extracted_count = 0; foreach (KeyValuePair <IntStringKey, object> entry in vars) { string name = entry.Key.ToString(); if (String.IsNullOrEmpty(name) && type != ExtractType.PrefixInvalid) { continue; } switch (type) { case ExtractType.Overwrite: // anything is overwritten: break; case ExtractType.Skip: // skips existing name: if (containsFn(name)) { continue; } break; case ExtractType.IfExists: // skips nonexistent name: if (!containsFn(name)) { continue; } break; case ExtractType.PrefixAll: // prefix anything: name = String.Concat(prefix, "_", name); break; case ExtractType.PrefixInvalid: // prefixes invalid, others are overwritten: if (!PhpVariable.IsValidName(name)) { name = String.Concat(prefix, "_", name); } break; case ExtractType.PrefixSame: // prefixes existing, others are overwritten: if (containsFn(name)) { name = String.Concat(prefix, "_", name); } break; case ExtractType.PrefixIfExists: // prefixes existing, others are skipped: if (containsFn(name)) { name = String.Concat(prefix, "_", name); } else { continue; } break; default: PhpException.InvalidArgument("type", LibResources.GetString("arg:invalid_value")); return(0); } // invalid names are skipped: if (PhpVariable.IsValidName(name)) { // write the value to locals or globals: updateVariableFn(name, entry.Value); extracted_count++; } } return(extracted_count); }
/// <summary> /// Import variables into the current variables table from an array. /// </summary> /// <param name="ctx">Runtime context.</param> /// <param name="locals">The table of defined variables.</param> /// <param name="vars">The <see cref="PhpArray"/> containing names of variables and values to be assigned to them.</param> /// <param name="type">The type of the extraction.</param> /// <param name="prefix">The prefix (can be a <B>null</B> reference) of variables names.</param> /// <returns>The number of variables actually affected by the extraction.</returns> /// <exception cref="PhpException"><paramref name="type"/> is invalid.</exception> /// <exception cref="PhpException"><paramref name="vars"/> is a <B>null</B> reference.</exception> /// <exception cref="InvalidCastException">Some key of <paramref name="locals"/> is not type of <see cref="string"/>.</exception> public static int extract(Context ctx, [ImportLocals] PhpArray locals, PhpArray vars, ExtractType type = ExtractType.Overwrite, string prefix = null) { if (vars == null) { //PhpException.ArgumentNull("vars"); //return 0; throw new ArgumentNullException(nameof(vars)); } if (vars.Count == 0) { return(0); } // unfortunately, type contains flags are combined with enumeration: bool refs = (type & ExtractType.Refs) != 0; type &= ExtractType.NonFlags; // // // int extracted_count = 0; using (var enumerator = vars.GetFastEnumerator()) while (enumerator.MoveNext()) { var name = enumerator.CurrentKey.ToString(); if (string.IsNullOrEmpty(name) && type != ExtractType.PrefixInvalid) { continue; } switch (type) { case ExtractType.Overwrite: // anything is overwritten: break; case ExtractType.Skip: // skips existing name: if (locals.ContainsKey(name)) { continue; } break; case ExtractType.IfExists: // skips nonexistent name: if (!locals.ContainsKey(name)) { continue; } break; case ExtractType.PrefixAll: // prefix anything: name = string.Concat(prefix, "_", name); break; case ExtractType.PrefixInvalid: // prefixes invalid, others are overwritten: if (!PhpVariable.IsValidName(name)) { name = string.Concat(prefix, "_", name); } break; case ExtractType.PrefixSame: // prefixes existing, others are overwritten: if (locals.ContainsKey(name)) { name = string.Concat(prefix, "_", name); } break; case ExtractType.PrefixIfExists: // prefixes existing, others are skipped: if (locals.ContainsKey(name)) { name = string.Concat(prefix, "_", name); } else { continue; } break; default: throw new ArgumentException(nameof(type)); //PhpException.InvalidArgument("type", LibResources.GetString("arg_invalid_value")); //return 0; } // invalid names are skipped: if (PhpVariable.IsValidName(name)) { // write the value to locals: if (refs) { // makes a reference and writes it back (deep copy is not necessary, "no duplicate pointers" rule preserved): locals.SetItemAlias(new IntStringKey(name), enumerator.CurrentValueAliased); } else { // deep copy the value and write into locals locals.SetItemValue(new IntStringKey(name), enumerator.CurrentValue.GetValue().DeepCopy()); } extracted_count++; } } // return(extracted_count); }
/// <summary> /// Checks whether a specified name is valid constant name. /// </summary> /// <param name="name">The constant name.</param> /// <seealso cref="PhpVariable.IsValidName"/> public static bool IsValidName(string name) { return(PhpVariable.IsValidName(name)); }