Exemple #1
1
        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;
        }
Exemple #2
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();
 }
Exemple #3
0
        public void ParseNextConcept_DontDescribeExceptionIfConceptNotRecognised()
        {
            string dsl = "a";
            List<IConceptParser> conceptParsers = new List<IConceptParser>() { new TestErrorParser("b") };

            TokenReader tokenReader = new TokenReader(Tokenizer.GetTokens(new DslSourceHelper(dsl)), 0);
            try
            {
                IConceptInfo actual = new TestDslParser(dsl).ParseNextConcept(tokenReader, null, conceptParsers);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Assert.IsFalse(e.Message.Contains(TestErrorParser.ErrorMessage), "Exception must not contain: " + TestErrorParser.ErrorMessage);
                throw;
            }
        }
Exemple #4
0
 public void CopyFrom(TokenReader tokenReader)
 {
     this.TokenList = tokenReader.TokenList;
     this.PositionInTokenList = tokenReader.PositionInTokenList;
 }
Exemple #5
0
 public TokenReader(TokenReader tokenReader)
 {
     CopyFrom(tokenReader);
 }
Exemple #6
0
 public TokenReader(TokenReader tokenReader)
 {
     CopyFrom(tokenReader);
 }
Exemple #7
0
 public void CopyFrom(TokenReader tokenReader)
 {
     this._tokenList          = tokenReader._tokenList;
     this.PositionInTokenList = tokenReader.PositionInTokenList;
 }
Exemple #8
0
        protected IEnumerable<IConceptInfo> ExtractConcepts(IEnumerable<IConceptParser> conceptParsers)
        {
            var stopwatch = Stopwatch.StartNew();

            TokenReader tokenReader = new TokenReader(Tokenizer.GetTokens(_dslSource), 0);

            List<IConceptInfo> newConcepts = new List<IConceptInfo>();
            Stack<IConceptInfo> context = new Stack<IConceptInfo>();
            while (!tokenReader.EndOfInput)
            {
                IConceptInfo conceptInfo = ParseNextConcept(tokenReader, context, conceptParsers);
                newConcepts.Add(conceptInfo);

                UpdateContextForNextConcept(tokenReader, context, conceptInfo);
            }

            _performanceLogger.Write(stopwatch, "DslParser.ExtractConcepts.");

            if (context.Count > 0)
                throw new DslSyntaxException(string.Format(
                    ReportErrorContext(context.Peek(), _dslSource.Script.Length - 1)
                    + "Expected \"}\" at the end of the script to close concept \"{0}\".", context.Peek()));

            return newConcepts;
        }
Exemple #9
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.CurrentPosition));
                sb.AppendFormat("Expected \";\" or \"{{\".");
                throw new DslSyntaxException(sb.ToString());
            }

            while (tokenReader.TryRead("}"))
            {
                if (context.Count == 0)
                    throw new DslSyntaxException(_dslSource.ReportError(tokenReader.CurrentPosition) + "\r\nUnexpected \"}\". ");
                context.Pop();
            }
        }
Exemple #10
0
        private (IConceptInfo ConceptInfo, List <string> Warnings) 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, 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()));
                    }
                }
            }

            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()}");
                }
            }

            Disambiguate(possibleInterpretations);
            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));
            }

            var parsedStatement = possibleInterpretations.Single();

            tokenReader.CopyFrom(parsedStatement.NextPosition);
            return(parsedStatement.ConceptInfo, parsedStatement.Warnings);
        }
Exemple #11
0
        private List <ConceptSyntaxNode> ExtractConcepts(MultiDictionary <string, IConceptParser> conceptParsers)
        {
            var stopwatch = Stopwatch.StartNew();

            var tokenizerResult = _tokenizer.GetTokens();

            if (tokenizerResult.SyntaxError != null)
            {
                ExceptionsUtility.Rethrow(tokenizerResult.SyntaxError);
            }
            var tokenReader = new TokenReader(tokenizerResult.Tokens, 0);

            var newConcepts = new List <ConceptSyntaxNode>();
            var context     = new Stack <ConceptSyntaxNode>();
            var warnings    = new List <string>();

            tokenReader.SkipEndOfFile();
            while (!tokenReader.EndOfInput)
            {
                var parsed = ParseNextConcept(tokenReader, context, conceptParsers);
                newConcepts.Add(parsed.ConceptInfo);

                if (parsed.Warnings != null)
                {
                    warnings.AddRange(parsed.Warnings);
                }

                UpdateContextForNextConcept(tokenReader, context, parsed.ConceptInfo);
                OnKeyword?.Invoke(tokenReader, null);

                if (context.Count == 0)
                {
                    tokenReader.SkipEndOfFile();
                }
            }

            _performanceLogger.Write(stopwatch, "ExtractConcepts (" + newConcepts.Count + " concepts).");

            if (context.Count > 0)
            {
                var(dslScript, position) = tokenReader.GetPositionInScript();
                throw new DslSyntaxException($"Expected \"}}\" to close concept \"{context.Peek()}\".",
                                             "RH0002", dslScript, position, 0, ReportPreviousConcept(context.Peek()));
            }

            foreach (string warning in warnings)
            {
                if (_syntax.Value.ExcessDotInKey == ExcessDotInKey.Ignore)
                {
                    _logger.Trace(warning);
                }
                else
                {
                    _logger.Warning(warning);
                }
            }
            if (_syntax.Value.ExcessDotInKey == ExcessDotInKey.Error && warnings.Any())
            {
                throw new DslSyntaxException(warnings.First());
            }

            return(newConcepts);
        }
Exemple #12
0
        private (ConceptSyntaxNode ConceptInfo, List <string> Warnings) ParseNextConcept(TokenReader tokenReader, Stack <ConceptSyntaxNode> 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
                        {
                            Node         = 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].Node.Concept.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.Node, parsedStatement.Warnings);
        }
Exemple #13
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)
            {
                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);
        }