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); }
private static TypeSpec Parse(string name, ref int p, bool is_recurse, bool allow_aqn) { // Invariants: // - On exit p, is updated to pos the current unconsumed character. // // - The callee peeks at but does not consume delimiters following // recurisve parse (so for a recursive call like the args of "Foo[P,Q]" // we'll return with p either on ',' or on ']'. If the name was aqn'd // "Foo[[P,assmblystuff],Q]" on return p with be on the ']' just // after the "assmblystuff") // // - If allow_aqn is True, assembly qualification is optional. // If allow_aqn is False, assembly qualification is prohibited. 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; case '\\': pos++; break; } if (in_modifiers) { break; } } if (name_start < pos) { data.AddName(name.Substring(name_start, pos - name_start)); } else if (name_start == pos) { data.AddName(string.Empty); } 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"); } // take subsequent '*'s too int pointer_level = 1; while (pos + 1 < name.Length && name[pos + 1] == '*') { ++pos; ++pointer_level; } data.AddModifier(new PointerSpec(pointer_level)); break; case ',': if (is_recurse && allow_aqn) { 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; return(data); } if (is_recurse) { p = pos; return(data); } if (allow_aqn) { 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.HasModifiers) { throw new ArgumentException("generic args after array spec or pointer type", "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)); BoundCheck(pos, name); if (aqn) { if (name[pos] == ']') { ++pos; } else { throw new ArgumentException("Unclosed assembly-qualified type name at " + name[pos], "typeName"); } BoundCheck(pos, name); } 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 (pos >= name.Length || 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.AddModifier(new IArraySpec(dimensions, bound)); } break; case ']': if (is_recurse) { p = pos; 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) { // Invariants: // - On exit p, is updated to pos the current unconsumed character. // // - The callee peeks at but does not consume delimiters following // recurisve parse (so for a recursive call like the args of "Foo[P,Q]" // we'll return with p either on ',' or on ']'. If the name was aqn'd // "Foo[[P,assmblystuff],Q]" on return p with be on the ']' just // after the "assmblystuff") // // - If allow_aqn is True, assembly qualification is optional. // If allow_aqn is False, assembly qualification is prohibited. 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; case '\\': pos++; 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"); // take subsequent '*'s too int pointer_level = 1; while (pos+1 < name.Length && name[pos+1] == '*') { ++pos; ++pointer_level; } data.AddModifier (new PointerSpec(pointer_level)); break; case ',': if (is_recurse && allow_aqn) { 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; return data; } if (is_recurse) { p = pos; return data; } if (allow_aqn) { 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.HasModifiers) throw new ArgumentException ("generic args after array spec or pointer type", "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)); BoundCheck (pos, name); if (aqn) { if (name [pos] == ']') ++pos; else throw new ArgumentException ("Unclosed assembly-qualified type name at " + name[pos], "typeName"); BoundCheck (pos, name); } 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 (pos >= name.Length || 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.AddModifier (new ArraySpec (dimensions, bound)); } break; case ']': if (is_recurse) { p = pos; 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; }