1 |
|
|
#include <string.h> |
2 |
|
|
#include "gwion_util.h" |
3 |
|
|
#include "gwion_ast.h" |
4 |
|
|
#include "gwion_env.h" |
5 |
|
|
#include "vm.h" |
6 |
|
|
#include "gwion.h" |
7 |
|
|
#include "instr.h" |
8 |
|
|
#include "emit.h" |
9 |
|
|
#include "object.h" |
10 |
|
|
#include "operator.h" |
11 |
|
|
#include "import.h" |
12 |
|
|
#include "traverse.h" |
13 |
|
|
#include "template.h" |
14 |
|
|
#include "parse.h" |
15 |
|
|
|
16 |
|
73 |
static OP_CHECK(opck_func_call) { |
17 |
|
73 |
Exp_Binary* bin = (Exp_Binary*)data; |
18 |
|
73 |
Exp_Call call = { .func=bin->rhs, .args=bin->lhs }; |
19 |
|
73 |
Exp e = exp_self(bin); |
20 |
|
73 |
e->exp_type = ae_exp_call; |
21 |
|
73 |
memcpy(&e->d.exp_call, &call, sizeof(Exp_Call)); |
22 |
|
73 |
++*mut; |
23 |
✓✓ |
73 |
return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_null]; |
24 |
|
|
} |
25 |
|
|
|
26 |
|
10 |
static inline void fptr_instr(const Emitter emit, const Func f, const m_uint i) { |
27 |
|
10 |
const Instr set = emit_add_instr(emit, RegSetImm); |
28 |
|
10 |
set->m_val = (m_uint)f; |
29 |
|
10 |
set->m_val2 = -SZ_INT*i; |
30 |
|
10 |
} |
31 |
|
|
|
32 |
|
35 |
static OP_EMIT(opem_func_assign) { |
33 |
|
35 |
Exp_Binary* bin = (Exp_Binary*)data; |
34 |
✓✓ |
35 |
if(bin->rhs->info->type->e->d.func->def->base->tmpl) |
35 |
|
8 |
fptr_instr(emit, bin->lhs->info->type->e->d.func, 2); |
36 |
|
35 |
const Instr instr = emit_add_instr(emit, int_r_assign); |
37 |
✓✓✓✓
|
35 |
if(!is_fptr(emit->gwion, bin->lhs->info->type) && GET_FLAG(bin->rhs->info->type->e->d.func, member)) { |
38 |
|
20 |
const Instr pop = emit_add_instr(emit, RegPop); |
39 |
|
20 |
pop->m_val = SZ_INT; |
40 |
|
20 |
const Instr cpy = emit_add_instr(emit, Reg2Reg); |
41 |
|
20 |
cpy->m_val = -SZ_INT; |
42 |
|
|
} |
43 |
|
35 |
return instr; |
44 |
|
|
} |
45 |
|
|
|
46 |
|
|
struct FptrInfo { |
47 |
|
|
Func lhs; |
48 |
|
|
const Func rhs; |
49 |
|
|
const Exp exp; |
50 |
|
|
const loc_t pos; |
51 |
|
|
}; |
52 |
|
|
|
53 |
|
50 |
ANN static m_bool fptr_tmpl_push(const Env env, struct FptrInfo *info) { |
54 |
✓✓ |
50 |
if(!info->rhs->def->base->tmpl) |
55 |
|
35 |
return GW_OK; |
56 |
|
15 |
ID_List t0 = info->lhs->def->base->tmpl->list, |
57 |
|
15 |
t1 = info->rhs->def->base->tmpl->list; |
58 |
|
15 |
nspc_push_type(env->gwion->mp, env->curr); |
59 |
✓✓ |
45 |
while(t0) { |
60 |
|
15 |
nspc_add_type(env->curr, t0->xid, env->gwion->type[et_undefined]); |
61 |
|
15 |
nspc_add_type(env->curr, t1->xid, env->gwion->type[et_undefined]); |
62 |
|
15 |
t0 = t0->next; |
63 |
|
15 |
t1 = t1->next; |
64 |
|
|
} |
65 |
|
15 |
return GW_OK; |
66 |
|
|
} |
67 |
|
|
|
68 |
|
66 |
static m_bool td_match(const Env env, Type_Decl *id[2]) { |
69 |
✗✓ |
66 |
DECL_OB(const Type, t0, = known_type(env, id[0])) |
70 |
✗✓ |
66 |
DECL_OB(const Type, t1, = known_type(env, id[1])) |
71 |
|
66 |
return isa(t0, t1); |
72 |
|
|
} |
73 |
|
|
|
74 |
|
50 |
ANN static m_bool fptr_args(const Env env, Func_Base *base[2]) { |
75 |
|
50 |
Arg_List arg0 = base[0]->args, arg1 = base[1]->args; |
76 |
✓✓ |
116 |
while(arg0) { |
77 |
✓✓ |
26 |
CHECK_OB(arg1) |
78 |
|
16 |
Type_Decl* td[2] = { arg0->td, arg1->td }; |
79 |
✗✓ |
16 |
CHECK_BB(td_match(env, td)) |
80 |
|
16 |
arg0 = arg0->next; |
81 |
|
16 |
arg1 = arg1->next; |
82 |
|
|
} |
83 |
✓✓ |
45 |
return !arg1 ? GW_OK : GW_ERROR; |
84 |
|
|
} |
85 |
|
|
|
86 |
|
51 |
ANN static m_bool fptr_check(const Env env, struct FptrInfo *info) { |
87 |
✗✓ |
51 |
if(!info->lhs->def->base->tmpl != !info->rhs->def->base->tmpl) |
88 |
|
|
return GW_ERROR; |
89 |
|
51 |
const Type l_type = info->lhs->value_ref->from->owner_class; |
90 |
|
51 |
const Type r_type = info->rhs->value_ref->from->owner_class; |
91 |
✓✓✓✓
|
51 |
if(!r_type && l_type) |
92 |
|
1 |
ERR_B(info->pos, _("can't assign member function to non member function pointer")) |
93 |
✓✓✓✓
|
50 |
else if(!l_type && r_type) { |
94 |
✓✗ |
1 |
if(!GET_FLAG(info->rhs, global)) |
95 |
|
1 |
ERR_B(info->pos, _("can't assign non member function to member function pointer")) |
96 |
✓✓✓✓
|
49 |
} else if(l_type && isa(r_type, l_type) < 0) |
97 |
|
1 |
ERR_B(info->pos, _("can't assign member function to a pointer of an other class")) |
98 |
✓✓ |
48 |
if(GET_FLAG(info->rhs, member)) { |
99 |
✓✓ |
23 |
if(!GET_FLAG(info->lhs, member)) |
100 |
|
1 |
ERR_B(info->pos, _("can't assign static function to member function pointer")) |
101 |
✓✓ |
25 |
} else if(GET_FLAG(info->lhs, member)) |
102 |
|
2 |
ERR_B(info->pos, _("can't assign member function to static function pointer")) |
103 |
|
45 |
return GW_OK; |
104 |
|
|
} |
105 |
|
|
|
106 |
|
50 |
ANN static inline m_bool fptr_rettype(const Env env, struct FptrInfo *info) { |
107 |
|
100 |
Type_Decl* td[2] = { info->lhs->def->base->td, |
108 |
|
50 |
info->rhs->def->base->td }; |
109 |
|
50 |
return td_match(env, td); |
110 |
|
|
} |
111 |
|
|
|
112 |
|
50 |
ANN static inline m_bool fptr_arity(struct FptrInfo *info) { |
113 |
|
100 |
return GET_FLAG(info->lhs->def, variadic) == |
114 |
|
50 |
GET_FLAG(info->rhs->def, variadic); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
45 |
ANN static Type fptr_type(const Env env, struct FptrInfo *info) { |
118 |
|
45 |
const Value v = info->lhs->value_ref; |
119 |
|
45 |
const Nspc nspc = v->from->owner; |
120 |
|
45 |
const m_str c = s_name(info->lhs->def->base->xid), |
121 |
✓✓ |
45 |
stmpl = !info->rhs->def->base->tmpl ? NULL : "template"; |
122 |
|
45 |
Type type = NULL; |
123 |
✓✓✓✓
|
190 |
for(m_uint i = 0; i <= v->from->offset && !type; ++i) { |
124 |
✗✓ |
115 |
const Symbol sym = (!info->lhs->def->base->tmpl || i != 0) ? |
125 |
✓✓ |
85 |
func_symbol(env, nspc->name, c, stmpl, i) : info->lhs->def->base->xid; |
126 |
✓✓ |
50 |
if(!is_class(env->gwion, info->lhs->value_ref->type)) |
127 |
✗✓ |
49 |
CHECK_OO((info->lhs = nspc_lookup_func1(nspc, sym))) |
128 |
|
|
else { |
129 |
✗✓ |
1 |
DECL_OO(const Type, t, = nspc_lookup_type1(nspc, info->lhs->def->base->xid)) |
130 |
|
1 |
info->lhs = actual_type(env->gwion, t)->e->d.func; |
131 |
|
|
} |
132 |
|
50 |
Func_Base *base[2] = { info->lhs->def->base, info->rhs->def->base }; |
133 |
✓✗ |
50 |
if(fptr_tmpl_push(env, info) > 0) { |
134 |
✓✗✓✗
|
100 |
if(fptr_rettype(env, info) > 0 && |
135 |
✓✓ |
100 |
fptr_arity(info) && fptr_args(env, base) > 0) |
136 |
✓✗ |
44 |
type = actual_type(env->gwion, info->lhs->value_ref->type) ?: info->lhs->value_ref->type; |
137 |
✓✓ |
50 |
if(info->rhs->def->base->tmpl) |
138 |
|
15 |
nspc_pop_type(env->gwion->mp, env->curr); |
139 |
|
|
} |
140 |
|
|
} |
141 |
|
45 |
return type; |
142 |
|
|
} |
143 |
|
|
|
144 |
|
7 |
ANN static m_bool _check_lambda(const Env env, Exp_Lambda *l, const Func_Def def) { |
145 |
|
7 |
Arg_List base = def->base->args, arg = l->def->base->args; |
146 |
✓✓✓✗
|
20 |
while(base && arg) { |
147 |
|
6 |
arg->td = base->td; |
148 |
|
6 |
base = base->next; |
149 |
|
6 |
arg = arg->next; |
150 |
|
|
} |
151 |
✓✗✓✓
|
7 |
if(base || arg) |
152 |
|
2 |
ERR_B(exp_self(l)->pos, _("argument number does not match for lambda")) |
153 |
|
5 |
l->def->flag = def->flag; |
154 |
|
5 |
l->def->base->td = cpy_type_decl(env->gwion->mp, def->base->td); |
155 |
|
5 |
SET_FLAG(l->def, abstract); // mark as non immediate lambda |
156 |
|
5 |
map_set(&env->curr->info->func->map, (m_uint)l->def->base, env->scope->depth); |
157 |
|
5 |
const m_bool ret = check_traverse_fdef(env, l->def); |
158 |
|
5 |
map_remove(&env->curr->info->func->map, (m_uint)l->def->base); |
159 |
✗✓ |
5 |
CHECK_BB(ret) |
160 |
|
5 |
arg = l->def->base->args; |
161 |
✓✓ |
14 |
while(arg) { |
162 |
|
4 |
arg->td = NULL; |
163 |
|
4 |
arg = arg->next; |
164 |
|
|
} |
165 |
|
5 |
return GW_OK; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
7 |
ANN m_bool check_lambda(const Env env, const Type t, Exp_Lambda *l) { |
169 |
|
7 |
const Func_Def fdef = t->e->d.func->def; |
170 |
|
14 |
struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)check_cdef, |
171 |
|
7 |
.scope=env->scope->depth, .flag=ae_flag_check }; |
172 |
|
7 |
l->owner = t->e->owner_class; |
173 |
✗✓ |
7 |
CHECK_BB(envset_push(&es, l->owner, t->e->owner)) |
174 |
|
7 |
const m_bool ret = _check_lambda(env, l, fdef); |
175 |
✗✓ |
7 |
if(es.run) |
176 |
|
|
envset_pop(&es, l->owner); |
177 |
✓✓ |
7 |
if(ret < 0) |
178 |
|
2 |
return GW_ERROR; |
179 |
|
5 |
exp_self(l)->info->type = l->def->base->func->value_ref->type; |
180 |
|
5 |
return GW_OK; |
181 |
|
|
} |
182 |
|
|
|
183 |
|
57 |
ANN static m_bool fptr_do(const Env env, struct FptrInfo *info) { |
184 |
✓✓ |
57 |
if(isa(info->exp->info->type, env->gwion->type[et_lambda]) < 0) { |
185 |
|
51 |
m_bool nonnull = GET_FLAG(info->exp->info->type, nonnull); |
186 |
✓✓ |
51 |
CHECK_BB(fptr_check(env, info)) |
187 |
✓✓ |
45 |
DECL_OB(const Type, t, = fptr_type(env, info)) |
188 |
✗✓ |
44 |
info->exp->info->type = !nonnull ? t : nonnul_type(env, t); |
189 |
|
44 |
return GW_OK; |
190 |
|
|
} |
191 |
|
6 |
Exp_Lambda *l = &info->exp->d.exp_lambda; |
192 |
|
6 |
return check_lambda(env, actual_type(env->gwion, info->rhs->value_ref->type), l); |
193 |
|
|
} |
194 |
|
|
|
195 |
|
1 |
static OP_CHECK(opck_auto_fptr) { |
196 |
|
1 |
const Exp_Binary* bin = (Exp_Binary*)data; |
197 |
|
|
// we'll only deal with auto fptr declaration |
198 |
✗✓✗✗
|
1 |
if(bin->rhs->exp_type != ae_exp_decl && bin->rhs->d.exp_decl.td->xid != insert_symbol("auto")) |
199 |
|
|
return env->gwion->type[et_null]; |
200 |
|
|
// create a matching signature |
201 |
|
|
// TODO: we could check first if there a matching existing one |
202 |
|
1 |
Func_Base *const fbase = cpy_func_base(env->gwion->mp, bin->lhs->info->type->e->d.func->def->base); |
203 |
|
1 |
const Fptr_Def fptr_def = new_fptr_def(env->gwion->mp, fbase, bin->lhs->info->type->e->d.func->def->flag); |
204 |
|
1 |
m_str name = NULL; |
205 |
|
1 |
asprintf(&name, "generated@%u:%u", bin->rhs->pos->first.line, bin->rhs->pos->first.column); |
206 |
|
1 |
fptr_def->base->xid = insert_symbol(name); |
207 |
|
1 |
free(name); |
208 |
|
1 |
const m_bool ret = traverse_fptr_def(env, fptr_def); |
209 |
|
1 |
const Type t = fptr_def->type; |
210 |
|
1 |
free_fptr_def(env->gwion->mp, fptr_def); |
211 |
|
1 |
REM_REF(t, env->gwion) |
212 |
✗✓ |
1 |
return ret > 0 ? t : env->gwion->type[et_null]; |
213 |
|
|
} |
214 |
|
|
|
215 |
|
49 |
static OP_CHECK(opck_fptr_at) { |
216 |
|
49 |
Exp_Binary* bin = (Exp_Binary*)data; |
217 |
✓✓✓✓
|
62 |
if(bin->rhs->info->type->e->d.func->def->base->tmpl && |
218 |
|
13 |
bin->rhs->info->type->e->d.func->def->base->tmpl->call) { |
219 |
|
27 |
struct FptrInfo info = { bin->lhs->info->type->e->d.func, bin->rhs->info->type->e->parent->e->d.func, |
220 |
|
18 |
bin->lhs, exp_self(bin)->pos }; |
221 |
✗✓ |
9 |
CHECK_BO(fptr_do(env, &info)) |
222 |
|
9 |
exp_setvar(bin->rhs, 1); |
223 |
|
9 |
return bin->rhs->info->type; |
224 |
|
|
} |
225 |
|
120 |
struct FptrInfo info = { bin->lhs->info->type->e->d.func, bin->rhs->info->type->e->d.func, |
226 |
|
80 |
bin->lhs, exp_self(bin)->pos }; |
227 |
✓✓ |
40 |
CHECK_BO(fptr_do(env, &info)) |
228 |
|
31 |
exp_setvar(bin->rhs, 1); |
229 |
|
31 |
return bin->rhs->info->type; |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
static OP_CHECK(opck_null_fptr_at) { |
233 |
|
|
Exp_Binary* bin = (Exp_Binary*)data; |
234 |
|
|
CHECK_NN(opck_const_rhs(env, bin, mut)) |
235 |
|
|
exp_setvar(bin->rhs, 1); |
236 |
|
|
return bin->rhs->info->type; |
237 |
|
|
} |
238 |
|
|
|
239 |
|
3 |
static OP_CHECK(opck_fptr_cast) { |
240 |
|
3 |
Exp_Cast* cast = (Exp_Cast*)data; |
241 |
|
3 |
const Type t = exp_self(cast)->info->type; |
242 |
|
9 |
struct FptrInfo info = { cast->exp->info->type->e->d.func, t->e->d.func, |
243 |
|
6 |
cast->exp, exp_self(cast)->pos }; |
244 |
✗✓ |
3 |
CHECK_BO(fptr_do(env, &info)) |
245 |
|
3 |
cast->func = cast->exp->info->type->e->d.func; |
246 |
|
3 |
return t; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
6 |
static void member_fptr(const Emitter emit) { |
250 |
|
6 |
const Instr instr = emit_add_instr(emit, RegPop); |
251 |
|
6 |
instr->m_val = SZ_INT; |
252 |
|
6 |
const Instr dup = emit_add_instr(emit, Reg2Reg); |
253 |
|
6 |
dup->m_val = -SZ_INT; |
254 |
|
6 |
} |
255 |
|
|
|
256 |
|
8 |
static int is_member(const Type from, const Type to) { |
257 |
✓✓✓✗
|
20 |
return GET_FLAG(from->e->d.func, member) && |
258 |
✓✗ |
12 |
!(GET_FLAG(from, nonnull) || GET_FLAG(to, nonnull)); |
259 |
|
|
} |
260 |
|
|
|
261 |
|
3 |
static OP_EMIT(opem_fptr_cast) { |
262 |
|
3 |
const Exp_Cast* cast = (Exp_Cast*)data; |
263 |
✓✓ |
3 |
if(exp_self(cast)->info->type->e->d.func->def->base->tmpl) |
264 |
|
1 |
fptr_instr(emit, cast->exp->info->type->e->d.func, 1); |
265 |
✓✗ |
3 |
if(is_member(cast->exp->info->type, exp_self(cast)->info->type)) |
266 |
|
3 |
member_fptr(emit); |
267 |
|
3 |
return (Instr)GW_OK; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
5 |
static OP_CHECK(opck_fptr_impl) { |
271 |
|
5 |
struct Implicit *impl = (struct Implicit*)data; |
272 |
|
15 |
struct FptrInfo info = { impl->e->info->type->e->d.func, impl->t->e->d.func, |
273 |
|
10 |
impl->e, impl->e->pos }; |
274 |
✗✓ |
5 |
CHECK_BO(fptr_do(env, &info)) |
275 |
|
5 |
return ((Exp)impl->e)->info->cast_to = impl->t; |
276 |
|
|
} |
277 |
|
|
|
278 |
|
5 |
static OP_EMIT(opem_fptr_impl) { |
279 |
|
5 |
struct Implicit *impl = (struct Implicit*)data; |
280 |
✓✓ |
5 |
if(is_member(impl->e->info->type, impl->t)) |
281 |
|
3 |
member_fptr(emit); |
282 |
✓✓ |
5 |
if(impl->t->e->d.func->def->base->tmpl) |
283 |
|
1 |
fptr_instr(emit, ((Exp)impl->e)->info->type->e->d.func, 1); |
284 |
|
5 |
return (Instr)GW_OK; |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
ANN Type check_exp_unary_spork(const Env env, const Stmt code); |
288 |
|
|
|
289 |
|
53 |
static OP_CHECK(opck_spork) { |
290 |
|
53 |
const Exp_Unary* unary = (Exp_Unary*)data; |
291 |
✓✓✓✓
|
53 |
if(unary->exp && unary->exp->exp_type == ae_exp_call) { |
292 |
|
27 |
const m_bool is_spork = unary->op == insert_symbol("spork"); |
293 |
✗✓ |
27 |
if(!is_spork) { |
294 |
|
|
const Stmt stmt = new_stmt_exp(env->gwion->mp, ae_stmt_exp, unary->exp); |
295 |
|
|
const Stmt_List list = new_stmt_list(env->gwion->mp, stmt, NULL); |
296 |
|
|
const Stmt code = new_stmt_code(env->gwion->mp, list); |
297 |
|
|
((Exp_Unary*)unary)->exp = NULL; |
298 |
|
|
((Exp_Unary*)unary)->code = code; |
299 |
|
|
} |
300 |
✓✗ |
27 |
return env->gwion->type[is_spork ? et_shred : et_fork]; |
301 |
|
|
} |
302 |
✓✓ |
26 |
if(unary->code) { |
303 |
|
25 |
++env->scope->depth; |
304 |
|
25 |
nspc_push_value(env->gwion->mp, env->curr); |
305 |
|
25 |
const m_bool ret = check_stmt(env, unary->code); |
306 |
|
25 |
nspc_pop_value(env->gwion->mp, env->curr); |
307 |
|
25 |
--env->scope->depth; |
308 |
✗✓ |
25 |
CHECK_BO(ret) |
309 |
✓✓ |
25 |
return env->gwion->type[unary->op == insert_symbol("spork") ? et_shred : et_fork]; |
310 |
|
|
} |
311 |
|
1 |
ERR_O(exp_self(unary)->pos, _("only function calls can be sporked...")) |
312 |
|
|
} |
313 |
|
|
|
314 |
|
52 |
static OP_EMIT(opem_spork) { |
315 |
|
52 |
const Exp_Unary* unary = (Exp_Unary*)data; |
316 |
|
52 |
const Env env = emit->env; |
317 |
|
52 |
const Instr ret = emit_exp_spork(emit, unary); |
318 |
✓✓ |
52 |
if(unary->op == insert_symbol("fork")) |
319 |
|
7 |
emit_add_instr(emit, GcAdd); |
320 |
|
52 |
return ret; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
45 |
static FREEARG(freearg_xork) { |
324 |
|
45 |
REM_REF((VM_Code)instr->m_val, gwion) |
325 |
|
45 |
} |
326 |
|
|
|
327 |
|
31 |
static FREEARG(freearg_dottmpl) { |
328 |
|
31 |
struct dottmpl_ *dt = (struct dottmpl_*)instr->m_val; |
329 |
✓✗ |
31 |
if(dt->tl) |
330 |
|
31 |
free_type_list(((Gwion)gwion)->mp, dt->tl); |
331 |
|
31 |
mp_free(((Gwion)gwion)->mp, dottmpl, dt); |
332 |
|
31 |
} |
333 |
|
|
|
334 |
|
730 |
GWION_IMPORT(func) { |
335 |
|
730 |
GWI_BB(gwi_oper_cond(gwi, "@func_ptr", BranchEqInt, BranchNeqInt)) |
336 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@function", NULL)) |
337 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_func_call)) |
338 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "=>", NULL)) |
339 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, NULL, "@func_ptr", "bool")) |
340 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "!", IntNot)) |
341 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, "@function", "@func_ptr", NULL)) |
342 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_fptr_at)) |
343 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_func_assign)) |
344 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) |
345 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_fptr_cast)) |
346 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_fptr_cast)) |
347 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "$", NULL)) |
348 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_fptr_impl)) |
349 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_fptr_impl)) |
350 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) |
351 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, "@null", "@func_ptr", NULL)) |
352 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_null_fptr_at)) |
353 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_func_assign)) |
354 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) |
355 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_fptr_cast)) |
356 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_fptr_cast)) |
357 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "$", NULL)) |
358 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_fptr_impl)) |
359 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_fptr_impl)) |
360 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) |
361 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, NULL, (m_str)OP_ANY_TYPE, NULL)) |
362 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_spork)) |
363 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_spork)) |
364 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "spork", NULL)) |
365 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_spork)) |
366 |
|
730 |
GWI_BB(gwi_oper_emi(gwi, opem_spork)) |
367 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "fork", NULL)) |
368 |
|
730 |
GWI_BB(gwi_oper_ini(gwi, "@function", "@function", NULL)) |
369 |
|
730 |
GWI_BB(gwi_oper_add(gwi, opck_auto_fptr)) |
370 |
|
730 |
GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) |
371 |
|
730 |
gwi_register_freearg(gwi, SporkIni, freearg_xork); |
372 |
|
730 |
gwi_register_freearg(gwi, DotTmpl, freearg_dottmpl); |
373 |
|
730 |
return GW_OK; |
374 |
|
|
} |