示例#1
1
 protected string ReportErrorContext(IConceptInfo conceptInfo, TokenReader tokenReader)
 {
     var sb = new StringBuilder();
     sb.AppendLine(tokenReader.ReportPosition());
     if (conceptInfo != null)
     {
         sb.AppendFormat("Previous concept: {0}", conceptInfo.GetUserDescription()).AppendLine();
         var properties = conceptInfo.GetType().GetProperties().ToList();
         properties.ForEach(it =>
             sb.AppendFormat("Property {0} ({1}) = {2}",
                 it.Name,
                 it.PropertyType.Name,
                 it.GetValue(conceptInfo, null) ?? "<null>")
                 .AppendLine());
     }
     return sb.ToString();
 }
示例#2
0
        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);
        }
示例#3
0
        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);
        }
示例#4
0
        protected string ReportErrorContext(IConceptInfo conceptInfo, TokenReader tokenReader)
        {
            var sb = new StringBuilder();

            sb.AppendLine(tokenReader.ReportPosition());
            if (conceptInfo != null)
            {
                sb.AppendFormat("Previous concept: {0}", conceptInfo.GetUserDescription()).AppendLine();
                var properties = conceptInfo.GetType().GetProperties().ToList();
                properties.ForEach(it =>
                                   sb.AppendFormat("Property {0} ({1}) = {2}",
                                                   it.Name,
                                                   it.PropertyType.Name,
                                                   it.GetValue(conceptInfo, null) ?? "<null>")
                                   .AppendLine());
            }
            return(sb.ToString());
        }
示例#5
0
        protected void UpdateContextForNextConcept(TokenReader tokenReader, Stack <IConceptInfo> context, IConceptInfo conceptInfo)
        {
            if (tokenReader.TryRead("{"))
            {
                context.Push(conceptInfo);
            }
            else if (!tokenReader.TryRead(";"))
            {
                var sb = new StringBuilder();
                sb.Append(ReportErrorContext(conceptInfo, tokenReader));
                sb.Append("Expected \";\" or \"{\".");
                throw new DslSyntaxException(sb.ToString());
            }

            while (tokenReader.TryRead("}"))
            {
                if (context.Count == 0)
                {
                    throw new DslSyntaxException(tokenReader.ReportPosition() + "\r\nUnexpected \"}\". ");
                }
                context.Pop();
            }
        }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        protected void UpdateContextForNextConcept(TokenReader tokenReader, Stack<IConceptInfo> context, IConceptInfo conceptInfo)
        {
            if (tokenReader.TryRead("{"))
                context.Push(conceptInfo);
            else if (!tokenReader.TryRead(";"))
            {
                var sb = new StringBuilder();
                sb.Append(ReportErrorContext(conceptInfo, tokenReader));
                sb.AppendFormat("Expected \";\" or \"{{\".");
                throw new DslSyntaxException(sb.ToString());
            }

            while (tokenReader.TryRead("}"))
            {
                if (context.Count == 0)
                    throw new DslSyntaxException(tokenReader.ReportPosition() + "\r\nUnexpected \"}\". ");
                context.Pop();
            }
        }
示例#9
0
        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;
        }