1 /* -*- c -*- */
2
3 /*
4 * builtins/value.c
5 *
6 * chpp
7 *
8 * Copyright (C) 1997-1998 Mark Probst
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <assert.h>
26 #include <string.h>
27
28 #include "../value.h"
29 #include "../output.h"
30 #include "../error.h"
31 #include "../internals.h"
32 #include "../environment.h"
33 #include "../bytecode.h"
34
35 #include "builtins.h"
36
37 void
builtInList(int numArgs,macroArgument * args,environment * env,outputWriter * ow)38 builtInList (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
39 {
40 value *theList;
41 int i;
42
43 theList = valueNewList();
44
45 for (i = 0; i < numArgs; ++i)
46 {
47 assureArgumentIsCopy(&args[i]);
48 valueListSetElement(theList, i, args[i].value.value);
49 }
50
51 OUT_VALUE_REF(ow, theList);
52 }
53
54 void
builtInHash(int numArgs,macroArgument * args,environment * env,outputWriter * ow)55 builtInHash (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
56 {
57 value *theHash;
58 int i;
59
60 if (!(numArgs == 1 || numArgs % 2 == 0))
61 {
62 issueError(ERRMAC_WRONG_NUM_ARGS, "hash");
63 return;
64 }
65
66 if (numArgs == 1)
67 {
68 if (transformArgumentToScalar(&args[0])->v.scalar.scalar.length > 0)
69 {
70 issueError(ERRMAC_WRONG_NUM_ARGS, "hash");
71 return;
72 }
73 }
74
75 theHash = valueNewHash();
76
77 for (i = 0; i < numArgs / 2; ++i)
78 {
79 transformArgumentToScalar(&args[i * 2]);
80 if (valueHashLookup(theHash, &args[i * 2].value.value->v.scalar.scalar) != 0)
81 issueWarning(WARNMAC_DUPLICATE_HASH_KEY,
82 args[i * 2].value.value->v.scalar.scalar.data);
83 assureArgumentIsCopy(&args[i * 2 + 1]);
84 valueHashDefine(theHash,
85 &args[i * 2].value.value->v.scalar.scalar,
86 args[i * 2 + 1].value.value);
87 }
88
89 OUT_VALUE_REF(ow, theHash);
90 }
91
92 void
builtInSame(int numArgs,macroArgument * args,environment * env,outputWriter * ow)93 builtInSame (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
94 {
95 if (!(numArgs == 2))
96 {
97 issueError(ERRMAC_WRONG_NUM_ARGS, "same");
98 return;
99 }
100
101 if (args[0].value.needCopy || args[1].value.needCopy)
102 {
103 OUT_CHAR(ow, '0');
104 }
105 else
106 {
107 if (valueAreSame(args[0].value.value, args[1].value.value))
108 {
109 OUT_CHAR(ow, '1');
110 }
111 else
112 {
113 OUT_CHAR(ow, '0');
114 }
115 }
116 }
117
118 void
builtInEqual(int numArgs,macroArgument * args,environment * env,outputWriter * ow)119 builtInEqual (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
120 {
121 if (!(numArgs == 2))
122 {
123 issueError(ERRMAC_WRONG_NUM_ARGS, "equal");
124 return;
125 }
126
127 if (valueAreEqual(args[0].value.value, args[1].value.value))
128 {
129 OUT_CHAR(ow, '1');
130 }
131 else
132 {
133 OUT_CHAR(ow, '0');
134 }
135 }
136
137 void
builtInTypeof(int numArgs,macroArgument * args,environment * env,outputWriter * ow)138 builtInTypeof (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
139 {
140 const char *type;
141
142 if (!(numArgs == 1))
143 {
144 issueError(ERRMAC_WRONG_NUM_ARGS, "typeof");
145 return;
146 }
147
148 type = cStringForValueType(args[0].value.value->type);
149
150 OUT_STRING(ow, type, strlen(type));
151 }
152
153 void
encodeDynstring(dynstring * ds,outputWriter * ow)154 encodeDynstring (dynstring *ds, outputWriter *ow)
155 {
156 int i;
157
158 OUT_CHAR(ow, *metaChar);
159 OUT_CHAR(ow, '\'');
160 for (i = 0; i < ds->length; ++i)
161 {
162 char c = ds->data[i];
163
164 if (c == '\'' || c == quoteChar)
165 OUT_CHAR(ow, quoteChar);
166 OUT_CHAR(ow, c);
167 }
168 OUT_CHAR(ow, '\'');
169 }
170
171 void encodeBytecode (bytecode *bc, outputWriter *ow);
172
173 void
encodeSubscripts(bcSubscript * subscript,outputWriter * ow)174 encodeSubscripts (bcSubscript *subscript, outputWriter *ow)
175 {
176 while (subscript != 0)
177 {
178 if (subscript->type == BYTECODE_SUBSCRIPT_LIST)
179 {
180 OUT_CHAR(ow, '[');
181 }
182 else
183 {
184 OUT_CHAR(ow, '{');
185 }
186 encodeBytecode(subscript->bc, ow);
187 if (subscript->type == BYTECODE_SUBSCRIPT_LIST)
188 {
189 OUT_CHAR(ow, ']');
190 }
191 else
192 {
193 OUT_CHAR(ow, '}');
194 }
195
196 subscript = subscript->next;
197 }
198 }
199
200 void
encodeBytecode(bytecode * bc,outputWriter * ow)201 encodeBytecode (bytecode *bc, outputWriter *ow)
202 {
203 while (bc != 0)
204 {
205 switch (bc->type)
206 {
207 case BYTECODE_STRING :
208 case BYTECODE_QUOTED_STRING :
209 encodeDynstring(&bc->v.string.string, ow);
210 break;
211
212 case BYTECODE_EVAL :
213 OUT_CHAR(ow, *metaChar);
214 OUT_CHAR(ow, '{');
215 encodeBytecode(bc->v.eval.bc, ow);
216 OUT_CHAR(ow, '}');
217 break;
218
219 case BYTECODE_ARITH :
220 OUT_CHAR(ow, *metaChar);
221 OUT_CHAR(ow, '[');
222 encodeBytecode(bc->v.arith.bc, ow);
223 OUT_CHAR(ow, ']');
224 break;
225
226 case BYTECODE_ASSIGNMENT :
227 {
228 bcSubscript *subscript;
229
230 OUT_CHAR(ow, *metaChar);
231 OUT_CHAR(ow, '<');
232 if (bc->v.assignment.modify)
233 OUT_CHAR(ow, '&');
234 encodeBytecode(bc->v.assignment.varName, ow);
235 encodeSubscripts(bc->v.assignment.subscript, ow);
236 OUT_CHAR(ow, '=');
237 encodeBytecode(bc->v.assignment.newValue, ow);
238 OUT_CHAR(ow, '>');
239 }
240 break;
241
242 case BYTECODE_MACRO :
243 {
244 bcSubscript *subscript;
245
246 OUT_CHAR(ow, *metaChar);
247 OUT_CHAR(ow, '<');
248 if (bc->v.macro.flags & BYTECODE_MACRO_BYREF)
249 OUT_CHAR(ow, '&');
250 if (bc->v.macro.flags & BYTECODE_MACRO_SUBVALUE)
251 OUT_CHAR(ow, '(');
252 encodeBytecode(bc->v.macro.nameOrValue, ow);
253 if (bc->v.macro.flags & BYTECODE_MACRO_SUBVALUE)
254 OUT_CHAR(ow, ')');
255 encodeSubscripts(bc->v.macro.subscript, ow);
256 if (bc->v.macro.numArgs >= 0)
257 {
258 bcArgument *argument;
259
260 OUT_CHAR(ow, '(');
261 for (argument = bc->v.macro.arguments; argument != 0; argument = argument->next)
262 {
263 encodeBytecode(argument->bc, ow);
264 if (argument->next != 0)
265 {
266 OUT_CHAR(ow, ',');
267 }
268 }
269 OUT_CHAR(ow, ')');
270 }
271 OUT_CHAR(ow, '>');
272 }
273 break;
274 }
275
276 bc = bc->next;
277 }
278 }
279
280 void
encodeValue(value * theValue,outputWriter * ow)281 encodeValue (value *theValue, outputWriter *ow)
282 {
283 assert(theValue != 0);
284
285 switch (theValue->type)
286 {
287 case VALUE_UNDEFINED :
288 return;
289
290 case VALUE_INTERNAL :
291 OUT_STRING(ow, "<internal>", 10);
292 break;
293
294 case VALUE_BUILT_IN :
295 OUT_STRING(ow, "<builtIn>", 9);
296 break;
297
298 case VALUE_SCALAR :
299 encodeDynstring(&theValue->v.scalar.scalar, ow);
300 break;
301
302 case VALUE_LIST :
303 {
304 int i;
305
306 OUT_CHAR(ow, *metaChar);
307 OUT_STRING(ow, "list(", 5);
308 if (valueListLength(theValue) > 0)
309 {
310 encodeValue(valueListGetElement(theValue, 0), ow);
311 for (i = 1; i < valueListLength(theValue); ++i)
312 {
313 OUT_CHAR(ow, ',');
314 encodeValue(valueListGetElement(theValue, i), ow);
315 }
316 }
317 OUT_CHAR(ow, ')');
318 }
319 break;
320
321 case VALUE_HASH :
322 {
323 value *aValue,
324 *keyValue;
325 char *aKey;
326 hstate state;
327
328 OUT_CHAR(ow, *metaChar);
329 OUT_STRING(ow, "hash(", 5);
330 state = hash_state(theValue->v.hash.hash);
331 if ((aValue = (value*)hash_next(&state, &aKey)) != 0)
332 {
333 keyValue = valueNewScalarFromCString(aKey);
334 encodeValue(keyValue, ow);
335 OUT_CHAR(ow, ',');
336 encodeValue(aValue, ow);
337 while ((aValue = (value*)hash_next(&state, &aKey)) != 0)
338 {
339 OUT_CHAR(ow, ',');
340 keyValue = valueNewScalarFromCString(aKey);
341 encodeValue(keyValue, ow);
342 OUT_CHAR(ow, ',');
343 encodeValue(aValue, ow);
344 }
345 }
346 OUT_CHAR(ow, ')');
347 }
348 break;
349
350 case VALUE_LAMBDA :
351 {
352 int i;
353
354 OUT_CHAR(ow, *metaChar);
355 OUT_STRING(ow, "lambda(", 7);
356 for (i = 0; i < theValue->v.lambda.numParams; ++i)
357 {
358 encodeDynstring(&theValue->v.lambda.paramNames[i], ow);
359 OUT_CHAR(ow, ',');
360 }
361 encodeBytecode(theValue->v.lambda.code, ow);
362 OUT_CHAR(ow, ')');
363 }
364 break;
365
366 case VALUE_ENVIRONMENT :
367 OUT_STRING(ow, "<environment>", 13);
368 break;
369
370 case VALUE_BYTECODE :
371 OUT_STRING(ow, "<bytecode>", 10);
372 break;
373
374 case VALUE_WHATSIT :
375 OUT_STRING(ow, "<whatsit>", 9);
376 break;
377
378 default :
379 assert(0);
380 }
381 }
382
383 void
builtInEncode(int numArgs,macroArgument * args,environment * env,outputWriter * ow)384 builtInEncode (int numArgs, macroArgument *args, environment *env, outputWriter *ow)
385 {
386 if (!(numArgs == 1))
387 {
388 issueError(ERRMAC_WRONG_NUM_ARGS, "encode");
389 return;
390 }
391
392 encodeValue(args[0].value.value, ow);
393 }
394
395 void
registerValues(void)396 registerValues (void)
397 {
398 registerBuiltIn("list", builtInList, 1, 0, 0);
399 registerBuiltIn("hash", builtInHash, 1, 0, 0);
400 registerBuiltIn("same", builtInSame, 1, 0, 0);
401 registerBuiltIn("equal", builtInEqual, 1, 0, 0);
402 registerBuiltIn("typeof", builtInTypeof, 1, 0, 0);
403 registerBuiltIn("encode", builtInEncode, 1, 0, 0);
404 }
405