Boron 2.1.0
construct.c
1/*
2 Copyright 2010,2013 Karl Robillard
3
4 This file is part of the Boron programming language.
5
6 Boron is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Boron is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with Boron. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20
21#define setBit(mem,n) (mem[(n)>>3] |= 1<<((n)&7))
22
23
24static void ur_binAppendInt( UBuffer* bin, uint32_t n,
25 UAtom size, int bigEndian )
26{
27 uint8_t* bp;
28
29 ur_binReserve( bin, bin->used + 4 );
30 bp = bin->ptr.b + bin->used;
31
32 switch( size )
33 {
34 case UR_ATOM_U8:
35 *bp = n;
36 bin->used += 1;
37 break;
38
39 case UR_ATOM_U16:
40 if( bigEndian )
41 {
42 *bp++ = n >> 8;
43 *bp = n;
44 }
45 else
46 {
47 *bp++ = n;
48 *bp = n >> 8;
49 }
50 bin->used += 2;
51 break;
52
53 case UR_ATOM_U32:
54 if( bigEndian )
55 {
56 *bp++ = n >> 24;
57 *bp++ = n >> 16;
58 *bp++ = n >> 8;
59 *bp = n;
60 }
61 else
62 {
63 *bp++ = n;
64 *bp++ = n >> 8;
65 *bp++ = n >> 16;
66 *bp = n >> 24;
67 }
68 bin->used += 4;
69 break;
70 }
71}
72
73
74#ifdef __BIG_ENDIAN__
75#define NATIVE_ENDIAN 1
76#else
77#define NATIVE_ENDIAN 0
78#endif
79
80union ConNum32 {
81 uint32_t i;
82 float f;
83};
84
85typedef struct {
86 UBuffer* bin;
87 int big;
88 UAtom size;
89} BinConstructState;
90
91static int binary_construct2(UThread* ut, BinConstructState* cs,
92 const UCell* cell)
93{
94switch_cell:
95 switch (ur_type(cell))
96 {
97 case UT_INT:
98 ur_binAppendInt(cs->bin, ur_int(cell), cs->size, cs->big);
99 break;
100
101 case UT_DOUBLE:
102 {
103 // Emit as 32-bit float for now.
104 union ConNum32 n;
105 n.f = ur_double(cell);
106 ur_binAppendInt(cs->bin, n.i, UR_ATOM_U32, cs->big);
107 }
108 break;
109
110 case UT_COORD:
111 {
112 int i, len = cell->coord.len;
113 for (i = 0; i < len; ++i)
114 ur_binAppendInt(cs->bin, cell->coord.n[i], cs->size, cs->big);
115 }
116 break;
117
118 case UT_VEC3:
119 if (cs->big == NATIVE_ENDIAN)
120 ur_binAppendData(cs->bin, (const uint8_t*) cell->vec3.xyz, 12);
121 else {
122 union ConNum32 n;
123 int i;
124 for (i = 0; i < 3; ++i) {
125 n.f = cell->vec3.xyz[i];
126 ur_binAppendInt(cs->bin, n.i, UR_ATOM_U32, cs->big);
127 }
128 }
129 break;
130
131 case UT_WORD:
132 switch (ur_atom(cell))
133 {
134 case UR_ATOM_U8:
135 case UR_ATOM_U16:
136 case UR_ATOM_U32:
137 cs->size = ur_atom(cell);
138 break;
139
140 case UR_ATOM_BIG_ENDIAN:
141 cs->big = 1;
142 break;
143
144 case UR_ATOM_LITTLE_ENDIAN:
145 cs->big = 0;
146 break;
147
148 default:
149 if( ! (cell = ur_wordCell(ut, cell)) )
150 return UR_THROW;
151 goto switch_cell;
152 }
153 break;
154
155 case UT_BINARY:
156 {
157 UBinaryIter b2;
158 ur_binSlice(ut, &b2, cell);
159 if (b2.end > b2.it)
160 ur_binAppendData(cs->bin, b2.it, b2.end - b2.it);
161 }
162 break;
163
164 case UT_BLOCK:
165 {
166 BinConstructState cs2 = *cs;
167 UBlockIt b2;
168 ur_blockIt(ut, &b2, cell);
169 ur_foreach(b2) {
170 if (binary_construct2(ut, &cs2, b2.it) == UR_THROW)
171 return UR_THROW;
172 }
173 }
174 break;
175
176 default:
177 return ur_error(ut, UR_ERR_TYPE,
178 "Invalid construct binary! type (%s)",
179 ur_atomCStr(ut, ur_type(cell)));
180 }
181 return UR_OK;
182}
183
184
185static int binary_construct( UThread* ut, const UCell* blkC, const UCell* binC )
186{
187 BinConstructState cs;
188 UBlockIt bi;
189
190 cs.big = 0;
191 cs.size = UR_ATOM_U32;
192 cs.bin = ur_bufferSerM(binC);
193 if (! cs.bin)
194 return UR_THROW;
195
196 ur_blockIt(ut, &bi, blkC);
197 ur_foreach(bi) {
198 if (binary_construct2(ut, &cs, bi.it) == UR_THROW)
199 return UR_THROW;
200 }
201 return UR_OK;
202}
203
204
205extern int string_append( UThread* ut, UBuffer* buf, const UCell* val );
206
207static int sc_appendEval( UThread* ut, UBuffer* str, const UCell* val )
208{
209 if( ur_is(val, UT_WORD) )
210 {
211 if( ! (val = ur_wordCell( ut, val )) )
212 return UR_THROW;
213 if( ur_is(val, UT_NONE) )
214 return UR_OK;
215 }
216 return string_append( ut, str, val );
217}
218
219
220/*
221 Create output string from input with changes.
222
223 The plan block is simply a list of search and replace values.
224*/
225static int string_construct( UThread* ut, UBuffer* str,
226 const UCell* inputC, const UCell* blkC )
227{
228#define SC_BIT_COUNT 256
229 USeriesIter in;
230 UBlockIt bi;
231 UBuffer cset;
232 const UCell* begin;
233 UIndex copyPos;
234 int ch;
235 int fp;
236
237
238 ur_blockIt( ut, &bi, blkC );
239 begin = bi.it;
240 if( (bi.end - bi.it) & 1 )
241 --bi.end;
242
243 // Create bitset of search value characters.
244 ur_binInit( &cset, SC_BIT_COUNT / 8 );
245 cset.used = SC_BIT_COUNT / 8;
246 memSet( cset.ptr.b, 0, cset.used );
247 for( ; bi.it != bi.end; bi.it += 2 )
248 {
249 if( ur_is(bi.it, UT_CHAR) )
250 {
251 ch = ur_int(bi.it);
252 }
253 else if( ur_is(bi.it, UT_STRING) )
254 {
255 USeriesIter si;
256 ur_seriesSlice( ut, &si, bi.it );
257 ch = ur_strChar( si.buf, si.it );
258 }
259 else
260 {
261 ch = -1;
262 }
263
264 if( ch >= 0 && ch < SC_BIT_COUNT )
265 setBit( cset.ptr.b, ch );
266 }
267
268 // Append to str with replacements.
269 ur_seriesSlice( ut, &in, inputC );
270 copyPos = in.it;
271 while( (fp = ur_strFindChars(in.buf, in.it, in.end, cset.ptr.b, cset.used))
272 > -1 )
273 {
274 ch = ur_strIsUcs2(in.buf) ? in.buf->ptr.u16[ fp ]
275 : in.buf->ptr.b[ fp ];
276
277 for( bi.it = begin; bi.it != bi.end; bi.it += 2 )
278 {
279 if( ur_is(bi.it, UT_CHAR) )
280 {
281 if( ch == ur_int(bi.it) )
282 {
283 in.it = fp + 1;
284match:
285 ur_strAppend( str, in.buf, copyPos, fp );
286 copyPos = in.it;
287 if( sc_appendEval( ut, str, bi.it + 1 ) != UR_OK )
288 return UR_THROW;
289 break;
290 }
291 }
292 else if( ur_is(bi.it, UT_STRING) )
293 {
294 USeriesIter inA;
295 USeriesIter si;
296 int len;
297
298 ur_seriesSlice( ut, &si, bi.it );
299 len = si.end - si.it;
300
301 inA.buf = in.buf;
302 inA.it = fp;
303 inA.end = in.end;
304
305 if( ur_strMatch( &inA, &si, 0 ) == len )
306 {
307 in.it = fp + len;
308 goto match;
309 }
310 }
311 }
312 if( bi.it == bi.end )
313 ++in.it;
314 }
315 ur_strAppend( str, in.buf, copyPos, in.end );
316
317 ur_binFree( &cset );
318 return UR_OK;
319}
320
321
322UStatus bitset_construct( UThread* ut, const UCell* strC, UCell* res )
323{
324 uint8_t* bits;
325 int c, prev, range;
326 int cmax = 0;
327 USeriesIter si;
328 UIndex start;
329
330 ur_seriesSlice( ut, &si, strC );
331 start = si.it;
332 ur_foreach( si )
333 {
334 c = ur_strChar( si.buf, si.it ) + 1;
335 if( cmax < c )
336 cmax = c;
337 }
338 if( cmax && cmax < 256 )
339 cmax = 256;
340
341 bits = ur_makeBitsetCell( ut, cmax, res )->ptr.b; // gc!
342 if( bits )
343 {
344 si.buf = ur_bufferSer( strC ); // Re-aquire buf.
345
346 prev = range = -1;
347 si.it = start;
348 ur_foreach( si )
349 {
350 c = ur_strChar( si.buf, si.it );
351 if (c == '-') {
352 if (prev >= 0 && range < 0) {
353 range = prev;
354 } else {
355 range = -1;
356 setBit(bits, c);
357 }
358 } else if (range >= 0) {
359 if (range > c) {
360 cmax = range;
361 range = c;
362 c = cmax;
363 }
364 for (; range <= c; ++range)
365 setBit(bits, range);
366 prev = range = -1;
367 } else {
368 if (prev >= 0)
369 setBit(bits, prev);
370 prev = c;
371 }
372 }
373 if (range >= 0)
374 setBit(bits, '-');
375 if (prev >= 0)
376 setBit(bits, prev);
377 }
378 return UR_OK;
379}
380
381
382extern int bitset_make( UThread* ut, const UCell* from, UCell* res );
383
384/*-cf-
385 construct
386 object datatype!/binary!/string!
387 plan string!/block!
388 return: New value.
389 group: data
390
391 Make or append values with a detailed specification.
392
393 The string! plan is simply pairs of search & replace values applied
394 to a copy of an existing string. Both the search pattern and replacement
395 value types must be char! or string!.
396
397 construct "$NAME travels > $CITY" [
398 '>' "to"
399 "$NAME" "Joseph"
400 "$CITY" "Paris"
401 ]
402 == "Joseph travels to Paris"
403
404 It is much more efficient to replace text using construct than calling the
405 replace function multiple times. In the future more rules may be added.
406
407 For bitset! the plan is a string in which dash characters denote a range
408 of bits to set. Use two consecutive dashes to include the dash character
409 itself. For example, a bitset of hexidecimal characters would be:
410
411 construct bitset! "a-fA-F0-9"
412
413 A binary! plan concatenates numbers with specified byte sizes and endianess.
414 These default to 'u32 and 'little-endian respectively.
415 Any words and blocks will be evaluated recursively.
416 Double! and vec3! values are always output as 32-bit floats.
417
418 header: [big-endian 0x11 0x2233]
419 data: [u16 0x11 0x2233]
420 construct binary! [header data]
421 == #{000000110000223311003322}
422*/
423CFUNC(cfunc_construct)
424{
425 const UCell* plan = a1+1;
426 const UBuffer* in;
427 int dt;
428
429 switch( ur_type(a1) )
430 {
431 case UT_DATATYPE:
432 dt = ur_datatype(a1);
433 if( dt == UT_BINARY )
434 {
435 ur_makeBinaryCell( ut, 0, res );
436 goto con_binary;
437 }
438 else if( dt == UT_BITSET )
439 {
440 if( ur_is(plan, UT_STRING) )
441 return bitset_construct( ut, plan, res );
442 if( ur_is(plan, UT_CHAR) )
443 return bitset_make( ut, plan, res );
444 goto bad_plan;
445 }
446 break;
447
448 case UT_BINARY:
449 *res = *a1;
450con_binary:
451 if( ! ur_is(plan, UT_BLOCK) )
452 goto bad_plan1;
453 return binary_construct( ut, plan, res );
454
455 case UT_STRING:
456 if( ! ur_is(plan, UT_BLOCK) )
457 goto bad_plan1;
458 in = ur_bufferSer(a1);
459 return string_construct( ut,
460 ur_makeStringCell( ut, in->form, in->used, res ), // gc!
461 a1, plan );
462 }
463 return boron_badArg( ut, ur_type(a1), 0 );
464
465bad_plan1:
466 dt = ur_type(a1);
467bad_plan:
468 return ur_error( ut, UR_ERR_TYPE, "Invalid plan type for construct %s",
469 ur_atomCStr(ut,dt) );
470}
471
472
473//EOF
#define CFUNC(name)
Macro to define C functions.
Definition boron.h:57
UStatus boron_badArg(UThread *, UIndex atom, int argN)
Throw a standardized error for an unexpected function argument.
Definition eval.c:696
void ur_binAppendData(UBuffer *, const uint8_t *data, int len)
Append data to binary buffer.
Definition binary.c:213
UBuffer * ur_makeBinaryCell(UThread *, int size, UCell *cell)
Generate a single binary and set cell to reference it.
Definition binary.c:74
void ur_binReserve(UBuffer *, int size)
Allocates enough memory to hold size bytes.
Definition binary.c:138
void ur_binInit(UBuffer *, int size)
Initialize buffer to type UT_BINARY.
Definition binary.c:93
void ur_binFree(UBuffer *)
Free binary data.
Definition binary.c:120
void ur_binSlice(UThread *, UBinaryIter *, const UCell *cell)
Set UBinaryIter to binary slice.
Definition binary.c:423
UBuffer * ur_makeStringCell(UThread *, int enc, int size, UCell *cell)
Generate a single string and set cell to reference it.
Definition string.c:104
int ur_strChar(const UBuffer *, UIndex pos)
Return the character at a given position.
Definition string.c:1659
UIndex ur_strFindChars(const UBuffer *, UIndex start, UIndex end, const uint8_t *charSet, int len)
Find the first character of a set in a string.
Definition string.c:1353
UIndex ur_strMatch(const USeriesIter *, const USeriesIter *, int matchCase)
Compare characters in two string or binary series.
Definition string.c:1584
void ur_strAppend(UBuffer *, const UBuffer *strB, UIndex itB, UIndex endB)
Append another string buffer to this string.
Definition string.c:899
void ur_seriesSlice(const UThread *, USeriesIter *si, const UCell *cell)
Set USeriesIter to series slice.
Definition env.c:1338
#define ur_bufferSer(c)
Convenience macro for ur_bufferSeries().
Definition urlan.h:752
const char * ur_atomCStr(UThread *, UAtom atom)
Get name of atom.
Definition atoms.c:47
UIndex it
Start position.
Definition urlan.h:338
UStatus ur_error(UThread *, int errorType, const char *fmt,...)
Create error! exception.
Definition env.c:964
const UCell * ur_wordCell(UThread *, const UCell *cell)
Get word value for read-only operations.
Definition env.c:1132
const UCell * end
End position.
Definition urlan.h:388
UIndex end
End position.
Definition urlan.h:339
const UCell * it
Start position.
Definition urlan.h:387
@ UR_THROW
Returned to indicate an evaluation exception occured.
Definition urlan.h:117
@ UR_OK
Returned to indicate successful evaluation/operation.
Definition urlan.h:118
#define ur_foreach(bi)
Loop over all members of an iterator struct.
Definition urlan.h:760
#define ur_bufferSerM(c)
Convenience macro for ur_bufferSeriesM().
Definition urlan.h:753
const UBuffer * ur_blockIt(const UThread *ut, UBlockIt *bi, const UCell *blkCell)
Set UBlockIt to the start and end of a block slice.
Definition env.c:1388
const UBuffer * buf
Buffer pointer.
Definition urlan.h:337
#define ur_type(c)
Return UrlanDataType of cell.
Definition urlan.h:695
Iterator for const UCell array.
Definition urlan.h:386
The UBuffer struct holds information about a resource, usually a chunk of memory.
Definition urlan.h:266
uint8_t * b
bytes
Definition urlan.h:277
uint8_t form
This can indicate a specific form of the data (such as a string encoding).
Definition urlan.h:269
int32_t * i
int32_t
Definition urlan.h:280
UIndex used
This typically holds the number of elements in the buffer.
Definition urlan.h:271
uint16_t * u16
uint16_t
Definition urlan.h:279
union UBuffer::@312146223224040072236377336057316010374162171270 ptr
This typically holds a pointer to a chunk of memory.
int16_t n[UR_COORD_MAX]
Holds six, 16-bit integers.
Definition urlan.h:195
uint16_t len
Number of integers used in array n.
Definition urlan.h:194
float xyz[3]
The three float values.
Definition urlan.h:203
Iterator for const series of any type.
Definition urlan.h:336
The UThread struct stores the data specific to a thread of execution.
Definition urlan.h:309
A cell holds a single value of a simple type or a reference (often to a UBuffer) for a complex type.
Definition urlan.h:248
UCellVec3 vec3
For vec3! type.
Definition urlan.h:254
UCellCoord coord
For coord! type.
Definition urlan.h:253
UStatus
Definition urlan.h:116
#define ur_datatype(c)
Access the UrlanDataType that a UCellDatatype represents.
Definition urlan.h:711
@ UR_ERR_TYPE
Invalid argument/parameter datatype.
Definition urlan.h:125
int32_t UIndex
This is an index into an array.
Definition urlan.h:150