summaryrefslogtreecommitdiff
path: root/examples/LAparser.py
diff options
context:
space:
mode:
authorJon Dufresne <jon.dufresne@gmail.com>2019-10-31 21:10:28 -0700
committerPaul McGuire <ptmcg@users.noreply.github.com>2019-10-31 23:10:28 -0500
commit53d1b4a6f48a53c4c4ec4ac7031362b691c0366d (patch)
tree088ad3cf3561b78a00af4fb2fd474f4a2b8ca70c /examples/LAparser.py
parent41752aa52cc97c710474bb2972cceab057b52ad4 (diff)
downloadpyparsing-git-53d1b4a6f48a53c4c4ec4ac7031362b691c0366d.tar.gz
Blacken the project (#141)
Diffstat (limited to 'examples/LAparser.py')
-rw-r--r--examples/LAparser.py674
1 files changed, 394 insertions, 280 deletions
diff --git a/examples/LAparser.py b/examples/LAparser.py
index 330b8f5..b72166f 100644
--- a/examples/LAparser.py
+++ b/examples/LAparser.py
@@ -57,41 +57,54 @@ Usage: To process LA equations embedded in source files, import this module and
"""
-import re,sys
-from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \
-, Combine, Optional, nums, Forward, ZeroOrMore, \
- StringEnd, alphanums
+import re, sys
+from pyparsing import (
+ Word,
+ alphas,
+ ParseException,
+ Literal,
+ CaselessLiteral,
+ Combine,
+ Optional,
+ nums,
+ Forward,
+ ZeroOrMore,
+ StringEnd,
+ alphanums,
+)
# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
-debug_flag=False
+debug_flag = False
-#----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
# Variables that hold intermediate parsing results and a couple of
# helper functions.
-exprStack = [] # Holds operators and operands parsed from input.
-targetvar = None # Holds variable name to left of '=' sign in LA equation.
+exprStack = [] # Holds operators and operands parsed from input.
+targetvar = None # Holds variable name to left of '=' sign in LA equation.
-def _pushFirst( str, loc, toks ):
- if debug_flag: print("pushing ", toks[0], "str is ", str)
- exprStack.append( toks[0] )
+def _pushFirst(str, loc, toks):
+ if debug_flag:
+ print("pushing ", toks[0], "str is ", str)
+ exprStack.append(toks[0])
-def _assignVar( str, loc, toks ):
+
+def _assignVar(str, loc, toks):
global targetvar
- targetvar = toks[0]
+ targetvar = toks[0]
+
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# The following statements define the grammar for the parser.
-point = Literal('.')
-e = CaselessLiteral('E')
-plusorminus = Literal('+') | Literal('-')
+point = Literal(".")
+e = CaselessLiteral("E")
+plusorminus = Literal("+") | Literal("-")
number = Word(nums)
-integer = Combine( Optional(plusorminus) + number )
-floatnumber = Combine( integer +
- Optional( point + Optional(number) ) +
- Optional( e + integer )
- )
+integer = Combine(Optional(plusorminus) + number)
+floatnumber = Combine(
+ integer + Optional(point + Optional(number)) + Optional(e + integer)
+)
lbracket = Literal("[")
rbracket = Literal("]")
@@ -100,57 +113,66 @@ ident = Forward()
## can include references to array elements, rows and columns, e.g., a = b[i] + 5.
## Expressions within []'s are not presently supported, so a = b[i+1] will raise
## a ParseException.
-ident = Combine(Word(alphas + '-',alphanums + '_') + \
- ZeroOrMore(lbracket + (Word(alphas + '-',alphanums + '_')|integer) + rbracket) \
- )
-
-plus = Literal( "+" )
-minus = Literal( "-" )
-mult = Literal( "*" )
-div = Literal( "/" )
-outer = Literal( "@" )
-lpar = Literal( "(" ).suppress()
-rpar = Literal( ")" ).suppress()
-addop = plus | minus
+ident = Combine(
+ Word(alphas + "-", alphanums + "_")
+ + ZeroOrMore(lbracket + (Word(alphas + "-", alphanums + "_") | integer) + rbracket)
+)
+
+plus = Literal("+")
+minus = Literal("-")
+mult = Literal("*")
+div = Literal("/")
+outer = Literal("@")
+lpar = Literal("(").suppress()
+rpar = Literal(")").suppress()
+addop = plus | minus
multop = mult | div | outer
-expop = Literal( "^" )
-assignop = Literal( "=" )
+expop = Literal("^")
+assignop = Literal("=")
expr = Forward()
-atom = ( ( e | floatnumber | integer | ident ).setParseAction(_pushFirst) |
- ( lpar + expr.suppress() + rpar )
- )
+atom = (e | floatnumber | integer | ident).setParseAction(_pushFirst) | (
+ lpar + expr.suppress() + rpar
+)
factor = Forward()
-factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( _pushFirst ) )
+factor << atom + ZeroOrMore((expop + factor).setParseAction(_pushFirst))
-term = factor + ZeroOrMore( ( multop + factor ).setParseAction( _pushFirst ) )
-expr << term + ZeroOrMore( ( addop + term ).setParseAction( _pushFirst ) )
+term = factor + ZeroOrMore((multop + factor).setParseAction(_pushFirst))
+expr << term + ZeroOrMore((addop + term).setParseAction(_pushFirst))
equation = (ident + assignop).setParseAction(_assignVar) + expr + StringEnd()
# End of grammar definition
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
## The following are helper variables and functions used by the Binary Infix Operator
## Functions described below.
-vprefix = 'V3_'
+vprefix = "V3_"
vplen = len(vprefix)
-mprefix = 'M3_'
+mprefix = "M3_"
mplen = len(mprefix)
## We don't support unary negation for vectors and matrices
-class UnaryUnsupportedError(Exception): pass
+class UnaryUnsupportedError(Exception):
+ pass
+
def _isvec(ident):
- if ident[0] == '-' and ident[1:vplen+1] == vprefix:
- raise UnaryUnsupportedError
- else: return ident[0:vplen] == vprefix
+ if ident[0] == "-" and ident[1 : vplen + 1] == vprefix:
+ raise UnaryUnsupportedError
+ else:
+ return ident[0:vplen] == vprefix
+
def _ismat(ident):
- if ident[0] == '-' and ident[1:mplen+1] == mprefix:
- raise UnaryUnsupportedError
- else: return ident[0:mplen] == mprefix
+ if ident[0] == "-" and ident[1 : mplen + 1] == mprefix:
+ raise UnaryUnsupportedError
+ else:
+ return ident[0:mplen] == mprefix
+
+
+def _isscalar(ident):
+ return not (_isvec(ident) or _ismat(ident))
-def _isscalar(ident): return not (_isvec(ident) or _ismat(ident))
## Binary infix operator (BIO) functions. These are called when the stack evaluator
## pops a binary operator like '+' or '*". The stack evaluator pops the two operand, a and b,
@@ -164,80 +186,121 @@ def _isscalar(ident): return not (_isvec(ident) or _ismat(ident))
## the appropriate prefix is placed on the outer function for removal later as the stack evaluation
## recurses toward the final assignment statement.
-def _addfunc(a,b):
- if _isscalar(a) and _isscalar(b): return "(%s+%s)"%(a,b)
- if _isvec(a) and _isvec(b): return "%svAdd(%s,%s)"%(vprefix,a[vplen:],b[vplen:])
- if _ismat(a) and _ismat(b): return "%smAdd(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
- else: raise TypeError
-
-def _subfunc(a,b):
- if _isscalar(a) and _isscalar(b): return "(%s-%s)"%(a,b)
- if _isvec(a) and _isvec(b): return "%svSubtract(%s,%s)"%(vprefix,a[vplen:],b[vplen:])
- if _ismat(a) and _ismat(b): return "%smSubtract(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
- else: raise TypeError
-
-def _mulfunc(a,b):
- if _isscalar(a) and _isscalar(b): return "%s*%s"%(a,b)
- if _isvec(a) and _isvec(b): return "vDot(%s,%s)"%(a[vplen:],b[vplen:])
- if _ismat(a) and _ismat(b): return "%smMultiply(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
- if _ismat(a) and _isvec(b): return "%smvMultiply(%s,%s)"%(vprefix,a[mplen:],b[vplen:])
- if _ismat(a) and _isscalar(b): return "%smScale(%s,%s)"%(mprefix,a[mplen:],b)
- if _isvec(a) and _isscalar(b): return "%svScale(%s,%s)"%(vprefix,a[mplen:],b)
- else: raise TypeError
-
-def _outermulfunc(a,b):
- ## The '@' operator is used for the vector outer product.
- if _isvec(a) and _isvec(b):
- return "%svOuterProduct(%s,%s)"%(mprefix,a[vplen:],b[vplen:])
- else: raise TypeError
-
-def _divfunc(a,b):
- ## The '/' operator is used only for scalar division
- if _isscalar(a) and _isscalar(b): return "%s/%s"%(a,b)
- else: raise TypeError
-
-def _expfunc(a,b):
- ## The '^' operator is used for exponentiation on scalars and
- ## as a marker for unary operations on vectors and matrices.
- if _isscalar(a) and _isscalar(b): return "pow(%s,%s)"%(str(a),str(b))
- if _ismat(a) and b=='-1': return "%smInverse(%s)"%(mprefix,a[mplen:])
- if _ismat(a) and b=='T': return "%smTranspose(%s)"%(mprefix,a[mplen:])
- if _ismat(a) and b=='Det': return "mDeterminant(%s)"%(a[mplen:])
- if _isvec(a) and b=='Mag': return "sqrt(vMagnitude2(%s))"%(a[vplen:])
- if _isvec(a) and b=='Mag2': return "vMagnitude2(%s)"%(a[vplen:])
- else: raise TypeError
-
-def _assignfunc(a,b):
- ## The '=' operator is used for assignment
- if _isscalar(a) and _isscalar(b): return "%s=%s"%(a,b)
- if _isvec(a) and _isvec(b): return "vCopy(%s,%s)"%(a[vplen:],b[vplen:])
- if _ismat(a) and _ismat(b): return "mCopy(%s,%s)"%(a[mplen:],b[mplen:])
- else: raise TypeError
+
+def _addfunc(a, b):
+ if _isscalar(a) and _isscalar(b):
+ return "(%s+%s)" % (a, b)
+ if _isvec(a) and _isvec(b):
+ return "%svAdd(%s,%s)" % (vprefix, a[vplen:], b[vplen:])
+ if _ismat(a) and _ismat(b):
+ return "%smAdd(%s,%s)" % (mprefix, a[mplen:], b[mplen:])
+ else:
+ raise TypeError
+
+
+def _subfunc(a, b):
+ if _isscalar(a) and _isscalar(b):
+ return "(%s-%s)" % (a, b)
+ if _isvec(a) and _isvec(b):
+ return "%svSubtract(%s,%s)" % (vprefix, a[vplen:], b[vplen:])
+ if _ismat(a) and _ismat(b):
+ return "%smSubtract(%s,%s)" % (mprefix, a[mplen:], b[mplen:])
+ else:
+ raise TypeError
+
+
+def _mulfunc(a, b):
+ if _isscalar(a) and _isscalar(b):
+ return "%s*%s" % (a, b)
+ if _isvec(a) and _isvec(b):
+ return "vDot(%s,%s)" % (a[vplen:], b[vplen:])
+ if _ismat(a) and _ismat(b):
+ return "%smMultiply(%s,%s)" % (mprefix, a[mplen:], b[mplen:])
+ if _ismat(a) and _isvec(b):
+ return "%smvMultiply(%s,%s)" % (vprefix, a[mplen:], b[vplen:])
+ if _ismat(a) and _isscalar(b):
+ return "%smScale(%s,%s)" % (mprefix, a[mplen:], b)
+ if _isvec(a) and _isscalar(b):
+ return "%svScale(%s,%s)" % (vprefix, a[mplen:], b)
+ else:
+ raise TypeError
+
+
+def _outermulfunc(a, b):
+ ## The '@' operator is used for the vector outer product.
+ if _isvec(a) and _isvec(b):
+ return "%svOuterProduct(%s,%s)" % (mprefix, a[vplen:], b[vplen:])
+ else:
+ raise TypeError
+
+
+def _divfunc(a, b):
+ ## The '/' operator is used only for scalar division
+ if _isscalar(a) and _isscalar(b):
+ return "%s/%s" % (a, b)
+ else:
+ raise TypeError
+
+
+def _expfunc(a, b):
+ ## The '^' operator is used for exponentiation on scalars and
+ ## as a marker for unary operations on vectors and matrices.
+ if _isscalar(a) and _isscalar(b):
+ return "pow(%s,%s)" % (str(a), str(b))
+ if _ismat(a) and b == "-1":
+ return "%smInverse(%s)" % (mprefix, a[mplen:])
+ if _ismat(a) and b == "T":
+ return "%smTranspose(%s)" % (mprefix, a[mplen:])
+ if _ismat(a) and b == "Det":
+ return "mDeterminant(%s)" % (a[mplen:])
+ if _isvec(a) and b == "Mag":
+ return "sqrt(vMagnitude2(%s))" % (a[vplen:])
+ if _isvec(a) and b == "Mag2":
+ return "vMagnitude2(%s)" % (a[vplen:])
+ else:
+ raise TypeError
+
+
+def _assignfunc(a, b):
+ ## The '=' operator is used for assignment
+ if _isscalar(a) and _isscalar(b):
+ return "%s=%s" % (a, b)
+ if _isvec(a) and _isvec(b):
+ return "vCopy(%s,%s)" % (a[vplen:], b[vplen:])
+ if _ismat(a) and _ismat(b):
+ return "mCopy(%s,%s)" % (a[mplen:], b[mplen:])
+ else:
+ raise TypeError
+
## End of BIO func definitions
##----------------------------------------------------------------------------
# Map operator symbols to corresponding BIO funcs
-opn = { "+" : ( _addfunc ),
- "-" : ( _subfunc ),
- "*" : ( _mulfunc ),
- "@" : ( _outermulfunc ),
- "/" : ( _divfunc),
- "^" : ( _expfunc ), }
+opn = {
+ "+": (_addfunc),
+ "-": (_subfunc),
+ "*": (_mulfunc),
+ "@": (_outermulfunc),
+ "/": (_divfunc),
+ "^": (_expfunc),
+}
##----------------------------------------------------------------------------
# Recursive function that evaluates the expression stack
-def _evaluateStack( s ):
- op = s.pop()
- if op in "+-*/@^":
- op2 = _evaluateStack( s )
- op1 = _evaluateStack( s )
- result = opn[op]( op1, op2 )
- if debug_flag: print(result)
- return result
- else:
- return op
+def _evaluateStack(s):
+ op = s.pop()
+ if op in "+-*/@^":
+ op2 = _evaluateStack(s)
+ op1 = _evaluateStack(s)
+ result = opn[op](op1, op2)
+ if debug_flag:
+ print(result)
+ return result
+ else:
+ return op
+
##----------------------------------------------------------------------------
# The parse function that invokes all of the above.
@@ -248,59 +311,76 @@ def parse(input_string):
calls that implement the expression.
"""
- global exprStack
+ global exprStack
global targetvar
# Start with a blank exprStack and a blank targetvar
exprStack = []
- targetvar=None
-
- if input_string != '':
- # try parsing the input string
- try:
- L=equation.parseString( input_string )
- except ParseException as err:
- print('Parse Failure', file=sys.stderr)
- print(err.line, file=sys.stderr)
- print(" "*(err.column-1) + "^", file=sys.stderr)
- print(err, file=sys.stderr)
- raise
-
- # show result of parsing the input string
- if debug_flag:
- print(input_string, "->", L)
- print("exprStack=", exprStack)
-
- # Evaluate the stack of parsed operands, emitting C code.
- try:
- result=_evaluateStack(exprStack)
- except TypeError:
- print("Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."%input_string, file=sys.stderr)
- raise
- except UnaryUnsupportedError:
- print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
- raise
-
- # Create final assignment and print it.
- if debug_flag: print("var=",targetvar)
- if targetvar != None:
- try:
- result = _assignfunc(targetvar,result)
- except TypeError:
- print("Left side tag does not match right side of '%s'"%input_string, file=sys.stderr)
+ targetvar = None
+
+ if input_string != "":
+ # try parsing the input string
+ try:
+ L = equation.parseString(input_string)
+ except ParseException as err:
+ print("Parse Failure", file=sys.stderr)
+ print(err.line, file=sys.stderr)
+ print(" " * (err.column - 1) + "^", file=sys.stderr)
+ print(err, file=sys.stderr)
raise
- except UnaryUnsupportedError:
- print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
+
+ # show result of parsing the input string
+ if debug_flag:
+ print(input_string, "->", L)
+ print("exprStack=", exprStack)
+
+ # Evaluate the stack of parsed operands, emitting C code.
+ try:
+ result = _evaluateStack(exprStack)
+ except TypeError:
+ print(
+ "Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."
+ % input_string,
+ file=sys.stderr,
+ )
+ raise
+ except UnaryUnsupportedError:
+ print(
+ "Unary negation is not supported for vectors and matrices: '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
raise
- return result
- else:
- print("Empty left side in '%s'"%input_string, file=sys.stderr)
- raise TypeError
+ # Create final assignment and print it.
+ if debug_flag:
+ print("var=", targetvar)
+ if targetvar != None:
+ try:
+ result = _assignfunc(targetvar, result)
+ except TypeError:
+ print(
+ "Left side tag does not match right side of '%s'" % input_string,
+ file=sys.stderr,
+ )
+ raise
+ except UnaryUnsupportedError:
+ print(
+ "Unary negation is not supported for vectors and matrices: '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
+ raise
+
+ return result
+ else:
+ print("Empty left side in '%s'" % input_string, file=sys.stderr)
+ raise TypeError
+
##-----------------------------------------------------------------------------------
-def fprocess(infilep,outfilep):
- """
+def fprocess(infilep, outfilep):
+ """
Scans an input file for LA equations between double square brackets,
e.g. [[ M3_mymatrix = M3_anothermatrix^-1 ]], and replaces the expression
with a comment containing the equation followed by nested function calls
@@ -313,106 +393,139 @@ def fprocess(infilep,outfilep):
The arguments are file objects (NOT file names) opened for reading and
writing, respectively.
"""
- pattern = r'\[\[\s*(.*?)\s*\]\]'
- eqn = re.compile(pattern,re.DOTALL)
- s = infilep.read()
- def parser(mo):
- ccode = parse(mo.group(1))
- return "/* %s */\n%s;\nLAParserBufferReset();\n"%(mo.group(1),ccode)
+ pattern = r"\[\[\s*(.*?)\s*\]\]"
+ eqn = re.compile(pattern, re.DOTALL)
+ s = infilep.read()
+
+ def parser(mo):
+ ccode = parse(mo.group(1))
+ return "/* %s */\n%s;\nLAParserBufferReset();\n" % (mo.group(1), ccode)
+
+ content = eqn.sub(parser, s)
+ outfilep.write(content)
- content = eqn.sub(parser,s)
- outfilep.write(content)
##-----------------------------------------------------------------------------------
def test():
- """
+ """
Tests the parsing of various supported expressions. Raises
an AssertError if the output is not what is expected. Prints the
input, expected output, and actual output for all tests.
"""
- print("Testing LAParser")
- testcases = [
- ("Scalar addition","a = b+c","a=(b+c)"),
- ("Vector addition","V3_a = V3_b + V3_c","vCopy(a,vAdd(b,c))"),
- ("Vector addition","V3_a=V3_b+V3_c","vCopy(a,vAdd(b,c))"),
- ("Matrix addition","M3_a = M3_b + M3_c","mCopy(a,mAdd(b,c))"),
- ("Matrix addition","M3_a=M3_b+M3_c","mCopy(a,mAdd(b,c))"),
- ("Scalar subtraction","a = b-c","a=(b-c)"),
- ("Vector subtraction","V3_a = V3_b - V3_c","vCopy(a,vSubtract(b,c))"),
- ("Matrix subtraction","M3_a = M3_b - M3_c","mCopy(a,mSubtract(b,c))"),
- ("Scalar multiplication","a = b*c","a=b*c"),
- ("Scalar division","a = b/c","a=b/c"),
- ("Vector multiplication (dot product)","a = V3_b * V3_c","a=vDot(b,c)"),
- ("Vector multiplication (outer product)","M3_a = V3_b @ V3_c","mCopy(a,vOuterProduct(b,c))"),
- ("Matrix multiplication","M3_a = M3_b * M3_c","mCopy(a,mMultiply(b,c))"),
- ("Vector scaling","V3_a = V3_b * c","vCopy(a,vScale(b,c))"),
- ("Matrix scaling","M3_a = M3_b * c","mCopy(a,mScale(b,c))"),
- ("Matrix by vector multiplication","V3_a = M3_b * V3_c","vCopy(a,mvMultiply(b,c))"),
- ("Scalar exponentiation","a = b^c","a=pow(b,c)"),
- ("Matrix inversion","M3_a = M3_b^-1","mCopy(a,mInverse(b))"),
- ("Matrix transpose","M3_a = M3_b^T","mCopy(a,mTranspose(b))"),
- ("Matrix determinant","a = M3_b^Det","a=mDeterminant(b)"),
- ("Vector magnitude squared","a = V3_b^Mag2","a=vMagnitude2(b)"),
- ("Vector magnitude","a = V3_b^Mag","a=sqrt(vMagnitude2(b))"),
- ("Complicated expression", "myscalar = (M3_amatrix * V3_bvector)^Mag + 5*(-xyz[i] + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(-xyz[i]+pow(2.03,2)))"),
- ("Complicated Multiline", "myscalar = \n(M3_amatrix * V3_bvector)^Mag +\n 5*(xyz + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(xyz+pow(2.03,2)))")
-
- ]
-
-
- all_passed = [True]
-
- def post_test(test, parsed):
-
- # copy exprStack to evaluate and clear before running next test
- parsed_stack = exprStack[:]
- exprStack.clear()
-
- name, testcase, expected = next(tc for tc in testcases if tc[1] == test)
-
- this_test_passed = False
- try:
- try:
- result=_evaluateStack(parsed_stack)
- except TypeError:
- print("Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."%input_string, file=sys.stderr)
- raise
- except UnaryUnsupportedError:
- print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
- raise
-
- # Create final assignment and print it.
- if debug_flag: print("var=",targetvar)
- if targetvar != None:
- try:
- result = _assignfunc(targetvar,result)
- except TypeError:
- print("Left side tag does not match right side of '%s'"%input_string, file=sys.stderr)
+ print("Testing LAParser")
+ testcases = [
+ ("Scalar addition", "a = b+c", "a=(b+c)"),
+ ("Vector addition", "V3_a = V3_b + V3_c", "vCopy(a,vAdd(b,c))"),
+ ("Vector addition", "V3_a=V3_b+V3_c", "vCopy(a,vAdd(b,c))"),
+ ("Matrix addition", "M3_a = M3_b + M3_c", "mCopy(a,mAdd(b,c))"),
+ ("Matrix addition", "M3_a=M3_b+M3_c", "mCopy(a,mAdd(b,c))"),
+ ("Scalar subtraction", "a = b-c", "a=(b-c)"),
+ ("Vector subtraction", "V3_a = V3_b - V3_c", "vCopy(a,vSubtract(b,c))"),
+ ("Matrix subtraction", "M3_a = M3_b - M3_c", "mCopy(a,mSubtract(b,c))"),
+ ("Scalar multiplication", "a = b*c", "a=b*c"),
+ ("Scalar division", "a = b/c", "a=b/c"),
+ ("Vector multiplication (dot product)", "a = V3_b * V3_c", "a=vDot(b,c)"),
+ (
+ "Vector multiplication (outer product)",
+ "M3_a = V3_b @ V3_c",
+ "mCopy(a,vOuterProduct(b,c))",
+ ),
+ ("Matrix multiplication", "M3_a = M3_b * M3_c", "mCopy(a,mMultiply(b,c))"),
+ ("Vector scaling", "V3_a = V3_b * c", "vCopy(a,vScale(b,c))"),
+ ("Matrix scaling", "M3_a = M3_b * c", "mCopy(a,mScale(b,c))"),
+ (
+ "Matrix by vector multiplication",
+ "V3_a = M3_b * V3_c",
+ "vCopy(a,mvMultiply(b,c))",
+ ),
+ ("Scalar exponentiation", "a = b^c", "a=pow(b,c)"),
+ ("Matrix inversion", "M3_a = M3_b^-1", "mCopy(a,mInverse(b))"),
+ ("Matrix transpose", "M3_a = M3_b^T", "mCopy(a,mTranspose(b))"),
+ ("Matrix determinant", "a = M3_b^Det", "a=mDeterminant(b)"),
+ ("Vector magnitude squared", "a = V3_b^Mag2", "a=vMagnitude2(b)"),
+ ("Vector magnitude", "a = V3_b^Mag", "a=sqrt(vMagnitude2(b))"),
+ (
+ "Complicated expression",
+ "myscalar = (M3_amatrix * V3_bvector)^Mag + 5*(-xyz[i] + 2.03^2)",
+ "myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(-xyz[i]+pow(2.03,2)))",
+ ),
+ (
+ "Complicated Multiline",
+ "myscalar = \n(M3_amatrix * V3_bvector)^Mag +\n 5*(xyz + 2.03^2)",
+ "myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(xyz+pow(2.03,2)))",
+ ),
+ ]
+
+ all_passed = [True]
+
+ def post_test(test, parsed):
+
+ # copy exprStack to evaluate and clear before running next test
+ parsed_stack = exprStack[:]
+ exprStack.clear()
+
+ name, testcase, expected = next(tc for tc in testcases if tc[1] == test)
+
+ this_test_passed = False
+ try:
+ try:
+ result = _evaluateStack(parsed_stack)
+ except TypeError:
+ print(
+ "Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."
+ % input_string,
+ file=sys.stderr,
+ )
raise
- except UnaryUnsupportedError:
- print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
+ except UnaryUnsupportedError:
+ print(
+ "Unary negation is not supported for vectors and matrices: '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
raise
- else:
- print("Empty left side in '%s'"%input_string, file=sys.stderr)
- raise TypeError
-
- parsed['result'] = result
- parsed['passed'] = this_test_passed = result == expected
+ # Create final assignment and print it.
+ if debug_flag:
+ print("var=", targetvar)
+ if targetvar != None:
+ try:
+ result = _assignfunc(targetvar, result)
+ except TypeError:
+ print(
+ "Left side tag does not match right side of '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
+ raise
+ except UnaryUnsupportedError:
+ print(
+ "Unary negation is not supported for vectors and matrices: '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
+ raise
+
+ else:
+ print("Empty left side in '%s'" % input_string, file=sys.stderr)
+ raise TypeError
+
+ parsed["result"] = result
+ parsed["passed"] = this_test_passed = result == expected
+
+ finally:
+ all_passed[0] = all_passed[0] and this_test_passed
+ print("\n" + name)
+
+ equation.runTests((t[1] for t in testcases), postParse=post_test)
+
+ ##TODO: Write testcases with invalid expressions and test that the expected
+ ## exceptions are raised.
+
+ print("Tests completed!")
+ print("PASSED" if all_passed[0] else "FAILED")
+ assert all_passed[0]
- finally:
- all_passed[0] = all_passed[0] and this_test_passed
- print('\n' + name)
-
- equation.runTests((t[1] for t in testcases), postParse=post_test)
-
-
- ##TODO: Write testcases with invalid expressions and test that the expected
- ## exceptions are raised.
-
- print("Tests completed!")
- print("PASSED" if all_passed[0] else "FAILED")
- assert all_passed[0]
##----------------------------------------------------------------------------
## The following is executed only when this module is executed as
@@ -420,43 +533,44 @@ def test():
## and then enters an interactive loop where you
## can enter expressions and see the resulting C code as output.
-if __name__ == '__main__':
+if __name__ == "__main__":
- import sys
- if not sys.flags.interactive:
- # run testcases
- test()
- sys.exit(0)
+ import sys
- # input_string
- input_string=''
+ if not sys.flags.interactive:
+ # run testcases
+ test()
+ sys.exit(0)
- # Display instructions on how to use the program interactively
- interactiveusage = """
+ # input_string
+ input_string = ""
+
+ # Display instructions on how to use the program interactively
+ interactiveusage = """
Entering interactive mode:
Type in an equation to be parsed or 'quit' to exit the program.
Type 'debug on' to print parsing details as each string is processed.
Type 'debug off' to stop printing parsing details
"""
- print(interactiveusage)
- input_string = input("> ")
-
- while input_string != 'quit':
- if input_string == "debug on":
- debug_flag = True
- elif input_string == "debug off":
- debug_flag = False
- else:
- try:
- print(parse(input_string))
- except Exception:
- pass
-
- # obtain new input string
+ print(interactiveusage)
input_string = input("> ")
- # if user types 'quit' then say goodbye
- print("Good bye!")
- import os
- os._exit(0)
-
+ while input_string != "quit":
+ if input_string == "debug on":
+ debug_flag = True
+ elif input_string == "debug off":
+ debug_flag = False
+ else:
+ try:
+ print(parse(input_string))
+ except Exception:
+ pass
+
+ # obtain new input string
+ input_string = input("> ")
+
+ # if user types 'quit' then say goodbye
+ print("Good bye!")
+ import os
+
+ os._exit(0)