Example #1
0
 def test_dict_list_ref(self):
     element = self.dict_list_ref
     state = self.translator.translate_dict_list_ref(TranslationState(element))
     expected_rule = jsgf.HiddenRule("fruit_dict",
                                     jsgf.AlternativeSet("apple", "mango"))
     self.assertEqual(jsgf.RuleRef(expected_rule), state.expansion)
     self.assertListEqual([expected_rule], state.dependencies)
Example #2
0
 def test_list_referencing_rule(self):
     element = self.fruit_list_ref
     r = Rule("fav_fruit", element, exported=True)
     state = self.translator.translate_rule(r)
     list_rule = jsgf.HiddenRule("fruit", jsgf.AlternativeSet(*self.fruit_list))
     expected_rule = LinkedRule("fav_fruit", True, jsgf.RuleRef(list_rule), r)
     self.assertEqual(state.jsgf_rule, expected_rule)
Example #3
0
 def translate_list(lst):
     """
     Translate a dragonfly List object into a JSGF rule representing it.
     The returned rule is a HiddenRule because lists can only be referenced by
     rules using ListRef, not spoken directly.
     :type lst: DragonflyList
     :return: HiddenRule
     """
     return jsgf.HiddenRule(lst.name, jsgf.AlternativeSet(*lst))
Example #4
0
 def _compile_alternative(self, element, *args, **kwargs):
     children = element.children
     if len(children) > 1:
         return jsgf.AlternativeSet(
             *[self.compile_element(c, *args, **kwargs) for c in children])
     elif len(children) == 1:
         # Skip redundant (1 child) alternatives.
         return self.compile_element(children[0], *args, **kwargs)
     else:
         # Compile an Empty element for empty alternatives.
         return self.compile_element(elements_.Empty(), *args, **kwargs)
Example #5
0
 def translate_dict_list(dict_list):
     """
     Translate a dragonfly DictList object into a JSGF rule representing it.
     The returned rule is a HiddenRule because dict lists can only be referenced
     by rules using DictListRef, not spoken directly.
     :type dict_list: DragonflyDictList
     :return: HiddenRule
     """
     keys = dict_list.keys()
     keys.sort()
     return jsgf.HiddenRule(dict_list.name, jsgf.AlternativeSet(*keys))
Example #6
0
    def test_repeated_referenced_dictation(self):
        """
        Test that dragonfly rules containing Dictation referenced by a RuleRef with
        a Repetition element as an ancestor is translated correctly, with rules
        joined as necessary.
        """
        g = Grammar("test")

        # Add two simple rules, a more complex MappingRule and a rule referencing it
        # that allows repetition of its mappings
        r1 = Rule("dict", Dictation("dictation"))
        r2 = Rule("test1", Repetition(RuleRef(r1)), exported=True)
        r3 = MappingRule("mapping", mapping={
            "testing": ActionBase(),
            "hello <dictation>": ActionBase(),
            "<dictation>": ActionBase(),
        }, extras=[Dictation("dictation")])
        r4 = Rule("test2", Repetition(RuleRef(r3)), exported=True)
        g.add_rule(r2)
        g.add_rule(r4)

        # Translate the 'test' grammar and make some assertions
        translated = self.translator.translate_grammar(g)
        expected_test1 = LinkedRule(
            "test1", True, jsgf.Repeat(jsgf.ext.Dictation()), r1
        )

        # Note: this is not how the engine sees MappingRules with Dictation
        # elements: they are further processed later on into JSGF SequenceRules.
        # This is the format the rules should be in for the later processing.
        expected_test2 = LinkedRule("test2", True, jsgf.Repeat(
            jsgf.AlternativeSet(
                "testing", jsgf.Sequence("hello", jsgf.ext.Dictation()),
                jsgf.ext.Dictation()
            )
        ), r4)

        # Neither of the referenced rules should be in the final grammar, only the
        # two joined rules
        self.assertListEqual(translated.rules, [expected_test1, expected_test2])
Example #7
0
 def test_dict_list(self):
     actual = self.translator.translate_dict_list(self.dict_list)
     expected = jsgf.HiddenRule("fruit_dict",
                                jsgf.AlternativeSet("apple", "mango"))
     self.assertEqual(expected, actual)
Example #8
0
 def test_list_ref(self):
     element = self.fruit_list_ref
     state = self.translator.translate_list_ref(TranslationState(element))
     jsgf_rule = jsgf.HiddenRule("fruit", jsgf.AlternativeSet(*self.fruit_list))
     self.assertEqual(jsgf.RuleRef(jsgf_rule), state.expansion)
     self.assertListEqual([jsgf_rule], state.dependencies)
Example #9
0
    def get_jsgf_equiv(self, state):
        """
        Take a TranslationState object containing a dragonfly element
        return the same object with the 'expansion' member set to the
        equivalent JSGF expansion object.
        :type state: TranslationState
        :return TranslationState
        """
        element = state.element

        def get_equiv_children():
            children = []
            for child in state.element.children:
                state.element = child
                self.get_jsgf_equiv(state)
                children.append(state.expansion)
            return children

        if isinstance(element, Literal):  # Literal == word list
            text = " ".join(element.words)
            state.expansion = jsgf.Literal(text)

        elif isinstance(element, (RuleRef, Rule)):
            # Translate the dragonfly rule reference
            self.translate_rule_ref(state)

        # DictListRef should be checked before ListRef because it is a subclass
        elif isinstance(element, (DictListRef, DictList)):
            self.translate_dict_list_ref(state)

        elif isinstance(element, (ListRef, List)):
            self.translate_list_ref(state)

        elif isinstance(element, Dictation):
            # A Sphinx decoder for handling dictation will be prepared and used
            # when necessary.
            state.expansion = jsgf.ext.Dictation()

        elif isinstance(element, Impossible):
            # VoidRef is the equivalent of dragonfly's Impossible element.
            # It is also automatically used by pyjsgf if an expansion that should
            # have at least one child (e.g. Sequence/Repeat) doesn't have any at
            # compile time.
            state.expansion = VoidRef()

        elif element.children == ():  # improbable ElementBase case
            state.expansion = jsgf.Expansion([])

        # Repetition should be checked before Sequence because it is a subclass
        elif isinstance(element, Repetition):
            # Repetition should have at least one child
            assert len(state.element.children) > 0

            if self._has_dictation_descendant(element):
                self.translate_repetition_with_dictation(state)
            else:
                # Translate the first child only. The second child is of the form:
                # [first_child [first_child ... first_child ] ... ]
                # This is how matching a limited number of repetitions is done.
                # Limitation (min/max) values for Repetition elements are ignored
                # for the Sphinx engine for the moment.
                equiv_child = get_equiv_children()[0]
                state.expansion = PatchedRepeat(equiv_child)

        elif isinstance(element, Sequence):
            state.expansion = jsgf.Sequence(*get_equiv_children())

        elif isinstance(element, Alternative):
            if len(state.element.children) == 1:
                # Skip redundant (1 child) alternatives
                state.element = state.element.children[0]
                self.get_jsgf_equiv(state)
            else:
                state.expansion = jsgf.AlternativeSet(*get_equiv_children())

        elif isinstance(element, Optional):
            equiv_children = get_equiv_children()
            if len(equiv_children) != 1:
                raise TranslationError("Optional grouping may only have 1 child.")
            state.expansion = jsgf.OptionalGrouping(equiv_children[0])

        return state
    def get_jsgf_equiv(self, state):
        """
        Take a TranslationState object containing a dragonfly element
        return the same object with the 'expansion' member set to the
        equivalent JSGF expansion object.
        :type state: TranslationState
        :return TranslationState
        """
        element = state.element

        def get_equiv_children():
            children = []
            for child in state.element.children:
                state.element = child
                self.get_jsgf_equiv(state)
                children.append(state.expansion)
            return children

        if isinstance(element, Literal):  # Literal == word list
            state.expansion = jsgf.Literal(element.gstring())

        elif isinstance(element, (RuleRef, Rule)):
            # Translate the dragonfly rule reference
            self.translate_rule_ref(state)

        # DictListRef should be checked before ListRef because it is a subclass
        elif isinstance(element, (DictListRef, DictList)):
            self.translate_dict_list_ref(state)

        elif isinstance(element, (ListRef, List)):
            self.translate_list_ref(state)

        elif isinstance(element, Dictation):
            # A Sphinx decoder for handling dictation will be prepared and used
            # when necessary.
            state.expansion = jsgf.ext.Dictation()

        elif isinstance(element, Impossible):
            state.expansion = JSGFImpossible()

        elif element.children == ():  # improbable ElementBase case
            state.expansion = jsgf.Expansion([])

        # Repetition should be checked before Sequence because it is a subclass
        elif isinstance(element, Repetition):
            # Repetition should have at least one child
            assert len(state.element.children) > 0

            if self._has_dictation_descendant(element):
                self.translate_repetition_with_dictation(state)
            elif len(element.children) == 1:
                state.expansion = jsgf.Repeat(*get_equiv_children())
            else:
                state.expansion = jsgf.Sequence(*get_equiv_children())

        elif isinstance(element, Sequence):
            state.expansion = jsgf.Sequence(*get_equiv_children())

        elif isinstance(element, Alternative):
            if len(state.element.children) == 1:
                # Skip redundant (1 child) alternatives
                state.element = state.element.children[0]
                self.get_jsgf_equiv(state)
            else:
                state.expansion = jsgf.AlternativeSet(*get_equiv_children())

        elif isinstance(element, Optional):
            equiv_children = get_equiv_children()
            if len(equiv_children) != 1:
                raise TranslationError(
                    "Optional grouping may only have 1 child.")
            state.expansion = jsgf.OptionalGrouping(equiv_children[0])

        return state