Beispiel #1
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
Beispiel #2
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
Beispiel #3
0
array_type = Or(*generate_type_tokens(symboltable.array_types))
array_element_type = Or(*generate_type_tokens(symboltable.array_element_types))

type_ = scalar_type | array_type | array_element_type

real = Token(UnsignedReal()) >> Real
integer = Token(UnsignedInteger()) >> Integer
number = integer | real
boolean = keyword("yes") >> Bool | keyword("no") >> Bool | keyword("true") >> Bool | keyword("false") >> Bool

width = integer
height = integer
depth = integer

unopened_size_block = (width & Optional(~comma & height & Optional(~comma & depth)) & symbol("]")) ** make_error(
    "no [ before {out_rest!s}"
) & symbol("]")
unclosed_size_block = (symbol("[") & width & Optional(~comma & height & Optional(~comma & depth))) ** make_error(
    "Array size specification is missing a closing ]"
)

size = Or(
    (~symbol("[") & width & Optional(~comma & height & Optional(~comma & depth)) & ~symbol("]")) ** with_line(Size),
    unopened_size_block,
    unclosed_size_block,
)

#### Expression Parsing ####
# Operator precedence, inside to outside
#  1 parentheses ()
#  2 not, unary minus (!, -)
Beispiel #4
0
def missing(label):
    """Provides feedback when a matcher fails.

    This function is commonly applied using the :class:`First`
    operator (short-hand: ``\%``).

    We'll consider the following example phrase:

    >>> example_phrase
    ['John' (W), 'Smith' (W), ',' (D), 16 (I), 'M' (W)]

    The following matcher illustrates the usage:

    >>> matcher = Word[1:] & lepl.Optional(
    ...     Delimiter & (Number & Word) % missing('age and sex'))

    Omitting the last token from our example phrase, we get the
    following feedback:

    >>> parse(matcher, example_phrase[:-1])[0]
    u'age and sex'

    To improve feedback, we can provide help for each case
    individually:

    >>> matcher = Word[1:] % missing('name') & lepl.Optional(
    ...     Delimiter & Number % missing('age') & Word % missing('sex'))

    The ``\%`` operator binds more strongly and parentheses are
    unnecessary for the most part.

    >>> parse(matcher, example_phrase[:-2])[0]
    u'age'
    >>> parse(matcher, example_phrase[:-1])[0]
    u'sex'

    Note that the full phrase still returns a match:

    >>> parse(matcher, example_phrase)
    ['John' (W), 'Smith' (W), 16 (I), 'M' (W)]

    So far we've dealt with missing input only; the function also
    guards against incorrect input:

    >>> phrase = example_phrase[:-2] + example_phrase[:1]
    >>> parse(matcher, phrase)[0]
    u'age'

    Finally, the function operates within a more complex environment
    of multiple paths.

    >>> matcher = Word[1:] % missing('name') & \\
    ...     lepl.Optional(
    ...         Delimiter & Number % missing('age') & Word % missing('sex')) & \\
    ...     lepl.Optional(
    ...         Delimiter & Number % missing('age'))

    >>> parse(matcher, example_phrase[:-2])[0]
    u'age'

    Omitting only the last token, this particular matcher chooses the
    path through the second optional clause and succeeds:

    >>> parse(matcher, example_phrase[:-1])
    ['John' (W), 'Smith' (W), 16 (I)]
    """

    return lepl.Any()[:] ** lepl.make_error(label)
Beispiel #5
0
type_ = scalar_type | array_type | array_element_type

real = Token(UnsignedReal()) >> Real
integer = Token(UnsignedInteger()) >> Integer
number = integer | real
boolean = keyword('yes') >> Bool | keyword('no') >> Bool | keyword(
    'true') >> Bool | keyword('false') >> Bool

width = integer
height = integer
depth = integer

unopened_size_block = (
    width & Optional(~comma & height & Optional(~comma & depth))
    & symbol(']'))**make_error('no [ before {out_rest!s}') & symbol(']')
unclosed_size_block = (
    symbol('[') & width & Optional(~comma & height & Optional(~comma & depth))
)**make_error('Array size specification is missing a closing ]')

size = Or((~symbol('[') & width
           & Optional(~comma & height
                      & Optional(~comma & depth))
           & ~symbol(']'))**with_line(Size), unopened_size_block,
          unclosed_size_block)

#### Expression Parsing ####
# Operator precedence, inside to outside
#  1 parentheses ()
#  2 not, unary minus (!, -)
#  3 multiplication, division (*, /, %)