1 /*
2 $Id: foldobj.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 "foldobj.h"
20 #include <string.h>
21 #include "values.h"
22 #include "eval.h"
23 #include "error.h"
24
25 #include "typeobj.h"
26 #include "strobj.h"
27 #include "errorobj.h"
28 #include "boolobj.h"
29
30 static Type obj;
31
32 Type *const FOLD_OBJ = &obj;
33
34 static Fold foldval = { { &obj, 1 }, NULL };
35
36 Obj *const fold_value = &foldval.v;
37
same(const Obj * o1,const Obj * o2)38 static FAST_CALL bool same(const Obj *o1, const Obj *o2) {
39 return o1 == o2;
40 }
41
hash(Obj * UNUSED (v1),int * hs,linepos_t UNUSED (epoint))42 static MUST_CHECK Obj *hash(Obj *UNUSED(v1), int *hs, linepos_t UNUSED(epoint)) {
43 *hs = 0; /* whatever, there's only one */
44 return NULL;
45 }
46
repr(Obj * UNUSED (v1),linepos_t UNUSED (epoint),size_t maxsize)47 static MUST_CHECK Obj *repr(Obj *UNUSED(v1), linepos_t UNUSED(epoint), size_t maxsize) {
48 Str *v;
49 if (3 > maxsize) return NULL;
50 v = foldval.repr;
51 if (v == NULL) {
52 v = new_str2(3);
53 if (v == NULL) return NULL;
54 v->chars = 3;
55 memset(v->data, '.', 3);
56 foldval.repr = v;
57 }
58 return val_reference(Obj(v));
59 }
60
calc2(oper_t op)61 static MUST_CHECK Obj *calc2(oper_t op) {
62 Obj *v2 = op->v2;
63 if (v2->obj->iterable && op->op != O_MEMBER && op->op != O_X) {
64 bool minmax = (op->op == O_MIN) || (op->op == O_MAX);
65 struct iter_s iter;
66 Obj *ret = NULL;
67 iter.data = v2; v2->obj->getiter(&iter);
68
69 while ((v2 = iter.next(&iter)) != NULL) {
70 Obj *val;
71 if (ret == NULL) {
72 ret = val_reference(v2);
73 continue;
74 }
75 op->v1 = ret;
76 op->v2 = v2;
77 op->inplace = (ret->refcount == 1 && !minmax) ? ret : NULL;
78 val = ret->obj->calc2(op);
79 if (minmax) {
80 if (val == true_value) val_replace(&val, ret);
81 else if (val == false_value) val_replace(&val, v2);
82 }
83 val_destroy(ret); ret = val;
84 }
85 iter_destroy(&iter);
86 return ret != NULL ? ret : Obj(new_error(ERROR____EMPTY_LIST, op->epoint2));
87 }
88 switch (v2->obj->type) {
89 case T_NONE:
90 case T_ERROR:
91 return val_reference(v2);
92 default:
93 break;
94 }
95 return obj_oper_error(op);
96 }
97
rcalc2(oper_t op)98 static MUST_CHECK Obj *rcalc2(oper_t op) {
99 Obj *v1 = op->v1;
100 if (v1->obj->iterable) {
101 if (op->op != O_IN) {
102 bool minmax = (op->op == O_MIN) || (op->op == O_MAX);
103 struct iter_s iter;
104 Obj *ret = NULL;
105 iter.data = v1; v1->obj->getriter(&iter);
106
107 while ((v1 = iter.next(&iter)) != NULL) {
108 Obj *val;
109 if (ret == NULL) {
110 ret = val_reference(v1);
111 continue;
112 }
113 op->v1 = v1;
114 op->v2 = ret;
115 op->inplace = (ret->refcount == 1 && !minmax) ? ret : NULL;
116 val = v1->obj->calc2(op);
117 if (minmax) {
118 if (val == true_value) val_replace(&val, v1);
119 else if (val == false_value) val_replace(&val, ret);
120 }
121 val_destroy(ret); ret = val;
122 }
123 iter_destroy(&iter);
124 return ret != NULL ? ret : Obj(new_error(ERROR____EMPTY_LIST, op->epoint));
125 }
126 }
127 switch (v1->obj->type) {
128 case T_NONE:
129 case T_ERROR:
130 return val_reference(v1);
131 default:
132 break;
133 }
134 return obj_oper_error(op);
135 }
136
foldobj_init(void)137 void foldobj_init(void) {
138 new_type(&obj, T_FOLD, "fold", sizeof(Fold));
139 obj.same = same;
140 obj.hash = hash;
141 obj.repr = repr;
142 obj.calc2 = calc2;
143 obj.rcalc2 = rcalc2;
144 }
145
foldobj_destroy(void)146 void foldobj_destroy(void) {
147 #ifdef DEBUG
148 if (fold_value->refcount != 1) fprintf(stderr, "fold %" PRIuSIZE "\n", fold_value->refcount - 1);
149 #endif
150 if (foldval.repr != NULL) val_destroy(Obj(foldval.repr));
151 }
152