static TypeSpec Parse (string name, ref int p, bool is_recurse, bool allow_aqn) { int pos = p; int name_start; bool in_modifiers = false; TypeSpec data = new TypeSpec (); SkipSpace (name, ref pos); name_start = pos; for (; pos < name.Length; ++pos) { switch (name [pos]) { case '+': data.AddName (name.Substring (name_start, pos - name_start)); name_start = pos + 1; break; case ',': case ']': data.AddName (name.Substring (name_start, pos - name_start)); name_start = pos + 1; in_modifiers = true; if (is_recurse && !allow_aqn) { p = pos; return data; } break; case '&': case '*': case '[': if (name [pos] != '[' && is_recurse) throw new ArgumentException ("Generic argument can't be byref or pointer type", "typeName"); data.AddName (name.Substring (name_start, pos - name_start)); name_start = pos + 1; in_modifiers = true; break; } if (in_modifiers) break; } if (name_start < pos) data.AddName (name.Substring (name_start, pos - name_start)); if (in_modifiers) { for (; pos < name.Length; ++pos) { switch (name [pos]) { case '&': if (data.is_byref) throw new ArgumentException ("Can't have a byref of a byref", "typeName"); data.is_byref = true; break; case '*': if (data.is_byref) throw new ArgumentException ("Can't have a pointer to a byref type", "typeName"); ++data.pointer_level; break; case ',': if (is_recurse) { int end = pos; while (end < name.Length && name [end] != ']') ++end; if (end >= name.Length) throw new ArgumentException ("Unmatched ']' while parsing generic argument assembly name"); data.assembly_name = name.Substring (pos + 1, end - pos - 1).Trim (); p = end + 1; return data; } data.assembly_name = name.Substring (pos + 1).Trim (); pos = name.Length; break; case '[': if (data.is_byref) throw new ArgumentException ("Byref qualifier must be the last one of a type", "typeName"); ++pos; if (pos >= name.Length) throw new ArgumentException ("Invalid array/generic spec", "typeName"); SkipSpace (name, ref pos); if (name [pos] != ',' && name [pos] != '*' && name [pos] != ']') {//generic args List<TypeSpec> args = new List <TypeSpec> (); if (data.IsArray) throw new ArgumentException ("generic args after array spec", "typeName"); while (pos < name.Length) { SkipSpace (name, ref pos); bool aqn = name [pos] == '['; if (aqn) ++pos; //skip '[' to the start of the type args.Add (Parse (name, ref pos, true, aqn)); if (pos >= name.Length) throw new ArgumentException ("Invalid generic arguments spec", "typeName"); if (name [pos] == ']') break; if (name [pos] == ',') ++pos; // skip ',' to the start of the next arg else throw new ArgumentException ("Invalid generic arguments separator " + name [pos], "typeName"); } if (pos >= name.Length || name [pos] != ']') throw new ArgumentException ("Error parsing generic params spec", "typeName"); data.generic_params = args; } else { //array spec int dimensions = 1; bool bound = false; while (pos < name.Length && name [pos] != ']') { if (name [pos] == '*') { if (bound) throw new ArgumentException ("Array spec cannot have 2 bound dimensions", "typeName"); bound = true; } else if (name [pos] != ',') throw new ArgumentException ("Invalid character in array spec " + name [pos], "typeName"); else ++dimensions; ++pos; SkipSpace (name, ref pos); } if (name [pos] != ']') throw new ArgumentException ("Error parsing array spec", "typeName"); if (dimensions > 1 && bound) throw new ArgumentException ("Invalid array spec, multi-dimensional array cannot be bound", "typeName"); data.AddArray (new ArraySpec (dimensions, bound)); } break; case ']': if (is_recurse) { p = pos + 1; return data; } throw new ArgumentException ("Unmatched ']'", "typeName"); default: throw new ArgumentException ("Bad type def, can't handle '" + name [pos]+"'" + " at " + pos, "typeName"); } } } p = pos; return data; }
static TypeSpec Parse(string name, ref int p, bool is_recurse, bool allow_aqn) { int pos = p; int name_start; bool in_modifiers = false; TypeSpec data = new TypeSpec(); SkipSpace(name, ref pos); name_start = pos; for (; pos < name.Length; ++pos) { switch (name [pos]) { case '+': data.AddName(name.Substring(name_start, pos - name_start)); name_start = pos + 1; break; case ',': case ']': data.AddName(name.Substring(name_start, pos - name_start)); name_start = pos + 1; in_modifiers = true; if (is_recurse && !allow_aqn) { p = pos; return(data); } break; case '&': case '*': case '[': if (name [pos] != '[' && is_recurse) { throw new ArgumentException("Generic argument can't be byref or pointer type", "typeName"); } data.AddName(name.Substring(name_start, pos - name_start)); name_start = pos + 1; in_modifiers = true; break; } if (in_modifiers) { break; } } if (name_start < pos) { data.AddName(name.Substring(name_start, pos - name_start)); } if (in_modifiers) { for (; pos < name.Length; ++pos) { switch (name [pos]) { case '&': if (data.is_byref) { throw new ArgumentException("Can't have a byref of a byref", "typeName"); } data.is_byref = true; break; case '*': if (data.is_byref) { throw new ArgumentException("Can't have a pointer to a byref type", "typeName"); } ++data.pointer_level; break; case ',': if (is_recurse) { int end = pos; while (end < name.Length && name [end] != ']') { ++end; } if (end >= name.Length) { throw new ArgumentException("Unmatched ']' while parsing generic argument assembly name"); } data.assembly_name = name.Substring(pos + 1, end - pos - 1).Trim(); p = end + 1; return(data); } data.assembly_name = name.Substring(pos + 1).Trim(); pos = name.Length; break; case '[': if (data.is_byref) { throw new ArgumentException("Byref qualifier must be the last one of a type", "typeName"); } ++pos; if (pos >= name.Length) { throw new ArgumentException("Invalid array/generic spec", "typeName"); } SkipSpace(name, ref pos); if (name [pos] != ',' && name [pos] != '*' && name [pos] != ']') //generic args { List <TypeSpec> args = new List <TypeSpec> (); if (data.IsArray) { throw new ArgumentException("generic args after array spec", "typeName"); } while (pos < name.Length) { SkipSpace(name, ref pos); bool aqn = name [pos] == '['; if (aqn) { ++pos; //skip '[' to the start of the type } args.Add(Parse(name, ref pos, true, aqn)); if (pos >= name.Length) { throw new ArgumentException("Invalid generic arguments spec", "typeName"); } if (name [pos] == ']') { break; } if (name [pos] == ',') { ++pos; // skip ',' to the start of the next arg } else { throw new ArgumentException("Invalid generic arguments separator " + name [pos], "typeName"); } } if (pos >= name.Length || name [pos] != ']') { throw new ArgumentException("Error parsing generic params spec", "typeName"); } data.generic_params = args; } else //array spec { int dimensions = 1; bool bound = false; while (pos < name.Length && name [pos] != ']') { if (name [pos] == '*') { if (bound) { throw new ArgumentException("Array spec cannot have 2 bound dimensions", "typeName"); } bound = true; } else if (name [pos] != ',') { throw new ArgumentException("Invalid character in array spec " + name [pos], "typeName"); } else { ++dimensions; } ++pos; SkipSpace(name, ref pos); } if (name [pos] != ']') { throw new ArgumentException("Error parsing array spec", "typeName"); } if (dimensions > 1 && bound) { throw new ArgumentException("Invalid array spec, multi-dimensional array cannot be bound", "typeName"); } data.AddArray(new ArraySpec(dimensions, bound)); } break; case ']': if (is_recurse) { p = pos + 1; return(data); } throw new ArgumentException("Unmatched ']'", "typeName"); default: throw new ArgumentException("Bad type def, can't handle '" + name [pos] + "'" + " at " + pos, "typeName"); } } } p = pos; return(data); }