# return a string that when executed in python using the exec function
# will define a function with name 'functionName' that applies the
# specified binary operation to two given arguments.
# E.g. createDefString("myAdd", "+") will return string result such that
# exec(result) will define function myAdd(x,y) that returns the sum of x and y
#
def createDefString(functionName, operationString):
    defString = 'def ' + functionName + "(x, y):\n\t" + "return " + "x " + operationString + "y"
    return defString

def testDefString():
    try:
        print(myAdd(3,4))
    except:
        print('As expected, myAdd is not yet defined')
    ds = createDefString('myAdd', '+')
    exec(ds, globals())
    print(myAdd(3,4))
    ds = createDefString('myMult', '*')
    exec(ds, globals())
    print(myMult(3,4))
    
# Assumes programString contains a properly formatted 'def' statement
# for a function that takes a single string as input
#
def runProgramOnInput(programString, dataString):
    programNamePlus = programString.split()[1]  # extract the first "line" of the fn def
    programName = programNamePlus[:programNamePlus.find('(')] # extract the name of the fn
    exec(programString, globals())              # execute the function definition
    print("About to run program:")
    print()
    print("   ", programString)
    print()
    print("on input: ", dataString)
    print()
    print("Output:")
    program = eval(programName)                 # retrieve the function associated with programName
    program(dataString)
    print("End of output.")

def testRunProgramOnInput():
    progString = 'def doubleLen(inString):\n\tprint(2*len(inString))\n\treturn'
    runProgramOnInput(progString, 'hello')
    print("\n-----\n")
    runProgramOnInput(progString, 'hi')

progString = 'def doubleLen(inString):\n\tprint(2*len(inString))\n\treturn'
dataString = 'hello'


