root/trunk/thune/component.c

Revision 458, 12.2 kB (checked in by krobillard, 15 months ago)

Merged Thune thread_safe branch into trunk (r386:457)

Line 
1/*============================================================================
2    Thune Interpreter
3    Copyright (C) 2005-2007  Karl Robillard
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18===========================================================================*/
19
20
21#include "internal.h"
22#include "component.h"
23#include "urlan_atoms.h"
24
25
26/*
27  Returns zero if signature is invalid.
28*/
29static UIndex _makeComponent( UThread* ut, UCell* res,
30                              const UCell* sigCell,
31                              const UCell* bodCell )
32{
33    //UIndex sigN;
34    UBlock* blk;
35    UCell* start;
36    UCell* it;
37    UCell* end;
38    int inC, outC, localC;
39    int* counter;
40    UAtom atom;
41    uint32_t special = 0;
42
43
44    blk = ur_blockSlice( ut, sigCell, &start, &end );
45    if( ! blk || ! start )
46        return 0;
47
48    // Count words in context.
49    inC = outC = localC = 0;
50    counter = &inC;
51    it = start;
52    while( it != end )
53    {
54        if( ur_is(it, UT_WORD) || ur_is(it, UT_OPCODE) )
55        {
56            if( ur_atom(it) == UR_ATOM_DDASH )
57                counter = &outC;
58            else if( ur_atom(it) == UR_ATOM_BAR )
59                counter = &localC;
60            else if( ur_atom(it) >= UT_BI_COUNT )
61                *counter = *counter + 1;
62        }
63        else if( ur_is(it, UT_SELECT) )
64        {
65            if( ur_atom(it) >= UT_BI_COUNT )
66            {
67                if( ur_selIsAtom(it) && (counter == &inC) )
68                {
69                    const char* str = ur_atomCStr( ur_sel(it), 0 );
70                    if( *str == 'q' )
71                        special |= 1 << inC;        // Quiet
72                    else if( *str == 's' )
73                        special |= 0x10000 << inC;  // Strobe
74                }
75                *counter = *counter + 1;
76            }
77        }
78        ++it;
79    }
80
81
82    ur_makeContext( res, COMPONENT_CELLS + inC + outC + localC );
83    ur_type(res) = UT_COMPONENT;
84
85    ur_internWord( res, UR_ATOM_SELF );
86    ur_internWord( res, ur_intern("component-counts", 16) );
87    ur_internWord( res, ur_intern("component-body", 14) );
88
89    // Create words in context.
90    it = start;
91    while( it != end )
92    {
93        if( ur_is(it, UT_WORD) || ur_is(it, UT_OPCODE) ||
94            ur_is(it, UT_SELECT) )
95        {
96            atom = ur_atom(it);
97            if( (atom >= UT_BI_COUNT) &&
98                (atom != UR_ATOM_DDASH) &&
99                (atom != UR_ATOM_BAR) )
100            {
101                ur_internWord( res, atom );
102            }
103        }
104        ++it;
105    }
106
107    blk = ur_blockPtr( res->ctx.valBlk );
108    it = blk->ptr.cells;
109
110    ur_copyCell( it, *res );        // self
111    ++it;
112    ur_initType( it, UT_COORD );    // component-counts
113    it->coord.len = 6;
114    ur_ccIn(it)   = inC;
115    ur_ccOut(it)  = outC;
116    ur_ccLoc(it)  = localC;
117    ur_ccMask(it) = 0xffff << inC;
118    ur_ccSpec(it) = special;
119    ++it;
120    ur_copyCell( it, *bodCell );    // component-body
121
122    if( localC )
123    {
124        // Initialize locals to none.
125        it += inC + outC + 1;
126        end = it + localC;
127        while( it != end )
128        {
129            ur_setNone(it);
130            ++it;
131        }
132    }
133
134    ur_bindT( ut, bodCell->series.n, res, UR_BIND_PLUG );
135
136    return 0; //sigN;
137}
138
139
140/*
141   (sig body -- comp)
142*/
143UR_CALL( uc_component )
144{
145    UCell* res;
146
147    if( ur_is(tos, UT_BLOCK) )
148    {
149        res = ur_s_prev(tos);
150        if( ur_is(res, UT_BLOCK) )
151        {
152            _makeComponent( ut, res, res, tos );
153            UR_S_DROP;
154            return;
155        }
156    }
157
158    ur_throwErr( UR_ERR_DATATYPE,
159                 "component expected signature & body blocks" );
160}
161
162
163static void initConnectWord( UCell* link, UAtom atom, const UCell* cc, int wrd )
164{
165    link->word.atom    = atom;
166    link->word.wordBlk = cc->ctx.wordBlk;
167    link->word.valBlk  = cc->ctx.valBlk;
168    link->word.index   = wrd;
169    link->word.sel     = 0;
170}
171
172
173/*
174   (from to -- )
175*/
176UR_CALL( uc_connect )
177{
178    UCell* arg1;
179    UCell* cc1;
180    UCell* cc2;
181    UCell* conn;
182    UCell* val;
183    UBlock* b1;
184    UAtom atom;
185    int wrd;
186    int wrd2;
187
188    // Connect to this component...
189    if( ur_is(tos, UT_SELECT) && ur_selIsAtom(tos) )
190    {
191        cc2 = ur_wordCell( ut, tos );
192        if( ! cc2 )
193            return;
194        if( ! ur_is(cc2, UT_COMPONENT) )
195            goto dt_err;
196        wrd2 = ur_lookup( cc2, ur_sel(tos) );
197        if( wrd2 < 0 )
198            goto dt_err;
199        atom = ur_sel(tos);
200    }
201    else if( ur_is(tos, UT_COMPONENT) )
202    {
203        // Use first input.
204        cc2  = tos;
205        wrd2 = COMPONENT_CELLS;
206
207        b1 = ur_blockPtr( cc2->ctx.wordBlk );
208        atom = b1->ptr.cells[ COMPONENT_CELLS ].word.atom;
209    }
210    else
211        goto dt_err;
212
213
214    // ...from this component.
215    arg1 = ur_s_prev(tos);
216    if( ur_is(arg1, UT_SELECT) && ur_selIsAtom(arg1) )
217    {
218        cc1 = ur_wordCell( ut, arg1 );
219        if( ! cc1 )
220            return;
221        if( ! ur_is(cc1, UT_COMPONENT) )
222            goto dt_err;
223        wrd = ur_lookup( cc1, ur_sel(arg1) );
224        if( wrd < 0 )
225            goto dt_err;
226        b1 = ur_blockPtr( cc1->ctx.valBlk );
227        cc1 = b1->ptr.cells + COMPONENT_COUNTS;
228        if( wrd < (COMPONENT_CELLS + ur_ccIn(cc1)) )
229            goto out_err;
230        if( wrd >= (COMPONENT_CELLS + ur_ccIn(cc1) + ur_ccOut(cc1)) )
231            goto out_err;
232        conn = b1->ptr.cells + wrd;
233    }
234    else if( ur_is(arg1, UT_COMPONENT) )
235    {
236        // Use first output.
237        b1 = ur_blockPtr( arg1->ctx.valBlk );
238        cc1 = b1->ptr.cells + COMPONENT_COUNTS;
239        if( ur_ccOut(cc1) < 1 )
240            goto out_err;
241        conn = b1->ptr.cells + COMPONENT_CELLS + ur_ccIn(cc1);
242    }
243    else
244        goto dt_err;
245
246       
247    if( ur_is(conn, UT_BLOCK) )
248    {
249        // Two or more connections exist.
250        val = ur_appendCell( tBlock( conn ), UT_WORD );
251        initConnectWord( val, atom, cc2, wrd2 );
252    }
253    else if( ur_is(conn, UT_WORD) )
254    {
255        // A single connection exists; create a block to hold more.
256        UBlock* connBlk;
257        UIndex n;
258
259        n = ur_makeBlockT( ut, 2, &connBlk );
260        connBlk->used = 2;
261
262        val = connBlk->ptr.cells;
263        ur_copyCell( val, *conn );
264
265        ++val;
266        ur_initType( val, UT_WORD );
267        initConnectWord( val, atom, cc2, wrd2 );
268
269        ur_initBlock( conn, n, 0 );
270    }
271    else
272    {
273        // No existing connections.
274        ur_initType( conn, UT_WORD );
275        initConnectWord( conn, atom, cc2, wrd2 );
276    }
277
278    UR_S_DROPN( 2 );
279    return;
280
281dt_err:
282
283    ur_throwErr( UR_ERR_DATATYPE,
284                 "connect expected select! select! bound to components" );
285    return;
286
287out_err:
288
289    ur_throwErr( UR_ERR_SCRIPT, "Must connect to a component output" );
290}
291
292
293/*
294   (from to -- )
295
296   TODO:
297     (from 'all -- )
298     ('all to -- )   ; This will be costly - must check all components.
299                     ; May want to save blkN of all connected input components.
300*/
301UR_CALL( uc_disconnect )
302{
303    UCell* arg1;
304    UCell* cc1;
305    UCell* cc2;
306    UCell* conn;
307    UCell* it;
308    UCell* end;
309    UBlock* b1;
310    UAtom atom;
311    int wrd;
312
313    // Disconnect this component input...
314    if( ur_is(tos, UT_SELECT) && ur_selIsAtom(tos) )
315    {
316        cc2 = ur_wordCell( ut, tos );
317        if( ! cc2 )
318            return;
319        if( ! ur_is(cc2, UT_COMPONENT) )
320            goto dt_err;
321        atom = ur_sel(tos);
322    }
323    else if( ur_is(tos, UT_COMPONENT) )
324    {
325        // Use first input.
326        cc2  = tos;
327        b1   = ur_blockPtr( cc2->ctx.wordBlk );
328        atom = b1->ptr.cells[ COMPONENT_CELLS ].word.atom;
329    }
330    else
331        goto dt_err;
332
333
334    // ...from this component output.
335    arg1 = ur_s_prev(tos);
336    if( ur_is(arg1, UT_SELECT) && ur_selIsAtom(arg1) )
337    {
338        cc1 = ur_wordCell( ut, arg1 );
339        if( ! cc1 )
340            return;
341        if( ! ur_is(cc1, UT_COMPONENT) )
342            goto dt_err;
343        wrd = ur_lookup( cc1, ur_sel(arg1) );
344        if( wrd < 0 )
345            goto dt_err;
346        b1 = ur_blockPtr( cc1->ctx.valBlk );
347        cc1 = b1->ptr.cells + COMPONENT_COUNTS;
348        if( wrd < (COMPONENT_CELLS + ur_ccIn(cc1)) )
349            goto out_err;
350        if( wrd >= (COMPONENT_CELLS + ur_ccIn(cc1) + ur_ccOut(cc1)) )
351            goto out_err;
352        conn = b1->ptr.cells + wrd;
353    }
354    else if( ur_is(arg1, UT_COMPONENT) )
355    {
356        // Use first output.
357        b1 = ur_blockPtr( arg1->ctx.valBlk );
358        cc1 = b1->ptr.cells + COMPONENT_COUNTS;
359        if( ur_ccOut(cc1) < 1 )
360            goto out_err;
361        conn = b1->ptr.cells + COMPONENT_CELLS + ur_ccIn(cc1);
362    }
363    else
364        goto dt_err;
365
366       
367    if( ur_is(conn, UT_BLOCK) )
368    {
369        // Multiple connections may exist.
370        b1 = tBlock( conn );
371        it  = b1->ptr.cells;
372        end = it + b1->used;
373        while( it != end )
374        {
375            assert( ur_is(it, UT_WORD) );
376            if( (ur_atom(it) == atom) &&
377                (it->word.valBlk == cc2->ctx.valBlk) )
378            {
379                ur_arrayErase( b1, sizeof(UCell), it - b1->ptr.cells, 1 );
380                break;
381            }
382            ++it;
383        }
384    }
385    else if( ur_is(conn, UT_WORD) )
386    {
387        // A single connection exists.
388        if( (ur_atom(conn) == atom) &&
389            (conn->word.valBlk == cc2->ctx.valBlk) )
390        {
391            ur_setNone( conn );
392        }
393    }
394    // Else no existing connections.
395
396    UR_S_DROPN( 2 );
397    return;
398
399dt_err:
400
401    ur_throwErr( UR_ERR_DATATYPE,
402                 "disconnect expected select! select! bound to components" );
403    return;
404
405out_err:
406
407    ur_throwErr( UR_ERR_SCRIPT, "Must disconnect from a component output" );
408}
409
410
411/**
412  \param blk   Component value block.
413  \param wrdN  Index into blk.
414  \param nval  Value to send through all connections.
415*/
416void ur_setPlug( UThread* ut, UBlock* blk, UIndex wrdN, const UCell* nval )
417{
418    UCell* plugCnts;
419    UCell* val;
420    int trigger;
421    uint32_t mask;
422    uint32_t special;
423
424    if( wrdN < COMPONENT_CELLS )
425        return;
426
427    val      = blk->ptr.cells + wrdN;
428    plugCnts = blk->ptr.cells + COMPONENT_COUNTS;
429
430    wrdN -= COMPONENT_CELLS;
431    if( wrdN < ur_ccIn(plugCnts) )
432    {
433        // Input
434
435        ur_copyCell( val, *nval );
436
437        mask = 0x10001 << wrdN;
438        special = ur_ccSpec(plugCnts) & mask;
439
440        trigger = ur_ccMask(plugCnts);
441        if( trigger != -1 )
442        {
443            trigger |= mask;
444
445            if( special < 0x10000 )             // Not Strobe
446                ur_ccMask(plugCnts) = trigger;
447
448            if( trigger != -1 )
449                return;
450        }
451
452        if( special & 0xffff )                  // Quiet
453            return;
454
455        // All inputs are set; add to execute list...
456#if 1
457        // Just eval immediately for now.
458        val = blk->ptr.cells + COMPONENT_BODY;
459        ur_eval( ut, val->series.n, 0 );
460        //if( ok == UR_EVAL_ERROR )
461#endif
462        return;
463    }
464
465    wrdN -= ur_ccIn(plugCnts);
466    if( wrdN < ur_ccOut(plugCnts) )
467    {
468        // Output
469
470        if( ur_is(val, UT_WORD) )
471        {
472            ur_setPlug( ut, tBlockPtr(val->word.valBlk),
473                        val->word.index, nval );
474        }
475        else if( ur_is(val, UT_BLOCK) )
476        {
477            UCell* end;
478            blk = tBlock( val );
479            val = blk->ptr.cells;
480            end = val + blk->used;
481            while( val != end )
482            {
483                if( ur_is(val, UT_WORD) )
484                {
485                    ur_setPlug( ut, tBlockPtr(val->word.valBlk),
486                                val->word.index, nval );
487                }
488                ++val;
489            }
490        }
491    }
492    else
493    {
494        // Local
495        ur_copyCell( val, *nval );
496    }
497}
498
499
500/*EOF*/
Note: See TracBrowser for help on using the browser.