def test_deref_collection_ptr(): tc = gc_scope_top_level() c_type = ctyp.collection(ctyp.terminal(ctyp.parse_type('int')), ctyp.parse_type('vector<int>*')) c = crep.cpp_collection('my_var', tc, c_type) d = crep.dereference_var(c) assert isinstance(d, crep.cpp_collection) cpp_type = d.cpp_type() assert isinstance(cpp_type, ctyp.collection) assert str(cpp_type) == 'vector<int>' assert str(cpp_type.element_type) == 'int'
def test_subscript(): q = atlas_xaod_query_ast_visitor() our_a = ast.Name(id='a') our_a.rep = crep.cpp_collection('jets', gc_scope_top_level(), ctyp.collection( ctyp.terminal('int'))) # type: ignore node = ast_parse_with_replacement('a[10]', { 'a': our_a }).body[0].value # type: ignore as_root = q.get_rep(node) assert isinstance(as_root, crep.cpp_value) assert str(as_root.cpp_type()) == 'int' assert as_root.as_cpp() == 'jets.at(10)'
def get_collection(self, md: EventCollectionSpecification, call_node: ast.Call): r''' Return a cpp ast for accessing the jet collection with the given arguments. ''' # Get the name jet collection to look at. if len(call_node.args) != 1: raise ValueError( f"Calling {md.name} - only one argument is allowed") if not isinstance(call_node.args[0], ast.Str): raise ValueError( f"Calling {md.name} - only acceptable argument is a string") # Fill in the CPP block next. r = cpp_ast.CPPCodeValue() r.args = [ 'collection_name', ] r.include_files += md.include_files r.link_libraries += md.libraries r.running_code += self.get_running_code(md.container_type) r.result = 'result' if issubclass(type(md.container_type), event_collection_collection_container): r.result_rep = lambda scope: crep.cpp_collection( unique_name(md.name.lower()), scope=scope, collection_type=md.container_type) # type: ignore else: r.result_rep = lambda scope: crep.cpp_variable( unique_name(md.name.lower()), scope=scope, cpp_type=md.container_type) # Replace it as the function that is going to get called. call_node.func = r # type: ignore return call_node
def build_CPPCodeValue(spec: CPPCodeSpecification, call_node: ast.Call) -> ast.Call: ''' Given the specification for a C++ code block, invoked as a function in our AST, replace the call node with a cpp spec callback AST so the C++ code is properly inserted into the call stream. Args: spec (CPPCodeSpecification): The specification, including the code, that we should insert at this call node call_node (ast.Call): The call node (with arguments) that we are going to replace with this C++ code. Raises: ValueError: Raised if something is wrong with the call site Returns: [type]: The C++ ast that can easily be emitted as code ''' if len(call_node.args) != len(spec.arguments): raise ValueError( f"The call of {spec.name}({', '.join(spec.arguments)}) has insufficient arguments ({len(call_node.args)})." ) if isinstance(call_node.func, ast.Attribute) and spec.method_object is None: raise ValueError( f"The {spec.name} is a function, but it is invoked like a method.") if isinstance(call_node.func, ast.Name) and spec.method_object is not None: raise ValueError( f"The {spec.name} is a method, but it is invoked like a function.") # Create an AST to hold onto all of this. r = CPPCodeValue() # We need TVector2 included here r.include_files += spec.include_files # We need all four arguments pushed through. r.args = spec.arguments # The code is three steps r.running_code += spec.code r.result = spec.result if spec.cpp_return_is_collection: r.result_rep = lambda scope: cpp_collection( unique_name(spec.name), scope=scope, collection_type=ctyp.collection(ctyp.terminal(spec.cpp_return_type) )) # type: ignore else: r.result_rep = lambda scope: cpp_variable(unique_name(spec.name), scope=scope, cpp_type=ctyp.terminal( spec.cpp_return_type)) # If this is a mehtod, copy the info over to generate the obj reference. if spec.method_object is not None: r.replacement_instance_obj = (spec.method_object, call_node.func.value.id) # type: ignore call_node.func = r # type: ignore return call_node