| File: Internal\SrgsCompiler\GrammarElement.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Speech.Internal.SrgsParser; namespace System.Speech.Internal.SrgsCompiler { internal class GrammarElement : ParseElement, IGrammar { #region Constructors internal GrammarElement(Backend backend, CustomGrammar cg) : base(null!) { _cg = cg; _backend = backend; } #endregion #region Internal Method string? IGrammar.Root { get { return _sRoot; } set { _sRoot = value; } } IRule IGrammar.CreateRule(string id, RulePublic publicRule, RuleDynamic dynamic, bool hasScript) { SPCFGRULEATTRIBUTES dwRuleAttributes = 0; // Determine rule attributes to apply based on RuleScope, IsDynamic, and IsRootRule. // IsRootRule RuleScope IsDynamic Rule Attributes // ---------------------------------------------------------------------- // true * true Root | Active | TopLevel | Export | Dynamic // true * false Root | Active | TopLevel | Export // false internal true TopLevel | Export | Dynamic // false internal false TopLevel | Export // false private true Dynamic // false private false 0 if (id == _sRoot) { dwRuleAttributes |= SPCFGRULEATTRIBUTES.SPRAF_Root | SPCFGRULEATTRIBUTES.SPRAF_Active | SPCFGRULEATTRIBUTES.SPRAF_TopLevel; _hasRoot = true; } if (publicRule == RulePublic.True) { dwRuleAttributes |= SPCFGRULEATTRIBUTES.SPRAF_TopLevel | SPCFGRULEATTRIBUTES.SPRAF_Export; } if (dynamic == RuleDynamic.True) { // BackEnd supports exported dynamic rules for SRGS grammars. dwRuleAttributes |= SPCFGRULEATTRIBUTES.SPRAF_Dynamic; } // Create rule with specified attributes Rule rule = GetRule(id, dwRuleAttributes); // Add this rule to the list of rules of the STG list if (publicRule == RulePublic.True || id == _sRoot || hasScript) { _cg._rules.Add(rule); } return rule; } void IElement.PostParse(IElement? parent) { if (_sRoot != null && !_hasRoot) { // "Root rule ""%s"" is undefined." XmlParser.ThrowSrgsException(SRID.RootNotDefined, _sRoot); } if (_undefRules.Count > 0) { // "Root rule ""%s"" is undefined." Rule rule = _undefRules[0]; XmlParser.ThrowSrgsException(SRID.UndefRuleRef, rule.Name); } // SAPI semantics only for .NET Semantics bool containsCode = ((IGrammar)this).CodeBehind.Count > 0 || ((IGrammar)this).ImportNamespaces.Count > 0 || ((IGrammar)this).AssemblyReferences.Count > 0 || CustomGrammar._scriptRefs.Count > 0; if (containsCode && ((IGrammar)this).TagFormat != System.Speech.Recognition.SrgsGrammar.SrgsTagFormat.KeyValuePairs) { XmlParser.ThrowSrgsException(SRID.InvalidSemanticProcessingType); } } internal void AddScript(string name, string code) { foreach (Rule rule in _cg._rules) { if (rule.Name == name) { rule.Script.Append(code); break; } } } #endregion #region Internal Properties /// <summary> /// Base URI of grammar (xml:base) /// </summary> Uri? IGrammar.XmlBase { set { if (value != null) { _backend.SetBasePath(value.ToString()); } } } /// <summary> /// GrammarElement language (xml:lang) /// </summary> CultureInfo IGrammar.Culture { set { ArgumentNullException.ThrowIfNull(value); _backend.LangId = value.LCID; } } /// <summary> /// GrammarElement mode. voice or dtmf /// </summary> GrammarType IGrammar.Mode { set { _backend.GrammarMode = value; } } /// <summary> /// GrammarElement mode. voice or dtmf /// </summary> AlphabetType IGrammar.PhoneticAlphabet { set { _backend.Alphabet = value; } } /// <summary> /// Tag format (srgs:tag-format) /// </summary> System.Speech.Recognition.SrgsGrammar.SrgsTagFormat IGrammar.TagFormat { get { return System.Speech.Recognition.SrgsGrammar.SrgsDocument.GrammarOptions2TagFormat(_backend.GrammarOptions); } set { _backend.GrammarOptions = System.Speech.Recognition.SrgsGrammar.SrgsDocument.TagFormat2GrammarOptions(value); } } /// <summary> /// Tag format (srgs:tag-format) /// </summary> Collection<string> IGrammar.GlobalTags { get { return _backend.GlobalTags; } set { _backend.GlobalTags = value; } } internal List<Rule> UndefRules { get { return _undefRules; } } internal Backend Backend { get { return _backend; } } /// <summary> /// language /// </summary> string? IGrammar.Language { get { return _cg._language; } set { _cg._language = value; } } /// <summary> /// namespace /// </summary> string? IGrammar.Namespace { get { return _cg._namespace; } set { _cg._namespace = value; } } /// <summary> /// CodeBehind /// </summary> Collection<string> IGrammar.CodeBehind { get { return _cg._codebehind; } set { _cg._codebehind = value; } } /// <summary> /// Add #line statements to the inline scripts if set /// </summary> bool IGrammar.Debug { set { _cg._fDebugScript = value; } } /// <summary> /// ImportNameSpaces /// </summary> Collection<string> IGrammar.ImportNamespaces { get { return _cg._importNamespaces; } set { _cg._importNamespaces = value; } } /// <summary> /// ImportNameSpaces /// </summary> Collection<string> IGrammar.AssemblyReferences { get { return _cg._assemblyReferences; } set { _cg._assemblyReferences = value; } } internal CustomGrammar CustomGrammar { get { return _cg; } } #endregion #region Private Methods /// <summary> /// Create a new rule with the specified name and attribute, and return the initial state. /// Verify if Rule is unique. A Rule may already have been created as a placeholder during RuleRef. /// </summary> /// <param name="sRuleId">Rule name</param> /// <param name="dwAttributes">Rule attributes</param> private Rule GetRule(string sRuleId, SPCFGRULEATTRIBUTES dwAttributes) { System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(sRuleId)); // Check if RuleID is unique. Rule? rule = _backend.FindRule(sRuleId); if (rule != null) { // Rule already defined. Check if it is a placeholder. int iRule = _undefRules.IndexOf(rule); if (iRule != -1) { // This is a UndefinedRule created as a placeholder for a RuleRef. // - Update placeholder rule with correct attributes. _backend.SetRuleAttributes(rule, dwAttributes); // - Remove this now defined rule from UndefinedRules. // Swap top element with this rule and pop the top element. _undefRules.RemoveAt(iRule); } else { // Multiple definitions of the same Rule. XmlParser.ThrowSrgsException(SRID.RuleRedefinition, sRuleId); // "Redefinition of rule ""%s""." } } else { // Rule not yet defined. Create a new rule and return the InitialState. rule = _backend.CreateRule(sRuleId, dwAttributes); } return rule; } #endregion #region Private Fields private Backend _backend; // Collection of referenced, but undefined, rules private List<Rule> _undefRules = new(); private CustomGrammar _cg; private string? _sRoot; private bool _hasRoot; #endregion } }