Esempio n. 1
0
    def test_safety(self):
        matcher3 = Delayed()
        matcher4 = Delayed()
        matcher1 = Any()[::'b', ...] & Eos()
        with Separator(Drop(Any('a')[:])):
            matcher2 = Any()[::'b', ...] & Eos()

            # pylint: disable-msg=W0613
            def target(matcher3=matcher3, matcher4=matcher4):
                matcher3 += Any()[::'b', ...] & Eos()
                with Separator(Drop(Any('b')[:])):
                    matcher4 += Any()[::'b', ...] & Eos()

            t = Thread(target=target)
            t.start()
            t.join()
            matcher5 = Any()[::'b', ...] & Eos()
        matcher6 = Any()[::'b', ...] & Eos()
        text = 'cababab'
        assert text == matcher1.parse_string(text)[0], matcher1.parse_string(
            text)
        assert 'cbbb' == matcher2.parse_string(text)[0], matcher2.parse_string(
            text)
        assert text == matcher3.parse_string(text)[0], matcher3.parse_string(
            text)
        assert 'caaa' == matcher4.parse_string(text)[0], matcher4.parse_string(
            text)
        assert 'cbbb' == matcher5.parse_string(text)[0], matcher5.parse_string(
            text)
        assert text == matcher6.parse_string(text)[0], matcher6.parse_string(
            text)
Esempio n. 2
0
 def test_ambiguity(self):
     '''
     A (signed) integer will consume a - sign. 
     '''
     tokens = (Token(Integer()) | Token(r'\-'))[:] & Eos()
     self.examples([(lambda: list(tokens.parse_all('1-2')), 
                     "[['1', '-2']]")])
     matchers = (Integer() | Literal('-'))[:] & Eos()
     self.examples([(lambda: list(matchers.parse_all('1-2')), 
                     "[['1', '-2'], ['1', '-', '2']]")])
Esempio n. 3
0
    def test_error(self):
        #basicConfig(level=INFO)

        class Term(Node):
            pass

        class Factor(Node):
            pass

        class Expression(Node):
            pass

        expression = Delayed()
        number = Digit()[1:, ...] > 'number'
        term = Or(
            AnyBut(Space() | Digit() | '(')[1:, ...]
            ^ 'unexpected text: {results[0]}', number > Term,
            number**make_error("no ( before '{stream_out}'") / ')' >>
            node_throw, '(' / expression / ')' > Term,
            ('(' / expression / Eos())**make_error("no ) for '{stream_in}'") >>
            node_throw)
        muldiv = Any('*/') > 'operator'
        factor = (term / (muldiv / term)[0:, r'\s*']) > Factor
        addsub = Any('+-') > 'operator'
        expression += (factor / (addsub / factor)[0:, r'\s*']) > Expression
        line = expression / Eos()

        parser = line.get_parse_string()

        try:
            parser('1 + 2 * 3 + 4 - 5)')[0]
            assert False, 'expected error'
        except SyntaxError as e:
            assert e.msg == "no ( before ')'", e.msg

        try:
            parser('1 + 2 * (3 + 4 - 5')
            assert False, 'expected error'
        except SyntaxError as e:
            assert e.msg == "no ) for '(3 + 4 - 5'", e.msg

        try:
            parser('1 + 2 * foo')
            assert False, 'expected error'
        except SyntaxError as e:
            assert e.msg == "unexpected text: foo", e.msg
Esempio n. 4
0
    def test_location(self):
        matcher = FullFirstMatch(Any('a')[:] & Eos())
        matcher.config.clear()
        try:
            list(matcher.match_string('aab'))
            assert False, 'expected error'
        except FullFirstMatchException as e:
            assert str(e) == """The match failed at 'b',
Line 1, character 2 of str: 'aab'.""", str(e)
Esempio n. 5
0
    def test_expr_with_functions(self):
        '''
        Expression with function calls and appropriate binding.
        '''
        
        #basicConfig(level=DEBUG)
        
        # pylint: disable-msg=C0111, C0321
        class Call(Node): pass
        class Term(Node): pass
        class Factor(Node): pass
        class Expression(Node): pass
            
        value  = Token(Float())                         > 'value'
        name   = Token('[a-z]+')
        symbol = Token('[^a-zA-Z0-9\\. ]')
        
        expr    = Delayed()
        open_   = ~symbol('(')
        close   = ~symbol(')')
        funcn   = name                                  > 'name'
        call    = funcn & open_ & expr & close          > Call
        term    = call | value | open_ & expr & close   > Term
        muldiv  = symbol(Any('*/'))                     > 'operator'
        factor  = term & (muldiv & term)[:]             > Factor
        addsub  = symbol(Any('+-'))                     > 'operator'
        expr   += factor & (addsub & factor)[:]         > Expression
        line    = expr & Eos()
        
        line.config.trace(True).lexer()
        parser = line.get_parse_string()
        results = str26(parser('1 + 2*sin(3+ 4) - 5')[0])
        assert results == """Expression
 +- Factor
 |   `- Term
 |       `- value '1'
 +- operator '+'
 +- Factor
 |   +- Term
 |   |   `- value '2'
 |   +- operator '*'
 |   `- Term
 |       `- Call
 |           +- name 'sin'
 |           `- Expression
 |               +- Factor
 |               |   `- Term
 |               |       `- value '3'
 |               +- operator '+'
 |               `- Factor
 |                   `- Term
 |                       `- value '4'
 +- operator '-'
 `- Factor
     `- Term
         `- value '5'""", '[' + results + ']'
Esempio n. 6
0
 def _assert_string(self, separator, expecteds, streams=STREAMS_3):
     with separator:
         parser = And(Optional('a') & Optional('b') & 'c', Eos())
     ok = True
     parser.config.no_full_first_match()
     for (stream, expected) in zip(streams, expecteds):
         parsed = parser.parse_string(stream) is not None
         if PRINT:
             print('{0!r:9} : {1!r:5} {2!r:5}'
                   .format(stream, parsed, parsed == expected))
         ok = ok and (parsed == expected)
     assert ok
Esempio n. 7
0
 def test_smart_spaces(self):
     with SmartSeparator1(Space()):
         parser = 'a' & Optional('b') & 'c' & Eos()
     parser.config.no_full_first_match()
     assert parser.parse('a b c')
     assert parser.parse('a c')
     assert not parser.parse('a b c ')
     assert not parser.parse('a c ')
     assert not parser.parse('a bc')
     assert not parser.parse('ab c')
     assert not parser.parse('abc')
     assert not parser.parse('ac')
     assert not parser.parse('a  c')
Esempio n. 8
0
    def test_complex(self):

        #basicConfig(level=DEBUG)

        class VerbPhrase(Node):
            pass

        class DetPhrase(Node):
            pass

        class SimpleTp(Node):
            pass

        class TermPhrase(Node):
            pass

        class Sentence(Node):
            pass

        verb = Literals('knows', 'respects', 'loves') > 'verb'
        join = Literals('and', 'or') > 'join'
        proper_noun = Literals('helen', 'john', 'pat') > 'proper_noun'
        determiner = Literals('every', 'some') > 'determiner'
        noun = Literals('boy', 'girl', 'man', 'woman') > 'noun'

        verbphrase = Delayed()
        verbphrase += verb | (verbphrase // join // verbphrase) > VerbPhrase
        det_phrase = determiner // noun > DetPhrase
        simple_tp = proper_noun | det_phrase > SimpleTp
        termphrase = Delayed()
        termphrase += simple_tp | (termphrase // join //
                                   termphrase) > TermPhrase
        sentence = termphrase // verbphrase // termphrase & Eos() > Sentence

        sentence.config.clear().left_memoize()
        p = sentence.get_match_string()
        print(p.matcher.tree())

        text = 'every boy or some girl and helen and john or pat knows ' \
               'and respects or loves every boy or some girl and pat or ' \
               'john and helen'
        #        text = 'every boy loves helen'
        count = 0
        for _meaning in p(text):
            count += 1
            if count < 3:
                #print(_meaning[0][0])
                pass
        #print(count)
        assert count == 392, count
Esempio n. 9
0
class ExtensionParser(object):
    """
    A class that parses extensions.
    """
    class ExtensionCall(Node):
        """
        An extension call.
        """

        _name = None
        _args = None
        _kwargs = None

        @property
        def name(self):
            return self._name[0] if self._name else None

        @property
        def args(self):
            return tuple(self._args) if self._args else tuple()

        @property
        def kwargs(self):
            return dict(self._kwargs) if self._kwargs else {}

    COMMA = Drop(',')
    NONE = Literal('None') >> (lambda x: None)
    BOOL = (Literal('True') | Literal('False')) >> (lambda x: x == 'True')
    IDENTIFIER = Word(Letter() | '_', Letter() | '_' | Digit())
    FLOAT = Real() >> float
    INTEGER = Integer() >> int
    STRING = String() | String("'")
    ITEM = STRING | INTEGER | FLOAT | NONE | BOOL | IDENTIFIER

    with Separator(~Regexp(r'\s*')):
        VALUE = Delayed()
        LIST = Drop('[') & VALUE[:, COMMA] & Drop(']') > list
        TUPLE = Drop('(') & VALUE[:, COMMA] & Drop(')') > tuple
        VALUE += LIST | TUPLE | ITEM
        ARGUMENT = VALUE >> '_args'
        KWARGUMENT = (IDENTIFIER & Drop('=') & VALUE > tuple) >> '_kwargs'
        ARGUMENTS = (KWARGUMENT | ARGUMENT)[:, COMMA]
        NAME = IDENTIFIER > '_name'
        EXTENSION = ((NAME & Drop('(') & ARGUMENTS & Drop(')'))
                     | NAME) & Eos() > ExtensionCall

    @property
    def parser(self):
        return self.EXTENSION.get_parse_string()
Esempio n. 10
0
def create_parser(delimiter):
    space = Space()
    comma = Drop(',') | Drop(',') + space

    if delimiter == ',':
        # by comma
        seperator = Separator(~Regexp(r'\s*'))

        delimiter = comma
    else:
        assert delimiter == ' ', 'delimiter "%s" not supported' % delimiter
        seperator = DroppedSpace()
        delimiter = space

    none = Literal('None') >> (lambda x: None)
    bool = (Literal('True') | Literal('False')) >> (lambda x: x == 'True')
    ident = Word(Letter() | '_', Letter() | '_' | Digit())
    float_ = Float() >> float
    int_ = Integer() >> int
    str_ = String() | String("'")

    dict_key = str_ | int_ | float_ | Word()
    dict_spaces = ~Whitespace()[:]
    dict_value = dict_key

    item = str_ | int_ | float_ | none | bool | ident | Word()

    with seperator:
        value = Delayed()
        list_ = Drop('[') & value[:, comma] & Drop(']') > list
        tuple_ = Drop('(') & value[:, comma] & Drop(')') > tuple

        dict_el = dict_key & Drop(':') & value > tuple
        dict_ = Drop('{') & dict_el[1:, Drop(',')] & Drop('}') > dict

        value += list_ | tuple_ | dict_ | item | space

        arg = value >> 'arg'
        karg = (ident & Drop('=') & value > tuple) >> 'karg'
        expr = (karg | arg)[:, delimiter] & Drop(Eos()) > Node

    return expr.get_parse()
Esempio n. 11
0
#
# If you wish to allow use of your version of this file only under the
# terms of the LGPL License and not to allow others to use your version
# of this file under the MPL, indicate your decision by deleting the
# provisions above and replace them with the notice and other provisions
# required by the LGPL License.  If you do not delete the provisions
# above, a recipient may use your version of this file under either the
# MPL or the LGPL License.
'''
Performance related tests.
'''

from lepl import Eos
from lepl.apps.rfc3696 import _HttpUrl

http = _HttpUrl() & Eos()

# values are before/after adding IP addresses
# value in pares is char count; other values are timing in secs

# (89041/115471) 1.17/1.20
#http.config.clear()

# (89441/115951) 1.02/1.08
#http.config.clear().direct_eval()

# (3089/7835) 0.48/0.53
#http.config.clear().compile_to_nfa()
# (3089/7835) 0.45/0.51
#http.config.clear().compile_to_dfa()
# (3352/10148) 0.23/0.29
Esempio n. 12
0
 def test_expression2(self):
     '''
     As before, but with evaluation.
     '''
     
     #basicConfig(level=DEBUG)
     
     # we could do evaluation directly in the parser actions. but by
     # using the nodes instead we allow future expansion into a full
     # interpreter
     
     # pylint: disable-msg=C0111, C0321
     class BinaryExpression(Node):
         op = lambda x, y: None
         def __float__(self):
             return self.op(float(self[0]), float(self[1]))
     
     class Sum(BinaryExpression): op = add
     class Difference(BinaryExpression): op = sub
     class Product(BinaryExpression): op = mul
     class Ratio(BinaryExpression): op = truediv
     
     class Call(Node):
         funs = {'sin': sin,
                 'cos': cos}
         def __float__(self):
             return self.funs[self[0]](self[1])
         
     # we use unsigned float then handle negative values explicitly;
     # this lets us handle the ambiguity between subtraction and
     # negation which requires context (not available to the the lexer)
     # to resolve correctly.
     number  = Token(UnsignedFloat())
     name    = Token('[a-z]+')
     symbol  = Token('[^a-zA-Z0-9\\. ]')
     
     expr    = Delayed()
     factor  = Delayed()
     
     float_  = Or(number                            >> float,
                  ~symbol('-') & number             >> (lambda x: -float(x)))
     
     open_   = ~symbol('(')
     close   = ~symbol(')')
     trig    = name(Or('sin', 'cos'))
     call    = trig & open_ & expr & close          > Call
     parens  = open_ & expr & close
     value   = parens | call | float_
     
     ratio   = value & ~symbol('/') & factor        > Ratio
     prod    = value & ~symbol('*') & factor        > Product
     factor += prod | ratio | value
     
     diff    = factor & ~symbol('-') & expr         > Difference
     sum_    = factor & ~symbol('+') & expr         > Sum
     expr   += sum_ | diff | factor | value
     
     line    = expr & Eos()
     parser  = line.get_parse()
     
     def myeval(text):
         return float(parser(text)[0])
     
     self.assertAlmostEqual(myeval('1'), 1)
     self.assertAlmostEqual(myeval('1 + 2*3'), 7)
     self.assertAlmostEqual(myeval('1 - 4 / (3 - 1)'), -1)
     self.assertAlmostEqual(myeval('1 -4 / (3 -1)'), -1)
     self.assertAlmostEqual(myeval('1 + 2*sin(3+ 4) - 5'), -2.68602680256)
Esempio n. 13
0
    def test_calculation(self):
        '''
        We could do evaluation directly in the parser actions. but by
        using the nodes instead we allow future expansion into a full
        interpreter.
        '''

        # pylint: disable-msg=C0111, C0321
        class BinaryExpression(Node):
            op = lambda x, y: None

            def __float__(self):
                return self.op(float(self[0]), float(self[1]))

        class Sum(BinaryExpression):
            op = add

        class Difference(BinaryExpression):
            op = sub

        class Product(BinaryExpression):
            op = mul

        class Ratio(BinaryExpression):
            op = truediv

        class Call(Node):
            funs = {'sin': sin, 'cos': cos}

            def __float__(self):
                return self.funs[self[0]](self[1])

        # we use unsigned float then handle negative values explicitly;
        # this lets us handle the ambiguity between subtraction and
        # negation which requires context (not available to the the lexer)
        # to resolve correctly.
        number = Token(UnsignedReal())
        name = Token('[a-z]+')
        symbol = Token('[^a-zA-Z0-9\\. ]')

        expr = Delayed()
        factor = Delayed()

        real_ = Or(number >> float, ~symbol('-') & number >>
                   (lambda x: -float(x)))

        open_ = ~symbol('(')
        close = ~symbol(')')
        trig = name(Or('sin', 'cos'))
        call = trig & open_ & expr & close > Call
        parens = open_ & expr & close
        value = parens | call | real_

        ratio = value & ~symbol('/') & factor > Ratio
        prod = value & ~symbol('*') & factor > Product
        factor += prod | ratio | value

        diff = factor & ~symbol('-') & expr > Difference
        sum_ = factor & ~symbol('+') & expr > Sum
        expr += sum_ | diff | factor | value

        line = expr & Eos()
        parser = line.get_parse()

        def calculate(text):
            return float(parser(text)[0])

        self.examples([(lambda: calculate('1'), '1.0'),
                       (lambda: calculate('1 + 2*3'), '7.0'),
                       (lambda: calculate('-1 - 4 / (3 - 1)'), '-3.0'),
                       (lambda: calculate('1 -4 / (3 -1)'), '-1.0'),
                       (lambda: str(calculate('1 + 2*sin(3+ 4) - 5'))[:5],
                        '-2.68')])
Esempio n. 14
0
 def target(matcher3=matcher3, matcher4=matcher4):
     matcher3 += Any()[::'b', ...] & Eos()
     with Separator(Drop(Any('b')[:])):
         matcher4 += Any()[::'b', ...] & Eos()