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