private void ParseAt(DataStructures.GameData.GameData gd, IEnumerator<LexObject> iterator) { iterator.MoveNext(); var type = iterator.Current.Value; if (type.Equals("include", StringComparison.InvariantCultureIgnoreCase)) { Expect(iterator, LexType.String); if (CurrentFile != null) { var filename = iterator.Current.GetValue(); var path = Path.GetDirectoryName(CurrentFile) ?? ""; var incfile = Path.Combine(path, filename); var current = CurrentFile; var incgd = GetGameDataFromFile(incfile); CurrentFile = current; if (!gd.Includes.Any(x => String.Equals(x, filename, StringComparison.InvariantCultureIgnoreCase))) gd.Includes.Add(filename); // Merge the included gamedata into the current one gd.MapSizeHigh = Math.Max(incgd.MapSizeHigh, gd.MapSizeHigh); gd.MapSizeLow = Math.Min(incgd.MapSizeLow, gd.MapSizeLow); gd.Includes.AddRange(incgd.Includes.Where(x => !gd.Includes.Contains(x))); gd.Classes.AddRange(incgd.Classes.Where(x => !gd.Classes.Any(y => String.Equals(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase)))); gd.AutoVisgroups.AddRange(incgd.AutoVisgroups.Where(x => !gd.AutoVisgroups.Any(y => String.Equals(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase)))); gd.MaterialExclusions.AddRange(incgd.MaterialExclusions.Where(x => !gd.MaterialExclusions.Any(y => String.Equals(x, y, StringComparison.InvariantCultureIgnoreCase)))); } else { throw new ProviderException("Unable to include a file when not reading from a file."); } } else if (type.Equals("mapsize", StringComparison.InvariantCultureIgnoreCase)) { Expect(iterator, LexType.So); Expect(iterator, LexType.Value); gd.MapSizeLow = Int32.Parse(iterator.Current.Value); Expect(iterator, LexType.Comma); Expect(iterator, LexType.Value); gd.MapSizeHigh = Int32.Parse(iterator.Current.Value); Expect(iterator, LexType.Already); } else if (type.Equals("materialexclusion", StringComparison.InvariantCultureIgnoreCase)) { Expect(iterator, LexType.Open); iterator.MoveNext(); while (iterator.Current.Type != LexType.Close) { Assert(iterator.Current.IsValueOrString(), "Expected value type, got " + iterator.Current.Type + "."); var exclusion = iterator.Current.GetValue(); gd.MaterialExclusions.Add(exclusion); iterator.MoveNext(); } } else if (type.Equals("autovisgroup", StringComparison.InvariantCultureIgnoreCase)) { Expect(iterator, LexType.Equals); iterator.MoveNext(); Assert(iterator.Current.IsValueOrString(), "Expected value type, got " + iterator.Current.Type + "."); var sectionName = iterator.Current.GetValue(); var sect = new AutoVisgroupSection {Name = sectionName}; Expect(iterator, LexType.Open); iterator.MoveNext(); while (iterator.Current.Type != LexType.Close) { Assert(iterator.Current.IsValueOrString(), "Expected value type, got " + iterator.Current.Type + "."); var groupName = iterator.Current.GetValue(); var grp = new AutoVisgroup {Name = groupName}; Expect(iterator, LexType.Open); iterator.MoveNext(); while (iterator.Current.Type != LexType.Close) { Assert(iterator.Current.IsValueOrString(), "Expected value type, got " + iterator.Current.Type + "."); var entity = iterator.Current.GetValue(); grp.EntityNames.Add(entity); iterator.MoveNext(); } sect.Groups.Add(grp); } gd.AutoVisgroups.Add(sect); } else { // Parsing: // @TypeClass name(param, param) name() var ct = ParseClassType(type); var gdo = new GameDataObject("", "", ct); iterator.MoveNext(); while (iterator.Current.Type == LexType.Value) { // Parsing: // @TypeClass {name(param, param) name()} var name = iterator.Current.Value; var bh = new Behaviour(name); iterator.MoveNext(); if (iterator.Current.Type == LexType.Value) { // Allow for the following (first seen in hl2 base): // @PointClass {halfgridsnap} base(Targetname) continue; } Assert(iterator.Current.Type == LexType.So, "Unexpected " + iterator.Current.Type); iterator.MoveNext(); while (iterator.Current.Type != LexType.Already) { // Parsing: // name({param, param}) if (iterator.Current.Type != LexType.Comma) { Assert(iterator.Current.Type == LexType.Value || iterator.Current.Type == LexType.String, "Unexpected " + iterator.Current.Type + "."); var value = iterator.Current.Value; if (iterator.Current.Type == LexType.String) value = value.Trim('"'); bh.Values.Add(value); } iterator.MoveNext(); } Assert(iterator.Current.Type == LexType.Already, "Unexpected " + iterator.Current.Type); // Treat base behaviour as a special case if (bh.Name == "base") { gdo.BaseClasses.AddRange(bh.Values); } else { gdo.Behaviours.Add(bh); } iterator.MoveNext(); } // = class_name : "Descr" + "iption" [ Assert(iterator.Current.Type == LexType.Equals, "Expected equals, got " + iterator.Current.Type); Expect(iterator, LexType.Value); gdo.Name = iterator.Current.Value; iterator.MoveNext(); if (iterator.Current.Type == LexType.Colon) { // Parsing: // : {"Descr" + "iption"} [ iterator.MoveNext(); gdo.Description = ParsePlusString(iterator); } Assert(iterator.Current.Type == LexType.Open, "Unexpected " + iterator.Current.Type); // Parsing: // name(type) : "Desc" : "Default" : "Long Desc" = [ ... ] // input name(type) : "Description" // output name(type) : "Description" iterator.MoveNext(); while (iterator.Current.Type != LexType.Close) { Assert(iterator.Current.Type == LexType.Value, "Unexpected " + iterator.Current.Type); var pt = iterator.Current.Value; if (pt == "input" || pt == "output") // IO { // input name(type) : "Description" var io = new IO(); Expect(iterator, LexType.Value); io.IOType = (IOType) Enum.Parse(typeof (IOType), pt, true); io.Name = iterator.Current.Value; Expect(iterator, LexType.So); Expect(iterator, LexType.Value); io.VariableType = ParseVariableType(iterator.Current.Value); Expect(iterator, LexType.Already); iterator.MoveNext(); // if not colon, this will be the value of the next io/property, or close if (iterator.Current.Type == LexType.Colon) { iterator.MoveNext(); io.Description = ParsePlusString(iterator); } gdo.InOuts.Add(io); } else // Property { Expect(iterator, LexType.So); Expect(iterator, LexType.Value); var vartype = ParseVariableType(iterator.Current.Value); Expect(iterator, LexType.Already); var prop = new Property(pt, vartype); iterator.MoveNext(); // if not colon or equals, this will be the value of the next io/property, or close if (iterator.Current.Type == LexType.Value) { // Check for additional flags on the property // e.g.: name(type) readonly : "This is a read only value" // name(type) report : "This value will show in the entity report" switch (iterator.Current.Value) { case "readonly": prop.ReadOnly = true; iterator.MoveNext(); break; case "report": prop.ShowInEntityReport = true; iterator.MoveNext(); break; } } do // Using do/while(false) so I can break out - reduces nesting. { // Short description if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); prop.ShortDescription = ParsePlusString(iterator); // Default value if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); if (iterator.Current.Type != LexType.Colon) // Allow for ': :' structure (no default) { if (iterator.Current.Type == LexType.String) { prop.DefaultValue = iterator.Current.Value.Trim('"'); } else { Assert(iterator.Current.Type == LexType.Value, "Unexpected " + iterator.Current.Type); prop.DefaultValue = iterator.Current.Value; } iterator.MoveNext(); } // Long description if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); prop.Description = ParsePlusString(iterator); } while (false); if (iterator.Current.Type == LexType.Equals) { Expect(iterator, LexType.Open); // Parsing property options: // value : description // value : description : 0 iterator.MoveNext(); while (iterator.Current.IsValueOrString()) { var opt = new Option { Key = iterator.Current.GetValue() }; Expect(iterator, LexType.Colon); // Some FGDs use values for property descriptions instead of strings iterator.MoveNext(); Assert(iterator.Current.IsValueOrString(), "Choices value must be value or string type."); if (iterator.Current.Type == LexType.String) { opt.Description = ParsePlusString(iterator); } else { opt.Description = iterator.Current.GetValue(); iterator.MoveNext(); // ParsePlusString moves next once it's complete, need to do the same here } prop.Options.Add(opt); if (iterator.Current.Type != LexType.Colon) { continue; } Expect(iterator, LexType.Value); opt.On = iterator.Current.Value == "1"; iterator.MoveNext(); } Assert(iterator.Current.Type == LexType.Close, "Unexpected " + iterator.Current.Type); iterator.MoveNext(); } gdo.Properties.Add(prop); } } Assert(iterator.Current.Type == LexType.Close, "Unexpected " + iterator.Current.Type); gd.Classes.Add(gdo); } }
private void ParseAt(DataStructures.GameData.GameData gd, IEnumerator<LexObject> iterator) { iterator.MoveNext(); var type = iterator.Current.Value; if (type == "include") { Expect(iterator, LexType.String); if (CurrentFile != null) { var filename = iterator.Current.GetValue(); var path = Path.GetDirectoryName(CurrentFile) ?? ""; var incfile = Path.Combine(path, filename); var incgd = GetGameDataFromFile(incfile); gd.MapSizeHigh = incgd.MapSizeHigh; gd.MapSizeLow = incgd.MapSizeLow; gd.Includes.Add(filename); gd.Classes.AddRange(incgd.Classes); } else { throw new ProviderException("Unable to include a file when not reading from a file."); } } else if (type == "mapsize") { Expect(iterator, LexType.So); Expect(iterator, LexType.Value); gd.MapSizeLow = Int32.Parse(iterator.Current.Value); Expect(iterator, LexType.Comma); Expect(iterator, LexType.Value); gd.MapSizeHigh = Int32.Parse(iterator.Current.Value); Expect(iterator, LexType.Already); } else { // Parsing: // @TypeClass name(param, param) name() var ct = ParseClassType(type); var gdo = new GameDataObject("", "", ct); iterator.MoveNext(); while (iterator.Current.Type == LexType.Value) { // Parsing: // @TypeClass {name(param, param) name()} var name = iterator.Current.Value; var bh = new Behaviour(name); iterator.MoveNext(); if (iterator.Current.Type == LexType.Value) { // Allow for the following (first seen in hl2 base): // @PointClass {halfgridsnap} base(Targetname) continue; } Assert(iterator.Current.Type == LexType.So, "Unexpected " + iterator.Current.Type); iterator.MoveNext(); while (iterator.Current.Type != LexType.Already) { // Parsing: // name({param, param}) if (iterator.Current.Type != LexType.Comma) { Assert(iterator.Current.Type == LexType.Value || iterator.Current.Type == LexType.String, "Unexpected " + iterator.Current.Type + "."); var value = iterator.Current.Value; if (iterator.Current.Type == LexType.String) value = value.Trim('"'); bh.Values.Add(value); } iterator.MoveNext(); } Assert(iterator.Current.Type == LexType.Already, "Unexpected " + iterator.Current.Type); // Treat base behaviour as a special case if (bh.Name == "base") { gdo.BaseClasses.AddRange(bh.Values); } else { gdo.Behaviours.Add(bh); } iterator.MoveNext(); } // = class_name : "Descr" + "iption" [ Assert(iterator.Current.Type == LexType.Equals, "Expected equals, got " + iterator.Current.Type); Expect(iterator, LexType.Value); gdo.Name = iterator.Current.Value; iterator.MoveNext(); if (iterator.Current.Type == LexType.Colon) { // Parsing: // : {"Descr" + "iption"} [ iterator.MoveNext(); gdo.Description = ParsePlusString(iterator); } Assert(iterator.Current.Type == LexType.Open, "Unexpected " + iterator.Current.Type); // Parsing: // name(type) : "Desc" : "Default" : "Long Desc" = [ ... ] // input name(type) : "Description" // output name(type) : "Description" iterator.MoveNext(); while (iterator.Current.Type != LexType.Close) { Assert(iterator.Current.Type == LexType.Value, "Unexpected " + iterator.Current.Type); var pt = iterator.Current.Value; if (pt == "input" || pt == "output") // IO { // input name(type) : "Description" var io = new IO(); Expect(iterator, LexType.Value); io.IOType = (IOType) Enum.Parse(typeof (IOType), pt, true); io.Name = iterator.Current.Value; Expect(iterator, LexType.So); Expect(iterator, LexType.Value); io.VariableType = ParseVariableType(iterator.Current.Value); Expect(iterator, LexType.Already); iterator.MoveNext(); // if not colon, this will be the value of the next io/property, or close if (iterator.Current.Type == LexType.Colon) { iterator.MoveNext(); io.Description = ParsePlusString(iterator); } gdo.InOuts.Add(io); } else // Property { Expect(iterator, LexType.So); Expect(iterator, LexType.Value); var vartype = ParseVariableType(iterator.Current.Value); Expect(iterator, LexType.Already); var prop = new Property(pt, vartype); iterator.MoveNext(); // if not colon or equals, this will be the value of the next io/property, or close if (iterator.Current.Type == LexType.Value && iterator.Current.Value == "readonly") { // Readonly properties require a special case: // name(type) readonly : "Description" prop.ReadOnly = true; iterator.MoveNext(); } do // Using do/while(false) so I can break out - reduces nesting. { // Short description if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); prop.ShortDescription = ParsePlusString(iterator); // Default value if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); if (iterator.Current.Type != LexType.Colon) // Allow for ': :' structure (no default) { if (iterator.Current.Type == LexType.String) { prop.DefaultValue = iterator.Current.Value.Trim('"'); } else { Assert(iterator.Current.Type == LexType.Value, "Unexpected " + iterator.Current.Type); prop.DefaultValue = iterator.Current.Value; } iterator.MoveNext(); } // Long description if (iterator.Current.Type != LexType.Colon) break; iterator.MoveNext(); prop.Description = ParsePlusString(iterator); } while (false); if (iterator.Current.Type == LexType.Equals) { Expect(iterator, LexType.Open); // Parsing property options: // value : description // value : description : 0 iterator.MoveNext(); while (iterator.Current.IsValueOrString()) { var opt = new Option { Key = iterator.Current.GetValue() }; Expect(iterator, LexType.Colon); // Some FGDs use values for property descriptions instead of strings iterator.MoveNext(); Assert(iterator.Current.IsValueOrString(), "Choices value must be value or string type."); if (iterator.Current.Type == LexType.String) { opt.Description = ParsePlusString(iterator); } else { opt.Description = iterator.Current.GetValue(); iterator.MoveNext(); // ParsePlusString moves next once it's complete, need to do the same here } prop.Options.Add(opt); if (iterator.Current.Type != LexType.Colon) { continue; } Expect(iterator, LexType.Value); opt.On = iterator.Current.Value == "1"; iterator.MoveNext(); } Assert(iterator.Current.Type == LexType.Close, "Unexpected " + iterator.Current.Type); iterator.MoveNext(); } gdo.Properties.Add(prop); } } Assert(iterator.Current.Type == LexType.Close, "Unexpected " + iterator.Current.Type); gd.Classes.Add(gdo); } }