1 /*
2 $Id: symbolobj.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 "symbolobj.h"
20 #include <string.h>
21 #include "eval.h"
22 #include "unicode.h"
23 #include "error.h"
24 #include "file.h"
25 #include "values.h"
26 #include "arguments.h"
27
28 #include "typeobj.h"
29 #include "strobj.h"
30 #include "errorobj.h"
31
32 static Type obj;
33
34 Type *const SYMBOL_OBJ = &obj;
35
new_symbol(const str_t * name,linepos_t epoint)36 Obj *new_symbol(const str_t *name, linepos_t epoint) {
37 Symbol *symbol = Symbol(val_alloc(SYMBOL_OBJ));
38 if (not_in_file(name->data, current_file_list->file)) str_cpy(&symbol->name, name);
39 else symbol->name = *name;
40 symbol->cfname.data = NULL;
41 symbol->cfname.len = 0;
42 symbol->hash = -1;
43 symbol->file_list = current_file_list;
44 symbol->epoint = *epoint;
45 return Obj(symbol);
46 }
47
symbol_destroy(Symbol * v1)48 static FAST_CALL NO_INLINE void symbol_destroy(Symbol *v1) {
49 free((char *)v1->name.data);
50 }
51
symbol_same(const Symbol * v1,const Symbol * v2)52 static FAST_CALL NO_INLINE bool symbol_same(const Symbol *v1, const Symbol *v2) {
53 return memcmp(v1->name.data, v2->name.data, v2->name.len) == 0;
54 }
55
same(const Obj * o1,const Obj * o2)56 static FAST_CALL bool same(const Obj *o1, const Obj *o2) {
57 const Symbol *v1 = Symbol(o1), *v2 = Symbol(o2);
58 if (o1->obj != o2->obj || v1->name.len != v2->name.len) return false;
59 switch (v1->name.len) {
60 case 0: return true;
61 case 1: return v1->name.data[0] == v2->name.data[0];
62 default: return v1->name.data == v2->name.data || symbol_same(v1, v2);
63 }
64 }
65
destroy(Obj * o1)66 static FAST_CALL void destroy(Obj *o1) {
67 Symbol *v1 = Symbol(o1);
68 const struct file_s *cfile = v1->file_list->file;
69 if (not_in_file(v1->name.data, cfile)) symbol_destroy(v1);
70 if (v1->cfname.data != NULL && v1->name.data != v1->cfname.data) free((uint8_t *)v1->cfname.data);
71 }
72
repr(Obj * o1,linepos_t UNUSED (epoint),size_t maxsize)73 static MUST_CHECK Obj *repr(Obj *o1, linepos_t UNUSED(epoint), size_t maxsize) {
74 Symbol *v1 = Symbol(o1);
75 size_t chars;
76 Str *v;
77 size_t len;
78
79 chars = calcpos(v1->name.data, v1->name.len) + 1;
80 if (chars < 1 || chars > maxsize) return NULL;/* overflow */
81 len = v1->name.len + 1;
82 if (len < 1) return NULL;/* overflow */
83 v = new_str2(len);
84 if (v == NULL) return NULL;
85 v->chars = chars;
86 v->data[0] = '.';
87 memcpy(v->data + 1, v1->name.data, len - 1);
88 return Obj(v);
89 }
90
str(Obj * o1,linepos_t UNUSED (epoint),size_t maxsize)91 static MUST_CHECK Obj *str(Obj *o1, linepos_t UNUSED(epoint), size_t maxsize) {
92 Symbol *v1 = Symbol(o1);
93 Str *v;
94 size_t chars = calcpos(v1->name.data, v1->name.len);
95 if (chars > maxsize) return NULL;
96 v = new_str2(v1->name.len);
97 if (v == NULL) return NULL;
98 v->chars = chars;
99 memcpy(v->data, v1->name.data, v1->name.len);
100 return Obj(v);
101 }
102
hash(Obj * o1,int * hs,linepos_t UNUSED (epoint))103 static MUST_CHECK Obj *hash(Obj *o1, int *hs, linepos_t UNUSED(epoint)) {
104 Symbol *v1 = Symbol(o1);
105 str_t s;
106 size_t l;
107 unsigned int h;
108 if (v1->name.len == 0) {
109 *hs = 0;
110 return NULL;
111 }
112 if (v1->hash >= 0) {
113 *hs = v1->hash;
114 return NULL;
115 }
116 if (v1->cfname.data == NULL) {
117 str_cfcpy(&v1->cfname, &v1->name);
118 if (v1->cfname.data != v1->name.data) str_cfcpy(&v1->cfname, NULL);
119 }
120 s = v1->cfname;
121 h = (unsigned int)*s.data << 7;
122 l = s.len;
123 while ((l--) != 0) h = (1000003 * h) ^ *s.data++;
124 h ^= (unsigned int)s.len;
125 *hs = v1->hash = h & ((~0U) >> 1);
126 return NULL;
127 }
128
symbol_cfsame(Symbol * v1,Symbol * v2)129 bool symbol_cfsame(Symbol *v1, Symbol *v2) {
130 str_t *n1 = &v1->cfname, *n2 = &v2->cfname;
131 if (n1->data == NULL) {
132 str_cfcpy(n1, &v1->name);
133 if (n1->data != v1->name.data) str_cfcpy(n1, NULL);
134 }
135 if (n2->data == NULL) {
136 str_cfcpy(n2, &v2->name);
137 if (n2->data != v2->name.data) str_cfcpy(n2, NULL);
138 }
139 if (str_cmp(n1, n2) != 0) return false;
140 if (diagnostics.case_symbol && str_cmp(&v1->name, &v2->name) != 0) err_msg_symbol_case2(v1, v2);
141 return true;
142 }
143
icmp(oper_t op)144 static inline int icmp(oper_t op) {
145 Symbol *v1 = Symbol(op->v1), *v2 = Symbol(op->v2);
146 str_t *n1 = &v1->cfname, *n2 = &v2->cfname;
147 int h;
148 if (n1->data == NULL) {
149 str_cfcpy(n1, &v1->name);
150 if (n1->data != v1->name.data) str_cfcpy(n1, NULL);
151 }
152 if (n2->data == NULL) {
153 str_cfcpy(n2, &v2->name);
154 if (n2->data != v2->name.data) str_cfcpy(n2, NULL);
155 }
156 h = memcmp(n1->data, n2->data, (n1->len < n2->len) ? n1->len : n2->len);
157 if (h != 0) return h;
158 if (n1->len < n2->len) return -1;
159 return (n1->len > n2->len) ? 1 : 0;
160 }
161
calc2(oper_t op)162 static MUST_CHECK Obj *calc2(oper_t op) {
163 Obj *o2 = op->v2;
164 int i;
165 switch (o2->obj->type) {
166 case T_SYMBOL:
167 i = icmp(op);
168 if (i == 0 && diagnostics.case_symbol && str_cmp(&Symbol(op->v1)->name, &Symbol(o2)->name) != 0) err_msg_symbol_case2(Symbol(op->v1), Symbol(o2));
169 return obj_oper_compare(op, i);
170 case T_NONE:
171 case T_ERROR:
172 return val_reference(o2);
173 default:
174 if (o2->obj->iterable && op->op != O_MEMBER && op->op != O_X) {
175 return o2->obj->rcalc2(op);
176 }
177 break;
178 }
179 return obj_oper_error(op);
180 }
181
rcalc2(oper_t op)182 static MUST_CHECK Obj *rcalc2(oper_t op) {
183 if (op->op == O_MEMBER) {
184 return op->v1->obj->calc2(op);
185 }
186 return obj_oper_error(op);
187 }
188
symbolobj_init(void)189 void symbolobj_init(void) {
190 new_type(&obj, T_SYMBOL, "symbol", sizeof(Symbol));
191 obj.destroy = destroy;
192 obj.same = same;
193 obj.hash = hash;
194 obj.repr = repr;
195 obj.str = str;
196 obj.calc2 = calc2;
197 obj.rcalc2 = rcalc2;
198 }
199