1 /*
2 $Id: mfuncobj.c 2593 2021-04-18 13:00:11Z soci $
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 */
19 #include "mfuncobj.h"
20 #include <string.h>
21 #include "values.h"
22 #include "eval.h"
23 #include "error.h"
24 #include "macro.h"
25 #include "file.h"
26
27 #include "typeobj.h"
28 #include "namespaceobj.h"
29 #include "listobj.h"
30
31 static Type mfunc_obj;
32 static Type sfunc_obj;
33
34 Type *const MFUNC_OBJ = &mfunc_obj;
35 Type *const SFUNC_OBJ = &sfunc_obj;
36
destroy(Obj * o1)37 static FAST_CALL void destroy(Obj *o1) {
38 Mfunc *v1 = Mfunc(o1);
39 const struct file_s *cfile = v1->file_list->file;
40 argcount_t i = v1->argc;
41 size_t k;
42 while ((i--) != 0) {
43 struct mfunc_param_s *param = &v1->param[i];
44 if (not_in_file(param->name.data, cfile)) free((char *)param->name.data);
45 if (param->name.data != param->cfname.data) free((char *)param->cfname.data);
46 if (param->init != NULL) val_destroy(param->init);
47 }
48 k = v1->nslen;
49 while ((k--) != 0) {
50 val_destroy(Obj(v1->namespaces[k]));
51 }
52 free(v1->namespaces);
53 val_destroy(Obj(v1->names));
54 val_destroy(Obj(v1->inamespaces));
55 free(v1->param);
56 if (v1->line != NULL) free((uint8_t *)v1->line);
57 }
58
garbage(Obj * o1,int j)59 static FAST_CALL void garbage(Obj *o1, int j) {
60 Mfunc *v1 = Mfunc(o1);
61 argcount_t i = v1->argc;
62 size_t k;
63 Obj *v ;
64 const struct file_s *cfile;
65 switch (j) {
66 case -1:
67 while ((i--) != 0) {
68 v = v1->param[i].init;
69 if (v != NULL) v->refcount--;
70 }
71 k = v1->nslen;
72 while ((k--) != 0) {
73 v = Obj(v1->namespaces[k]);
74 v->refcount--;
75 }
76 v = Obj(v1->names);
77 v->refcount--;
78 v = Obj(v1->inamespaces);
79 v->refcount--;
80 return;
81 case 0:
82 cfile = v1->file_list->file;
83 while ((i--) != 0) {
84 struct mfunc_param_s *param = &v1->param[i];
85 if (not_in_file(param->name.data, cfile)) free((char *)param->name.data);
86 if (param->name.data != param->cfname.data) free((char *)param->cfname.data);
87 }
88 free(v1->param);
89 free(v1->namespaces);
90 if (v1->line != NULL) free((uint8_t *)v1->line);
91 return;
92 case 1:
93 while ((i--) != 0) {
94 v = v1->param[i].init;
95 if (v != NULL) {
96 if ((v->refcount & SIZE_MSB) != 0) {
97 v->refcount -= SIZE_MSB - 1;
98 v->obj->garbage(v, 1);
99 } else v->refcount++;
100 }
101 }
102 k = v1->nslen;
103 while ((k--) != 0) {
104 v = Obj(v1->namespaces[k]);
105 if ((v->refcount & SIZE_MSB) != 0) {
106 v->refcount -= SIZE_MSB - 1;
107 v->obj->garbage(v, 1);
108 } else v->refcount++;
109 }
110 v = Obj(v1->names);
111 if ((v->refcount & SIZE_MSB) != 0) {
112 v->refcount -= SIZE_MSB - 1;
113 v->obj->garbage(v, 1);
114 } else v->refcount++;
115 v = Obj(v1->inamespaces);
116 if ((v->refcount & SIZE_MSB) != 0) {
117 v->refcount -= SIZE_MSB - 1;
118 v->obj->garbage(v, 1);
119 } else v->refcount++;
120 return;
121 }
122 }
123
same(const Obj * o1,const Obj * o2)124 static FAST_CALL bool same(const Obj *o1, const Obj *o2) {
125 const Mfunc *v1 = Mfunc(o1), *v2 = Mfunc(o2);
126 argcount_t i;
127 size_t k;
128 if (o1->obj != o2->obj || v1->file_list != v2->file_list || v1->epoint.line != v2->epoint.line || v1->epoint.pos != v2->epoint.pos) return false;
129 if (v1->argc != v2->argc || v1->nslen != v2->nslen) return false;
130 for (i = 0; i < v1->argc; i++) {
131 if (str_cmp(&v1->param[i].name, &v2->param[i].name) != 0) return false;
132 if ((v1->param[i].name.data != v1->param[i].cfname.data || v2->param[i].name.data != v2->param[i].cfname.data) && str_cmp(&v1->param[i].cfname, &v2->param[i].cfname) != 0) return false;
133 if (v1->param[i].init != v2->param[i].init && (v1->param[i].init == NULL || v2->param[i].init == NULL || !v1->param[i].init->obj->same(v1->param[i].init, v2->param[i].init))) return false;
134 if (v1->param[i].epoint.pos != v2->param[i].epoint.pos) return false;
135 }
136 for (k = 0; k < v1->nslen; k++) {
137 if (v1->namespaces[k] != v2->namespaces[k] && !v1->namespaces[k]->v.obj->same(Obj(v1->namespaces[k]), Obj(v2->namespaces[k]))) return false;
138 }
139 if (v1->names != v2->names && !v1->names->v.obj->same(Obj(v1->names), Obj(v2->names))) return false;
140 if (v1->line != v2->line && (v1->line == NULL || v2->line == NULL || strcmp((const char *)v1->line, (const char *)v2->line) != 0)) return false;
141 return true;
142 }
143
calc2(oper_t op)144 static MUST_CHECK Obj *calc2(oper_t op) {
145 switch (op->v2->obj->type) {
146 case T_FUNCARGS:
147 if (op->op == O_FUNC) {
148 Mfunc *v1 = Mfunc(op->v1);
149 Funcargs *v2 = Funcargs(op->v2);
150 Obj *val;
151 argcount_t i, max = 0, args = v2->len;
152 for (i = args; i < v1->argc; i++) {
153 if (v1->param[i].init == NULL) {
154 max = i + 1;
155 }
156 }
157 if (max != 0) err_msg_argnum(args, max, v1->argc, op->epoint2);
158 eval_enter();
159 val = mfunc2_recurse(v1, v2, op->epoint);
160 eval_leave();
161 return (val != NULL) ? val : val_reference(null_tuple);
162 }
163 break;
164 case T_NONE:
165 case T_ERROR:
166 return val_reference(op->v2);
167 default:
168 if (op->op == O_MEMBER) {
169 return namespace_member(op, Mfunc(op->v1)->names);
170 }
171 break;
172 }
173 return obj_oper_error(op);
174 }
175
mfuncobj_init(void)176 void mfuncobj_init(void) {
177 new_type(&mfunc_obj, T_MFUNC, "function", sizeof(Mfunc));
178 mfunc_obj.destroy = destroy;
179 mfunc_obj.garbage = garbage;
180 mfunc_obj.same = same;
181 mfunc_obj.calc2 = calc2;
182 new_type(&sfunc_obj, T_SFUNC, "sfunction", sizeof(Sfunc));
183 sfunc_obj.destroy = destroy;
184 sfunc_obj.garbage = garbage;
185 sfunc_obj.same = same;
186 sfunc_obj.calc2 = calc2;
187 }
188
189