def compile(self, namespace, scenario, syntax=None): """Create a closure testing the requirement in the correct runtime state. While we're at it, determine whether the requirement implies any relations we can use for pruning, and gather all of its dependencies. """ bindings, ego, line = self.bindings, self.egoObject, self.line condition = self.condition # Check whether requirement implies any relations used for pruning if self.ty.constrainsSampling and syntax: relations.inferRelationsFrom(syntax, bindings, ego, line) # Gather dependencies of the requirement deps = set() for value in bindings.values(): if needsSampling(value): deps.add(value) if needsLazyEvaluation(value): raise InvalidScenarioError( f'requirement on line {line} uses value {value}' ' undefined outside of object definition') if ego is not None: assert isinstance(ego, Samplable) deps.add(ego) # Construct closure def closure(values): global evaluatingRequirement, currentScenario # rebind any names referring to sampled objects for name, value in bindings.items(): if value in values: namespace[name] = values[value] # rebind ego object, which can be referred to implicitly boundEgo = None if ego is None else values[ego] # evaluate requirement condition, reporting errors on the correct line import scenic.syntax.veneer as veneer with veneer.executeInRequirement(scenario, boundEgo): result = condition() assert not needsSampling(result) if needsLazyEvaluation(result): raise InvalidScenarioError( f'requirement on line {line} uses value' ' undefined outside of object definition') return result return CompiledRequirement(self, closure, deps)
def storeScenarioStateIn(namespace, requirementSyntax, lineMap, filename): """Post-process an executed Scenic module, extracting state from the veneer.""" # Extract created Objects namespace['_objects'] = tuple(veneer.allObjects) namespace['_egoObject'] = veneer.egoObject # Extract global parameters namespace['_params'] = veneer.globalParameters for name, value in veneer.globalParameters.items(): if needsLazyEvaluation(value): raise InvalidScenarioError( f'parameter {name} uses value {value}' ' undefined outside of object definition') # Extract external parameters namespace['_externalParams'] = tuple(veneer.externalParameters) # Extract requirements, scan for relations used for pruning, and create closures requirements = veneer.pendingRequirements finalReqs = veneer.inheritedReqs requirementDeps = set( ) # things needing to be sampled to evaluate the requirements namespace['_requirements'] = finalReqs namespace['_requirementDeps'] = requirementDeps def makeClosure(req, bindings, ego, line): """Create a closure testing the requirement in the correct runtime state.""" def evaluator(): result = req() assert not needsSampling(result) if needsLazyEvaluation(result): raise InvalidScenarioError( f'requirement on line {line} uses value' ' undefined outside of object definition') return result def closure(values): # rebind any names referring to sampled objects for name, value in bindings.items(): if value in values: namespace[name] = values[value] # rebind ego object, which can be referred to implicitly if ego is not None: veneer.egoObject = values[ego] # evaluate requirement condition, reporting errors on the correct line try: veneer.evaluatingRequirement = True result = executePythonFunction(evaluator, lineMap, filename) finally: veneer.evaluatingRequirement = False return result return closure for reqID, (req, bindings, ego, line, prob) in requirements.items(): # Check whether requirement implies any relations used for pruning reqNode = requirementSyntax[reqID] relations.inferRelationsFrom(reqNode, bindings, ego, line, lineMap) # Gather dependencies of the requirement for value in bindings.values(): if needsSampling(value): requirementDeps.add(value) if needsLazyEvaluation(value): raise InvalidScenarioError( f'requirement on line {line} uses value {value}' ' undefined outside of object definition') if ego is not None: assert isinstance(ego, Samplable) requirementDeps.add(ego) # Construct closure finalReqs.append((makeClosure(req, bindings, ego, line), prob))
def storeScenarioStateIn(namespace, requirementSyntax, filename): # extract created Objects namespace['_objects'] = tuple(veneer.allObjects) namespace['_egoObject'] = veneer.egoObject # extract global parameters namespace['_params'] = veneer.globalParameters for name, value in veneer.globalParameters.items(): if needsLazyEvaluation(value): raise InvalidScenarioError( f'parameter {name} uses value {value}' ' undefined outside of object definition') # extract requirements and create proper closures requirements = veneer.pendingRequirements finalReqs = veneer.inheritedReqs requirementDeps = set( ) # things needing to be sampled to evaluate the requirements namespace['_requirements'] = finalReqs namespace['_requirementDeps'] = requirementDeps def makeClosure(req, bindings, ego, line): def closure(values): # rebind any names referring to sampled objects for name, value in bindings.items(): if value in values: namespace[name] = values[value] # rebind ego object, which can be referred to implicitly if ego is not None: veneer.egoObject = values[ego] # evaluate requirement condition, reporting errors on the correct line try: veneer.evaluatingRequirement = True result = req() assert not needsSampling(result) if needsLazyEvaluation(result): raise RuntimeParseError( f'requirement on line {line} uses value' ' undefined outside of object definition') return result except RuntimeParseError as e: cause = e if showInternalBacktrace else None raise InterpreterParseError(e, line) from cause finally: veneer.evaluatingRequirement = False return closure for reqID, (req, bindings, ego, line, prob) in requirements.items(): # Check whether requirement implies any relations used for pruning reqNode = requirementSyntax[reqID] relations.inferRelationsFrom(reqNode, bindings, ego, line) # Gather dependencies of the requirement for value in bindings.values(): if needsSampling(value): requirementDeps.add(value) if needsLazyEvaluation(value): raise InvalidScenarioError( f'requirement on line {line} uses value {value}' ' undefined outside of object definition') if ego is not None: assert isinstance(ego, Samplable) requirementDeps.add(ego) # Construct closure finalReqs.append((makeClosure(req, bindings, ego, line), prob))