123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453# 1 "lambda/translattribute.ml"(**************************************************************************)(* *)(* OCaml *)(* *)(* Pierre Chambart, OCamlPro *)(* *)(* Copyright 2015 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. *)(* *)(**************************************************************************)openTypedtreeopenLambdaopenLocationletis_inline_attribute=function|{txt=("inline"|"ocaml.inline")}->true|_->falseletis_inlined_attribute=function|{txt=("inlined"|"ocaml.inlined")}->true|{txt=("unrolled"|"ocaml.unrolled")}whenConfig.flambda->true|_->falseletis_specialise_attribute=function|{txt=("specialise"|"ocaml.specialise")}whenConfig.flambda->true|_->falseletis_specialised_attribute=function|{txt=("specialised"|"ocaml.specialised")}whenConfig.flambda->true|_->falseletis_local_attribute=function|{txt=("local"|"ocaml.local")}->true|_->falseletis_tmc_attribute=function|{txt=("tail_mod_cons"|"ocaml.tail_mod_cons")}->true|_->falseletis_poll_attribute=function|{txt=("poll")}->true|_->falseletfind_attributepattributes=letinline_attribute,other_attributes=List.partition(funa->pa.Parsetree.attr_name)attributesinletattr=matchinline_attributewith|[]->None|[attr]->Someattr|_::{Parsetree.attr_name={txt;loc};_}::_->Location.prerr_warningloc(Warnings.Duplicated_attributetxt);Noneinattr,other_attributesletis_unrolled=function|{txt="unrolled"|"ocaml.unrolled"}->true|{txt="inline"|"ocaml.inline"|"inlined"|"ocaml.inlined"}->false|_->assertfalseletget_payloadget_from_exp=letopenParsetreeinfunction|PStr[{pstr_desc=Pstr_eval(exp,[])}]->get_from_expexp|_->Result.Error()letget_optional_payloadget_from_exp=letopenParsetreeinfunction|PStr[]->Result.OkNone|other->Result.mapOption.some(get_payloadget_from_expother)letget_id_from_exp=letopenParsetreeinfunction|{pexp_desc=Pexp_ident{txt=Longident.Lidentid}}->Result.Okid|_->Result.Error()letget_int_from_exp=letopenParsetreeinfunction|{pexp_desc=Pexp_constant(Pconst_integer(s,None))}->beginmatchMisc.Int_literal_converter.intswith|n->Result.Okn|exception(Failure_)->Result.Error()end|_->Result.Error()letget_construct_from_exp=letopenParsetreeinfunction|{pexp_desc=Pexp_construct({txt=Longident.Lidentconstr},None)}->Result.Okconstr|_->Result.Error()letget_bool_from_expexp=Result.bind(get_construct_from_expexp)(function|"true"->Result.Oktrue|"false"->Result.Okfalse|_->Result.Error())letparse_id_payloadtxtloc~default~emptycasespayload=let[@local]warn()=let(%>)fgx=g(fx)inletmsg=cases|>List.map(fst%>Printf.sprintf"'%s'")|>String.concat", "|>Printf.sprintf"It must be either %s or empty"inLocation.prerr_warningloc(Warnings.Attribute_payload(txt,msg));defaultinmatchget_optional_payloadget_id_from_exppayloadwith|Error()->warn()|OkNone->empty|Ok(Someid)->matchList.assoc_optidcaseswith|Somer->r|None->warn()letparse_inline_attributeattr=matchattrwith|None->Default_inline|Some{Parsetree.attr_name={txt;loc}asid;attr_payload=payload}->ifis_unrolledidthenbegin(* the 'unrolled' attributes must be used as [@unrolled n]. *)letwarningtxt=Warnings.Attribute_payload(txt,"It must be an integer literal")inmatchget_payloadget_int_from_exppayloadwith|Okn->Unrolln|Error()->Location.prerr_warningloc(warningtxt);Default_inlineendelseparse_id_payloadtxtloc~default:Default_inline~empty:Always_inline["never",Never_inline;"always",Always_inline;"hint",Hint_inline;]payloadletparse_specialise_attributeattr=matchattrwith|None->Default_specialise|Some{Parsetree.attr_name={txt;loc};attr_payload=payload}->parse_id_payloadtxtloc~default:Default_specialise~empty:Always_specialise["never",Never_specialise;"always",Always_specialise;]payloadletparse_local_attributeattr=matchattrwith|None->Default_local|Some{Parsetree.attr_name={txt;loc};attr_payload=payload}->parse_id_payloadtxtloc~default:Default_local~empty:Always_local["never",Never_local;"always",Always_local;"maybe",Default_local;]payloadletparse_poll_attributeattr=matchattrwith|None->Default_poll|Some{Parsetree.attr_name={txt;loc};attr_payload=payload}->parse_id_payloadtxtloc~default:Default_poll~empty:Default_poll["error",Error_poll;]payloadletget_inline_attributel=letattr,_=find_attributeis_inline_attributelinparse_inline_attributeattrletget_specialise_attributel=letattr,_=find_attributeis_specialise_attributelinparse_specialise_attributeattrletget_local_attributel=letattr,_=find_attributeis_local_attributelinparse_local_attributeattrletget_poll_attributel=letattr,_=find_attributeis_poll_attributelinparse_poll_attributeattrletcheck_local_inlinelocattr=matchattr.local,attr.inlinewith|Always_local,(Always_inline|Hint_inline|Unroll_)->Location.prerr_warningloc(Warnings.Duplicated_attribute"local/inline")|_->()letcheck_poll_inlinelocattr=matchattr.poll,attr.inlinewith|Error_poll,(Always_inline|Hint_inline|Unroll_)->Location.prerr_warningloc(Warnings.Inlining_impossible"[@poll error] is incompatible with inlining")|_->()letcheck_poll_locallocattr=matchattr.poll,attr.localwith|Error_poll,Always_local->Location.prerr_warningloc(Warnings.Inlining_impossible"[@poll error] is incompatible with local function optimization")|_->()letlfunction_with_attr~attr{kind;params;return;body;attr=_;loc}=lfunction~kind~params~return~body~attr~locletadd_inline_attributeexprlocattributes=matchexpr,get_inline_attributeattributeswith|expr,Default_inline->expr|Lfunction({attr={stub=false}asattr}asfunct),inline->beginmatchattr.inlinewith|Default_inline->()|Always_inline|Hint_inline|Never_inline|Unroll_->Location.prerr_warningloc(Warnings.Duplicated_attribute"inline")end;letattr={attrwithinline}incheck_local_inlinelocattr;check_poll_inlinelocattr;lfunction_with_attr~attrfunct|expr,(Always_inline|Hint_inline|Never_inline|Unroll_)->Location.prerr_warningloc(Warnings.Misplaced_attribute"inline");exprletadd_specialise_attributeexprlocattributes=matchexpr,get_specialise_attributeattributeswith|expr,Default_specialise->expr|Lfunction({attr={stub=false}asattr}asfunct),specialise->beginmatchattr.specialisewith|Default_specialise->()|Always_specialise|Never_specialise->Location.prerr_warningloc(Warnings.Duplicated_attribute"specialise")end;letattr={attrwithspecialise}inlfunction_with_attr~attrfunct|expr,(Always_specialise|Never_specialise)->Location.prerr_warningloc(Warnings.Misplaced_attribute"specialise");exprletadd_local_attributeexprlocattributes=matchexpr,get_local_attributeattributeswith|expr,Default_local->expr|Lfunction({attr={stub=false}asattr}asfunct),local->beginmatchattr.localwith|Default_local->()|Always_local|Never_local->Location.prerr_warningloc(Warnings.Duplicated_attribute"local")end;letattr={attrwithlocal}incheck_local_inlinelocattr;check_poll_locallocattr;lfunction_with_attr~attrfunct|expr,(Always_local|Never_local)->Location.prerr_warningloc(Warnings.Misplaced_attribute"local");exprletadd_tmc_attributeexprlocattributes=letis_tmc_attributea=is_tmc_attributea.Parsetree.attr_nameinifList.existsis_tmc_attributeattributesthenmatchexprwith|Lfunctionfunct->iffunct.attr.tmc_candidatethenLocation.prerr_warningloc(Warnings.Duplicated_attribute"tail_mod_cons");letattr={funct.attrwithtmc_candidate=true}inlfunction_with_attr~attrfunct|expr->Location.prerr_warningloc(Warnings.Misplaced_attribute"tail_mod_cons");exprelseexprletadd_poll_attributeexprlocattributes=matchexpr,get_poll_attributeattributeswith|expr,Default_poll->expr|Lfunction({attr={stub=false}asattr}asfunct),poll->beginmatchattr.pollwith|Default_poll->()|Error_poll->Location.prerr_warningloc(Warnings.Duplicated_attribute"error_poll")end;letattr={attrwithpoll}incheck_poll_inlinelocattr;check_poll_locallocattr;letattr={attrwithinline=Never_inline;local=Never_local}inlfunction_with_attr~attrfunct|expr,Error_poll->Location.prerr_warningloc(Warnings.Misplaced_attribute"error_poll");expr(* Get the [@inlined] attribute payload (or default if not present).
It also returns the expression without this attribute. This is
used to ensure that this attribute is not misplaced: If it
appears on any expression, it is an error, otherwise it would
have been removed by this function *)letget_and_remove_inlined_attributee=letattr,exp_attributes=find_attributeis_inlined_attributee.exp_attributesinletinlined=parse_inline_attributeattrininlined,{ewithexp_attributes}letget_and_remove_inlined_attribute_on_modulee=letrecget_and_removemod_expr=letattr,mod_attributes=find_attributeis_inlined_attributemod_expr.mod_attributesinletattr=parse_inline_attributeattrinletattr,mod_desc=matchmod_expr.Typedtree.mod_descwith|Tmod_constraint(me,mt,mtc,mc)->letinner_attr,me=get_and_removemeinletattr=matchattrwith|Always_inline|Hint_inline|Never_inline|Unroll_->attr|Default_inline->inner_attrinattr,Tmod_constraint(me,mt,mtc,mc)|md->attr,mdinattr,{mod_exprwithmod_desc;mod_attributes}inget_and_removeeletget_and_remove_specialised_attributee=letattr,exp_attributes=find_attributeis_specialised_attributee.exp_attributesinletspecialised=parse_specialise_attributeattrinspecialised,{ewithexp_attributes}(* It also removes the attribute from the expression, like
get_inlined_attribute *)letget_tailcall_attributee=letis_tailcall_attribute=function|{Parsetree.attr_name={txt=("tailcall"|"ocaml.tailcall")};_}->true|_->falseinlettailcalls,other_attributes=List.partitionis_tailcall_attributee.exp_attributesinlettailcall_attribute=matchtailcallswith|[]->Default_tailcall|{Parsetree.attr_name={txt;loc};attr_payload=payload}::r->beginmatchrwith|[]->()|{Parsetree.attr_name={txt;loc};_}::_->Location.prerr_warningloc(Warnings.Duplicated_attributetxt)end;matchget_optional_payloadget_bool_from_exppayloadwith|Ok(None|Sometrue)->Tailcall_expectationtrue|Ok(Somefalse)->Tailcall_expectationfalse|Error()->letmsg="Only an optional boolean literal is supported."inLocation.prerr_warningloc(Warnings.Attribute_payload(txt,msg));Default_tailcallintailcall_attribute,{ewithexp_attributes=other_attributes}letcheck_attributee{Parsetree.attr_name={txt;loc};_}=matchtxtwith|"inline"|"ocaml.inline"|"specialise"|"ocaml.specialise"|"poll"->beginmatche.exp_descwith|Texp_function_->()|_->Location.prerr_warningloc(Warnings.Misplaced_attributetxt)end|"inlined"|"ocaml.inlined"|"specialised"|"ocaml.specialised"|"tailcall"|"ocaml.tailcall"->(* Removed by the Texp_apply cases *)Location.prerr_warningloc(Warnings.Misplaced_attributetxt)|_->()letcheck_attribute_on_modulee{Parsetree.attr_name={txt;loc};_}=matchtxtwith|"inline"|"ocaml.inline"->beginmatche.mod_descwith|Tmod_functor_->()|_->Location.prerr_warningloc(Warnings.Misplaced_attributetxt)end|"inlined"|"ocaml.inlined"->(* Removed by the Texp_apply cases *)Location.prerr_warningloc(Warnings.Misplaced_attributetxt)|_->()letadd_function_attributeslamlocattr=letlam=add_inline_attributelamlocattrinletlam=add_specialise_attributelamlocattrinletlam=add_local_attributelamlocattrinletlam=add_tmc_attributelamlocattrinletlam=(* last because poll overrides inline and local *)add_poll_attributelamlocattrinlam