// Computes set of expected terms in a parser state. While there may be extended list of symbols expected at some point,
        // we want to reorganize and reduce it. For example, if the current state expects all arithmetic operators as an input,
        // it would be better to not list all operators (+, -, *, /, etc) but simply put "operator" covering them all.
        // To achieve this grammar writer can group operators (or any other terminals) into named groups using Grammar's methods
        // AddTermReportGroup, AddNoReportGroup etc. Then instead of reporting each operator separately, Irony would include
        // a single "group name" to represent them all.
        // The "expected report set" is not computed during parser construction (it would bite considerable time), but on demand during parsing,
        // when error is detected and the expected set is actually needed for error message.
        // Multi-threading concerns. When used in multi-threaded environment (web server), the LanguageData would be shared in
        // application-wide cache to avoid rebuilding the parser data on every request. The LanguageData is immutable, except
        // this one case - the expected sets are constructed late by CoreParser on the when-needed basis.
        // We don't do any locking here, just compute the set and on return from this function the state field is assigned.
        // We assume that this field assignment is an atomic, concurrency-safe operation. The worst thing that might happen
        // is "double-effort" when two threads start computing the same set around the same time, and the last one to finish would
        // leave its result in the state field.
        #endregion
        internal static StringSet ComputeGroupedExpectedSetForState(Grammar grammar, ParserState state)
        {
            var terms = new TerminalSet();

            terms.UnionWith(state.ExpectedTerminals);
            var result = new StringSet();

            //Eliminate no-report terminals
            foreach (var group in grammar.TermReportGroups)
            {
                if (group.GroupType == TermReportGroupType.Exclude)
                {
                    terms.ExceptWith(group.Terminals);
                }
            }
            //Add normal and operator groups
            foreach (var group in grammar.TermReportGroups)
            {
                if (group.GroupType == TermReportGroupType.Normal || group.GroupType == TermReportGroupType.Operator && terms.Overlaps(group.Terminals))
                {
                    result.Add(group.Alias);
                    terms.ExceptWith(group.Terminals);
                }
            }
            //Add remaining terminals "as is"
            foreach (var terminal in terms)
            {
                result.Add(terminal.ErrorAlias);
            }
            return(result);
        }
        string _startSymbolsFirsts; //first chars  of start-end symbols
        #endregion

        #region overrides: Init, GetFirsts, ReadBody, etc...
        public override void Init(GrammarData grammarData)
        {
            base.Init(grammarData);
            _startSymbolsFirsts = string.Empty;
            if (_subtypes.Count == 0)
            {
                grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrInvStrDef, this.Name); //"Error in string literal [{0}]: No start/end symbols specified."
                return;
            }
            //collect all start-end symbols in lists and create strings of first chars
            var allStartSymbols = new StringSet(); //to detect duplicate start symbols

            _subtypes.Sort(StringSubType.LongerStartFirst);
            bool isTemplate = false;

            foreach (StringSubType subType in _subtypes)
            {
                if (allStartSymbols.Contains(subType.Start))
                {
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null,
                                                    Resources.ErrDupStartSymbolStr, subType.Start, this.Name); //"Duplicate start symbol {0} in string literal [{1}]."
                }
                allStartSymbols.Add(subType.Start);
                _startSymbolsFirsts += subType.Start[0].ToString();
                if ((subType.Flags & StringOptions.IsTemplate) != 0)
                {
                    isTemplate = true;
                }
            }
            if (!CaseSensitive)
            {
                _startSymbolsFirsts = _startSymbolsFirsts.ToLower() + _startSymbolsFirsts.ToUpper();
            }
            //Set multiline flag
            foreach (StringSubType info in _subtypes)
            {
                if ((info.Flags & StringOptions.AllowsLineBreak) != 0)
                {
                    SetFlag(TermFlags.IsMultiline);
                    break;
                }
            }
            //For templates only
            if (isTemplate)
            {
                //Check that template settings object is provided
                var templateSettings = this.AstNodeConfig as StringTemplateSettings;
                if (templateSettings == null)
                {
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplNoSettings, this.Name); //"Error in string literal [{0}]: IsTemplate flag is set, but TemplateSettings is not provided."
                }
                else if (templateSettings.ExpressionRoot == null)
                {
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplMissingExprRoot, this.Name); //""
                }
                else if (!Grammar.SnippetRoots.Contains(templateSettings.ExpressionRoot))
                {
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplExprNotRoot, this.Name); //""
                }
            }//if
            //Create editor info
            if (this.EditorInfo == null)
            {
                this.EditorInfo = new TokenEditorInfo(TokenType.String, TokenColor.String, TokenTriggers.None);
            }
        }//method
Beispiel #3
0
        public override void Initialize(GrammarData grammarData)
        {
            base.Initialize(grammarData);
            _startSymbolsFirsts = new CharHashSet(CaseSensitivePrefixesSuffixes);
            if (_subtypes.Count == 0)
            {
                //"Error in string literal [{0}]: No start/end symbols specified."
                grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrInvStrDef, Name);
                return;
            }
            //collect all start-end symbols in lists and create strings of first chars
            var allStartSymbols = new StringSet(); //to detect duplicate start symbols

            _subtypes.Sort(StringSubType.LongerStartFirst);
            var isTemplate = false;

            foreach (var subType in _subtypes)
            {
                if (allStartSymbols.Contains(subType.Start))
                {
                    //"Duplicate start symbol {0} in string literal [{1}]."
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrDupStartSymbolStr, subType.Start, Name);
                }

                allStartSymbols.Add(subType.Start);
                _startSymbolsFirsts.Add(subType.Start[0]);
                if ((subType.Flags & StringOptions.IsTemplate) != 0)
                {
                    isTemplate = true;
                }
            }

            //Set multiline flag
            if (_subtypes.Any(info => (info.Flags & StringOptions.AllowsLineBreak) != 0))
            {
                SetFlag(TermFlags.IsMultiline);
            }

            //For templates only
            if (isTemplate)
            {
                //Check that template settings object is provided
                var templateSettings = AstConfig.Data as StringTemplateSettings;
                if (templateSettings == null)
                {
                    //"Error in string literal [{0}]: IsTemplate flag is set, but TemplateSettings is not provided."
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplNoSettings, Name);
                }
                else if (templateSettings.ExpressionRoot == null)
                {
                    //""
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplMissingExprRoot, Name);
                }
                else if (!Grammar.SnippetRoots.Contains(templateSettings.ExpressionRoot))
                {
                    //""
                    grammarData.Language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTemplExprNotRoot, Name);
                }
            }

            //Create editor info
            if (EditorInfo == null)
            {
                EditorInfo = new TokenEditorInfo(TokenType.String, TokenColor.String, TokenTriggers.None);
            }
        }