1 /* Copyright (c) 1997-2021
2    Ewgenij Gawrilow, Michael Joswig, and the polymake team
3    Technische Universität Berlin, Germany
4    https://polymake.org
5 
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version: http://www.gnu.org/licenses/gpl.txt.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 --------------------------------------------------------------------------------
16 */
17 
18 #include "polymake/perl/glue.h"
19 
20 namespace pm { namespace perl {
21 
set_descr(const std::type_info & ti)22 bool type_infos::set_descr(const std::type_info& ti)
23 {
24    dTHX;
25    const char* const type_name = ti.name();
26    if (SV** const descr_p = hv_fetch((HV*)SvRV(PmArray(GvSV(glue::CPP_root))[glue::CPP_typeids_index]),
27                                      type_name, I32(strlen(type_name)), false)) {
28       descr = *descr_p;
29       return true;
30    }
31    return false;
32 }
33 
set_descr()34 void type_infos::set_descr()
35 {
36    dTHX;
37    SV* const opts = PmArray(proto)[glue::PropertyType_cppoptions_index];
38    if (SvROK(opts)) {
39       descr = PmArray(opts)[glue::CPPOptions_descr_index];
40       if (!SvROK(descr)) {
41          descr = nullptr;
42       } else if (SvTYPE(SvRV(descr)) == SVt_PVCV) {
43          PmStartFuncall(0);
44          const int ret = call_sv(descr, G_VOID | G_EVAL);
45          if (__builtin_expect(ret>0, 0)) {
46             descr = nullptr;
47             PmFuncallFailed;
48          }
49          FREETMPS; LEAVE;
50          descr = PmArray(opts)[glue::CPPOptions_descr_index];
51       }
52    }
53 }
54 
set_proto(SV * known_proto)55 void type_infos::set_proto(SV* known_proto)
56 {
57    dTHX;
58    if (known_proto) {
59       proto = newSVsv(known_proto);
60    } else {
61       SV** type_gvp = hv_fetch((HV*)SvRV(PmArray(descr)[glue::TypeDescr_pkg_index]), "type", 4, false);
62       if (type_gvp) {
63          PmStartFuncall(0);
64          proto = glue::call_func_scalar(aTHX_ *type_gvp, true);
65       } else {
66          return;
67       }
68    }
69    SV* opts = PmArray(proto)[glue::PropertyType_cppoptions_index];
70    if (SvROK(opts)) {
71       SV* builtin = PmArray(opts)[glue::CPPOptions_builtin_index];
72       magic_allowed = !SvTRUE(builtin);
73    }
74 }
75 
set_proto_with_prescribed_pkg(SV * prescribed_pkg,SV * app_stash_ref,const std::type_info & ti,SV * super_proto)76 void type_infos::set_proto_with_prescribed_pkg(SV* prescribed_pkg, SV* app_stash_ref, const std::type_info& ti, SV* super_proto)
77 {
78    dTHX;
79    PmStartFuncall(3);
80    PUSHs(prescribed_pkg);
81    const char* const type_name = ti.name();
82    mPUSHp(type_name, strlen(type_name));
83    if (super_proto) PUSHs(super_proto);
84    PUTBACK;
85    proto = glue::call_func_scalar(aTHX_ glue::fetch_typeof_gv(aTHX_ (HV*)SvRV(app_stash_ref), SvPVX(prescribed_pkg), SvCUR(prescribed_pkg)), true);
86    magic_allowed = true;
87 }
88 
89 namespace {
90 SV* resolve_auto_function_cv=nullptr;
91 }
92 
get_function_wrapper(SV * src,SV * dst_descr,int auto_func_index)93 char* type_cache_base::get_function_wrapper(SV* src, SV* dst_descr, int auto_func_index)
94 {
95    dTHX; dSP;
96    SV* auto_func = PmArray(GvSV(glue::CPP_root))[auto_func_index];
97    char* ret = nullptr;
98    if (!resolve_auto_function_cv)
99       resolve_auto_function_cv = (SV*)get_cv("Polymake::Core::CPlusPlus::resolve_auto_function", FALSE);
100 
101    AV* fake_args = newAV();
102    av_extend(fake_args, 2);
103    AvFILLp(fake_args) = 1;
104    AvREAL_off(fake_args);
105    SV* fake_args_ref = newRV_noinc((SV*)fake_args);
106 
107    ENTER; SAVETMPS;
108    PUSHMARK(SP);
109    XPUSHs(auto_func);
110    AvARRAY(fake_args)[0] = dst_descr;
111    AvARRAY(fake_args)[1] = src;
112    XPUSHs(fake_args_ref);
113    PUTBACK;
114    call_sv(resolve_auto_function_cv, G_SCALAR | G_EVAL);
115    SPAGAIN;
116    SV* cv = POPs;
117    if (SvROK(cv) && (cv = SvRV(cv), CvISXSUB(cv))) {
118       AV* func_descr = (AV*)CvXSUBANY(cv).any_ptr;
119       ret = reinterpret_cast<char*>(AvARRAY(func_descr)[glue::FuncDescr_wrapper_index]);
120    }
121    PUTBACK; FREETMPS; LEAVE;
122    SvREFCNT_dec(fake_args_ref);
123 
124    if (__builtin_expect(SvTRUE(ERRSV), 0))
125       throw exception();
126    return ret;
127 }
128 
get_conversion_operator(SV * src,SV * dst_descr)129 char* type_cache_base::get_conversion_operator(SV* src, SV* dst_descr)
130 {
131    return dst_descr ? get_function_wrapper(src, dst_descr, glue::CPP_auto_conversion_index) : nullptr;
132 }
133 
get_assignment_operator(SV * src,SV * dst_descr)134 char* type_cache_base::get_assignment_operator(SV* src, SV* dst_descr)
135 {
136    return dst_descr ? get_function_wrapper(src, dst_descr, glue::CPP_auto_assignment_index) : nullptr;
137 }
138 
139 namespace {
140 
141 inline
perl_error_text()142 const char* perl_error_text()
143 {
144    dTHX;
145    return SvPV_nolen(ERRSV);
146 }
147 
148 }
149 
exception()150 exception::exception() :
151    std::runtime_error(perl_error_text()) {}
152 
153 } }
154 
155 // Local Variables:
156 // mode:C++
157 // c-basic-offset:3
158 // indent-tabs-mode:nil
159 // End:
160