protected IConceptInfo ParseNextConcept(TokenReader tokenReader, Stack<IConceptInfo> context, IEnumerable<IConceptParser> conceptParsers) { var errors = new List<ErrorContext>(); List<Interpretation> possibleInterpretations = new List<Interpretation>(); foreach (var conceptParser in conceptParsers) { TokenReader nextPosition = new TokenReader(tokenReader); var conceptInfoOrError = conceptParser.Parse(nextPosition, context); if (!conceptInfoOrError.IsError) possibleInterpretations.Add(new Interpretation { ConceptInfo = conceptInfoOrError.Value, NextPosition = nextPosition }); else if (!string.IsNullOrEmpty(conceptInfoOrError.Error)) // Empty error means that this parser is not for this keyword. errors.Add(new ErrorContext { Error = conceptInfoOrError.Error, Postion = tokenReader.CurrentPosition, ParserName = conceptParser.GetType().Name, DslSource = _dslSource }); } if (possibleInterpretations.Count == 0) { string msg = "Unrecognized concept. " + _dslSource.ReportError(tokenReader.CurrentPosition); if (errors.Count > 0) { string listedErrors = string.Join("\r\n", errors); if (listedErrors.Length > 500) listedErrors = listedErrors.Substring(0, 500) + "..."; msg = msg + "\r\n\r\nPossible causes:\r\n" + listedErrors; } throw new DslSyntaxException(msg); } int largest = possibleInterpretations.Max(i => i.NextPosition.PositionInTokenList); possibleInterpretations.RemoveAll(i => i.NextPosition.PositionInTokenList < largest); if (possibleInterpretations.Count > 1) { string msg = "Ambiguous syntax. " + _dslSource.ReportError(tokenReader.CurrentPosition) + "\r\n Possible interpretations: " + string.Join(", ", possibleInterpretations.Select(i => i.ConceptInfo.GetType().Name)) + "."; throw new DslSyntaxException(msg); } tokenReader.CopyFrom(possibleInterpretations.Single().NextPosition); return possibleInterpretations.Single().ConceptInfo; }
protected IConceptInfo ParseNextConcept(TokenReader tokenReader, Stack <IConceptInfo> context, IEnumerable <IConceptParser> conceptParsers) { var errors = new List <string>(); List <Interpretation> possibleInterpretations = new List <Interpretation>(); foreach (var conceptParser in conceptParsers) { TokenReader nextPosition = new TokenReader(tokenReader); var conceptInfoOrError = conceptParser.Parse(nextPosition, context); if (!conceptInfoOrError.IsError) { possibleInterpretations.Add(new Interpretation { ConceptInfo = conceptInfoOrError.Value, NextPosition = nextPosition }); } else if (!string.IsNullOrEmpty(conceptInfoOrError.Error)) // Empty error means that this parser is not for this keyword. { errors.Add(string.Format("{0}: {1}\r\n{2}", conceptParser.GetType().Name, conceptInfoOrError.Error, tokenReader.ReportPosition())); } } if (possibleInterpretations.Count == 0) { var nextToken = new TokenReader(tokenReader).ReadText(); // Peek, without changing the original tokenReader's position. string keyword = nextToken.IsError ? null : nextToken.Value; if (errors.Count > 0) { string errorsReport = string.Join("\r\n", errors).Limit(500, "..."); throw new DslSyntaxException($"Invalid parameters after keyword '{keyword}'. {tokenReader.ReportPosition()}\r\n\r\nPossible causes:\r\n{errorsReport}"); } else if (!string.IsNullOrEmpty(keyword)) { throw new DslSyntaxException($"Unrecognized concept keyword '{keyword}'. {tokenReader.ReportPosition()}"); } else { throw new DslSyntaxException($"Invalid DSL script syntax. {tokenReader.ReportPosition()}"); } } int largest = possibleInterpretations.Max(i => i.NextPosition.PositionInTokenList); possibleInterpretations.RemoveAll(i => i.NextPosition.PositionInTokenList < largest); if (possibleInterpretations.Count > 1) { string msg = "Ambiguous syntax. " + tokenReader.ReportPosition() + "\r\n Possible interpretations: " + string.Join(", ", possibleInterpretations.Select(i => i.ConceptInfo.GetType().Name)) + "."; throw new DslSyntaxException(msg); } tokenReader.CopyFrom(possibleInterpretations.Single().NextPosition); return(possibleInterpretations.Single().ConceptInfo); }
protected IConceptInfo ParseNextConcept(TokenReader tokenReader, Stack <IConceptInfo> context, IEnumerable <IConceptParser> conceptParsers) { var errors = new List <string>(); List <Interpretation> possibleInterpretations = new List <Interpretation>(); foreach (var conceptParser in conceptParsers) { TokenReader nextPosition = new TokenReader(tokenReader); var conceptInfoOrError = conceptParser.Parse(nextPosition, context); if (!conceptInfoOrError.IsError) { possibleInterpretations.Add(new Interpretation { ConceptInfo = conceptInfoOrError.Value, NextPosition = nextPosition }); } else if (!string.IsNullOrEmpty(conceptInfoOrError.Error)) // Empty error means that this parser is not for this keyword. { errors.Add(string.Format("{0}: {1}\r\n{2}", conceptParser.GetType().Name, conceptInfoOrError.Error, tokenReader.ReportPosition())); } } if (possibleInterpretations.Count == 0) { string msg = "Unrecognized concept. " + tokenReader.ReportPosition(); if (errors.Count > 0) { string listedErrors = string.Join("\r\n", errors); if (listedErrors.Length > 500) { listedErrors = listedErrors.Substring(0, 500) + "..."; } msg = msg + "\r\n\r\nPossible causes:\r\n" + listedErrors; } throw new DslSyntaxException(msg); } int largest = possibleInterpretations.Max(i => i.NextPosition.PositionInTokenList); possibleInterpretations.RemoveAll(i => i.NextPosition.PositionInTokenList < largest); if (possibleInterpretations.Count > 1) { string msg = "Ambiguous syntax. " + tokenReader.ReportPosition() + "\r\n Possible interpretations: " + string.Join(", ", possibleInterpretations.Select(i => i.ConceptInfo.GetType().Name)) + "."; throw new DslSyntaxException(msg); } tokenReader.CopyFrom(possibleInterpretations.Single().NextPosition); return(possibleInterpretations.Single().ConceptInfo); }
private (IConceptInfo ConceptInfo, List <string> Warnings) ParseNextConcept(TokenReader tokenReader, Stack <IConceptInfo> context, MultiDictionary <string, IConceptParser> conceptParsers) { var errorReports = new List <Func <(string formattedError, string simpleError)> >(); List <Interpretation> possibleInterpretations = new List <Interpretation>(); var keywordReader = new TokenReader(tokenReader).ReadText(); // Peek, without changing the original tokenReader's position. var keyword = keywordReader.IsError ? null : keywordReader.Value; _onKeyword?.Invoke(tokenReader, keyword); if (keyword != null) { foreach (var conceptParser in conceptParsers.Get(keyword)) { TokenReader nextPosition = new TokenReader(tokenReader); var conceptInfoOrError = conceptParser.Parse(nextPosition, context, out var warnings); if (!conceptInfoOrError.IsError) { possibleInterpretations.Add(new Interpretation { ConceptInfo = conceptInfoOrError.Value, NextPosition = nextPosition, Warnings = warnings }); } else if (!string.IsNullOrEmpty(conceptInfoOrError.Error)) // Empty error means that this parser is not for this keyword. { errorReports.Add(() => (string.Format("{0}: {1}\r\n{2}", conceptParser.GetType().Name, conceptInfoOrError.Error, tokenReader.ReportPosition()), conceptInfoOrError.Error)); } } } if (possibleInterpretations.Count == 0) { var(dslScript, position) = tokenReader.GetPositionInScript(); if (errorReports.Count > 0) { var errorReportValues = errorReports.Select(x => x.Invoke()).ToList(); var errorsReport = string.Join("\r\n", errorReportValues.Select(x => x.formattedError)).Limit(500, "..."); var simpleErrorsReport = string.Join("\n", errorReportValues.Select(x => x.simpleError)); var simpleMessage = $"Invalid parameters after keyword '{keyword}'. Possible causes: {simpleErrorsReport}"; var possibleCauses = $"Possible causes:\r\n{errorsReport}"; throw new DslSyntaxException(simpleMessage, "RH0003", dslScript, position, 0, possibleCauses); } else if (!string.IsNullOrEmpty(keyword)) { var simpleMessage = $"Unrecognized concept keyword '{keyword}'."; throw new DslSyntaxException(simpleMessage, "RH0004", dslScript, position, 0, null); } else { var simpleMessage = $"Invalid DSL script syntax."; throw new DslSyntaxException(simpleMessage, "RH0005", dslScript, position, 0, null); } } Disambiguate(possibleInterpretations); if (possibleInterpretations.Count > 1) { var interpretations = new List <string>(); for (int i = 0; i < possibleInterpretations.Count; i++) { interpretations.Add($"{i + 1}. {possibleInterpretations[i].ConceptInfo.GetType().AssemblyQualifiedName}"); } var simpleMessage = $"Ambiguous syntax. There are multiple possible interpretations of keyword '{keyword}': {string.Join(", ", interpretations)}."; var(dslScript, position) = tokenReader.GetPositionInScript(); throw new DslSyntaxException(simpleMessage, "RH0006", dslScript, position, 0, null); } var parsedStatement = possibleInterpretations.Single(); tokenReader.CopyFrom(parsedStatement.NextPosition); return(parsedStatement.ConceptInfo, parsedStatement.Warnings); }
protected IConceptInfo ParseNextConcept(TokenReader tokenReader, Stack <IConceptInfo> context, MultiDictionary <string, IConceptParser> conceptParsers) { var errorReports = new List <Func <string> >(); List <Interpretation> possibleInterpretations = new List <Interpretation>(); var keywordReader = new TokenReader(tokenReader).ReadText(); // Peek, without changing the original tokenReader's position. var keyword = keywordReader.IsError ? null : keywordReader.Value; if (keyword != null) { foreach (var conceptParser in conceptParsers.Get(keyword)) { TokenReader nextPosition = new TokenReader(tokenReader); var conceptInfoOrError = conceptParser.Parse(nextPosition, context); if (!conceptInfoOrError.IsError) { possibleInterpretations.Add(new Interpretation { ConceptInfo = conceptInfoOrError.Value, NextPosition = nextPosition }); } else if (!string.IsNullOrEmpty(conceptInfoOrError.Error)) // Empty error means that this parser is not for this keyword. { errorReports.Add(() => string.Format("{0}: {1}\r\n{2}", conceptParser.GetType().Name, conceptInfoOrError.Error, tokenReader.ReportPosition())); } } } if (possibleInterpretations.Count == 0) { if (errorReports.Count > 0) { string errorsReport = string.Join("\r\n", errorReports.Select(x => x.Invoke())).Limit(500, "..."); throw new DslSyntaxException($"Invalid parameters after keyword '{keyword}'. {tokenReader.ReportPosition()}\r\n\r\nPossible causes:\r\n{errorsReport}"); } else if (!string.IsNullOrEmpty(keyword)) { throw new DslSyntaxException($"Unrecognized concept keyword '{keyword}'. {tokenReader.ReportPosition()}"); } else { throw new DslSyntaxException($"Invalid DSL script syntax. {tokenReader.ReportPosition()}"); } } int largest = possibleInterpretations.Max(i => i.NextPosition.PositionInTokenList); possibleInterpretations.RemoveAll(i => i.NextPosition.PositionInTokenList < largest); if (possibleInterpretations.Count > 1) { var report = new List <string>(); report.Add($"Ambiguous syntax. {tokenReader.ReportPosition()}"); report.Add($"There are multiple possible interpretations of keyword '{keyword}':"); for (int i = 0; i < possibleInterpretations.Count; i++) { report.Add($"{i + 1}. {possibleInterpretations[i].ConceptInfo.GetType().AssemblyQualifiedName}"); } throw new DslSyntaxException(string.Join("\r\n", report)); } tokenReader.CopyFrom(possibleInterpretations.Single().NextPosition); return(possibleInterpretations.Single().ConceptInfo); }