// 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.DoNotReport) { 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); }
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.DoNotReport) 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; }