Skip to content
Snippets Groups Projects
Commit 953816dd authored by Jiří Kalvoda's avatar Jiří Kalvoda
Browse files

ConfigParser: Section name and key could be interpreted as value

parent f3b3b66f
No related branches found
No related tags found
No related merge requests found
......@@ -66,35 +66,35 @@ class ConfigDuplicitKeyException: ConfigDuplicitException
}
class ConfigNoAmenException: ConfigException
{
public ConfigValue Value;
public ConfigNoAmenException(ConfigValue value)
public ConfigKeyValue Value;
public ConfigNoAmenException(ConfigKeyValue value)
{
Value = value;
}
public override string ErrorString()
{
return $"End string \"{Value.amen}\" for block {Value.Key} starting at line {Value.Line} not found";
return $"End string \"{Value.amen}\" for block \"{Value.Key}\" starting at line {Value.Line} not found";
}
}
class ConfigMixedTabException: ConfigException
{
public ConfigValue Value;
public ConfigKeyValue Value;
public int Line;
public ConfigMixedTabException(ConfigValue value, int line)
public ConfigMixedTabException(ConfigKeyValue value, int line)
{
Value = value;
Line = line;
}
public override string ErrorString()
{
return $"{Line}: {Value.FullName}: Combination of tabs and spaces is not supported.";
return $"{Value.Place}: Combination of tabs and spaces is not supported.";
}
}
class ConfigWrongIndentException: ConfigException
{
public ConfigValue? Value;
public ConfigKeyValue? Value;
public int Line;
public ConfigWrongIndentException(ConfigValue? value, int line)
public ConfigWrongIndentException(ConfigKeyValue? value, int line)
{
Value = value;
Line = line;
......@@ -103,7 +103,7 @@ class ConfigWrongIndentException: ConfigException
{
if(Value == null)
return $"{Line}: Wrong indent.";
return $"{Line}: {Value.FullName}: Wrong indent.";
return $"{Value.Place}: Wrong indent.";
}
}
class ConfigSectionNotDefinedException: ConfigException
......@@ -115,7 +115,7 @@ class ConfigSectionNotDefinedException: ConfigException
}
public override string ErrorString()
{
return $"Section {Name} is not defined.";
return $"Section \"{Name}\" is not defined.";
}
}
class ConfigNotDefinedException: ConfigException
......@@ -129,7 +129,7 @@ class ConfigNotDefinedException: ConfigException
}
public override string ErrorString()
{
return $"{Section.SectionName ?? "[global]"}: Attribute {Name} is not defined.";
return $"{Section.SectionName ?? "[global]"}: Option \"{Name}\" is not defined.";
}
}
class ConfigNoValueException: ConfigException
......@@ -143,22 +143,21 @@ class ConfigNoValueException: ConfigException
}
public override string ErrorString()
{
return $"{Value.Line}: Attribute {Value.FullName} need value." ;
return $"{Value.Place}: Value needed." ;
}
}
class ConfigParseAttributeException: ConfigException
class ConfigParseValueException: ConfigException
{
public ConfigValue Value;
public string? Reason;
public ConfigParseAttributeException(ConfigValue value, string? reason=null)
public ConfigParseValueException(ConfigValue value, string? reason=null)
{
Value = value;
Reason = reason;
}
public override string ErrorString()
{
string name = Value.Section.SectionName != null ? $"{Value.Section.SectionName}: {Value.Key}" : Value.Key;
return $"{Value.Line}: Parsing attribute {Value.FullName} fail" +
return $"{Value.Place}: Parsing fail" +
(Reason==null?".":$": {Reason}.");
}
}
......@@ -173,24 +172,19 @@ class ConfigMistake: ConfigException
}
public override string ErrorString()
{
string name = Value.Section.SectionName != null ? $"{Value.Section.SectionName}: {Value.Key}" : Value.Key;
return $"{Value.Line}: {Value.FullName}: {Text}";
return $"{Value.Place}: {Text}";
}
}
class ConfigValue
abstract class ConfigValue
{
public ConfigSection Section {get; init;}
internal string? amen;
internal string? tabs;
public string Key {get; init;}
public int Line;
internal string? Value;
public bool HasText() => Value != null;
public int Line;
public string FullName
{
get => Section.SectionName != null ? $"{Section.SectionName}: {Key}" : Key;
}
public virtual string Place{get => $"{Line}: {FullName}";}
public abstract string FullName{get;} // For showing in error
public string AsString()
{
if(Value == null) throw new ConfigNoValueException(this);
......@@ -235,7 +229,7 @@ class ConfigValue
return System.Drawing.ColorTranslator.FromHtml(AsString());
} catch (ArgumentException)
{
throw new ConfigParseAttributeException(this, "String is not color");
throw new ConfigParseValueException(this, "String is not color");
}
}
public bool AsBool()
......@@ -246,7 +240,7 @@ class ConfigValue
return true;
if(v == "false" || v == "no" || v == "unuse" || v == "0")
return false;
throw new ConfigParseAttributeException(this, "String is not bool");
throw new ConfigParseValueException(this, "String is not bool");
}
public double AsDouble()
......@@ -256,7 +250,7 @@ class ConfigValue
return double.Parse(AsString());
} catch (FormatException)
{
throw new ConfigParseAttributeException(this, "String is not number");
throw new ConfigParseValueException(this, "String is not number");
}
}
public int AsInt()
......@@ -266,7 +260,7 @@ class ConfigValue
return int.Parse(AsString());
} catch (FormatException)
{
throw new ConfigParseAttributeException(this, "String is not int");
throw new ConfigParseValueException(this, "String is not int");
}
}
public int AsMs()
......@@ -278,34 +272,86 @@ class ConfigValue
return new ConfigParser(AsString(), Line);
}
public static implicit operator string(ConfigValue v) => v.AsString();
internal ConfigValue(ConfigSection _Section, string _Key, int _line)
}
class ConfigKeyValue: ConfigValue
{
public ConfigSection Section {get; init;}
internal string? amen;
internal string? tabs;
public string Key {get; init;}
public override string FullName
{
get => Section.SectionName != null ? $"{Section.SectionName}: {Key}" : Key;
}
internal ConfigKeyValue(ConfigSection _Section, string _Key, int _line)
{
Section = _Section;
Key = _Key;
Line = _line;
}
public ConfigKeyAsValue KeyAsValue() => new(this);
}
class ConfigSection: IReadOnlyList<ConfigValue>
class ConfigKeyAsValue: ConfigValue
{
public ConfigSection Section {get; init;}
public override string FullName
{
get => (Section.SectionName != null ? $"{Section.SectionName}: " : "") + $"Key {Value}";
}
internal ConfigKeyAsValue(ConfigKeyValue keyValue)
{
Line = keyValue.Line;
Value = keyValue.Key;
Section = keyValue.Section;
}
}
class ConfigSectionNameAsValue: ConfigValue
{
public ConfigSection Section {get; init;}
public override string FullName
{
get => "Section name " + (Section.SectionName != null ? $"\"{Section.SectionName}\"" : "of main section");
}
internal ConfigSectionNameAsValue(ConfigSection _Section)
{
Section = _Section;
Value = Section.SectionName;
Line = Section.Line;
}
}
class ConfigSectionNameAsDefaultValue: ConfigSectionNameAsValue
{
protected string defaultFor;
internal ConfigSectionNameAsDefaultValue(ConfigSection _Section, string _defaultFor): base(_Section)
{
defaultFor = _defaultFor;
}
public override string FullName
{
get => base.FullName + $" as default for \"{defaultFor}\" option";
}
}
class ConfigSection: IReadOnlyList<ConfigKeyValue>
{
public ConfigParser Root {get; init;}
public string? SectionName {get; init;}
public int Line;
List<ConfigValue> values = new();
Dictionary<string, ConfigValue> valueByName = new();
List<ConfigKeyValue> values = new();
Dictionary<string, ConfigKeyValue> valueByName = new();
internal ConfigSection(ConfigParser _Root, string? _SectionName, int _line)
{
Root = _Root;
SectionName = _SectionName;
Line = _line;
}
internal void Add(ConfigValue v)
internal void Add(ConfigKeyValue v)
{
if(valueByName.ContainsKey(v.Key))
throw new ConfigDuplicitKeyException(v.Key, v.Line, valueByName[v.Key].Line);
valueByName[v.Key] = v;
values.Add(v);
}
public IEnumerator<ConfigValue> GetEnumerator()
public IEnumerator<ConfigKeyValue> GetEnumerator()
{
foreach(var s in values)
yield return s;
......@@ -313,21 +359,25 @@ class ConfigSection: IReadOnlyList<ConfigValue>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
=> GetEnumerator();
public int Count{ get{return values.Count;}}
public ConfigValue this[int i]
public ConfigKeyValue this[int i]
{
get { return values[i]; }
}
public ConfigValue? this[string key]
public ConfigKeyValue? this[string key]
{
get { return Optional(key); }
}
public ConfigValue? Optional(string key)
public ConfigKeyValue? Optional(string key)
{
if(!valueByName.TryGetValue(key, out var r))
return null;
return r;
}
public ConfigValue Mandatory(string key)
public ConfigValue OptionalDefaultIsSectionName(string key)
{
return (ConfigValue?)Optional(key) ?? new ConfigSectionNameAsDefaultValue(this, key);
}
public ConfigKeyValue Mandatory(string key)
{
if(!valueByName.TryGetValue(key, out var r))
throw new ConfigNotDefinedException(this, key);
......@@ -345,6 +395,7 @@ class ConfigSection: IReadOnlyList<ConfigValue>
w.WriteLine($"'{x.Key}' = '{(x.HasText() ? x.AsString() : "null")}'");
}
}
public ConfigSectionNameAsValue SectionNameAsValue() => new(this);
}
class ConfigParser: IReadOnlyList<ConfigSection>
{
......@@ -355,7 +406,7 @@ class ConfigParser: IReadOnlyList<ConfigSection>
{
string[] lines = s.Split("\n");
var currentSection = MainSection = new(this, null, 0);
ConfigValue? lastVal = null;
ConfigKeyValue? lastVal = null;
for(int i=0;i<lines.Count();i++)
{
string l = lines[i];
......@@ -408,12 +459,12 @@ class ConfigParser: IReadOnlyList<ConfigSection>
int indexArrow = l.IndexOf("<<");
if(indexIs == -1 && indexArrow == -1)
{
currentSection.Add(lastVal = new ConfigValue(currentSection, tl, firstLineIndex + i));
currentSection.Add(lastVal = new ConfigKeyValue(currentSection, tl, firstLineIndex + i));
continue;
}
int index = indexIs == -1 ? indexArrow : indexArrow == -1 ? indexIs : Math.Min(indexIs, indexArrow);
string key = l[0..index].Trim();
currentSection.Add(lastVal = new ConfigValue(currentSection, key, firstLineIndex + i));
currentSection.Add(lastVal = new ConfigKeyValue(currentSection, key, firstLineIndex + i));
if(indexIs != -1 && (indexArrow == -1 || indexIs < indexArrow))
{
string val = l[(indexIs+1)..].Trim();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment