123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164(*
* Copyright (C) Cloud Software Group, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)(** [Typedtree] and [Primitive] have an unstable API (depends on compiler version),
so extract the parts we need and convert to types defined in this file.
If the build breaks with new compiler versions then only this module needs
to be updated (perhaps by using Dune's support to conditionally select
files based on compiler versions)
*)(** the C type of an argument *)typenative_arg=|Value(** an OCaml value *)|Double(** an unboxed double *)|Int32(** an unboxed int32 *)|Int64(** an unboxed int64 *)|Intnatof{untagged_int:bool}(** an unboxed intnat, @see <https://v2.ocaml.org/manual/intfc.html#ss:c-unboxed> on the use of [intnat]*)|Bytecode_argv(** bytecode argv when arity > 5 *)|Bytecode_argn(** number of arguments when arity > 5 for bytecode *)letnative_arg_of_primitivearg=letopenPrimitiveinmatchargwith|Same_as_ocaml_repr->Value|Unboxed_float->Double|Unboxed_integerPnativeint->Intnat{untagged_int=false}|Unboxed_integerPint32->Int32|Unboxed_integerPint64->Int64|Untagged_int->(* the range of this is one bit less than Pnativeint, but still same type on C side *)Intnat{untagged_int=true}(** [ctype_of_native_arg arg] returns the C type used when implementing
primitives for native code mode.
@see <https://v2.ocaml.org/manual/intfc.html#ss:c-unboxed> on the use of [intnat]*)letctype_of_native_arg=function|Value->"value"|Double->"double"|Int32->"int32_t"|Int64->"int64_t"|Intnat_->"intnat"|Bytecode_argv->"value *"|Bytecode_argn->"int"typet={byte_name:string(** name of C function implementing the primitive in bytecode mode *);native_name:string(** name of C function implementinmg the primitive in native code mode *);arity:int(** number of arguments to C function in native code mode *);alloc:bool(** whether it allocates/raises exceptions *);native_result:native_arg(** result type of the C function implementing the primitive in native code mode*);native_args:native_arglist(** type of the arguments of the C function implementing the primitive in native code mode *)}(** [with_report_exceptions f] will report any compiler-libs exceptions
escaping from [f] and exit the process with code 2. *)letwith_report_exceptionsf=tryf()withe->(* if there are any errors loading or processing the .cmt file,
or other exceptions escaping from compiler-libs this will report them properly *)Location.report_exceptionFormat.err_formattere;exit2(** [warning loc fmt] prints a warning at source location [loc],
with message format defined by [fmt].
This will issue a warning 22 (preprocessor).
*)letwarningloc=Printf.ksprintf@@funmsg->Location.prerr_warningloc(Preprocessormsg)(** [iter_primitives_exn ~path primitive_description] will load the .cmt/.cmti file
[path] and iterate on any primitives defined using [primitive_description].
Exceptions from compiler-libs may escape, so it is recommended to wrap calls
using [with_report_exceptions].
*)letiter_primitives_exn~pathf=letprimitive_descriptiontype_exprpd=letopenPrimitiveinifnative_name_is_externalpdthen(* only process primitives implemented by the user, not the ones defined
by the compiler itself *)lett={byte_name=byte_namepd;native_name=native_namepd;arity=pd.prim_arity;native_result=native_arg_of_primitivepd.prim_native_repr_res;alloc=pd.prim_alloc;native_args=List.mapnative_arg_of_primitivepd.prim_native_repr_args}inftype_exprtinletvalue_description_vd=letopenTypedtreeinletopenTypesinmatchvd.val_val.val_kindwith|Val_primprim->primitive_descriptionvd.val_val.val_typeprim|_->()inlettype_kind_tkind=letopenTypedtreeinmatchtkindwith|Ttype_abstract->()|Ttype_record_->()(* TODO *)|Ttype_variant_cnstr->()|Ttype_open->()inletopenTast_iteratorinletiterator={default_iteratorwithvalue_description;type_kind}inpath|>Cmt_format.read_cmt|>letopenCmt_formatinfunction|{cmt_annots=Implementationstructure;_}->iterator.structureiteratorstructure|{cmt_annots=Interfacesignature;_}->(* this won't find all primitives, because the interface is allowed to
hide the implementation detail by using 'val ...' instead of 'external ...'
*)warning(Location.in_filepath)"Loaded a .cmti file. May not contain all primitives";iterator.signatureiteratorsignature|_->invalid_arg"Could not find an implementation or interface in the .cmt/.cmti file"