ocaml/typing/primitive.ml

228 lines
7.7 KiB
OCaml

(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Description of primitive functions *)
open Misc
open Parsetree
type boxed_integer = Pnativeint | Pint32 | Pint64
type native_repr =
| Same_as_ocaml_repr
| Unboxed_float
| Unboxed_integer of boxed_integer
| Untagged_int
type description =
{ prim_name: string; (* Name of primitive or C function *)
prim_arity: int; (* Number of arguments *)
prim_alloc: bool; (* Does it allocates or raise? *)
prim_native_name: string; (* Name of C function for the nat. code gen. *)
prim_native_repr_args: native_repr list;
prim_native_repr_res: native_repr }
type error =
| Old_style_float_with_native_repr_attribute
| Old_style_noalloc_with_noalloc_attribute
| No_native_primitive_with_repr_attribute
exception Error of Location.t * error
let is_ocaml_repr = function
| Same_as_ocaml_repr -> true
| Unboxed_float
| Unboxed_integer _
| Untagged_int -> false
let is_unboxed = function
| Same_as_ocaml_repr
| Untagged_int -> false
| Unboxed_float
| Unboxed_integer _ -> true
let is_untagged = function
| Untagged_int -> true
| Same_as_ocaml_repr
| Unboxed_float
| Unboxed_integer _ -> false
let rec make_native_repr_args arity x =
if arity = 0 then
[]
else
x :: make_native_repr_args (arity - 1) x
let simple ~name ~arity ~alloc =
{prim_name = name;
prim_arity = arity;
prim_alloc = alloc;
prim_native_name = "";
prim_native_repr_args = make_native_repr_args arity Same_as_ocaml_repr;
prim_native_repr_res = Same_as_ocaml_repr}
let make ~name ~alloc ~native_name ~native_repr_args ~native_repr_res =
{prim_name = name;
prim_arity = List.length native_repr_args;
prim_alloc = alloc;
prim_native_name = native_name;
prim_native_repr_args = native_repr_args;
prim_native_repr_res = native_repr_res}
let parse_declaration valdecl ~native_repr_args ~native_repr_res =
let arity = List.length native_repr_args in
let name, native_name, old_style_noalloc, old_style_float =
match valdecl.pval_prim with
| name :: "noalloc" :: name2 :: "float" :: _ -> (name, name2, true, true)
| name :: "noalloc" :: name2 :: _ -> (name, name2, true, false)
| name :: name2 :: "float" :: _ -> (name, name2, false, true)
| name :: "noalloc" :: _ -> (name, "", true, false)
| name :: name2 :: _ -> (name, name2, false, false)
| name :: _ -> (name, "", false, false)
| [] ->
fatal_error "Primitive.parse_declaration"
in
let noalloc_attribute =
Attr_helper.has_no_payload_attribute ["noalloc"; "ocaml.noalloc"]
valdecl.pval_attributes
in
if old_style_float &&
not (List.for_all is_ocaml_repr native_repr_args &&
is_ocaml_repr native_repr_res) then
raise (Error (valdecl.pval_loc,
Old_style_float_with_native_repr_attribute));
if old_style_noalloc && noalloc_attribute then
raise (Error (valdecl.pval_loc,
Old_style_noalloc_with_noalloc_attribute));
(* The compiler used to assume "noalloc" with "float", we just make this
explicit now (GPR#167): *)
let old_style_noalloc = old_style_noalloc || old_style_float in
if old_style_float then
Location.deprecated valdecl.pval_loc
"[@@unboxed] + [@@noalloc] should be used\n\
instead of \"float\""
else if old_style_noalloc then
Location.deprecated valdecl.pval_loc
"[@@noalloc] should be used instead of \"noalloc\"";
if native_name = "" &&
not (List.for_all is_ocaml_repr native_repr_args &&
is_ocaml_repr native_repr_res) then
raise (Error (valdecl.pval_loc,
No_native_primitive_with_repr_attribute));
let noalloc = old_style_noalloc || noalloc_attribute in
let native_repr_args, native_repr_res =
if old_style_float then
(make_native_repr_args arity Unboxed_float, Unboxed_float)
else
(native_repr_args, native_repr_res)
in
{prim_name = name;
prim_arity = arity;
prim_alloc = not noalloc;
prim_native_name = native_name;
prim_native_repr_args = native_repr_args;
prim_native_repr_res = native_repr_res}
open Outcometree
let rec add_native_repr_attributes ty attrs =
match ty, attrs with
| Otyp_arrow (label, a, b), attr_opt :: rest ->
let b = add_native_repr_attributes b rest in
let a =
match attr_opt with
| None -> a
| Some attr -> Otyp_attribute (a, attr)
in
Otyp_arrow (label, a, b)
| _, [Some attr] -> Otyp_attribute (ty, attr)
| _ ->
assert (List.for_all (fun x -> x = None) attrs);
ty
let oattr_unboxed = { oattr_name = "unboxed" }
let oattr_untagged = { oattr_name = "untagged" }
let oattr_noalloc = { oattr_name = "noalloc" }
let print p osig_val_decl =
let prims =
if p.prim_native_name <> "" then
[p.prim_name; p.prim_native_name]
else
[p.prim_name]
in
let for_all f =
List.for_all f p.prim_native_repr_args && f p.prim_native_repr_res
in
let all_unboxed = for_all is_unboxed in
let all_untagged = for_all is_untagged in
let attrs = if p.prim_alloc then [] else [oattr_noalloc] in
let attrs =
if all_unboxed then
oattr_unboxed :: attrs
else if all_untagged then
oattr_untagged :: attrs
else
attrs
in
let attr_of_native_repr = function
| Same_as_ocaml_repr -> None
| Unboxed_float
| Unboxed_integer _ -> if all_unboxed then None else Some oattr_unboxed
| Untagged_int -> if all_untagged then None else Some oattr_untagged
in
let type_attrs =
List.map attr_of_native_repr p.prim_native_repr_args @
[attr_of_native_repr p.prim_native_repr_res]
in
{ osig_val_decl with
oval_prims = prims;
oval_type = add_native_repr_attributes osig_val_decl.oval_type type_attrs;
oval_attributes = attrs }
let native_name p =
if p.prim_native_name <> ""
then p.prim_native_name
else p.prim_name
let byte_name p =
p.prim_name
let native_name_is_external p =
let nat_name = native_name p in
nat_name <> "" && nat_name.[0] <> '%'
let report_error ppf err =
match err with
| Old_style_float_with_native_repr_attribute ->
Format.fprintf ppf "Cannot use \"float\" in conjunction with \
[%@unboxed]/[%@untagged]."
| Old_style_noalloc_with_noalloc_attribute ->
Format.fprintf ppf "Cannot use \"noalloc\" in conjunction with \
[%@%@noalloc]."
| No_native_primitive_with_repr_attribute ->
Format.fprintf ppf
"[@The native code version of the primitive is mandatory@ \
when attributes [%@untagged] or [%@unboxed] are present.@]"
let () =
Location.register_error_of_exn
(function
| Error (loc, err) ->
Some (Location.error_of_printer ~loc report_error err)
| _ ->
None
)