Error when passing class to Pyparsing setParseAction() class for “if/else” structure











up vote
1
down vote

favorite












I'm trying to use pyparsing to create a very simple langage for a maze bot solver in python.



Because pyparsing seems powerfull but not easy to manipulate, i'm starting by a simple exemple with assignment and if [expression] then [code] elsif [expression] then [code] else [code] structure



simple_example_assignement = '''
SET x 3 + 2
SET y 2
'''

simple_example_condition = '''
IF x NOT MATCH 3 THEN { SET b 2 }
ELSIF y NOT MATCH 2 THEN {SET d 4}
ELSE { SET c 3}
'''


The code for evaluation of arithmetic expression during assignment



# store variable value for evaluation
vars = {}

class EvalAddOp():
"""Class to evaluate addition and subtraction expressions."""

def __init__(self, tokens):

self.value = tokens[0]

print(self.value)

def eval(self, vars_):

if type(self.value[0]) in [EvalAddOp]:
print("ENTER EVAL ADD OPP")
sum = self.value[0].eval(vars_)
else:
sum = self.checkNum(self.value[0], vars_)

return self.ops(sum, vars_)

def checkNum(self, val, _vars):
print(type(val), " = ", val)
if type(val) in [int, float]:
return val
elif type(val) in [EvalAddOp]:
return val.eval(_vars)
else:
return _vars[val]

def ops(self, sum, vars_):
for op, val in operatorOperands(self.value[1:]):
if op == '+':
sum += self.checkNum(val, vars_)
if op == '-':
sum -= self.checkNum(val, vars_)
return sum

def eval_expression(expr):
if isinstance(expr, str):
if expr[0] in '"'': # string literal
return expr[1:-1] # remove quotes
else:
return vars.get(expr)
elif isinstance(expr, EvalAddOp):
return expr.eval(vars)

return expr
integer = Word(nums).setParseAction(lambda t: int(t[0]))
variable = Word(alphas, exact=1)
operand = integer | variable
plusop = oneOf('+ -')
signop = oneOf('+ -')
multop = oneOf('* /')
matching = Keyword('MATCH')

arithmeticExpression = infixNotation(operand,
[(signop, 1, opAssoc.RIGHT),
(multop, 2, opAssoc.LEFT),
(plusop, 2, opAssoc.LEFT, EvalAddOp), ]
)


The code to determine parsing of assignement and condition statement :



expression = Forward()
exprOperators = Forward()
code_block = Forward()

literal = quotedString ^ pyparsing_common.number

commonExpression = literal ^ variable ^ arithmeticExpression
matchingExpression = Group(commonExpression + exprOperators + commonExpression)

expression << matchingExpression ^ commonExpression

exprOperators << infixNotation(matching,[("NOT", 1, opAssoc.RIGHT)])

# Assignment rules
set_assignment = Group(Keyword('SET') + variable + commonExpression)

# If/Else rules
simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)

# all possible statements in the example prorgam
stmt = set_assignment ^ simple_if_group

# Code to evaluate
code_block << Group(Literal('{').suppress() + OneOrMore(stmt) + Literal('}').suppress()).setName('code block')

program = Dict(OneOrMore(stmt))


I try to attach an Action using setParseAction on simple_if_group variable, calling the class IfEval. Majority of example attach a function as Action, but in the case of a If/Else structure, i'm supposing that a more structured class is better to evaluate condition later... I'm not sure this is the good way, so i take any advice



class IFEval():

def __init__(self):
self.ifStructure = {}

def __len__(self):
return len(self.ifStructure)

def __getitem__(self, item):
return self.ifStructure["item"]

def __setitem__(self, key, value):
self.ifStructure[key] = value

def __delitem__(self, key):
pass

def __copy__(self):
return self.ifStructure[:]

@traceParseAction
def IfEval(s, l, tokens):

if_stmt = IFEval()
if Keyword("IF").parseString(tokens[0][1]):
if_stmt["then_codeblock"] = tokens[0][3]

if Keyword("ELSIF").parseString(tokens[0][4]):
if_stmt["elsif_codeblock"] = tokens[0][6]

if Keyword("ELSE").parseString(tokens[0][8]):
if_stmt["else_codeblock"] = tokens[0][9]

return if_stmt


Assignments using SET works without problem :



parsed = program.parseString(simple_example_assignement)

for _, name, value in parsed:
vars[name] = eval_expression(value)
print(vars)

[3, '+', 2]
<class 'int'> = 3
<class 'int'> = 2
{'y': 2, 'x': 5}


Now, even before evaluation, i'm trying to parse the second exemple which call the setParseAction method to IFEval class :



parsed = program.parseString()


return an str() error ? probably because i don't understand how the parseAction function when you try to use a class and not a method :



>>entering IfEval(line: 'IF x NOT MATCH 3 THEN { SET b 2 } ', 21, ([(['IF', (['x', (['NOT', 'MATCH'], {}), 3], {}), 'THEN', ([(['SET', 'b', 2], {})], {}), 'ELSIF', (['y', (['NOT', 'MATCH'], {}), 2], {}), 'THEN', ([(['SET', 'd', 4], {})], {}), 'ELSE', ([(['SET', 'c', 3], {})], {})], {})], {}))
<<leaving IfEval (exception: 'str' object is not callable)
Traceback (most recent call last):
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 246, in <module>
parsed = program.parseString(conditional_test)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1666, in parseString
loc, tokens = self._parse( instring, 0 )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3805, in parseImpl
return self.expr._parse( instring, loc, doActions, callPreParse=False )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4033, in parseImpl
loc, tmptokens = self_expr_parse( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3555, in parseImpl
return e._parse( instring, loc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1445, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4588, in z
ret = f(*paArgs)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable









share|improve this question






















  • Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
    – PaulMcG
    Nov 8 at 14:14















up vote
1
down vote

favorite












I'm trying to use pyparsing to create a very simple langage for a maze bot solver in python.



Because pyparsing seems powerfull but not easy to manipulate, i'm starting by a simple exemple with assignment and if [expression] then [code] elsif [expression] then [code] else [code] structure



simple_example_assignement = '''
SET x 3 + 2
SET y 2
'''

simple_example_condition = '''
IF x NOT MATCH 3 THEN { SET b 2 }
ELSIF y NOT MATCH 2 THEN {SET d 4}
ELSE { SET c 3}
'''


The code for evaluation of arithmetic expression during assignment



# store variable value for evaluation
vars = {}

class EvalAddOp():
"""Class to evaluate addition and subtraction expressions."""

def __init__(self, tokens):

self.value = tokens[0]

print(self.value)

def eval(self, vars_):

if type(self.value[0]) in [EvalAddOp]:
print("ENTER EVAL ADD OPP")
sum = self.value[0].eval(vars_)
else:
sum = self.checkNum(self.value[0], vars_)

return self.ops(sum, vars_)

def checkNum(self, val, _vars):
print(type(val), " = ", val)
if type(val) in [int, float]:
return val
elif type(val) in [EvalAddOp]:
return val.eval(_vars)
else:
return _vars[val]

def ops(self, sum, vars_):
for op, val in operatorOperands(self.value[1:]):
if op == '+':
sum += self.checkNum(val, vars_)
if op == '-':
sum -= self.checkNum(val, vars_)
return sum

def eval_expression(expr):
if isinstance(expr, str):
if expr[0] in '"'': # string literal
return expr[1:-1] # remove quotes
else:
return vars.get(expr)
elif isinstance(expr, EvalAddOp):
return expr.eval(vars)

return expr
integer = Word(nums).setParseAction(lambda t: int(t[0]))
variable = Word(alphas, exact=1)
operand = integer | variable
plusop = oneOf('+ -')
signop = oneOf('+ -')
multop = oneOf('* /')
matching = Keyword('MATCH')

arithmeticExpression = infixNotation(operand,
[(signop, 1, opAssoc.RIGHT),
(multop, 2, opAssoc.LEFT),
(plusop, 2, opAssoc.LEFT, EvalAddOp), ]
)


The code to determine parsing of assignement and condition statement :



expression = Forward()
exprOperators = Forward()
code_block = Forward()

literal = quotedString ^ pyparsing_common.number

commonExpression = literal ^ variable ^ arithmeticExpression
matchingExpression = Group(commonExpression + exprOperators + commonExpression)

expression << matchingExpression ^ commonExpression

exprOperators << infixNotation(matching,[("NOT", 1, opAssoc.RIGHT)])

# Assignment rules
set_assignment = Group(Keyword('SET') + variable + commonExpression)

# If/Else rules
simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)

# all possible statements in the example prorgam
stmt = set_assignment ^ simple_if_group

# Code to evaluate
code_block << Group(Literal('{').suppress() + OneOrMore(stmt) + Literal('}').suppress()).setName('code block')

program = Dict(OneOrMore(stmt))


I try to attach an Action using setParseAction on simple_if_group variable, calling the class IfEval. Majority of example attach a function as Action, but in the case of a If/Else structure, i'm supposing that a more structured class is better to evaluate condition later... I'm not sure this is the good way, so i take any advice



class IFEval():

def __init__(self):
self.ifStructure = {}

def __len__(self):
return len(self.ifStructure)

def __getitem__(self, item):
return self.ifStructure["item"]

def __setitem__(self, key, value):
self.ifStructure[key] = value

def __delitem__(self, key):
pass

def __copy__(self):
return self.ifStructure[:]

@traceParseAction
def IfEval(s, l, tokens):

if_stmt = IFEval()
if Keyword("IF").parseString(tokens[0][1]):
if_stmt["then_codeblock"] = tokens[0][3]

if Keyword("ELSIF").parseString(tokens[0][4]):
if_stmt["elsif_codeblock"] = tokens[0][6]

if Keyword("ELSE").parseString(tokens[0][8]):
if_stmt["else_codeblock"] = tokens[0][9]

return if_stmt


Assignments using SET works without problem :



parsed = program.parseString(simple_example_assignement)

for _, name, value in parsed:
vars[name] = eval_expression(value)
print(vars)

[3, '+', 2]
<class 'int'> = 3
<class 'int'> = 2
{'y': 2, 'x': 5}


Now, even before evaluation, i'm trying to parse the second exemple which call the setParseAction method to IFEval class :



parsed = program.parseString()


return an str() error ? probably because i don't understand how the parseAction function when you try to use a class and not a method :



>>entering IfEval(line: 'IF x NOT MATCH 3 THEN { SET b 2 } ', 21, ([(['IF', (['x', (['NOT', 'MATCH'], {}), 3], {}), 'THEN', ([(['SET', 'b', 2], {})], {}), 'ELSIF', (['y', (['NOT', 'MATCH'], {}), 2], {}), 'THEN', ([(['SET', 'd', 4], {})], {}), 'ELSE', ([(['SET', 'c', 3], {})], {})], {})], {}))
<<leaving IfEval (exception: 'str' object is not callable)
Traceback (most recent call last):
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 246, in <module>
parsed = program.parseString(conditional_test)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1666, in parseString
loc, tokens = self._parse( instring, 0 )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3805, in parseImpl
return self.expr._parse( instring, loc, doActions, callPreParse=False )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4033, in parseImpl
loc, tmptokens = self_expr_parse( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3555, in parseImpl
return e._parse( instring, loc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1445, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4588, in z
ret = f(*paArgs)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable









share|improve this question






















  • Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
    – PaulMcG
    Nov 8 at 14:14













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm trying to use pyparsing to create a very simple langage for a maze bot solver in python.



Because pyparsing seems powerfull but not easy to manipulate, i'm starting by a simple exemple with assignment and if [expression] then [code] elsif [expression] then [code] else [code] structure



simple_example_assignement = '''
SET x 3 + 2
SET y 2
'''

simple_example_condition = '''
IF x NOT MATCH 3 THEN { SET b 2 }
ELSIF y NOT MATCH 2 THEN {SET d 4}
ELSE { SET c 3}
'''


The code for evaluation of arithmetic expression during assignment



# store variable value for evaluation
vars = {}

class EvalAddOp():
"""Class to evaluate addition and subtraction expressions."""

def __init__(self, tokens):

self.value = tokens[0]

print(self.value)

def eval(self, vars_):

if type(self.value[0]) in [EvalAddOp]:
print("ENTER EVAL ADD OPP")
sum = self.value[0].eval(vars_)
else:
sum = self.checkNum(self.value[0], vars_)

return self.ops(sum, vars_)

def checkNum(self, val, _vars):
print(type(val), " = ", val)
if type(val) in [int, float]:
return val
elif type(val) in [EvalAddOp]:
return val.eval(_vars)
else:
return _vars[val]

def ops(self, sum, vars_):
for op, val in operatorOperands(self.value[1:]):
if op == '+':
sum += self.checkNum(val, vars_)
if op == '-':
sum -= self.checkNum(val, vars_)
return sum

def eval_expression(expr):
if isinstance(expr, str):
if expr[0] in '"'': # string literal
return expr[1:-1] # remove quotes
else:
return vars.get(expr)
elif isinstance(expr, EvalAddOp):
return expr.eval(vars)

return expr
integer = Word(nums).setParseAction(lambda t: int(t[0]))
variable = Word(alphas, exact=1)
operand = integer | variable
plusop = oneOf('+ -')
signop = oneOf('+ -')
multop = oneOf('* /')
matching = Keyword('MATCH')

arithmeticExpression = infixNotation(operand,
[(signop, 1, opAssoc.RIGHT),
(multop, 2, opAssoc.LEFT),
(plusop, 2, opAssoc.LEFT, EvalAddOp), ]
)


The code to determine parsing of assignement and condition statement :



expression = Forward()
exprOperators = Forward()
code_block = Forward()

literal = quotedString ^ pyparsing_common.number

commonExpression = literal ^ variable ^ arithmeticExpression
matchingExpression = Group(commonExpression + exprOperators + commonExpression)

expression << matchingExpression ^ commonExpression

exprOperators << infixNotation(matching,[("NOT", 1, opAssoc.RIGHT)])

# Assignment rules
set_assignment = Group(Keyword('SET') + variable + commonExpression)

# If/Else rules
simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)

# all possible statements in the example prorgam
stmt = set_assignment ^ simple_if_group

# Code to evaluate
code_block << Group(Literal('{').suppress() + OneOrMore(stmt) + Literal('}').suppress()).setName('code block')

program = Dict(OneOrMore(stmt))


I try to attach an Action using setParseAction on simple_if_group variable, calling the class IfEval. Majority of example attach a function as Action, but in the case of a If/Else structure, i'm supposing that a more structured class is better to evaluate condition later... I'm not sure this is the good way, so i take any advice



class IFEval():

def __init__(self):
self.ifStructure = {}

def __len__(self):
return len(self.ifStructure)

def __getitem__(self, item):
return self.ifStructure["item"]

def __setitem__(self, key, value):
self.ifStructure[key] = value

def __delitem__(self, key):
pass

def __copy__(self):
return self.ifStructure[:]

@traceParseAction
def IfEval(s, l, tokens):

if_stmt = IFEval()
if Keyword("IF").parseString(tokens[0][1]):
if_stmt["then_codeblock"] = tokens[0][3]

if Keyword("ELSIF").parseString(tokens[0][4]):
if_stmt["elsif_codeblock"] = tokens[0][6]

if Keyword("ELSE").parseString(tokens[0][8]):
if_stmt["else_codeblock"] = tokens[0][9]

return if_stmt


Assignments using SET works without problem :



parsed = program.parseString(simple_example_assignement)

for _, name, value in parsed:
vars[name] = eval_expression(value)
print(vars)

[3, '+', 2]
<class 'int'> = 3
<class 'int'> = 2
{'y': 2, 'x': 5}


Now, even before evaluation, i'm trying to parse the second exemple which call the setParseAction method to IFEval class :



parsed = program.parseString()


return an str() error ? probably because i don't understand how the parseAction function when you try to use a class and not a method :



>>entering IfEval(line: 'IF x NOT MATCH 3 THEN { SET b 2 } ', 21, ([(['IF', (['x', (['NOT', 'MATCH'], {}), 3], {}), 'THEN', ([(['SET', 'b', 2], {})], {}), 'ELSIF', (['y', (['NOT', 'MATCH'], {}), 2], {}), 'THEN', ([(['SET', 'd', 4], {})], {}), 'ELSE', ([(['SET', 'c', 3], {})], {})], {})], {}))
<<leaving IfEval (exception: 'str' object is not callable)
Traceback (most recent call last):
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 246, in <module>
parsed = program.parseString(conditional_test)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1666, in parseString
loc, tokens = self._parse( instring, 0 )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3805, in parseImpl
return self.expr._parse( instring, loc, doActions, callPreParse=False )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4033, in parseImpl
loc, tmptokens = self_expr_parse( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3555, in parseImpl
return e._parse( instring, loc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1445, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4588, in z
ret = f(*paArgs)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable









share|improve this question













I'm trying to use pyparsing to create a very simple langage for a maze bot solver in python.



Because pyparsing seems powerfull but not easy to manipulate, i'm starting by a simple exemple with assignment and if [expression] then [code] elsif [expression] then [code] else [code] structure



simple_example_assignement = '''
SET x 3 + 2
SET y 2
'''

simple_example_condition = '''
IF x NOT MATCH 3 THEN { SET b 2 }
ELSIF y NOT MATCH 2 THEN {SET d 4}
ELSE { SET c 3}
'''


The code for evaluation of arithmetic expression during assignment



# store variable value for evaluation
vars = {}

class EvalAddOp():
"""Class to evaluate addition and subtraction expressions."""

def __init__(self, tokens):

self.value = tokens[0]

print(self.value)

def eval(self, vars_):

if type(self.value[0]) in [EvalAddOp]:
print("ENTER EVAL ADD OPP")
sum = self.value[0].eval(vars_)
else:
sum = self.checkNum(self.value[0], vars_)

return self.ops(sum, vars_)

def checkNum(self, val, _vars):
print(type(val), " = ", val)
if type(val) in [int, float]:
return val
elif type(val) in [EvalAddOp]:
return val.eval(_vars)
else:
return _vars[val]

def ops(self, sum, vars_):
for op, val in operatorOperands(self.value[1:]):
if op == '+':
sum += self.checkNum(val, vars_)
if op == '-':
sum -= self.checkNum(val, vars_)
return sum

def eval_expression(expr):
if isinstance(expr, str):
if expr[0] in '"'': # string literal
return expr[1:-1] # remove quotes
else:
return vars.get(expr)
elif isinstance(expr, EvalAddOp):
return expr.eval(vars)

return expr
integer = Word(nums).setParseAction(lambda t: int(t[0]))
variable = Word(alphas, exact=1)
operand = integer | variable
plusop = oneOf('+ -')
signop = oneOf('+ -')
multop = oneOf('* /')
matching = Keyword('MATCH')

arithmeticExpression = infixNotation(operand,
[(signop, 1, opAssoc.RIGHT),
(multop, 2, opAssoc.LEFT),
(plusop, 2, opAssoc.LEFT, EvalAddOp), ]
)


The code to determine parsing of assignement and condition statement :



expression = Forward()
exprOperators = Forward()
code_block = Forward()

literal = quotedString ^ pyparsing_common.number

commonExpression = literal ^ variable ^ arithmeticExpression
matchingExpression = Group(commonExpression + exprOperators + commonExpression)

expression << matchingExpression ^ commonExpression

exprOperators << infixNotation(matching,[("NOT", 1, opAssoc.RIGHT)])

# Assignment rules
set_assignment = Group(Keyword('SET') + variable + commonExpression)

# If/Else rules
simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)

# all possible statements in the example prorgam
stmt = set_assignment ^ simple_if_group

# Code to evaluate
code_block << Group(Literal('{').suppress() + OneOrMore(stmt) + Literal('}').suppress()).setName('code block')

program = Dict(OneOrMore(stmt))


I try to attach an Action using setParseAction on simple_if_group variable, calling the class IfEval. Majority of example attach a function as Action, but in the case of a If/Else structure, i'm supposing that a more structured class is better to evaluate condition later... I'm not sure this is the good way, so i take any advice



class IFEval():

def __init__(self):
self.ifStructure = {}

def __len__(self):
return len(self.ifStructure)

def __getitem__(self, item):
return self.ifStructure["item"]

def __setitem__(self, key, value):
self.ifStructure[key] = value

def __delitem__(self, key):
pass

def __copy__(self):
return self.ifStructure[:]

@traceParseAction
def IfEval(s, l, tokens):

if_stmt = IFEval()
if Keyword("IF").parseString(tokens[0][1]):
if_stmt["then_codeblock"] = tokens[0][3]

if Keyword("ELSIF").parseString(tokens[0][4]):
if_stmt["elsif_codeblock"] = tokens[0][6]

if Keyword("ELSE").parseString(tokens[0][8]):
if_stmt["else_codeblock"] = tokens[0][9]

return if_stmt


Assignments using SET works without problem :



parsed = program.parseString(simple_example_assignement)

for _, name, value in parsed:
vars[name] = eval_expression(value)
print(vars)

[3, '+', 2]
<class 'int'> = 3
<class 'int'> = 2
{'y': 2, 'x': 5}


Now, even before evaluation, i'm trying to parse the second exemple which call the setParseAction method to IFEval class :



parsed = program.parseString()


return an str() error ? probably because i don't understand how the parseAction function when you try to use a class and not a method :



>>entering IfEval(line: 'IF x NOT MATCH 3 THEN { SET b 2 } ', 21, ([(['IF', (['x', (['NOT', 'MATCH'], {}), 3], {}), 'THEN', ([(['SET', 'b', 2], {})], {}), 'ELSIF', (['y', (['NOT', 'MATCH'], {}), 2], {}), 'THEN', ([(['SET', 'd', 4], {})], {}), 'ELSE', ([(['SET', 'c', 3], {})], {})], {})], {}))
<<leaving IfEval (exception: 'str' object is not callable)
Traceback (most recent call last):
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 246, in <module>
parsed = program.parseString(conditional_test)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1666, in parseString
loc, tokens = self._parse( instring, 0 )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3805, in parseImpl
return self.expr._parse( instring, loc, doActions, callPreParse=False )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4033, in parseImpl
loc, tmptokens = self_expr_parse( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1412, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 3555, in parseImpl
return e._parse( instring, loc, doActions )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1445, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 4588, in z
ret = f(*paArgs)
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1082, in wrapper
ret = func(*args[limit[0]:])
File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable






python-3.x pyparsing






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 5 at 13:32









reyman64

281956




281956












  • Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
    – PaulMcG
    Nov 8 at 14:14


















  • Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
    – PaulMcG
    Nov 8 at 14:14
















Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
– PaulMcG
Nov 8 at 14:14




Set this aside for a bit and just think through what the BNF for this language would be. Doesn't need to be exhaustive; where you allow an arith-expression just put arith-expression. But it will help you conceptualize the commands, common phrase formats, etc.
– PaulMcG
Nov 8 at 14:14












1 Answer
1






active

oldest

votes

















up vote
1
down vote



+50










(This is a huge! question - you'll get better response on SO if you can strip your problem down to something small.)



Looking at the last 2 lines of your traceback:



  File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable


You have passed a ParseResults to parseString, not a string. Then when pyparsing tries to call str functions on the input parameter, the ParseResults interprets these as attempts to read attributes, which it default to returning ''. Dissecting this a bit more:



instring.expandtabs()

^^^^^^^^
a ParseResults, not a str
^^^^^^^^^^
an undefined attribute in the ParseResults, so returns ''
^^
trying to "call" the str - but str's aren't callable, so exception!


traceParseAction is okay for parse actions that take simple tokens, but this one is some complex, I'd recommend that you print(tokens.dump()) as the first line in your parse action, to better visualize just what kind of structure you are getting.



Your method for detecting IF, ELSIF, and ELSE is also error-prone, and you are better off using results names in your grammar. Instead of:



simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)


do:



from pyparsing import *

# fake expressions, not intended to replace those in the original problem
ident = pyparsing_common.identifier
integer = pyparsing_common.integer
expression = ident + "MATCH" + (ident | integer)
code_block = originalTextFor(nestedExpr('{', '}'))

simple_if_stmt = Group(Keyword('IF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_if_stmt = Group(Keyword('ELSIF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_stmt = Group(Keyword('ELSE') + code_block('code'))

simple_if_group = Group(simple_if_stmt('if_')
+ Optional(OneOrMore(else_if_stmt('elsif*')))
+ Optional(else_stmt('else_')))


Now here is a parse action that makes use of those results names:



def IfStatement(s, l, tokens):

# peel of outer grouping layer
tokens = tokens[0]

# dump out inner structure of parsed results
print(tokens.dump())

print('IF:', tokens.if_.condition, '->', tokens.if_.code)

if 'elsif' in tokens:
for elsif in tokens.elsif:
print('ELSIF:', elsif.condition, '->', elsif.code)

if 'else_' in tokens:
print('ELSE:', '->', tokens.else_.code)

print()

simple_if_group.addParseAction(IfStatement)


For this sample (note starting small, then getting more complicated):



sample = """
IF X MATCH Y THEN { this is some code }

IF X MATCH Y THEN { this is some code }
ELSE { do this instead }

IF X MATCH Y THEN { this is some Y code }
ELSIF X MATCH Z THEN { this is some Z code }
ELSIF X MATCH A THEN { this is some A code }
ELSE { do this instead }
"""

result = OneOrMore(simple_if_group).parseString(sample)


We get:



[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']]
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }
ELSE: -> { do this instead }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }'], ['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- elsif: [['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']]
[0]:
['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }']
- code: '{ this is some Z code }'
- condition: ['X', 'MATCH', 'Z']
[1]:
['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']
- code: '{ this is some A code }'
- condition: ['X', 'MATCH', 'A']
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }']
- code: '{ this is some Y code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some Y code }
ELSIF: ['X', 'MATCH', 'Z'] -> { this is some Z code }
ELSIF: ['X', 'MATCH', 'A'] -> { this is some A code }
ELSE: -> { do this instead }





share|improve this answer























  • Thanks for your very detailled answer !
    – reyman64
    Nov 8 at 19:36










  • One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
    – reyman64
    Nov 8 at 19:44










  • These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
    – PaulMcG
    Nov 8 at 22:38










  • Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
    – reyman64
    Nov 10 at 16:11








  • 1




    Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
    – reyman64
    Nov 10 at 16:16











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53155419%2ferror-when-passing-class-to-pyparsing-setparseaction-class-for-if-else-struc%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



+50










(This is a huge! question - you'll get better response on SO if you can strip your problem down to something small.)



Looking at the last 2 lines of your traceback:



  File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable


You have passed a ParseResults to parseString, not a string. Then when pyparsing tries to call str functions on the input parameter, the ParseResults interprets these as attempts to read attributes, which it default to returning ''. Dissecting this a bit more:



instring.expandtabs()

^^^^^^^^
a ParseResults, not a str
^^^^^^^^^^
an undefined attribute in the ParseResults, so returns ''
^^
trying to "call" the str - but str's aren't callable, so exception!


traceParseAction is okay for parse actions that take simple tokens, but this one is some complex, I'd recommend that you print(tokens.dump()) as the first line in your parse action, to better visualize just what kind of structure you are getting.



Your method for detecting IF, ELSIF, and ELSE is also error-prone, and you are better off using results names in your grammar. Instead of:



simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)


do:



from pyparsing import *

# fake expressions, not intended to replace those in the original problem
ident = pyparsing_common.identifier
integer = pyparsing_common.integer
expression = ident + "MATCH" + (ident | integer)
code_block = originalTextFor(nestedExpr('{', '}'))

simple_if_stmt = Group(Keyword('IF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_if_stmt = Group(Keyword('ELSIF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_stmt = Group(Keyword('ELSE') + code_block('code'))

simple_if_group = Group(simple_if_stmt('if_')
+ Optional(OneOrMore(else_if_stmt('elsif*')))
+ Optional(else_stmt('else_')))


Now here is a parse action that makes use of those results names:



def IfStatement(s, l, tokens):

# peel of outer grouping layer
tokens = tokens[0]

# dump out inner structure of parsed results
print(tokens.dump())

print('IF:', tokens.if_.condition, '->', tokens.if_.code)

if 'elsif' in tokens:
for elsif in tokens.elsif:
print('ELSIF:', elsif.condition, '->', elsif.code)

if 'else_' in tokens:
print('ELSE:', '->', tokens.else_.code)

print()

simple_if_group.addParseAction(IfStatement)


For this sample (note starting small, then getting more complicated):



sample = """
IF X MATCH Y THEN { this is some code }

IF X MATCH Y THEN { this is some code }
ELSE { do this instead }

IF X MATCH Y THEN { this is some Y code }
ELSIF X MATCH Z THEN { this is some Z code }
ELSIF X MATCH A THEN { this is some A code }
ELSE { do this instead }
"""

result = OneOrMore(simple_if_group).parseString(sample)


We get:



[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']]
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }
ELSE: -> { do this instead }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }'], ['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- elsif: [['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']]
[0]:
['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }']
- code: '{ this is some Z code }'
- condition: ['X', 'MATCH', 'Z']
[1]:
['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']
- code: '{ this is some A code }'
- condition: ['X', 'MATCH', 'A']
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }']
- code: '{ this is some Y code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some Y code }
ELSIF: ['X', 'MATCH', 'Z'] -> { this is some Z code }
ELSIF: ['X', 'MATCH', 'A'] -> { this is some A code }
ELSE: -> { do this instead }





share|improve this answer























  • Thanks for your very detailled answer !
    – reyman64
    Nov 8 at 19:36










  • One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
    – reyman64
    Nov 8 at 19:44










  • These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
    – PaulMcG
    Nov 8 at 22:38










  • Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
    – reyman64
    Nov 10 at 16:11








  • 1




    Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
    – reyman64
    Nov 10 at 16:16















up vote
1
down vote



+50










(This is a huge! question - you'll get better response on SO if you can strip your problem down to something small.)



Looking at the last 2 lines of your traceback:



  File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable


You have passed a ParseResults to parseString, not a string. Then when pyparsing tries to call str functions on the input parameter, the ParseResults interprets these as attempts to read attributes, which it default to returning ''. Dissecting this a bit more:



instring.expandtabs()

^^^^^^^^
a ParseResults, not a str
^^^^^^^^^^
an undefined attribute in the ParseResults, so returns ''
^^
trying to "call" the str - but str's aren't callable, so exception!


traceParseAction is okay for parse actions that take simple tokens, but this one is some complex, I'd recommend that you print(tokens.dump()) as the first line in your parse action, to better visualize just what kind of structure you are getting.



Your method for detecting IF, ELSIF, and ELSE is also error-prone, and you are better off using results names in your grammar. Instead of:



simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)


do:



from pyparsing import *

# fake expressions, not intended to replace those in the original problem
ident = pyparsing_common.identifier
integer = pyparsing_common.integer
expression = ident + "MATCH" + (ident | integer)
code_block = originalTextFor(nestedExpr('{', '}'))

simple_if_stmt = Group(Keyword('IF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_if_stmt = Group(Keyword('ELSIF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_stmt = Group(Keyword('ELSE') + code_block('code'))

simple_if_group = Group(simple_if_stmt('if_')
+ Optional(OneOrMore(else_if_stmt('elsif*')))
+ Optional(else_stmt('else_')))


Now here is a parse action that makes use of those results names:



def IfStatement(s, l, tokens):

# peel of outer grouping layer
tokens = tokens[0]

# dump out inner structure of parsed results
print(tokens.dump())

print('IF:', tokens.if_.condition, '->', tokens.if_.code)

if 'elsif' in tokens:
for elsif in tokens.elsif:
print('ELSIF:', elsif.condition, '->', elsif.code)

if 'else_' in tokens:
print('ELSE:', '->', tokens.else_.code)

print()

simple_if_group.addParseAction(IfStatement)


For this sample (note starting small, then getting more complicated):



sample = """
IF X MATCH Y THEN { this is some code }

IF X MATCH Y THEN { this is some code }
ELSE { do this instead }

IF X MATCH Y THEN { this is some Y code }
ELSIF X MATCH Z THEN { this is some Z code }
ELSIF X MATCH A THEN { this is some A code }
ELSE { do this instead }
"""

result = OneOrMore(simple_if_group).parseString(sample)


We get:



[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']]
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }
ELSE: -> { do this instead }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }'], ['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- elsif: [['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']]
[0]:
['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }']
- code: '{ this is some Z code }'
- condition: ['X', 'MATCH', 'Z']
[1]:
['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']
- code: '{ this is some A code }'
- condition: ['X', 'MATCH', 'A']
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }']
- code: '{ this is some Y code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some Y code }
ELSIF: ['X', 'MATCH', 'Z'] -> { this is some Z code }
ELSIF: ['X', 'MATCH', 'A'] -> { this is some A code }
ELSE: -> { do this instead }





share|improve this answer























  • Thanks for your very detailled answer !
    – reyman64
    Nov 8 at 19:36










  • One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
    – reyman64
    Nov 8 at 19:44










  • These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
    – PaulMcG
    Nov 8 at 22:38










  • Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
    – reyman64
    Nov 10 at 16:11








  • 1




    Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
    – reyman64
    Nov 10 at 16:16













up vote
1
down vote



+50







up vote
1
down vote



+50




+50




(This is a huge! question - you'll get better response on SO if you can strip your problem down to something small.)



Looking at the last 2 lines of your traceback:



  File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable


You have passed a ParseResults to parseString, not a string. Then when pyparsing tries to call str functions on the input parameter, the ParseResults interprets these as attempts to read attributes, which it default to returning ''. Dissecting this a bit more:



instring.expandtabs()

^^^^^^^^
a ParseResults, not a str
^^^^^^^^^^
an undefined attribute in the ParseResults, so returns ''
^^
trying to "call" the str - but str's aren't callable, so exception!


traceParseAction is okay for parse actions that take simple tokens, but this one is some complex, I'd recommend that you print(tokens.dump()) as the first line in your parse action, to better visualize just what kind of structure you are getting.



Your method for detecting IF, ELSIF, and ELSE is also error-prone, and you are better off using results names in your grammar. Instead of:



simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)


do:



from pyparsing import *

# fake expressions, not intended to replace those in the original problem
ident = pyparsing_common.identifier
integer = pyparsing_common.integer
expression = ident + "MATCH" + (ident | integer)
code_block = originalTextFor(nestedExpr('{', '}'))

simple_if_stmt = Group(Keyword('IF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_if_stmt = Group(Keyword('ELSIF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_stmt = Group(Keyword('ELSE') + code_block('code'))

simple_if_group = Group(simple_if_stmt('if_')
+ Optional(OneOrMore(else_if_stmt('elsif*')))
+ Optional(else_stmt('else_')))


Now here is a parse action that makes use of those results names:



def IfStatement(s, l, tokens):

# peel of outer grouping layer
tokens = tokens[0]

# dump out inner structure of parsed results
print(tokens.dump())

print('IF:', tokens.if_.condition, '->', tokens.if_.code)

if 'elsif' in tokens:
for elsif in tokens.elsif:
print('ELSIF:', elsif.condition, '->', elsif.code)

if 'else_' in tokens:
print('ELSE:', '->', tokens.else_.code)

print()

simple_if_group.addParseAction(IfStatement)


For this sample (note starting small, then getting more complicated):



sample = """
IF X MATCH Y THEN { this is some code }

IF X MATCH Y THEN { this is some code }
ELSE { do this instead }

IF X MATCH Y THEN { this is some Y code }
ELSIF X MATCH Z THEN { this is some Z code }
ELSIF X MATCH A THEN { this is some A code }
ELSE { do this instead }
"""

result = OneOrMore(simple_if_group).parseString(sample)


We get:



[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']]
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }
ELSE: -> { do this instead }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }'], ['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- elsif: [['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']]
[0]:
['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }']
- code: '{ this is some Z code }'
- condition: ['X', 'MATCH', 'Z']
[1]:
['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']
- code: '{ this is some A code }'
- condition: ['X', 'MATCH', 'A']
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }']
- code: '{ this is some Y code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some Y code }
ELSIF: ['X', 'MATCH', 'Z'] -> { this is some Z code }
ELSIF: ['X', 'MATCH', 'A'] -> { this is some A code }
ELSE: -> { do this instead }





share|improve this answer














(This is a huge! question - you'll get better response on SO if you can strip your problem down to something small.)



Looking at the last 2 lines of your traceback:



  File "/home/reyman/Projets/cours/exercice/labyrinthe_matplot_python/parsingLanguage.py", line 99, in IfEval
if Keyword("IF").parseString(tokens[0][1]):
File "/home/reyman/.pyenv/versions/labyrinthes/lib/python3.5/site-packages/pyparsing.py", line 1664, in parseString
instring = instring.expandtabs()
TypeError: 'str' object is not callable


You have passed a ParseResults to parseString, not a string. Then when pyparsing tries to call str functions on the input parameter, the ParseResults interprets these as attempts to read attributes, which it default to returning ''. Dissecting this a bit more:



instring.expandtabs()

^^^^^^^^
a ParseResults, not a str
^^^^^^^^^^
an undefined attribute in the ParseResults, so returns ''
^^
trying to "call" the str - but str's aren't callable, so exception!


traceParseAction is okay for parse actions that take simple tokens, but this one is some complex, I'd recommend that you print(tokens.dump()) as the first line in your parse action, to better visualize just what kind of structure you are getting.



Your method for detecting IF, ELSIF, and ELSE is also error-prone, and you are better off using results names in your grammar. Instead of:



simple_if_stmt = Keyword('IF') + expression + Keyword('THEN') + code_block
else_if_stmt = Keyword('ELSIF') + expression + Keyword('THEN') + code_block
else_stmt = Keyword('ELSE') + code_block
simple_if_group = Group(simple_if_stmt + Optional(OneOrMore(else_if_stmt)) + Optional(else_stmt)).setParseAction(IfEval)


do:



from pyparsing import *

# fake expressions, not intended to replace those in the original problem
ident = pyparsing_common.identifier
integer = pyparsing_common.integer
expression = ident + "MATCH" + (ident | integer)
code_block = originalTextFor(nestedExpr('{', '}'))

simple_if_stmt = Group(Keyword('IF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_if_stmt = Group(Keyword('ELSIF') + expression('condition')
+ Keyword('THEN') + code_block('code'))
else_stmt = Group(Keyword('ELSE') + code_block('code'))

simple_if_group = Group(simple_if_stmt('if_')
+ Optional(OneOrMore(else_if_stmt('elsif*')))
+ Optional(else_stmt('else_')))


Now here is a parse action that makes use of those results names:



def IfStatement(s, l, tokens):

# peel of outer grouping layer
tokens = tokens[0]

# dump out inner structure of parsed results
print(tokens.dump())

print('IF:', tokens.if_.condition, '->', tokens.if_.code)

if 'elsif' in tokens:
for elsif in tokens.elsif:
print('ELSIF:', elsif.condition, '->', elsif.code)

if 'else_' in tokens:
print('ELSE:', '->', tokens.else_.code)

print()

simple_if_group.addParseAction(IfStatement)


For this sample (note starting small, then getting more complicated):



sample = """
IF X MATCH Y THEN { this is some code }

IF X MATCH Y THEN { this is some code }
ELSE { do this instead }

IF X MATCH Y THEN { this is some Y code }
ELSIF X MATCH Z THEN { this is some Z code }
ELSIF X MATCH A THEN { this is some A code }
ELSE { do this instead }
"""

result = OneOrMore(simple_if_group).parseString(sample)


We get:



[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']]
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some code }']
- code: '{ this is some code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some code }
ELSE: -> { do this instead }

[['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }'], ['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }'], ['ELSE', '{ do this instead }']]
- else_: ['ELSE', '{ do this instead }']
- code: '{ do this instead }'
- elsif: [['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }'], ['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']]
[0]:
['ELSIF', 'X', 'MATCH', 'Z', 'THEN', '{ this is some Z code }']
- code: '{ this is some Z code }'
- condition: ['X', 'MATCH', 'Z']
[1]:
['ELSIF', 'X', 'MATCH', 'A', 'THEN', '{ this is some A code }']
- code: '{ this is some A code }'
- condition: ['X', 'MATCH', 'A']
- if_: ['IF', 'X', 'MATCH', 'Y', 'THEN', '{ this is some Y code }']
- code: '{ this is some Y code }'
- condition: ['X', 'MATCH', 'Y']
IF: ['X', 'MATCH', 'Y'] -> { this is some Y code }
ELSIF: ['X', 'MATCH', 'Z'] -> { this is some Z code }
ELSIF: ['X', 'MATCH', 'A'] -> { this is some A code }
ELSE: -> { do this instead }






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 8 at 14:36

























answered Nov 8 at 12:01









PaulMcG

45.4k866111




45.4k866111












  • Thanks for your very detailled answer !
    – reyman64
    Nov 8 at 19:36










  • One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
    – reyman64
    Nov 8 at 19:44










  • These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
    – PaulMcG
    Nov 8 at 22:38










  • Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
    – reyman64
    Nov 10 at 16:11








  • 1




    Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
    – reyman64
    Nov 10 at 16:16


















  • Thanks for your very detailled answer !
    – reyman64
    Nov 8 at 19:36










  • One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
    – reyman64
    Nov 8 at 19:44










  • These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
    – PaulMcG
    Nov 8 at 22:38










  • Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
    – reyman64
    Nov 10 at 16:11








  • 1




    Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
    – reyman64
    Nov 10 at 16:16
















Thanks for your very detailled answer !
– reyman64
Nov 8 at 19:36




Thanks for your very detailled answer !
– reyman64
Nov 8 at 19:36












One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
– reyman64
Nov 8 at 19:44




One more question perhaps. About evaluation which follow this parsing, what did you advice ? A see some tutorials using isInstance(...) to pattern match object and apply the good evaluation for the good element. Is it a best pratice ?
– reyman64
Nov 8 at 19:44












These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
– PaulMcG
Nov 8 at 22:38




These aren't pyparsing tutorials, I hope. Please look at the SimpleBool.py and eval_arith.py examples in the pyparsing examples directory.
– PaulMcG
Nov 8 at 22:38












Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
– reyman64
Nov 10 at 16:11






Thx, i looks the examples, if i understand well with simple example, i think a more complex example (like if/else evaluation) in pyparsing examples directory could be very cool for beginer like me in parsing.
– reyman64
Nov 10 at 16:11






1




1




Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
– reyman64
Nov 10 at 16:16




Why, because i follow this type of tutorial to try to make if/else parsing, and there are lot of isinstance() call : ralsina.me/weblog/posts/creating-languages-for-dummies.html
– reyman64
Nov 10 at 16:16


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53155419%2ferror-when-passing-class-to-pyparsing-setparseaction-class-for-if-else-struc%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini