def provider(): all_providers = ( tuple(def_provider_builders) + self.external_def_providers ) return Transformer.first_of( *(p(provider) for p in all_providers) )
def provide_subprogram_access(inner_provider): # This provider is composed of several providers in the following # manner: # 1. A first transformer (get_subprogram_access_signature) # constructs dynamically the Signature object of the subprogram # being accessed and returns the pair (access_sig, subp_sig) # where access_sig is the signature of the function which # creates the subprogram access, and subp_sig is the signature # of the subprogram being accessed. # # 2. A second transformer (inner_provider) transforms the second # element of this pair in order to retrieve the forward and # backward implementations of the subprogram being accessed. # # 3. A third transformer (subprogram_access_provider) creates the # definition of the subprogram access is finally constructed # using the pair (access_sig, subp_defs). @Transformer.as_transformer def get_subprogram_access_signature(sig): if isinstance(sig.name, access_paths.Subprogram): if sig.output_domain == ptr_dom: if sig.name.interface.does_return: input_domains = sig.userdata[:-1] output_domain = sig.userdata[-1] else: input_domains = sig.userdata output_domain = None subp_signature = Signature( sig.name.subp_obj, tuple(input_domains), output_domain, tuple(sig.name.interface.out_indices)) return sig, subp_signature @def_provider def subprogram_access_provider(args): access_sig, subp_defs = args subp = access_sig.name.subp_obj interface = access_sig.name.interface return (access_paths_ops.subp_address(ptr_dom, subp, interface, subp_defs), access_paths_ops.inv_subp_address()) return (get_subprogram_access_signature >> (Transformer.identity() & inner_provider) >> subprogram_access_provider)
def subp_ret_typer(inner): """ :param types.Typer[lal.AdaNode] inner: Typer for return type components. :rtype: types.Typer[lal.AdaNode] """ @Transformer.as_transformer def get_components(hint): if hint.is_a(ExtendedCallReturnType): return (hint.out_indices, hint.out_types if hint.ret_type is None else hint.out_types + (hint.ret_type, )) @Transformer.as_transformer def to_output(x): out_indices, out_types = x return types.FunOutput(tuple(out_indices), out_types) return (get_components >> (Transformer.identity() & inner.lifted()) >> to_output)
def record_typer(comp_typer): """ :param types.Typer[lal.ComponentDecl | lal.DiscriminantSpec] comp_typer: A typer for components of products. :return: A typer for record types. :rtype: types.Typer[lal.AdaNode] """ @Transformer.as_transformer def get_elements(hint): """ :param lal.AdaNode hint: the lal type. :return: The components of the record type, if relevant. :rtype: list[lal.AdaNode] """ if hint.is_a(lal.TypeDecl): if hint.f_type_def.is_a(lal.RecordTypeDef): return [field.decl for field in record_fields(hint)] to_product = Transformer.as_transformer(types.Product) # Get the elements -> type them all -> generate the product type. return get_elements >> comp_typer.lifted() >> to_product
def name_typer(inner_typer): """ :param types.Typer[lal.AdaNode] inner_typer: A typer for elements being referred by identifiers. :return: A typer for names. :rtype: types.Typer[lal.AdaNode] """ # Create a simple placeholder object for when there are no constraint. # (object() is called because None would mean that we failed to fetch the # constraint). no_constraint = object() @Transformer.as_transformer def resolved_name_and_constraint(hint): """ :param lal.AdaNode hint: the lal type expression. :return: The type declaration associated to the name, if relevant, as well as the optional constraint. :rtype: (lal.BaseTypeDecl, lal.AdaNode) """ if hint.is_a(lal.SubtypeIndication): try: return ( hint.p_designated_type_decl, hint.f_constraint if hint.f_constraint is not None else no_constraint ) except lal.PropertyError: pass def identity_if_is_a(tpe): """ Given a type tpe, returns a transformer which fails if its element to transform is not of type tpe, or else leaves it untouched. """ @Transformer.as_transformer def f(x): if x.is_a(tpe): return x return f @Transformer.as_transformer def get_range(constraint): """ If the given constraint is a range constraint, returns the expressions for its left and right hand side in a pair. """ if constraint is not no_constraint: if constraint.is_a(lal.RangeConstraint): rng = constraint.f_range.f_range if rng.is_a(lal.BinOp) and rng.f_op.is_a(lal.OpDoubleDot): return rng.f_left, rng.f_right @Transformer.as_transformer def refined_int_range(args): """ From the given pair containing an IntRange type on the left and an evaluated range constraint on the right (a pair of integers), return a new IntRange instance with the constraint applied. """ tpe, (c_left, c_right) = args assert (tpe.frm <= c_left and tpe.to >= c_right) return type(tpe)(c_left, c_right) # Transforms a lal.RangeConstraint into a pair of int ('First and 'Last) get_range_constraint = get_range >> (_eval_as_int & _eval_as_int) # Transforms a pair (types.IntRange, lal.RangeConstraint) into a new, # refined types.IntRange instance. when_constrained_range = ( (identity_if_is_a(types.IntRange) & get_range_constraint) >> refined_int_range ) # 1. Resolve the name reference and the optional constraint into a pair. # 2. Type the left (0th) element of the tuple (which contains the referred # declaration). # 3. If the computed type is an IntRange and the constraint is a range # constraint, refine the IntRange. Else ignore the constraint and simply # return the previously computed type which is in the left (0th) element # of the tuple. return (resolved_name_and_constraint >> inner_typer.for_index(0) >> (when_constrained_range | Transformer.project(0)))
@Transformer.as_transformer def _eval_as_int(x): """ Given an arbitrary Ada node, tries to evaluate it to an integer. :param lal.AdaNode x: The node to evaluate :rtype: int | None """ try: return x.p_eval_as_int except (lal.PropertyError, lal.NativeException, OSError): return None _eval_as_real = ( Transformer.as_transformer(eval_as_real).catch(NotImplementedError) ) @types.delegating_typer def int_range_typer(): """ :return: A typer for int ranges. :rtype: types.Typer[lal.AdaNode] """ @Transformer.as_transformer def get_operands(hint): if hint.is_a(lal.TypeDecl): if hint.f_type_def.is_a(lal.SignedIntTypeDef): rng = hint.f_type_def.f_range.f_range
def provider(): return ( original_signature >> (Transformer.identity() & actual_interp.def_provider_builder) >> transform_implementation) | model_provider
def provider(): aggregate_provider = Transformer.first_of( *(p(provider) for p in def_provider_builders)) return (aggregate_provider if self.external_def_provider is None else (aggregate_provider | self.external_def_provider(provider)))