1 /*
2     $Id: typeobj.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 "typeobj.h"
20 #include <string.h>
21 #include "variables.h"
22 #include "eval.h"
23 #include "error.h"
24 
25 #include "strobj.h"
26 #include "errorobj.h"
27 #include "functionobj.h"
28 
29 static Type obj;
30 
31 Type *const TYPE_OBJ = &obj;
32 
33 static struct Slot *values_free[32];
34 
35 #define ALIGN sizeof(int *)
36 
new_type(Type * t,Type_types type,const char * name,size_t length)37 void new_type(Type *t, Type_types type, const char *name, size_t length) {
38     t->v.obj = TYPE_OBJ;
39     t->v.refcount = 1;
40     t->type = type;
41     t->length = (length + (ALIGN - 1)) / ALIGN;
42     t->slot = &values_free[t->length];
43     t->name = name;
44     obj_init(t);
45 }
46 
type_from_obj(Obj * v1,linepos_t UNUSED (epoint))47 static MUST_CHECK Obj *type_from_obj(Obj *v1, linepos_t UNUSED(epoint)) {
48     switch (v1->obj->type) {
49     case T_NONE:
50     case T_ERROR: return val_reference(v1);
51     default: break;
52     }
53     return val_reference((Obj *)Obj(v1->obj));
54 }
55 
convert(oper_t op)56 static MUST_CHECK Obj *convert(oper_t op) {
57     return type_from_obj(op->v2, op->epoint2);
58 }
59 
same(const Obj * o1,const Obj * o2)60 static FAST_CALL bool same(const Obj *o1, const Obj *o2) {
61     return o1 == o2;
62 }
63 
hash(Obj * o1,int * hs,linepos_t UNUSED (epoint))64 static MUST_CHECK Obj *hash(Obj *o1, int *hs, linepos_t UNUSED(epoint)) {
65     *hs = (int)Type(o1)->type;
66     return NULL;
67 }
68 
repr(Obj * o1,linepos_t epoint,size_t maxsize)69 static MUST_CHECK Obj *repr(Obj *o1, linepos_t epoint, size_t maxsize) {
70     Type *v1 = Type(o1);
71     Str *v;
72     uint8_t *s;
73     const char *name;
74     size_t ln, ln2;
75     if (epoint == NULL) return NULL;
76     name = v1->name;
77     ln = strlen(name);
78     ln2 = ln + 9;
79     if (ln2 > maxsize) return NULL;
80     v = new_str2(ln2);
81     if (v == NULL) return NULL;
82     v->chars = ln2;
83     s = v->data;
84     memcpy(s, "<type '", 7);
85     s += 7;
86     memcpy(s, name, ln);
87     s[ln] = '\'';
88     s[ln + 1] = '>';
89     return Obj(v);
90 }
91 
icmp(oper_t op)92 static inline int icmp(oper_t op) {
93     Type_types v1 = Type(op->v1)->type;
94     Type_types v2 = Type(op->v2)->type;
95     return (v1 < v2) ? -1 : (v1 > v2) ? 1 : 0;
96 }
97 
calc2(oper_t op)98 static MUST_CHECK Obj *calc2(oper_t op) {
99     Obj *o2 = op->v2;
100 
101     switch (o2->obj->type) {
102     case T_TYPE:
103         return obj_oper_compare(op, icmp(op));
104     case T_FUNCARGS:
105         if (op->op == O_FUNC) {
106             const Type *v1 = Type(op->v1);
107             Funcargs *v2 = Funcargs(o2);
108             argcount_t args = v2->len;
109             if (args != 1) {
110                 return apply_convert2(op);
111             }
112             op->v2 = v2->val->val;
113             op->inplace = op->v2->refcount == 1 ? op->v2 : NULL;
114             if (v1->iterable || v1 == TYPE_OBJ) {
115                 return v1->convert(op);
116             }
117             return apply_convert(op);
118         }
119         break;
120     case T_NONE:
121     case T_ERROR:
122         return val_reference(o2);
123     default:
124         if (o2->obj->iterable && op->op != O_MEMBER && op->op != O_X) {
125             return o2->obj->rcalc2(op);
126         }
127         break;
128     }
129     return obj_oper_error(op);
130 }
131 
132 
typeobj_init(void)133 void typeobj_init(void) {
134     new_type(&obj, T_TYPE, "type", sizeof(Type));
135     obj.convert = convert;
136     obj.same = same;
137     obj.hash = hash;
138     obj.repr = repr;
139     obj.calc2 = calc2;
140 }
141 
typeobj_names(void)142 void typeobj_names(void) {
143     new_builtin("type", val_reference(Obj(TYPE_OBJ)));
144 }
145