File: message_ext.cpp

package info (click to toggle)
falconpl 0.9.6.9-git20120606-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 46,176 kB
  • sloc: cpp: 181,389; ansic: 109,025; yacc: 2,310; xml: 1,218; sh: 403; objc: 245; makefile: 82; sql: 20
file content (846 lines) | stat: -rw-r--r-- 25,113 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
/*
   FALCON - The Falcon Programming Language.
   FILE: message_ext.cpp

   Attribute support functions for scripts.
   -------------------------------------------------------------------
   Author: Giancarlo Niccolai
   Begin: Thu, 14 Aug 2008 02:33:46 +0200

   -------------------------------------------------------------------
   (C) Copyright 2008: the FALCON developers (see list in AUTHORS file)

   See LICENSE file for licensing details.
*/

#include "core_module.h"

/*#
   @beginmodule core
*/

namespace Falcon {
namespace core {


static void check_assertion( VMachine *vm, CoreSlot *cs, const Item &itm )
{
   if ( cs->hasAssert() )
   {
      vm->pushParameter( cs->assertion() );

      if ( ! itm.isCallable() )
      {
         if( itm.isComposed() )
         {
            // may throw
            Item tmp;
            itm.asDeepItem()->readProperty( "on_" + cs->name(), tmp );
            tmp.readyFrame( vm, 1 );
         }
         else
         {
            throw new CodeError( ErrorParam( e_non_callable, __LINE__ ).extra( "broadcast" ) );
         }
      }
      else
         itm.readyFrame( vm, 1 );
   }
}

/*#
   @funset set_message_model Message oriented model functions
   @brief Functions supporting Message Oriented Programming (MOP)
   @see message_model

   This is the list of functions working together to implement the
   message oriented model. Other than this functions, it is possible
   to use the @a VMSlot class for direct access to reflected virtual
   machine slots. On this regards, see the @a message_model group.
*/

/*#
   @group message_model Message oriented model
   @brief Functions and classes supporting Message Oriented Programming (MOP)

   @begingroup message_model
*/


/*#
   @function broadcast
   @param msg A message (string) to be broadcast.
   @optparam ... Zero or more data to be broadcaset.
   @brief Sends a message to every callable item subscribed to a message.
   @return true if @b msg is found, false if it doesn't exist.
   @inset set_message_model
   @see VMSlot
   @see getSlot

   Broadcast function implicitly searches for a Virtual Machine Message Slot (@a VMSlot)
   with the given @b msg name, and if it finds it, it emits a broadcast on that.

   If the message is not found, the broadcast is silently dropped (no error is raised),
   but the function returns false.

   As calling this function requires a scan in the virtual machine message slot
   table, in case of repeated operations it is preferable to explicitly search for
   a slot with @a getSlot, or to create it as an @a VMSlot instance. On the other hand,
   if the reference to a VMSlot is not needed, this function allows to broadcast on the
   slot without adding the overhead required by the creation of the @a VMSlot wrapper.
*/

FALCON_FUNC  broadcast( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );
   if ( ! i_msg->isString() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S,..." ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), false );
   if ( cs )
   {
      cs->prepareBroadcast( vm->currentContext(), 1, vm->paramCount() - 1 );
      vm->regA().setBoolean(true);
   }
   else
      vm->regA().setBoolean(false);

   // otherwise, we're nothing to do here.
}

/*#
   @function subscribe
   @inset set_message_model
   @brief Registers a callback to a message slot.
   @param msg A string with the message name on which the item should be registered.
   @param handler A callable item or instance providing callback support.
   @optparam prio Set to true to insert this subscription in front of the subscription list.
*/

FALCON_FUNC subscribe( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );
   Item *i_handler = vm->param( 1 );
   Item *i_prio = vm->param(2);
   
   if ( i_msg == 0 || ! i_msg->isString()
        || i_handler == 0  || ! ( i_handler->isCallable() || i_handler->isComposed() ) )
   {
      throw new ParamError( ErrorParam( e_inv_params )
         .origin( e_orig_runtime )
         .extra( "S,C" ) );
   }

   String *sub = i_msg->asString();
   CoreSlot* cs = vm->getSlot( *sub, true );
   if ( i_prio != 0 && i_prio->isTrue() )
      cs->push_front( *i_handler );
   else
      cs->push_back( *i_handler );
      
   check_assertion( vm, cs, *i_handler );
}

/*#
   @function unsubscribe
   @inset set_message_model
   @brief Unregisters a registered callback from a slot.
   @param msg A string with the message name on which the item should be registered.
   @param handler A callable item or instance providing callback support.
   @raise CodeError if the @b handler is not registered with this slot.
   @raise AccessError if the named message slot doesn't exist.
*/

FALCON_FUNC unsubscribe( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );
   Item *i_handler = vm->param( 1 );

   if ( i_msg == 0 || ! i_msg->isString()
        || i_handler == 0 || ! ( i_handler->isCallable() || i_handler->isComposed() ) )
   {
      throw new ParamError( ErrorParam( e_inv_params ).
         extra( "S,C" ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), false );
   if ( cs == 0 )
   {
      throw new AccessError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( *i_msg->asString() ) );
   }

   if( ! cs->remove( *i_handler ) )
   {
      throw new CodeError( ErrorParam( e_param_range, __LINE__ )
         .origin( e_orig_runtime ).extra( "unsubscribe" ) );
   }

   if ( cs->empty() && ! cs->hasAssert() )
   {
      vm->removeSlot( cs->name() );
   }
}


/*#
   @function getSlot
   @inset set_message_model
   @brief Retreives a MOP Message slot.
   @param msg The message slot that must be taken or created.
   @optparam make If true (default) create the slot if it doesn't exist.
   @return The message slot coresponding with this name.
*/
FALCON_FUNC getSlot( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );

   if ( i_msg == 0 || ! i_msg->isString() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S" ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), (vm->param(1) == 0 || vm->param(1)->isTrue())  );
   if ( cs == 0 )
   {
      throw new MessageError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( *i_msg->asString() ) );
   }
   else
   {
      Item* cc_slot = vm->findWKI( "VMSlot" );
      fassert( cc_slot != 0 );
      // the factory function takes care of increffing cs
      CoreObject *obj = cc_slot->asClass()->createInstance( cs );
      cs->decref();
      vm->retval( obj );
   }
}


/*#
   @function consume
   @inset set_message_model
   @brief Consumes currently being broadcasted signal.
*/
FALCON_FUNC consume( ::Falcon::VMachine *vm )
{
   // TODO: report error.
   vm->consumeSignal();
}

/*#
   @function assert
   @inset set_message_model
   @brief Creates a message assertion on a certain message slot.
   @param msg The message to be asserted.
   @param data The value of the assertion.

   If there are already subscribed callbacks for this message
   a broadcast on them is performed now.
*/
FALCON_FUNC assert( ::Falcon::VMachine *vm )
{
   // TODO: report error.
   Item *i_msg = vm->param( 0 );
   Item *i_data = vm->param( 1 );
   if ( i_msg == 0 || ! i_msg->isString() || i_data == 0  )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S,X" ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), true );
   cs->setAssertion( vm, *i_data );
}

/*#
   @function retract
   @inset set_message_model
   @brief Removes a previous assertion on a message.
   @param msg The message slot to be retracted.
*/
FALCON_FUNC retract( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );
   if ( i_msg == 0 || ! i_msg->isString()  )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S" ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), true );
   if( cs != 0 )
   {
      cs->retract();
      if( cs->empty() )
      {
         vm->removeSlot( cs->name() );
      }
   }

     // TODO: report error if the slot is not found
}

/*#
   @function getAssert
   @inset set_message_model
   @brief Returns the given assertion, if it exists.
   @param msg The message slot on which the assertion is to be ckeched.
   @optparam default If given, instead of raising in case the assertion is not found, return this item.
   @raise MessageError if the given message is not asserted.
*/
FALCON_FUNC getAssert( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );
   Item *i_defalut = vm->param(1);
   
   if ( i_msg == 0 || ! i_msg->isString()  )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S" ) );
   }

   CoreSlot* cs = vm->getSlot( *i_msg->asString(), true );
   if ( cs == 0 )
   {
      if ( i_defalut != 0 )
      {
         vm->regA() = *i_defalut;
      }
      else {
         throw new MessageError( ErrorParam( e_inv_params, __LINE__ )
            .origin( e_orig_runtime )
            .extra( *i_msg->asString() ) );
      }
   }
   else
   {
      if( cs->hasAssert() )
      {
         vm->regA() = cs->assertion();
      }
      else
      {
         if ( i_defalut != 0 )
         {
            vm->regA() = *i_defalut;
         }
         else {
            throw new MessageError( ErrorParam( e_inv_params )
               .origin( e_orig_runtime )
               .extra( *i_msg->asString() ) );
         }

      }
   }
}

//================================================================================
// VMSlot wrapper class.
//

/*#
   @class VMSlot
   @brief VM Interface for message oriented programming operations.
   @optparam name The name of the mesasge managed by this VMSlot.

   The VMSlot instance is a direct interface to the messaging
   facility of the VM creating it. It is implicitly created by
   the @a getSlot function, but it can be directly created by
   the user.

   If a slot with the given name didn't previously exist,
   a new message slot is created in the virtual machine, otherwise
   the already existing slot is wrapped in the returned instance.

   @code
      // create a message slot
      x = VMSlot( "message" )
      x.subscribe( handler )
      ...
      y = VMSlot( "message" )
      y.broadcast( "value" )  // handler is called.
   @endcode

   Same happens if the VMSlot is created via @a getSlot, or implicitly
   referenced via @a subscribe function. Slots are considered
   unique by name, so that comparisons on slots are performed
   on their names.

   If the @b name parameter is not given, the slot will be created as
   "anonymous", and won't be registered with this virtual machine. It will
   be possible to use it only through its methods.

   @section ev_anonym_slots Anonymous slots

   An anonymous slot can be created using an empty call to the VMSlot class
   constructor. This will make the slot private for the users that can
   access it; in other words, the slot won't be published to the VM and
   it won't be possible to broadcast on it using the standard functions
   @a broadcast or @a assert functions.

   @section ev_slots Automatic broadcast marshaling

   If a listener subscribed to a slot is a callable item, then it's called in
   case of broadcasts. If it's a non-callable property provider (class instances,
   blessed dictionaries, non-callable arrays) then a callable property named
   like "on_<slot_name>" is searched; if found, it's called (as a method of the
   host entity), otherwise a catch all method named "__on_event" is searched.

   If the "__on_event" method is found, it's called with the first parameter
   containing the broadcast name. Otherwise, an access error is raised.

   @section ev_events Events

   Events are "named broadcasts". They are issued on slots and excite all the listeners
   that are subscribed to that slot. The main difference is that automatic marshalling
   is directed to the name of the @i event rather to the name of the @i slot.

   See the following code:

   @code
      object Receiver
         _count = 0

         function display(): > "Count is now ", self._count
         function on_add(): self._count++
         function on_sub(): self._count--
         function __on_event( evname ): > "Received an unknown event: ", evname
      end

      s = VMSlot()  // creates an anonymous slot

      s.subscribe( Receiver )

      s.send( "add" ) // Instead of sending a broadcast ...
      s.send( "add" ) // ... generate some events via send()

      s.send( "A strange event", "some param" )  // will complain
      Receiver.display()   // show the count
   @endcode

   The @a VMSlot.send  method works similarly to the @a VMSlot.broadcast method,
   but it allows to specify an arbitrary event name. Callbacks subscribed to this
   slot would be called for @i every event, be it generated through a broadcast or
   via a send call.

   @section ev_subslots Registering to events and Sub-slots

   While callbacks subscribed to the slot will be excited no matter what kind of
   event is generated, it is possible to @i register callbacks to respond only to
   @i particular @i events via the @a VMSlot.register method.

   See the following example:

   @code
   slot = VMSlot()  // creates an anonymous slot
   slot.register( "first",
      { param => printl( "First called with ", param ) } )

   slot.register( "second",
      { param => printl( "Second called with ", param ) } )

   // send "first" and "second" events
   slot.send( "first", "A parameter" )
   slot.send( "second", "Another parameter" )

   // this will actually do nothing
   slot.broadcast( "A third parameter" )
   @endcode

   As no callback is @i subscribed to the slot, but some are just @i register to
   some events, a generic @i broadcast will have no effect.

   An interesting thing about registering to events is that a slot keeps tracks
   of callbacks and items registered to a specific event via a named slot. For
   example, to know who is currently subscribed to the "first" event, it's possible
   to call the @a VMSlot.getEvent method and inspect the returned slot. Any change
   in that returned slot will cause the event registration to change.

   For example, continuing the above code...

   @code
      //...
      fevt = slot.getEvent( "first" )

      // display each subscribed item
      for elem in fevt: > elem.toString()

      // and broadcast on the event first
      fevt.broadcast( "The parameter" )
   @endcode

   As seen, a broadcast on a sub-slot is equivalent to an event send on the parent
   slot.

   @note It is then possible to cache repeatedly broadcast slots, so that the virtual
   machine is not forced to search across the subscribed events.

   This structure can be freely replicated at any level. In the above example,
   @b fevt may be subject of send() and register() method application, and its own
   events can be retrieved trough its @a VMSlot.getEvent method.
*/

/*#
   @endgroup
*/

FALCON_FUNC VMSlot_init( ::Falcon::VMachine *vm )
{
   Item *i_msg = vm->param( 0 );

   if ( i_msg != 0 && ! (i_msg->isString()||i_msg->isNil()) )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "[S]" ) );
   }

   CoreSlot* vms;
   if ( i_msg != 0 && i_msg->isString() )
   {
      vms = vm->getSlot( *i_msg->asString(), true );
      fassert( vms != 0 );
   }
   else
   {
      vms = new CoreSlot("");
   }

   CoreSlotCarrier* self = dyncast<CoreSlotCarrier *>( vm->self().asObjectSafe() );
   self->setSlot( vms );
   vms->decref();
}


/*#
   @method broadcast VMSlot
   @brief Performs broadcast on this slot.
   @param ... Extra parameters to be sent to listeners.

*/

FALCON_FUNC VMSlot_broadcast( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   cs->prepareBroadcast( vm->currentContext(), 0, vm->paramCount() );
}


/*#
   @method send VMSlot
   @brief Performs an event generation on this slot.
   @param event Event name.
   @param ... Extra parameters to be sent to listeners.

   The send method works as broadcast, with two major differences;
   - In case of objects being subscribed to this slot, the name of the
     broadcast message is that specified as a parameter, and not that
     of this slot. This means that automatic marshaling will be performed
     on methods named like on_<event>, and not on_<self.name>.
   - Items registered with @a VMSlot.register gets activated only if the
     @b event name is the same to which they are registered to.

*/

FALCON_FUNC VMSlot_send( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();

   Item *i_msg = vm->param( 0 );
   if ( i_msg == 0 || ! i_msg->isString() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S" ) );
   }

   // better to cache the name
   Item iName = *i_msg;
   cs->prepareBroadcast( vm->currentContext(), 1, vm->paramCount()-1, 0, iName.asString() );
}

/*#
   @method register VMSlot
   @brief Registers a listener for a specific event.
   @param event A string representing the event name.
   @param handler Handler to associate to this event.

   This function associates the given @b handler to a sub-slot named after
   the @b event parameter. This operation is equivalent to call
   @a VMSlot.getEvent() to create the desired sub-slot, and then call
   @a VMSlot.subscribe() on that named slot.

   @see VMSlot.send
*/

FALCON_FUNC VMSlot_register( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();

   Item *i_event = vm->param( 0 );
   Item *i_handler = vm->param( 1 );

   if ( i_event == 0 || ! i_event->isString()
       || i_handler == 0 || ! (i_handler->isComposed() || i_handler->isCallable() ) )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S,C|O" ) );
   }

   // Get the child core slot
   CoreSlot* child = cs->getChild( *i_event->asString(), true );
   child->append( *i_handler );
}

/*#
   @method getEvent VMSlot
   @brief Returns an event (as a child VMSlot) handled by this slot.
   @param event A string representing the event name.
   @optparam force Pass true to create the event if it is not existing.
   @return a VMSlot representing the given event in this slot, or @b nil
           if not found.

   This method returns a named VMSlot that will be excited by @a VMSlot.send
   applied on this slot with the same @b event name.

   In other words, subscribing or unsubscribing items from the returned slot would
   add or remove listeners for a @a VMSlot.send call on this slot.

   Also, a broadcast on the returned VMSlot has the same effect of a @a VMSlot.send
   with the same name as the @b event passed.

   @see VMSlot.send
*/

FALCON_FUNC VMSlot_getEvent( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();

   Item *i_event = vm->param( 0 );
   Item *i_force = vm->param( 1 );

   if ( i_event == 0 || ! i_event->isString() )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S" ) );
   }

   // Get the child core slot
   CoreSlot* child = cs->getChild( *i_event->asString(),
         i_force != 0 && i_force->isTrue() ); // force creation if required
   if( child != 0 )
   {
      // found or to be created.
      Item* icc = vm->findWKI("VMSlot");
      fassert( icc != 0 );
      fassert( icc->isClass() );
      vm->retval( icc->asClass()->createInstance(child) );
      child->decref();
   }
   else
   {
      vm->retnil();
   }
}

/*#
   @method name VMSlot
   @brief Returns the name of this slot
   @return The name of the event bind to this slot (as a string).
*/

FALCON_FUNC VMSlot_name( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   vm->retval( new CoreString(cs->name()) );
}


/*#
   @method subscribe VMSlot
   @brief Registers a callback handler on this slot.
   @param handler A callable item or instance providing callback support.
   @optparam prio Set to true to have this handler called before the previous ones.
*/

FALCON_FUNC VMSlot_subscribe( ::Falcon::VMachine *vm )
{
   Item *callback = vm->param(0);
   Item *i_prio = vm->param(1);
   if ( callback == 0 || ! ( callback->isCallable() || callback->isComposed() ) )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "C" ));
   }

   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   if( i_prio != 0 && i_prio->isTrue() )
      cs->push_front( *callback );
   else
      cs->push_back( *callback );
   
   check_assertion( vm, cs, *callback );
}

/*#
   @method unsubscribe VMSlot
   @brief Unregisters a callback handler from this slot.
   @param handler The callable that must be unregistered.
   @raise CodeError if the @b handler is not registered with this slot.
*/

FALCON_FUNC VMSlot_unsubscribe( ::Falcon::VMachine *vm )
{
   Item *callback = vm->param(0);
   if ( callback == 0 )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "S,C" ) );
   }

   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   if( ! cs->remove( *callback ) )
   {
      throw new CodeError( ErrorParam( e_param_range, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "unregister" ) );
   }

   if ( cs->empty() && ! cs->hasAssert() )
   {
      vm->removeSlot( cs->name() );
   }
}

/*#
   @method prepend VMSlot
   @brief Registers a callback handler that will be called before the others.
   @param handler The callable that must be unregistered.
*/

FALCON_FUNC VMSlot_prepend( ::Falcon::VMachine *vm )
{
   Item *callback = vm->param(0);
   if ( callback == 0 || ! ( callback->isCallable() || callback->isComposed() ) )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "C" ) );
   }

   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   cs->push_front( *callback );
   check_assertion( vm, cs, *callback );
}

/*#
   @method assert VMSlot
   @brief Creates a message assertion on this certain message slot.
   @param data The value of the assertion.

   If there are already subscribed callbacks for this message
   a broadcast on them is performed now.
*/
FALCON_FUNC VMSlot_assert( ::Falcon::VMachine *vm )
{
   Item *i_data = vm->param( 0 );
   if ( i_data == 0  )
   {
      throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
         .origin( e_orig_runtime )
         .extra( "X" ) );
   }

   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   cs->setAssertion( vm, *i_data );
}

/*#
   @method retract VMSlot
   @brief Removes a previous assertion on a message.
*/
FALCON_FUNC VMSlot_retract( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   cs->retract();
   if( cs->empty() )
   {
      vm->removeSlot( cs->name() );
   }
}

/*#
   @method getAssert VMSlot
   @brief Gets the item asserted for this slot.
   @optparam default If given, instead of raising in case the essartion is not found, return this item.
   @raise MessageError if the item has not an assertion and a default is not given.
*/
FALCON_FUNC VMSlot_getAssert( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   if( cs->hasAssert() )
   {
      vm->regA() = cs->assertion();
   }
   else
   {
      if ( vm->paramCount() > 0 )
      {
         vm->regA() = *vm->param(0);
      }
      else {
         throw new MessageError( ErrorParam( e_inv_params, __LINE__ )
            .origin( e_orig_runtime )
            .extra( "..." ) );
      }
   }
}

/*#
   @method first VMSlot
   @brief Gets an iterator to the first subscriber.
   @return An iterator to the first subscriber of this message slot.
*/
FALCON_FUNC VMSlot_first( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   Item* cc = vm->findWKI( "Iterator" );
   fassert( cc != 0 );
   CoreObject *oi = cc->asClass()->createInstance( new Iterator( cs ) );
   vm->retval( oi );
}

/*#
   @method last VMSlot
   @brief Gets an iterator to the last subscriber.
   @return An iterator to the last subscriber of this message slot.
*/
FALCON_FUNC VMSlot_last( ::Falcon::VMachine *vm )
{
   CoreSlot* cs = (CoreSlot*) vm->self().asObject()->getUserData();
   Item* cc = vm->findWKI( "Iterator" );
   fassert( cc != 0 );
   CoreObject *oi = cc->asClass()->createInstance( new Iterator( cs, true) );
   vm->retval( oi );
}
}
}

/* end of message_ext.cpp */