def convertClassInstanceDescription(self, objectId, classInstanceDescription, convertedValues): classMemberNameToImplVal = { classMemberName: convertedValues[memberId] for classMemberName, memberId in classInstanceDescription.classMemberNameToClassMemberId.iteritems() } classImplVal = convertedValues[classInstanceDescription.classId] if classImplVal.isSymbol(): convertedValues[objectId] = classImplVal return memberNames = tuple(sorted(name for name in classMemberNameToImplVal.iterkeys())) memberValues = tuple(classMemberNameToImplVal[name] for name in memberNames) convertedValueOrNone = ForaNative.simulateApply( ForaNative.ImplValContainer( (classImplVal, Symbol_CreateInstance, ForaNative.CreateNamedTuple(memberValues, memberNames)) ) ) if convertedValueOrNone is None: raise pyfora.PythonToForaConversionError( ("An internal error occurred: " + "function stage 1 simulation unexpectedly returned None") ) convertedValues[objectId] = convertedValueOrNone
def _specializeFreeVariablesAndEvaluate( self, foraExpression, renamedVariableMapping ): allAreIVC = True for _, v in renamedVariableMapping.iteritems(): if not isinstance(v, ForaNative.ImplValContainer): allAreIVC = False if allAreIVC: missingVariableDefinitions = [ x for x in foraExpression.freeVariables if x not in renamedVariableMapping ] if missingVariableDefinitions: raise pyfora.PythonToForaConversionError( ("An internal error occurred: we didn't provide a " + "definition for the following variables: %s" % missingVariableDefinitions + ". Most likely, there is a mismatch between our analysis of the " "python code and the generated FORA code underneath. Please file a bug report." )) #we need to determine whether we should bind the free variables in this expression as constants #inline in the code, or as class members. Binding them as constants speeds up the compiler, #but if we have the same function bound repeatedly with many constants, we'll end up #producing far too much code. This algorithm binds as constants the _First_ time we bind #a given expression with given arguments, and as members any future set of times. This #should cause it to bind modules and classes that don't have any data flowing through them #as constants, and closures and functions we're calling repeatedly using class members. shouldMapArgsAsConstants = True boundValues = tuple(renamedVariableMapping[k].hash for k in sorted(renamedVariableMapping)) if foraExpression.hash() not in self.boundExpressions: self.boundExpressions[foraExpression.hash()] = boundValues else: bound = self.boundExpressions[foraExpression.hash()] if boundValues != bound: shouldMapArgsAsConstants = False return ForaNative.evaluateRootLevelCreateObjectExpression( foraExpression, renamedVariableMapping, shouldMapArgsAsConstants ) else: #function that evaluates the CreateObject. #Args are the free variables, in lexical order expressionAsIVC = foraExpression.toFunctionImplval(False) args = [] for f in foraExpression.freeVariables: args.append(renamedVariableMapping[f]) res = ComputedValue.ComputedValue( args=(expressionAsIVC, Symbol_Call) + tuple(args) ) return res
def convertNativePythonToForaConversionError(err, path): """Convert a ForaNative.PythonToForaConversionError to a python version of the exception""" return pyfora.PythonToForaConversionError(err.error, trace=[{ 'path': path, 'line': err.range.start.line }])
def registerObjectMembers(self, objectImplVal, renamedObjectMapping): for objectId, memberName in renamedObjectMapping.iteritems(): memberImplValOrNone = objectImplVal.getObjectMember(memberName) if memberImplValOrNone is None: raise pyfora.PythonToForaConversionError( ("An internal error occurred: " + "getObjectMember unexpectedly returned None")) self.convertedValues[objectId] = memberImplValOrNone
def _assertContainerDoesNotReferenceItself(self, containerId, dependencyGraph, stronglyConnectedComponents): assert containerId in stronglyConnectedComponents[-1] if len(stronglyConnectedComponents[-1]) > 1 or \ containerId in dependencyGraph[containerId]: raise pyfora.PythonToForaConversionError( "don't know how to convert lists or tuples which reference themselves" )
def _getCreateObjectExpressionAndMemberToObjectIdMap(self, objectIdToObjectDefinition, stronglyConnectedComponent): naiveConvertedFunctions = dict() for objectId in stronglyConnectedComponent: objectDefinition = objectIdToObjectDefinition[objectId] if isinstance(objectDefinition, TypeDescription.ClassInstanceDescription): classDesc = objectIdToObjectDefinition[objectDefinition.classId] sourceFile = objectIdToObjectDefinition[classDesc.sourceFileId] lineNumber = classDesc.lineNumber raise pyfora.PythonToForaConversionError( "Classes and instances cannot be mutually recursive", trace=[{'path': sourceFile.path, 'line': lineNumber}] ) assert isinstance( objectDefinition, (TypeDescription.FunctionDefinition, TypeDescription.ClassDefinition)), type(objectDefinition) naiveConvertedFunctions[objectId] = \ self._convertPyClassOrFunctionDefinitionToForaFunctionExpression( objectDefinition, objectIdToObjectDefinition ) # at this point, naiveConvertedFunctions is a map: objectId -> functionExpr # renamedObjectMapping is a map: objectId -> varname, # where varname is (essentially) just the hash of the corresponding functionExpr renamedObjectMapping = self._computeRenamedObjectMapping( naiveConvertedFunctions ) # replace the known free var chains in the strongly connected component # with the varnames coming from the renamedObjectMapping convertedFunctions = self._replaceKnownMemberChainsWithRenamedVariables( naiveConvertedFunctions, renamedObjectMapping, objectIdToObjectDefinition, stronglyConnectedComponent ) createObjectExpression = empytObjectExpression for objectId, varname in sorted(renamedObjectMapping.items(), key=lambda p: p[1]): createObjectExpression = ForaNative.prependMemberToCreateObjectExpression( createObjectExpression, varname, convertedFunctions[objectId] ) return createObjectExpression, renamedObjectMapping
def convertNamedSingleton(self, objectDefinition): if self.singletonAndExceptionConverter is None: logging.error("Can't convert %s without a converter", objectDefinition.singletonName) singleton = self.singletonAndExceptionConverter.convertSingletonByName( objectDefinition.singletonName) if singleton is None: raise pyfora.PythonToForaConversionError( "No singleton named %s" % objectDefinition.singletonName) return singleton
def getCreateObjectExpressionAndMemberToObjectIdMap( self, objectIdToObjectDefinition, stronglyConnectedComponent): naiveConvertedFunctions = dict() for objectId in stronglyConnectedComponent: objectDefinition = objectIdToObjectDefinition[objectId] if isinstance(objectDefinition, TypeDescription.ClassInstanceDescription): classDesc = objectIdToObjectDefinition[ objectDefinition.classId] sourceFile = objectIdToObjectDefinition[classDesc.sourceFileId] lineNumber = classDesc.lineNumber raise pyfora.PythonToForaConversionError( "Classes and instances cannot be mutually recursive", trace=[{ 'path': sourceFile.path, 'line': lineNumber }]) assert isinstance( objectDefinition, (TypeDescription.FunctionDefinition, TypeDescription.ClassDefinition)), type(objectDefinition) naiveConvertedFunctions[objectId] = \ self.convertPyClassOrFunctionDefinitionToForaFunctionExpression( objectDefinition, objectIdToObjectDefinition ) renamedObjectMapping = self.computeRenamedObjectMapping( naiveConvertedFunctions) convertedFunctions = self.transformFunctions( naiveConvertedFunctions, renamedObjectMapping, objectIdToObjectDefinition, stronglyConnectedComponent) createObjectExpression = empytObjectExpression for objectId, functionExpression in convertedFunctions.iteritems(): createObjectExpression = ForaNative.prependMemberToCreateObjectExpression( createObjectExpression, renamedObjectMapping[objectId], functionExpression) return createObjectExpression, renamedObjectMapping
def _convert(self, objectId, dependencyGraph, objectIdToObjectDefinition): objectDefinition = objectIdToObjectDefinition[objectId] logging.info("ObjectDefinition: %s", objectDefinition) if TypeDescription.isPrimitive(objectDefinition) or isinstance( objectDefinition, list): return self.convertPrimitive(objectDefinition) elif isinstance(objectDefinition, TypeDescription.RemotePythonObject): return self.convertRemotePythonObject(objectDefinition) elif isinstance(objectDefinition, TypeDescription.NamedSingleton): return self.convertNamedSingleton(objectDefinition) elif isinstance(objectDefinition, TypeDescription.BuiltinExceptionInstance): return self.convertBuiltinExceptionInstance(objectDefinition) elif isinstance(objectDefinition, (TypeDescription.FunctionDefinition, TypeDescription.ClassDefinition, TypeDescription.ClassInstanceDescription, TypeDescription.InstanceMethod)): return (self.convertObjectWithDependencies( objectId, dependencyGraph, objectIdToObjectDefinition)) elif isinstance(objectDefinition, TypeDescription.List): return (self.convertList(objectId, dependencyGraph, objectIdToObjectDefinition)) elif isinstance(objectDefinition, TypeDescription.Tuple): return (self.convertTuple(objectId, dependencyGraph, objectIdToObjectDefinition)) elif isinstance(objectDefinition, TypeDescription.Dict): return (self.convertDict(objectId, objectDefinition, dependencyGraph, objectIdToObjectDefinition)) elif isinstance(objectDefinition, TypeDescription.WithBlockDescription): return (self.convertObjectWithDependencies( objectId, dependencyGraph, objectIdToObjectDefinition)) else: raise pyfora.PythonToForaConversionError( "don't know how to convert %s of type %s" % (objectDefinition, type(objectDefinition)))
def convertClassInstanceDescription(self, objectId, classInstanceDescription): classMemberNameToImplVal = { classMemberName: self.convertedValues[memberId] for classMemberName, memberId in classInstanceDescription. classMemberNameToClassMemberId.iteritems() } classImplVal = self.convertedValues[classInstanceDescription.classId] #note that we need to strip off the first character of membernames defined in the #class implval because the object holds 'x' as '@x' so that it doesn't capture #all references to 'x' classMembersInForaDeclarationOrder = \ [str(val)[1:] for val in classImplVal.getDataMembers] assert set(classMembersInForaDeclarationOrder) == \ set(classMemberNameToImplVal.keys()), "%s vs %s" % ( set(classMembersInForaDeclarationOrder), set(classMemberNameToImplVal.keys()) ) classMemberImplVals = [] for classMemberName in classMembersInForaDeclarationOrder: ivc = classMemberNameToImplVal[classMemberName] classMemberImplVals.append(ivc) applyArgs = [classImplVal, Symbol_CreateInstance] + classMemberImplVals convertedValueOrNone = ForaNative.simulateApply( ForaNative.ImplValContainer(tuple(applyArgs))) if convertedValueOrNone is None: raise pyfora.PythonToForaConversionError( ("An internal error occurred: " + "function stage 1 simulation unexpectedly returned None")) self.convertedValues[objectId] = convertedValueOrNone
def _convert(self, objectId, dependencyGraph, objectIdToObjectDefinition): objectDefinition = objectIdToObjectDefinition[objectId] if TypeDescription.isPrimitive(objectDefinition) or isinstance(objectDefinition, list): return self.convertPrimitive(objectDefinition) elif isinstance(objectDefinition, TypeDescription.RemotePythonObject): return self.convertRemotePythonObject(objectDefinition) elif isinstance(objectDefinition, TypeDescription.NamedSingleton): return self.convertNamedSingleton(objectDefinition) elif isinstance(objectDefinition, TypeDescription.BuiltinExceptionInstance): return self.convertBuiltinExceptionInstance( objectDefinition ) elif isinstance(objectDefinition, (TypeDescription.FunctionDefinition, TypeDescription.ClassDefinition, TypeDescription.ClassInstanceDescription, TypeDescription.InstanceMethod) ): return ( self.convertObjectWithDependencies( objectId, dependencyGraph, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.List): return ( self.convertList( objectId, dependencyGraph, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.PackedHomogenousData): return ( self.convertPackedHomogenousDataAsList( objectId, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.Tuple): return ( self.convertTuple( objectId, dependencyGraph, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.Dict): return ( self.convertDict( objectId, objectDefinition, dependencyGraph, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.WithBlockDescription): return ( self.convertObjectWithDependencies( objectId, dependencyGraph, objectIdToObjectDefinition ) ) elif isinstance(objectDefinition, TypeDescription.Unconvertible): return self.convertUnconvertibleValue(objectId, objectDefinition.module_path) elif isinstance(objectDefinition, TypeDescription.UnresolvedVarWithPosition): return self.convertUnresolvedVarWithPosition(objectId, objectDefinition) else: raise pyfora.PythonToForaConversionError( "don't know how to convert %s of type %s" % ( objectDefinition, type(objectDefinition) ) )