Beispiel #1
0
    def test_left_less_than_right(self):
        l_op = Number(1)
        r_op = NumVar()
        operation = LessEqual(l_op, r_op)

        context = {'num': 2}
        ok_(operation(context))
Beispiel #2
0
    def test_left_greater_than_right(self):
        l_op = Number(3)
        r_op = NumVar()
        operation = LessEqual(l_op, r_op)

        context = {'num': 2}
        assert_false(operation(context))
Beispiel #3
0
 def test_parsing_with_localized_grammars(self):
     castilian_grammar = Grammar(decimal_separator=",",
                                 thousands_separator=".")
     mgr = EvaluableParseManager(self.symbol_table,
                                 Grammar(),
                                 es=castilian_grammar)
     parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3,00",
                            "es")
     expected_tree = EvaluableParseTree(
         LessEqual(PedestriansCrossingRoad(), Number(3.0)))
     eq_(parse_tree, expected_tree)
Beispiel #4
0
 def test_parsing_with_localized_grammars(self):
     castilian_grammar = Grammar(decimal_separator=",",
                                 thousands_separator=".")
     mgr = ConvertibleParseManager(Grammar(), es=castilian_grammar)
     parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3,00",
                            "es")
     expected_tree = ConvertibleParseTree(
         LessEqual(
             PlaceholderVariable("peatones_cruzando_calle", (u"tráfico", )),
             Number(3.0)))
     eq_(parse_tree, expected_tree)
Beispiel #5
0
 def test_adding_grammar(self):
     """It should be possible to add grammars after instantiation."""
     castilian_grammar = Grammar(decimal_separator=",",
                                 thousands_separator=".")
     mgr = EvaluableParseManager(self.symbol_table, Grammar())
     mgr.add_parser("es", castilian_grammar)
     parse_tree = mgr.parse(u'tráfico:peatones_cruzando_calle <= 3,00',
                            "es")
     expected_tree = EvaluableParseTree(
         LessEqual(PedestriansCrossingRoad(), Number(3.0)))
     eq_(parse_tree, expected_tree)
Beispiel #6
0
 def test_parsing_with_defined_grammar_but_no_available_translations(self):
     """
     When an expression is written in an supported grammar but there are no
     translated bindings, the default names must be used along with the
     custom grammar.
     
     """
     french_grammar = Grammar(decimal_separator=",",
                              thousands_separator=".")
     mgr = EvaluableParseManager(self.symbol_table,
                                 Grammar(),
                                 fr=french_grammar)
     # French grammar is not supported:
     parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3,0",
                            "fr")
     expected_tree = EvaluableParseTree(
         LessEqual(PedestriansCrossingRoad(), Number(3)))
     eq_(parse_tree, expected_tree)
Beispiel #7
0
 def test_parsing_with_undefined_grammar_but_available_translations(self):
     """
     When an expression is written in an unsupported grammar, a parser
     based on the generic grammar must be created and used.
     
     The respective translated bindings must be used if available.
     
     """
     log_handler = LoggingHandlerFixture()
     mgr = EvaluableParseManager(self.symbol_table, Grammar())
     # Castilian grammar is not supported:
     parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3.0", "es")
     expected_tree = EvaluableParseTree(
         LessEqual(PedestriansCrossingRoad(), Number(3)))
     eq_(parse_tree, expected_tree)
     # Checking the log:
     info = "Generated parser for unknown grammar 'es'"
     ok_(info in log_handler.handler.messages['info'])
     log_handler.undo()
Beispiel #8
0
 def test_parsing_with_undefined_grammar_and_no_translated_bindings(self):
     """
     When an expression is written in an unsupported grammar, a parser
     based on the generic grammar must be created and used.
     
     If there are no translated bindings, the default names must be used.
     
     """
     log_handler = LoggingHandlerFixture()
     mgr = EvaluableParseManager(self.symbol_table, Grammar())
     # French grammar is not supported:
     parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3.0",
                            "fr")
     expected_tree = EvaluableParseTree(
         LessEqual(PedestriansCrossingRoad(), Number(3)))
     eq_(parse_tree, expected_tree)
     # Checking the log:
     info = "Generated parser for unknown grammar 'fr'"
     ok_(info in log_handler.handler.messages['info'])
     log_handler.undo()
Beispiel #9
0
 def test_identical_values(self):
     l_op = Number(3)
     r_op = Number(3)
     operation = LessEqual(l_op, r_op)
     ok_(operation(None))
Beispiel #10
0
 def convert_less_equal(self, master_operand, slave_operand):
     return LessEqual(master_operand, slave_operand)
Beispiel #11
0
class TestDefaultGrammar(BaseGrammarTest):
    """
    Tests for the parser of the default/generic grammar.
    
    """

    grammar = Grammar()

    expressions = {
        # Literals-only expressions:
        '  "a string" == 245    ':
        Equal(String("a string"), Number(245)),
        '   2 > 5   ':
        GreaterThan(Number(2), Number(5)),
        # Identifiers-only expressions:
        '  today > yesterday ':
        GreaterThan(PlaceholderVariable("today"),
                    PlaceholderVariable("yesterday")),
        'time:today > time:yesterday ':
        GreaterThan(PlaceholderVariable("today", ("time", )),
                    PlaceholderVariable("yesterday", ("time", ))),
        # Literals + non-literal expressions:
        'today > "1999-06-01"':
        GreaterThan(PlaceholderVariable("today"), String("1999-06-01")),
        'get_parents("Gustavo") == {"Liliana", "Carlos"}':
        Equal(PlaceholderFunction("get_parents", None, String("Gustavo")),
              Set(String("Liliana"), String("Carlos"))),
        # Set-specific operations:
        u'"hi" ∈ {"hi", "bye"}':
        BelongsTo(String("hi"), Set(String("hi"), String("bye"))),
        u'salutation ∈ {"hi", "bye"}':
        BelongsTo(PlaceholderVariable("salutation"),
                  Set(String("hi"), String("bye"))),
        u'"good morning" ∈ salutations':
        BelongsTo(String("good morning"), PlaceholderVariable("salutations")),
        u'relatives:sister ∈ relatives:siblings':
        BelongsTo(PlaceholderVariable("sister", ("relatives", )),
                  PlaceholderVariable("siblings", ("relatives", ))),
        u'{"hi", "bye"} ⊂ {"hello", "hi", "bye"}':
        IsSubset(Set(String("hi"), String("bye")),
                 Set(String("hello"), String("hi"), String("bye"))),
        u'salutations ⊂ {"morning", "hi", "bye", "later"}':
        IsSubset(
            PlaceholderVariable("salutations"),
            Set(String("morning"), String("hi"), String("bye"),
                String("later"))),
        u'{"hi", "bye"} ⊂ salutations':
        IsSubset(Set(String("hi"), String("bye")),
                 PlaceholderVariable("salutations")),
        u'relatives:siblings ⊂ relatives:everyone':
        IsSubset(PlaceholderVariable("siblings", ("relatives", )),
                 PlaceholderVariable("everyone", ("relatives", ))),
        # Relational operations:
        'now == today:time':
        Equal(PlaceholderVariable("now"),
              PlaceholderVariable("time", ("today", ))),
        '3.1416 == Pi':
        Equal(Number(3.1416), PlaceholderVariable("pi")),
        'Pi == 3.1416':
        Equal(PlaceholderVariable("pi"), Number(3.1416)),
        'days:today != days:yesterday':
        NotEqual(PlaceholderVariable("today", ("days", )),
                 PlaceholderVariable("yesterday", ("days", ))),
        '3.00 != Pi':
        NotEqual(Number(3.0), PlaceholderVariable("pi")),
        'Pi != 3.00':
        Equal(PlaceholderVariable("pi"), Number(3.00)),
        'days:today > days:yesterday':
        GreaterThan(PlaceholderVariable("today", ("days", )),
                    PlaceholderVariable("yesterday", ("days", ))),
        '3.00 > Pi':
        GreaterThan(Number(3.0), PlaceholderVariable("pi")),
        'Pi > 3.00':
        GreaterThan(PlaceholderVariable("pi"), Number(3.00)),
        'days:today < days:yesterday':
        LessThan(PlaceholderVariable("today", ("days", )),
                 PlaceholderVariable("yesterday", ("days", ))),
        '3.00 < Pi':
        LessThan(Number(3.0), PlaceholderVariable("pi")),
        'Pi < 3.00':
        LessThan(PlaceholderVariable("pi"), Number(3.00)),
        'days:today >= days:yesterday':
        GreaterEqual(PlaceholderVariable("today", ("days", )),
                     PlaceholderVariable("yesterday", ("days", ))),
        '3.00 >= Pi':
        GreaterEqual(Number(3.0), PlaceholderVariable("pi")),
        'Pi >= 3.00':
        GreaterEqual(PlaceholderVariable("pi"), Number(3.00)),
        'days:today <= days:yesterday':
        LessEqual(PlaceholderVariable("today", ("days", )),
                  PlaceholderVariable("yesterday", ("days", ))),
        '3.00 <= Pi':
        LessEqual(Number(3.0), PlaceholderVariable("pi")),
        'Pi <= 3.00':
        LessEqual(PlaceholderVariable("pi"), Number(3.00)),
        # Logical connectives:
        '~today_will_rain()':
        Not(PlaceholderFunction("today_will_rain")),
        '~(today_will_rain())':
        Not(PlaceholderFunction("today_will_rain")),
        '~ today_will_rain()':
        Not(PlaceholderFunction("today_will_rain")),
        '~~today_will_rain()':
        Not(Not(PlaceholderFunction("today_will_rain"))),
        '~ today_is_friday':
        Not(PlaceholderVariable("today_is_friday")),
        '~ time:days:today > "1999-06-01"':
        Not(
            GreaterThan(PlaceholderVariable("today", ("time", "days")),
                        String("1999-06-01"))),
        '~ (time:days:today > "1999-06-01")':
        Not(
            GreaterThan(PlaceholderVariable("today", ("time", "days")),
                        String("1999-06-01"))),
        '~ today_is_friday & today_will_rain':
        And(Not(PlaceholderVariable("today_is_friday")),
            PlaceholderVariable("today_will_rain")),
        '~ today_is_friday & ~ today_will_rain':
        And(Not(PlaceholderVariable("today_is_friday")),
            Not(PlaceholderVariable("today_will_rain"))),
        'today_is_friday & ~ today_will_rain':
        And(PlaceholderVariable("today_is_friday"),
            Not(PlaceholderVariable("today_will_rain"))),
        '~ (today_is_friday & today_will_rain)':
        Not(
            And(PlaceholderVariable("today_is_friday"),
                PlaceholderVariable("today_will_rain"))),
        '~ X > 3 & Z < X':
        And(Not(GreaterThan(PlaceholderVariable("X"), Number(3))),
            LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X"))),
        '~ X > 3 & ~ Z < X':
        And(Not(GreaterThan(PlaceholderVariable("X"), Number(3))),
            Not(LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X")))),
        'X > 3 & ~ Z < X':
        And(GreaterThan(PlaceholderVariable("X"), Number(3)),
            Not(LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X")))),
        '~ (X > 3 & Z < X)':
        Not(
            And(GreaterThan(PlaceholderVariable("X"), Number(3)),
                LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X")))),
        '~ (X > 3 ^ Z < X)':
        Not(
            Xor(GreaterThan(PlaceholderVariable("X"), Number(3)),
                LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X")))),
        '~ (X > 3 | Z < X)':
        Not(
            Or(GreaterThan(PlaceholderVariable("X"), Number(3)),
               LessThan(PlaceholderVariable("Z"), PlaceholderVariable("X")))),
        'today_will_rain() & Pi > 3.0':
        And(PlaceholderFunction("today_will_rain"),
            GreaterThan(PlaceholderVariable("Pi"), Number(3.0))),
        'weather:today_rains & Pi > e & today_is_monday()':
        And(
            PlaceholderVariable("today_rains", ("weather", )),
            And(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        'weather:today_rains & (Pi > e & today_is_monday())':
        And(
            PlaceholderVariable("today_rains", ("weather", )),
            And(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        '(weather:today_rains & Pi > e) & today_is_monday()':
        And(
            And(
                PlaceholderVariable("today_rains", ("weather", )),
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e"))),
            PlaceholderFunction("today_is_monday")),
        'today_will_rain() ^ Pi > 3.0':
        Xor(PlaceholderFunction("today_will_rain"),
            GreaterThan(PlaceholderVariable("Pi"), Number(3.0))),
        'weather:today_rains ^ Pi > e ^ today_is_monday()':
        Xor(
            PlaceholderVariable("today_rains", ("weather", )),
            Xor(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        'weather:today_rains ^ (Pi > e ^ today_is_monday())':
        Xor(
            PlaceholderVariable("today_rains", ("weather", )),
            Xor(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        '(weather:today_rains ^ Pi > e) ^ today_is_monday()':
        Xor(
            Xor(
                PlaceholderVariable("today_rains", ("weather", )),
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e"))),
            PlaceholderFunction("today_is_monday")),
        'today_will_rain() | Pi > 3.0':
        Or(PlaceholderFunction("today_will_rain"),
           GreaterThan(PlaceholderVariable("Pi"), Number(3.0))),
        'weather:today_rains | Pi > e | today_is_monday()':
        Or(
            PlaceholderVariable("today_rains", ("weather", )),
            Or(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        'weather:today_rains | (Pi > e | today_is_monday())':
        Or(
            PlaceholderVariable("today_rains", ("weather", )),
            Or(
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e")),
                PlaceholderFunction("today_is_monday"))),
        '(weather:today_rains | Pi > e) | today_is_monday()':
        Or(
            Or(
                PlaceholderVariable("today_rains", ("weather", )),
                GreaterThan(PlaceholderVariable("Pi"),
                            PlaceholderVariable("e"))),
            PlaceholderFunction("today_is_monday")),
        # Checking operator precedence rules:
        'today == "monday" & yesterday != "sunday" ^ Y > 0':
        Xor(
            And(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        '(today == "monday" & yesterday != "sunday") ^ Y > 0':
        Xor(
            And(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'today == "monday" & (yesterday != "sunday" ^ Y > 0)':
        And(
            Equal(PlaceholderVariable("today"), String("monday")),
            Xor(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" ^ yesterday != "sunday" & Y > 0':
        Xor(
            Equal(PlaceholderVariable("today"), String("monday")),
            And(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" ^ (yesterday != "sunday" & Y > 0)':
        Xor(
            Equal(PlaceholderVariable("today"), String("monday")),
            And(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        '(today == "monday" ^ yesterday != "sunday") & Y > 0':
        And(
            Xor(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'today == "monday" & yesterday != "sunday" | Y > 0':
        Or(
            And(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        '(today == "monday" & yesterday != "sunday") | Y > 0':
        Or(
            And(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'today == "monday" & (yesterday != "sunday" | Y > 0)':
        And(
            Equal(PlaceholderVariable("today"), String("monday")),
            Or(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
               GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" | yesterday != "sunday" & Y > 0':
        Or(
            Equal(PlaceholderVariable("today"), String("monday")),
            And(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" | (yesterday != "sunday" & Y > 0)':
        Or(
            Equal(PlaceholderVariable("today"), String("monday")),
            And(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        '(today == "monday" | yesterday != "sunday") & Y > 0':
        And(
            Or(Equal(PlaceholderVariable("today"), String("monday")),
               NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'today == "monday" ^ yesterday != "sunday" | Y > 0':
        Or(
            Xor(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        '(today == "monday" ^ yesterday != "sunday") | Y > 0':
        Or(
            Xor(Equal(PlaceholderVariable("today"), String("monday")),
                NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'today == "monday" ^ (yesterday != "sunday" | Y > 0)':
        Xor(
            Equal(PlaceholderVariable("today"), String("monday")),
            Or(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
               GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" | yesterday != "sunday" ^ Y > 0':
        Or(
            Equal(PlaceholderVariable("today"), String("monday")),
            Xor(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        'today == "monday" | (yesterday != "sunday" ^ Y > 0)':
        Or(
            Equal(PlaceholderVariable("today"), String("monday")),
            Xor(NotEqual(PlaceholderVariable("yesterday"), String("sunday")),
                GreaterThan(PlaceholderVariable("Y"), Number(0))),
        ),
        '(today == "monday" | yesterday != "sunday") ^ Y > 0':
        Xor(
            Or(Equal(PlaceholderVariable("today"), String("monday")),
               NotEqual(PlaceholderVariable("yesterday"), String("sunday"))),
            GreaterThan(PlaceholderVariable("Y"), Number(0))),
        'W == 0   &   X != 1   ^   Y > 2   |   Z < 3':
        Or(
            Xor(
                And(Equal(PlaceholderVariable("W"), Number(0)),
                    NotEqual(PlaceholderVariable("X"), Number(1))),
                GreaterThan(PlaceholderVariable("Y"), Number(2))),
            LessThan(PlaceholderVariable("Z"), Number(3))),
        'W == 0   |   X != 1   ^   Y > 2   &   Z < 3':
        Or(
            Equal(PlaceholderVariable("W"), Number(0)),
            Xor(
                NotEqual(PlaceholderVariable("X"), Number(1)),
                And(GreaterThan(PlaceholderVariable("Y"), Number(2)),
                    LessThan(PlaceholderVariable("Z"), Number(3))),
            ),
        ),
        'W == 0   |   (X != 1   ^   (Y > 2   &   Z < 3))':
        Or(
            Equal(PlaceholderVariable("W"), Number(0)),
            Xor(
                NotEqual(PlaceholderVariable("X"), Number(1)),
                And(GreaterThan(PlaceholderVariable("Y"), Number(2)),
                    LessThan(PlaceholderVariable("Z"), Number(3))),
            ),
        ),
        '(W == 0   |   X != 1)   ^   (Y > 2   &   Z < 3)':
        Xor(
            Or(Equal(PlaceholderVariable("W"), Number(0)),
               NotEqual(PlaceholderVariable("X"), Number(1))),
            And(GreaterThan(PlaceholderVariable("Y"), Number(2)),
                LessThan(PlaceholderVariable("Z"), Number(3)))),
        '(W == 0   |   X != 1   ^   Y > 2)   &   Z < 3':
        And(
            Or(
                Equal(PlaceholderVariable("W"), Number(0)),
                Xor(
                    NotEqual(PlaceholderVariable("X"), Number(1)),
                    GreaterThan(PlaceholderVariable("Y"), Number(2)),
                )), LessThan(PlaceholderVariable("Z"), Number(3))),
        '((W == 0   |   X != 1)   ^   Y > 2)   &   Z < 3':
        And(
            Xor(
                Or(Equal(PlaceholderVariable("W"), Number(0)),
                   NotEqual(PlaceholderVariable("X"), Number(1))),
                GreaterThan(PlaceholderVariable("Y"), Number(2))),
            LessThan(PlaceholderVariable("Z"), Number(3))),
        '(W == 0   |   (X != 1   ^   Y > 2))   &   Z < 3':
        And(
            Or(
                Equal(PlaceholderVariable("W"), Number(0)),
                Xor(NotEqual(PlaceholderVariable("X"), Number(1)),
                    GreaterThan(PlaceholderVariable("Y"), Number(2)))),
            LessThan(PlaceholderVariable("Z"), Number(3))),
        'W == 0   |   (X != 1   ^   Y > 2   &   Z < 3)':
        Or(
            Equal(PlaceholderVariable("W"), Number(0)),
            Xor(
                NotEqual(PlaceholderVariable("X"), Number(1)),
                And(GreaterThan(PlaceholderVariable("Y"), Number(2)),
                    LessThan(PlaceholderVariable("Z"), Number(3))))),
        'W == 0   |   (X != 1   ^   (Y > 2   &   Z < 3))':
        Or(
            Equal(PlaceholderVariable("W"), Number(0)),
            Xor(
                NotEqual(PlaceholderVariable("X"), Number(1)),
                And(GreaterThan(PlaceholderVariable("Y"), Number(2)),
                    LessThan(PlaceholderVariable("Z"), Number(3))))),
        'W == 0   |   ((X != 1   ^   Y > 2)   &   Z < 3)':
        Or(
            Equal(PlaceholderVariable("W"), Number(0)),
            And(
                Xor(
                    NotEqual(PlaceholderVariable("X"), Number(1)),
                    GreaterThan(PlaceholderVariable("Y"), Number(2)),
                ), LessThan(PlaceholderVariable("Z"), Number(3)))),
        # Let's make sure whitespace doesn't change anything:
        '''
        
        variable == "hi"
        
        ''':
        Equal(PlaceholderVariable("variable"), String("hi")),
        '''
        
        variable 
        == 
        
        "hi"
        
        ''':
        Equal(PlaceholderVariable("variable"), String("hi")),
        '''
        \t variable == "hi"
        &
        \t today_is_thursday()
        ''':
        And(Equal(PlaceholderVariable("variable"), String("hi")),
            PlaceholderFunction("today_is_thursday")),
    }

    badformed_expressions = (
        "",
        " ",
        "\t",
        "\n",
        "\r",
        "== 3 4",
        "3 4 ==",
    )

    single_operands = {
        # ----- Strings
        '"oneword"': String("oneword"),
        '"double quotes"': String("double quotes"),
        "'single quotes'": String("single quotes"),
        "''": String(""),
        '""': String(""),
        "'something with \"quotes\"'": String('something with "quotes"'),
        '"something with \'quotes\'"': String("something with 'quotes'"),
        u'"áéíóúñçÁÉÍÓÚÑÇ"': String(u"áéíóúñçÁÉÍÓÚÑÇ"),
        u'"海納百川,有容乃大"': String(u"海納百川,有容乃大"),
        u"'مقالة مختارة'": String(u"مقالة مختارة"),
        u'"вільної енциклопедії"': String(u"вільної енциклопедії"),
        # ----- Numbers
        '1': Number(1),
        '01': Number(1),
        '5000': Number(5000),
        '+3': Number(3),
        '-3': Number(-3),
        '2.34': Number(2.34),
        '2.2': Number(2.2),
        '+3.1416': Number(3.1416),
        '-3.1416': Number(-3.1416),
        '5,000': Number(5000),
        '1,000,000.34': Number(1000000.34),
        '+1,000,000.22': Number(1000000.22),
        '-1,000,000.22': Number(-1000000.22),
        # ----- Sets:
        ' {} ': Set(),
        '{{}, {}}': Set(Set(), Set()),
        '{1,000, 3.05}': Set(Number(1000), Number(3.05)),
        '{1,234,567}': Set(Number(1234567)),
        '{23,24,25}': Set(Number(23), Number(24), Number(25)),
        '{100, 200, 300}': Set(Number(100), Number(200), Number(300)),
        '{1, 2, {"orange", "apple"}, 3}': Set(
            Number(1),
            Number(2),
            Number(3),
            Set(String("orange"), String("apple"))
            ),
        u'{"españa", {"caracas", {"las chimeneas", "el trigal"}}, "france"}': \
            Set(
                String(u"españa"),
                String("france"),
                Set(
                    String("caracas"),
                    Set(String("el trigal"), String("las chimeneas"))
                ),
            ),
        '{var1, var2}': Set(PlaceholderVariable("var1"),
                            PlaceholderVariable("var2")),
        '{var, "string"}': Set(PlaceholderVariable("var"), String("string")),
        '{3, var, "string"}': Set(Number(3), String("string"),
                                  PlaceholderVariable("var")),
        '{varA, funcB()}': Set(PlaceholderVariable("varA"),
                               PlaceholderFunction("funcB")),
        '{"hi", 3.1416, len({1, 2, 3, 5, 7}), var0}': Set(
            String("hi"),
            Number(3.1416),
            PlaceholderFunction("len", (), Set(
                Number(1), Number(2), Number(3), Number(5), Number(7))),
            PlaceholderVariable("var0")
            ),
        # ----- Variables:
        'today': PlaceholderVariable("today"),
        'camelCase': PlaceholderVariable("camelCase"),
        'with_underscore': PlaceholderVariable("with_underscore"),
        ' v1 ': PlaceholderVariable("v1"),
        'var1_here': PlaceholderVariable("var1_here"),
        u'résumé': PlaceholderVariable(u"résumé"),
        u'有容乃大': PlaceholderVariable(u"有容乃大"),
        '    spaces': PlaceholderVariable("spaces"),
        'spaces    ': PlaceholderVariable("spaces"),
        '  spaces  ': PlaceholderVariable("spaces"),
        '_protected_var': PlaceholderVariable("_protected_var"),
        '__private_var': PlaceholderVariable("__private_var"),
        'one_underscore': PlaceholderVariable("one_underscore"),
        'two__underscores__here': PlaceholderVariable("two__underscores__here"),
        'case_insensitive_var': PlaceholderVariable("CASE_INSENSITIVE_VAR"),
        'CASE_INSENSITIVE_VAR': PlaceholderVariable("case_insensitive_var"),
        'cAsE_iNsEnSiTiVe_VaR': PlaceholderVariable("CaSe_InSeNsItIvE_vAr"),
        u'MAYÚSCULA_minúscula': PlaceholderVariable(u"mayúscula_MINÚSCULA"),
        'ns:variable': PlaceholderVariable("variable", ("ns", )),
        'ns0:ns1:variable': PlaceholderVariable("variable", ("ns0", "ns1")),
        'ns0:ns1:ns2:variable': PlaceholderVariable("variable",
                                                    ("ns0", "ns1", "ns2")),
        'ns:sub_ns:variable': PlaceholderVariable("variable", ("ns", "sub_ns")),
        u'ñŝ0:ñŝ1:variable': PlaceholderVariable("variable", (u"ñŝ0", u"ñŝ1")),
        # ----- Functions:
        'stop()': PlaceholderFunction("stop"),
        'stop ()': PlaceholderFunction("stop"),
        'stop( )': PlaceholderFunction("stop"),
        'stop ( )': PlaceholderFunction("stop"),
        'camelCase()': PlaceholderFunction("camelCase"),
        'with_underscore()': PlaceholderFunction("with_underscore"),
        ' v1() ': PlaceholderFunction("v1"),
        'var1_here()': PlaceholderFunction("var1_here"),
        u'résumé()': PlaceholderFunction(u"résumé"),
        u'有容乃大()': PlaceholderFunction(u"有容乃大"),
        '    spaces()': PlaceholderFunction("spaces"),
        'spaces()    ': PlaceholderFunction("spaces"),
        '  spaces()  ': PlaceholderFunction("spaces"),
        '_protected_function()': PlaceholderFunction("_protected_function"),
        '__private_function()': PlaceholderFunction("__private_function"),
        'one_underscore()': PlaceholderFunction("one_underscore"),
        'two__underscores__()': PlaceholderFunction("two__underscores__"),
        'case_insensitive_func()': PlaceholderFunction("CASE_INSENSITIVE_FUNC"),
        'CASE_INSENSITIVE_FUNC()': PlaceholderFunction("case_insensitive_func"),
        'cAsE_iNsEnSiTiVe_FuNc()': PlaceholderFunction("CaSe_InSeNsItIvE_fUnC"),
        u'MAYÚSCULA_minúscula()': PlaceholderFunction(u"mayúscula_MINÚSCULA"),
        'func("argument")': PlaceholderFunction("func", (), String("argument")),
        'function("arg1", variable, 3)': PlaceholderFunction("function",
            (),
            String("arg1"),
            PlaceholderVariable("variable"),
            Number(3),
            ),
        'function("arg1", ns:variable, 3)': PlaceholderFunction(
            "function",
            (),
            String("arg1"),
            PlaceholderVariable("variable", ("ns", )),
            Number(3),
            ),
        'ns:function("arg1", ns:variable, 3)': PlaceholderFunction(
            "function",
            ("ns", ),
            String("arg1"),
            PlaceholderVariable("variable", ("ns", )),
            Number(3),
            ),
        'function("arg1", ns:sub_function(), 3.0)': PlaceholderFunction(
            "function",
            (),
            String("arg1"),
            PlaceholderFunction("sub_function", ("ns", )),
            Number(3),
            ),
        'ns:function("arg1", ns:sub_function(), 3.0)': PlaceholderFunction(
            "function",
            ("ns", ),
            String("arg1"),
            PlaceholderFunction("sub_function", ("ns", )),
            Number(3),
            ),
        'ns:function()': PlaceholderFunction("function", ("ns", )),
        'ns0:ns1:function()': PlaceholderFunction("function", ("ns0", "ns1")),
        'ns0:ns1:ns2:function()': PlaceholderFunction("function",
                                                      ("ns0", "ns1", "ns2")),
        'ns:sub_ns:function("with argument")': PlaceholderFunction("function",
            ("ns", "sub_ns"),
            String("with argument"),
            ),
        u'ñŝ:ñś1:function()': PlaceholderFunction("function", (u"ñŝ", u"ñś1")),
        u'ñŝ:ñś1:función()': PlaceholderFunction(u"función", (u"ñŝ", u"ñś1")),
    }

    invalid_operands = (
        # Invalid strings:
        '\'mixed quotes"',
        # Invalid numbers:
        "3 . 1416",
        "3. 1416",
        "3 .1416",
        "1,00",
        "12.4,500,000",
        # Invalid variables:
        "dashes-here-cant-you-see-them",
        "1st_variable",
        "25th_variable",
        "namespace-here:variable",
        "1stnamespace:var",
        "global:2ndlevel:var",
        "namespace:1st_variable",
        # Invalid functions:
        "func(",
        "func)",
        "func)(",
        "func[]",
        "func{}",
        "func(,)",
        "func(arg1, )",
        "func(, arg2)",
        "func(, arg2, )",
        "function-name()",
        "1st_function()",
        "25th_function()",
        "namespace-here:function()",
        "1stnamespace:function()",
        "global:2ndlevel:function()",
        "namespace:1st_function()",
        "foo( bad-namespace:baz() )",
        # Invalid sets:
        "[]",
        "{]",
        "[}",
        "}{",
        "{key: 'value'}",
        "[element1, element2, element3]",
        "{element 1, element 2}",
        "{element1; element2; element3}",
        "{element == 'string'}",
        # Default operators:
        "==",
        "!=",
        "<",
        ">",
        "<=",
        ">=",
        "~",
        "&",
        "^",
        "|",
        u"∈",
        u"⊂",
        # Miscellaneous:
        "-",
        "this is definitely not an operand",
    )

    def test_custom_tokens_against_trees(self):
        """
        All the custom tokens in the grammar must be taken into account by the
        parser.
        
        To test that custom tokens are used, and in order to test many scenarios
        writen few lines of code, we're going to convert operation nodes into
        boolean expressions (using the relevant grammar), and then these
        expressions will be parsed to check if the result is the original
        tree.
        
        """

        grammars = (
            # A grammar that overrides all the default tokens:
            Grammar(
                **{
                    'not': "not",
                    'and': "and",
                    'xor': "xor",
                    'or': "or",
                    'eq': "equals",
                    'ne': "different-from",
                    'lt': "less-than",
                    'le': "less-equal",
                    'gt': "greater-than",
                    'ge': "greater-equal",
                    'belongs_to': "belongs-to",
                    'is_subset': "is-subset-of",
                    'set_start': "\\",
                    'set_end': "/",
                    'element_separator': ";",
                    'arguments_start': "[",
                    'arguments_end': "]",
                    'arguments_separator': ";",
                    'namespace_separator': ".",
                }),
            # Now let's try a grammar where some operators represent the
            # initial characters of other operators:
            Grammar(
                **{
                    'eq': "is",
                    'ne': "isn't",
                    'lt': "is less than",
                    'gt': "is greater than",
                    'le': "is less than or equal to",
                    'ge': "is greater than or equal to",
                    'belongs_to': "is included in",
                    'is_subset': "is subset of",
                }))

        for grammar_num in range(len(grammars)):
            grammar = grammars[grammar_num]
            parser = ConvertibleParser(grammar)
            convert_to_string = StringConverter(grammar)

            for operation in self.expressions.values():
                expression = convert_to_string(operation)

                # Using a Nose test generator:
                def check():
                    new_operation = parser(expression).root_node
                    eq_(
                        operation, new_operation,
                        u'Original operation: %s --- Returned operation: %s' %
                        (repr(operation), repr(new_operation)))

                check.description = (u"The following expression is valid in "
                                     u"the grammar #%s: %s" %
                                     (grammar_num, expression))

                yield check