cpp
[m6w6/ext-psi] / src / token.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27
28 #include <ctype.h>
29
30 #include "token.h"
31 #include "parser.h"
32
33 size_t psi_token_alloc_size(size_t token_len, size_t fname_len) {
34 return sizeof(struct psi_token) + token_len + fname_len + 2;
35 }
36
37 struct psi_token *psi_token_alloc(struct psi_parser *P) {
38 struct psi_token *T;
39 size_t token_len, fname_len;
40 token_t token_typ;
41
42 if (P->cur < P->tok) {
43 return NULL;
44 }
45
46 token_typ = P->num;
47 token_len = P->cur - P->tok;
48 fname_len = strlen(P->file.fn);
49
50 T = calloc(1, psi_token_alloc_size(token_len, fname_len));
51 T->type = token_typ;
52 T->size = token_len;
53 T->text = &T->buf[0];
54 T->file = &T->buf[token_len + 1];
55 T->line = P->line;
56 T->col = P->col;
57
58 memcpy(T->text, P->tok, token_len);
59 memcpy(T->file, P->file.fn, fname_len);
60
61 return T;
62 }
63
64 void psi_token_free(struct psi_token **token_ptr) {
65 if (*token_ptr) {
66 struct psi_token *token = *token_ptr;
67
68 *token_ptr = NULL;
69 free(token);
70 }
71 }
72
73 struct psi_token *psi_token_copy(struct psi_token *src) {
74 size_t strct_len = psi_token_alloc_size(src->size, strlen(src->file));
75 struct psi_token *ptr = malloc(strct_len);
76
77 memcpy(ptr, src, strct_len);
78
79 ptr->text = &ptr->buf[0];
80 ptr->file = &ptr->buf[ptr->size + 1];
81
82 return ptr;
83 }
84
85 void psi_token_copy_ctor(struct psi_token **tok) {
86 *tok = psi_token_copy(*tok);
87 }
88
89 struct psi_token *psi_token_cat(unsigned argc, ...) {
90 va_list argv;
91 unsigned i;
92 struct psi_token *T = NULL;
93
94 va_start(argv, argc);
95 for (i = 0; i < argc; ++i) {
96 struct psi_token *arg = va_arg(argv, struct psi_token *);
97
98 if (T) {
99 size_t token_len = T->size, fname_len = strlen(T->file);
100 struct psi_token *tmp = realloc(T, psi_token_alloc_size(T->size += arg->size + 1, fname_len));
101
102 if (tmp) {
103 T = tmp;
104 } else {
105 free(T);
106 va_end(argv);
107 return NULL;
108 }
109
110 T->text = &T->buf[0];
111 T->file = &T->buf[T->size + 1];
112 T->buf[token_len] = ' ';
113 memmove(&T->buf[T->size + 1], &T->buf[token_len + 1], fname_len + 1);
114 memcpy(&T->buf[token_len + 1], arg->text, arg->size + 1);
115 } else {
116 T = psi_token_copy(arg);
117 T->type = PSI_T_NAME;
118 }
119 }
120 va_end(argv);
121
122 return T;
123 }
124
125 struct psi_token *psi_token_append(struct psi_token *T, unsigned argc, ...) {
126 va_list argv;
127 unsigned i;
128
129 va_start(argv, argc);
130 for (i = 0; i < argc; ++i) {
131 char *str = va_arg(argv, char *);
132 size_t str_len = strlen(str), token_len = T->size, fname_len = strlen(T->file);
133
134 T = realloc(T, psi_token_alloc_size(T->size += str_len + 1, fname_len));
135 T->text = &T->buf[0];
136 T->file = &T->buf[T->size + 1];
137 T->buf[token_len] = ' ';
138 memmove(&T->buf[T->size + 1], &T->buf[token_len + 1], fname_len + 1);
139 memcpy(&T->buf[token_len + 1], str, str_len + 1);
140 }
141 va_end(argv);
142
143 return T;
144 }
145
146 char *php_strtr(char *str, size_t len, char *str_from, char *str_to, size_t trlen);
147 struct psi_token *psi_token_translit(struct psi_token *T, char *from, char *to) {
148 php_strtr(T->text, T->size, from, to, MIN(strlen(from), strlen(to)));
149 return T;
150 }
151
152 static inline uint64_t psi_hash(char *digest_buf, ...)
153 {
154 uint64_t hash = 5381;
155 uint8_t c;
156 const uint8_t *ptr;
157 va_list argv;
158
159 va_start(argv, digest_buf);
160 while ((ptr = va_arg(argv, const uint8_t *))) {
161 while ((c = *ptr++)) {
162 hash = ((hash << 5) + hash) + c;
163 }
164 }
165 va_end(argv);
166
167 if (digest_buf) {
168 sprintf(digest_buf, "%" PRIx64, hash);
169 }
170
171 return hash;
172 }
173
174 uint64_t psi_token_hash(struct psi_token *t, char *digest_buf) {
175 char loc_buf[48];
176
177 sprintf(loc_buf, "%u%u", t->line, t->col);
178 return psi_hash(digest_buf, t->file, loc_buf, (char *) NULL);
179 }
180
181 void psi_token_dump(int fd, struct psi_token *t)
182 {
183 size_t i;
184
185 dprintf(fd, "TOKEN %p (%d) \"", t, t->type);
186 for (i = 0; i < MIN(t->size, 16); ++i) {
187 switch (t->text[i]) {
188 case '\0':
189 dprintf(fd, "\\0");
190 break;
191 case '\a':
192 dprintf(fd, "\\a");
193 break;
194 case '\b':
195 dprintf(fd, "\\b");
196 break;
197 case '\f':
198 dprintf(fd, "\\f");
199 break;
200 case '\n':
201 dprintf(fd, "\\n");
202 break;
203 case '\r':
204 dprintf(fd, "\\r");
205 break;
206 case '\t':
207 dprintf(fd, "\\t");
208 break;
209 case '\v':
210 dprintf(fd, "\\v");
211 break;
212 case '"':
213 dprintf(fd, "\\\"");
214 break;
215 default:
216 if (isprint(t->text[i])) {
217 dprintf(fd, "%c", t->text[i]);
218 } else {
219 dprintf(fd, "\\%03hho", t->text[i]);
220 }
221 break;
222 }
223 }
224 dprintf(fd, "\" at col %u in %s on line %u\n", t->col, t->file, t->line);
225 }