/// <summary> /// Parsing process, processing single trimmed FULL-line as new section start /// </summary> /// <param name="oneLine">Line to be processed</param> /// <param name="fullLineComment">Comment to given section</param> /// <param name="curLine">Current line number, for when exception occurs</param> /// <param name="knownSections">Dictionary of all pre-parsed sections</param> /// <returns>Newly entered section</returns> internal static QualifiedSectionName processSingleLineAsSectionStart(string oneLine, string fullLineComment, uint curLine, Dictionary <QualifiedSectionName, InnerSection> knownSections) { //{ a-z, A-Z, 0-9, _, ~, -, ., :, $, mezera } začínající znakem z množiny { a-z, A-Z, . , $, : } bool matchesSection = System.Text.RegularExpressions.Regex.IsMatch(oneLine, "\\[[a-zA-Z,\\.$:][a-zA-Z0-9_~\\.:$ -]*\\]"); // Mismatching format if (!matchesSection) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine + " unexpected section start", developerMsg: "Unexpected start of the file on line " + curLine + ", section start does not match desired format", line: curLine); } // extract values int rightBracket = oneLine.IndexOf(']'); string sectionName = oneLine.Substring(1, rightBracket - 1); QualifiedSectionName qName = new QualifiedSectionName(sectionName); // Section redefinition if (knownSections.ContainsKey(qName)) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine + " redefinition of section " + sectionName, developerMsg: "Error when parsing file on line " + curLine + " redefinition of section " + sectionName, line: curLine, section: sectionName); } // Create new section & return it knownSections.Add(qName, new InnerSection(qName, fullLineComment)); return(qName); }
/// <summary> /// Read configuration data from given stream /// </summary> /// <param name="input">Stream from which data is to be read</param> private void readConfig(StreamReader input) { // Reset known sections and options knownSections = new Dictionary <QualifiedSectionName, InnerSection>(); // State variables QualifiedSectionName curSection = null; uint curLine = 0; // Crawl full stream try { string oneLine; string fullLineComment = ""; while ((oneLine = input.ReadLine()) != null) { // Trim & update state variables oneLine = trimRespectLastEscapedSpace(oneLine); ++curLine; // blank line if (oneLine == "") { continue; } // switching logic switch (oneLine[0]) { case '[': curSection = Parser.processSingleLineAsSectionStart(oneLine, fullLineComment, curLine, knownSections); fullLineComment = ""; break; case ';': fullLineComment = oneLine.Substring(1); break; default: Parser.processSingleLineAsOption(oneLine, curLine, curSection, knownSections); fullLineComment = ""; break; } } } catch (ParserException) { throw; } catch (Exception ex) { throw new ParserExceptionWithinConfig( userMsg: "Parsing of file failed on line " + curLine, developerMsg: "Unexpected exception ocurred on line " + curLine + ", see inner exception for more details", line: curLine, section: curSection.ID, inner: ex); } }
/// <summary> /// Set option info and it's value. /// NOTE: Only options which are set via this call can be ADDED into output (readed options are included automatically). /// </summary> /// <param name="info">Structure describing option format</param> /// <param name="value">Structure wearing option value</param> internal void SetOption(OptionInfo info, OptionValue value) { // Check inner constraints checkValidity(info, value); // obtain qNames QualifiedSectionName qSect = value.Name.Section; QualifiedOptionName qOpt = value.Name; // Check that section exists if (!knownSections.ContainsKey(qSect)) { throw new ParserException( userMsg: "error, unknown section", developerMsg: "tried to set option in unknown section, sections needs to be retrieved from RegisterStructure() or from the actual file"); } // Ensure option exists if (!knownSections[qSect].Options.ContainsKey(qOpt)) { InnerOption newOpt = new InnerOption(qOpt, null); knownSections[qSect].Options.Add(qOpt, newOpt); newOpt.Comment = info.DefaultComment; } // along the way, check the comment checkOptionCommentAndSeen(info, knownSections); // Pass value into option InnerOption curOpt = knownSections[qSect].Options[qOpt]; IValueConverter converter; try { converter = Converters.ConfigConverters.getConverter(info); } catch (Exception ex) { throw new ParserException(userMsg: "Error when deserializing value", developerMsg: "Unsupported value tried to be deserialized", inner: ex); } if (info.IsContainer) { curOpt.strValues.Clear(); foreach (var elem in ConfigRW.ConfigCreation.StructureFactory.GetContainerElements(value.ConvertedValue)) { curOpt.strValues.Add(converter.Serialize(elem)); } } else { curOpt.strValues.Clear(); curOpt.strValues.Add(converter.Serialize(value.ConvertedValue)); } }
internal SectionInfo( QualifiedSectionName name, PropertyInfo associatedProperty, bool isOptional, string defaultComment, List <OptionInfo> options ) { Name = name; AssociatedProperty = associatedProperty.Name; DescribingType = associatedProperty.PropertyType; IsOptional = isOptional; foreach (var option in options) { _options[option.Name] = option; } Options = _options.Values; DefaultComment = defaultComment; }
/// <summary> /// Evaluates last link in the lexes list /// </summary> private void evaluateLink() { var lnkOption = lexes.Last(); lexes.RemoveAt(lexes.Count - 1); var lnkSection = lexes.Last(); lexes.RemoveAt(lexes.Count - 1); if (lnkSection.Item1 != Lexes.NT_LinkSection || lnkOption.Item1 != Lexes.NT_LinkOption) { throw new ParserException(userMsg: "Error when parsing configuration file", developerMsg: "unexpected element instead of Link parts in Lexer::evaluateLink"); } QualifiedSectionName qSec = new QualifiedSectionName(lnkSection.Item2); QualifiedOptionName qOpt = new QualifiedOptionName(qSec, lnkOption.Item2); InnerOption opt; try { opt = knownSections[qSec].Options[qOpt]; } catch (Exception ex) { throw new ParserException( userMsg: "Error when evaluating link during parsing of configuration file", developerMsg: "Link inside option value points to nonexistent section#option", inner: ex); } foreach (string val in opt.strValues) { lexes.Add(new Tuple <Lexes, string>(Lexes.T_ValuePart, val)); } }
internal QualifiedOptionName(QualifiedSectionName section, string optionID) { ID = optionID; Section = section; }
/// <summary> /// Parsing process, processing single trimmed FULL-line as option /// </summary> /// <param name="oneLine">Line to be processed</param> /// <param name="curLine">Current line number, for when exception occurs</param> /// <param name="curSection">Currently processed section</param> /// <param name="knownSections">Dictionary of all pre-parsed sections</param> internal static void processSingleLineAsOption(string oneLine, uint curLine, QualifiedSectionName curSection, Dictionary <QualifiedSectionName, InnerSection> knownSections) { // no section started yet if (curSection == null) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine + " unexpected element outside of section", developerMsg: "Unexpected start of the file on line " + curLine + ", option with no section", line: curLine, section: curSection.ID); } try { Lexer lineLexer = new Lexer(oneLine, knownSections); var lexes = lineLexer.GetLexes(); var lxName = lexes[0]; lexes.RemoveAt(0); if (lxName.Item1 != Lexer.Lexes.T_Identifier) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine, developerMsg: "Lexer process does not provided option identifier", line: curLine, section: curSection.ID); } QualifiedOptionName qName = new QualifiedOptionName(curSection, lxName.Item2); if (knownSections[curSection].Options.ContainsKey(qName)) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine + ", duplicit option", developerMsg: "Duplicit option ID occurred inside this section", line: curLine, section: curSection.ID, option: qName.ID); } InnerOption newOpt = new InnerOption(qName, curLine); knownSections[curSection].Options.Add(qName, newOpt); foreach (var lexeme in lexes) { if (lexeme.Item1 == Lexer.Lexes.T_Comment && lexeme == lexes[lexes.Count - 1]) { newOpt.Comment = lexeme.Item2; } else if (lexeme.Item1 == Lexer.Lexes.T_ValuePart) { newOpt.strValues.Add(lexeme.Item2); } else { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine, developerMsg: "unexpected lexeme pop off the lexer", line: curLine, section: curSection.ID, option: qName.ID); } } } catch (ParserException ex) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine, developerMsg: "Exception ocurred in Lexer process", line: curLine, section: curSection.ID, inner: ex); } catch (Exception ex) { throw new ParserExceptionWithinConfig( userMsg: "Error when parsing file on line " + curLine, developerMsg: "Unexpected exception ocurred in Lexer process", line: curLine, section: curSection.ID, inner: ex); } }
/// <summary> /// Name of section as seen in config /// </summary> /// <param name="name">Qualified name</param> /// <param name="comment">Section comment</param> internal InnerSection(QualifiedSectionName name, string comment) { Name = name; Comment = comment; }