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