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
|
/*
FALCON - The Falcon Programming Language.
FILE: fal_include.cpp
Include function - Dynamic module loading.
-------------------------------------------------------------------
Author: Giancarlo Niccolai
Begin: Sun, 31 Aug 2008 19:01:59 +0200
-------------------------------------------------------------------
(C) Copyright 2008: the FALCON developers (see list in AUTHORS file)
See LICENSE file for licensing details.
*/
#include <falcon/setup.h>
#include <falcon/vm.h>
#include <falcon/module.h>
#include <falcon/modloader.h>
/*#
@beginmodule core
*/
namespace Falcon {
namespace core {
/*#
@function include
@brief Dynamically loads a module as a plugin.
@param file The relative filename of the module.
@optparam inputEnc Input encoding.
@optparam path A string of ';' separated search paths.
@optparam symDict Symbols to be queried (or nil).
@raise IoError if the module cannot be found or loaded.
A module indicated by filename is compiled, loaded and linked in the
running Virtual Machine. The inclusion is relative to the current
path, be it set in the script, in the current embedding application
or in the falcon command line interpreter. It is possible to use
a path relative to the current script path by using the scriptPath
variable.
If a dictionary of symbols to be queried is @b not provided, the module
is loaded and its main code, if present, is executed.
If @b symDict is provided, its keys are strings which refer to symbol names
to be searched in the loaded module. If present, the entry are filled with
symbols coming from the loaded module. When @b symDict is provided, the
linked module won't have its main code executed (it is possible to execute
it at a later time adding "__main__" to the searched symbols). If a symbol
is not found, its entry in the dictionary will be set to nil. When loaded
this way, the export requests in the loaded module are @b not honored (import/from
semantic).
The @b compiler Feather module provides a more complete interface to dynamic
load and compilation, but this minimal dynamic load support is provided at
base level for flexibility.
*/
FALCON_FUNC fal_include( Falcon::VMachine *vm )
{
Falcon::Item *i_file = vm->param(0);
Falcon::Item *i_enc = vm->param(1);
Falcon::Item *i_path = vm->param(2);
Falcon::Item *i_syms = vm->param(3);
if( i_file == 0 || ! i_file->isString()
|| (i_syms != 0 && ! (i_syms->isDict() || i_syms->isNil()) )
|| (i_enc != 0 && !(i_enc->isString() || i_enc->isNil()) )
|| (i_path != 0 && !(i_path->isString() || i_path->isNil()) )
)
{
throw new Falcon::ParamError(
Falcon::ErrorParam( Falcon::e_inv_params, __LINE__ )
.origin(e_orig_runtime)
.extra( "S,[S],[S],[D]" ) );
}
// create the loader/runtime pair.
ModuleLoader cpl( i_path == 0 || i_path->isNil() ? vm->appSearchPath() : String(*i_path->asString()) );
cpl.delayRaise(true);
Runtime rt( &cpl, vm );
rt.hasMainModule( false );
// minimal config
if ( i_enc != 0 && ! i_enc->isNil() )
{
cpl.sourceEncoding( *i_enc->asString() );
}
else
{
String sEnc, sIoEnc;
Engine::getEncodings( sEnc, sIoEnc );
cpl.sourceEncoding( sEnc );
}
bool execAtLink = vm->launchAtLink();
//! Copy the filename so to be sure to display it correctly in an eventual error.
String fileName = *i_file->asString();
fileName.bufferize();
// load and link
try {
rt.loadFile( fileName, true );
vm->launchAtLink( i_syms == 0 || i_syms->isNil() );
LiveModule *lmod = vm->link( &rt );
// shall we read the symbols?
if( lmod != 0 && ( i_syms != 0 && i_syms->isDict() ) )
{
CoreDict *dict = i_syms->asDict();
// traverse the dictionary
Iterator iter( &dict->items() );
while( iter.hasCurrent() )
{
// if the key is a string and a corresponding item is found...
Item *ival;
if ( iter.getCurrentKey().isString() &&
( ival = lmod->findModuleItem( *iter.getCurrentKey().asString() ) ) != 0 )
{
// copy it locally
iter.getCurrent() = *ival;
}
else {
iter.getCurrent().setNil();
}
iter.next();
}
}
// reset launch status
vm->launchAtLink( execAtLink );
}
catch(Error* err)
{
CodeError *ce = new CodeError( ErrorParam( e_loaderror, __LINE__ ).
extra( fileName ) );
ce->appendSubError(err);
err->decref();
// reset launch status
vm->launchAtLink( execAtLink );
throw ce;
}
}
}
}
|