Logo Search packages:      
Sourcecode: falconpl version File versions  Download package

LiveModule * Falcon::VMachine::link ( Module module,
bool  isMainModule = true 
)

Links a single module. The last-linked module is usually set as the main module, but it is possible to link a non-main module.

After linking, the caller may release the reference if the module is needed only in this VM; the VM keeps a reference to the module.

The VM holds a reference to the module also in case of errors: the module may be still needed for error reports or debug. To destroy definitely the module, the VM must be destroyed or the module must be unlinked.

In case of link error, the error handler of the VM is signaled and the function returns false, otherwise it returns true. If the VM hasn't an error handler set, nothing is signaled, but the error is still available after return through exitError() method.

Note:
The main module is the module that is preferentially searched for start symbol(s) by prepare() function.
Parameters:
rt the runtime to be linked
isMainModule false to prevent this module to be chosen as startup module.
Returns:
0 time error, the internally built LiveModule instance on success.

Definition at line 334 of file vm.cpp.

References Falcon::VarDef::asBool(), Falcon::Item::asClass(), Falcon::VarDef::asInteger(), Falcon::VarDef::asNumeric(), Falcon::VarDef::asString(), Falcon::Map::begin(), callItem(), Falcon::ClassDef::constructor(), Falcon::CoreClass::createInstance(), Falcon::ListElement::data(), Falcon::Symbol::declaredAt(), e_callInst, Falcon::Symbol::exported(), Falcon::Map::find(), Falcon::Symbol::getClassDef(), Falcon::Symbol::getInstance(), Falcon::Module::getServiceMap(), Falcon::Symbol::getVarDef(), Falcon::LiveModule::globals(), Falcon::Map::insert(), Falcon::Item::isClass(), Falcon::Symbol::isInstance(), Falcon::Symbol::isUndefined(), Falcon::Symbol::isWKS(), Falcon::SymModule::item(), Falcon::Symbol::itemId(), linkClass(), Falcon::SymModule::liveModule(), m_attributes, m_event, m_globalSyms, m_liveModules, m_mainModule, m_wellKnownSyms, Falcon::Symbol::module(), Falcon::Symbol::name(), Falcon::Module::name(), Falcon::ListElement::next(), Falcon::AttribHandler::prev(), publishService(), raiseError(), referenceItem(), Falcon::Item::setBoolean(), Falcon::Item::setInteger(), Falcon::Item::setNumeric(), Falcon::Item::setString(), Falcon::CoreClass::symbol(), Falcon::SymModule::symbol(), Falcon::Module::symbolTable(), Falcon::VarDef::type(), Falcon::Symbol::type(), Falcon::SymModule::wkiid(), and Falcon::LiveModule::wkitems().

{
   ItemVector *globs;

   // first of all link the exported services.
   MapIterator svmap_iter = mod->getServiceMap().begin();
   while( svmap_iter.hasCurrent() )
   {
      if ( ! publishService( *(Service ** ) svmap_iter.currentValue() ) )
         return false;
      svmap_iter.next();
   }

   // we need to record the classes in the module as they have to be evaluated last.
   SymbolList modClasses;
   SymbolList modObjects;

   // then we always need the symbol table.
   SymbolTable *symtab = &mod->symbolTable();

   // Ok, the module is now in.
   // We can now increment reference count and add it to ourselves
   LiveModule *livemod = new LiveModule( this, mod );
   m_liveModules.insert( &mod->name(), livemod );

   // by default, set the main module to the lastly linked module.
   if ( isMainModule )
      m_mainModule = livemod;

   // A shortcut
   globs = &livemod->globals();

   // resize() creates a series of NIL items.
   globs->resize( symtab->size()+1 );

   bool success = true;
   // now, the symbol table must be traversed.
   MapIterator iter = symtab->map().begin();
   while( iter.hasCurrent() )
   {
      Symbol *sym = *(Symbol **) iter.currentValue();
      if ( ! sym->isUndefined() )
      {
         // create an appropriate item here.
         switch( sym->type() )
         {
            case Symbol::tfunc:
            case Symbol::textfunc:
               globs->itemAt( sym->itemId() ).setFunction( sym, livemod );
            break;

            case Symbol::tclass:
               modClasses.pushBack( sym );
            break;

            case Symbol::tattribute:
               {
                  // create a new attribute
                  Attribute *attrib = new Attribute( sym );

                  // define the item as an attribute
                  globs->itemAt( sym->itemId() ).setAttribute( attrib );

                  // add the attribute to the list of known attributes
                  if ( m_attributes == 0 )
                  {
                     m_attributes = new AttribHandler( attrib, 0 );
                  }
                  else {
                     m_attributes->prev( new AttribHandler( attrib, 0, 0, m_attributes ) );
                     m_attributes = m_attributes->prev();
                  }
               }
            break;

            case Symbol::tinst:
            {
               modObjects.pushBack( sym );
            }
            break;

            case Symbol::tvar:
            case Symbol::tconst:
            {
               Item *itm = globs->itemPtrAt( sym->itemId() );
               VarDef *vd = sym->getVarDef();
               switch( vd->type() ) {
                  case VarDef::t_bool: itm->setBoolean( vd->asBool() ); break;
                  case VarDef::t_int: itm->setInteger( vd->asInteger() ); break;
                  case VarDef::t_num: itm->setNumeric( vd->asNumeric() ); break;
                  case VarDef::t_string:
                  {
                     itm->setString( new GarbageString( this, *vd->asString() ) );
                  }
                  break;
               }
            }
            break;
         }

         // Is this symbol exported?
         if ( sym->exported() && sym->name().getCharAt(0) != '_' )
         {
            // as long as the module is referenced, the symbols are alive, and as we
            // hold a reference to the module, we are sure that symbols are alive here.
            // also, in case an entry already exists, the previous item is just overwritten.

            if ( m_globalSyms.find( &sym->name() ) != 0 ) {

               raiseError(
                  new CodeError( ErrorParam( e_already_def, sym->declaredAt() ).origin( e_orig_vm ).
                        module( mod->name() ).
                        symbol( sym->name() ) )
                  );
               return false;
            }

            SymModule tmp( globs->itemPtrAt( sym->itemId() ), livemod, sym );
            m_globalSyms.insert( &sym->name(), &tmp );

            // export also the instance, if it is not already exported.
            if ( sym->isInstance() ) {
               sym = sym->getInstance();
               if ( ! sym->exported() ) {
                  SymModule tmp( globs->itemPtrAt( sym->itemId() ), livemod, sym );
                  m_globalSyms.insert( &sym->name(), &tmp );
               }
            }
         }

         // Is this symbol a well known item?
         if ( sym->isWKS() ) {

            if ( m_wellKnownSyms.find( &sym->name() ) != 0 )
            {
               raiseError(
                  new CodeError( ErrorParam( e_already_def, sym->declaredAt() ).origin( e_orig_vm ).
                        module( mod->name() ).
                        symbol( sym->name() ).
                        extra( "Well Known Item" ) )
                  );
               return false;
            }

            SymModule tmp( livemod->wkitems().size(), livemod, sym );
            m_wellKnownSyms.insert( &sym->name(), &tmp );

            // and don't forget to add a copy of the item
            livemod->wkitems().push( globs->itemPtrAt( sym->itemId() ) );
         }
      }
      else
      {
         // try to find the imported symbol.
         SymModule *sm = (SymModule *) m_globalSyms.find( &sym->name() );
         if( sm != 0 )
         {
            // link successful, we must set the current item as a reference of the original
            Symbol *sym2 = sm->symbol();
            referenceItem( globs->itemAt( sym->itemId() ), *sm->item() );
         }
         else {
            // raise undefined symbol.
            Error *error = new CodeError(
                  ErrorParam( e_undef_sym, sym->declaredAt() ).origin( e_orig_vm ).
                  module( mod->name() ).
                  extra( sym->name() )
                  );

            raiseError( error );
            // we're doomed to fail
            success = false;
         }
      }

      // next symbol
      iter.next();
   }

   // exit if link failed.
   if ( ! success )
      return 0;

   // now that the symbols in the module have been linked, link the classes.
   ListElement *cls_iter = modClasses.begin();
   while( cls_iter != 0 )
   {
      Symbol *sym = (Symbol *) cls_iter->data();
      CoreClass *cc = linkClass( livemod, sym );

      // we need to add it anyhow to the GC to provoke its destruction at VM end.
      // and hey, you could always destroy symbols if your mood is so from falcon ;-)
      // dereference as other classes may have referenced this item1
      globs->itemAt( cc->symbol()->itemId() ).dereference()->setClass( cc );

      // if this class was a WKI, we must also set the relevant exported symbol
      if ( sym->isWKS() )
      {
         SymModule *tmp = (SymModule *) m_wellKnownSyms.find( &sym->name() );
         fassert( tmp != 0 ); // we just added it
         tmp->liveModule()->wkitems().itemAt( tmp->wkiid() ) = cc;
      }

      cls_iter = cls_iter->next();
   }

   // then, prepare the instances of standalone objects
   ListElement *obj_iter = modObjects.begin();
   while( obj_iter != 0 )
   {
      Symbol *obj = (Symbol *) obj_iter->data();
      fassert( obj->isInstance() );
      Symbol *cls = obj->getInstance();
      Item *clsItem = globs->itemAt( cls->itemId() ).dereference();
      if ( ! clsItem->isClass() ) {
         raiseError(
            new CodeError( ErrorParam( e_no_cls_inst, obj->declaredAt() ).origin( e_orig_vm ).
               symbol( obj->name() ).
               module( obj->module()->name() ) )
         );
         return 0;
      }
      else {
         CoreObject *co = clsItem->asClass()->createInstance();
         globs->itemAt( obj->itemId() ).dereference()->setObject( co );

         // if this class was a WKI, we must also set the relevant exported symbol
         if ( obj->isWKS() )
         {
            SymModule *tmp = (SymModule *) m_wellKnownSyms.find( &obj->name() );
            fassert( tmp != 0 ); // we just added it
            tmp->liveModule()->wkitems().itemAt( tmp->wkiid() ) = co;
         }
      }
      obj_iter = obj_iter->next();
   }

   // and eventually call their constructor
   obj_iter = modObjects.begin();

   // In case we have some objects to link
   if( obj_iter !=  0 )
   {
      // save S1 and S2, or we won't be able to link in scripts
      Item oldS1 = m_regS1;
      Item oldS2 = m_regS2;

      while( obj_iter != 0 )
      {
         Symbol *obj = (Symbol *) obj_iter->data();
         Symbol *cls = obj->getInstance();
         if ( cls->getClassDef()->constructor() != 0 )
         {
            Item *clsItem = globs->itemAt( cls->itemId() ).dereference();
            m_regS1 = globs->itemAt( obj->itemId() ) ;
            m_event = eventNone;
            callItem( *clsItem, 0, e_callInst );
            if ( m_event == eventRisen )
               return 0;
         }
         obj_iter = obj_iter->next();
      }

      // clear S1
      m_regS1 = oldS1;
      // and s2 for safety
      m_regS2 = oldS2;
   }

   return livemod;
}


Generated by  Doxygen 1.6.0   Back to index