/* // Dao Virtual Machine // http://daoscript.org // // Copyright (c) 2006-2017, Limin Fu // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include"daoNamespace.h" #include"daoVmspace.h" #include"daoParser.h" #include"daoBytecode.h" #include"daoStream.h" #include"daoRoutine.h" #include"daoNumtype.h" #include"daoClass.h" #include"daoObject.h" #include"daoRoutine.h" #include"daoRegex.h" #include"daoStdlib.h" #include"daoProcess.h" #include"daoGC.h" #include"daoTasklet.h" #include"daoValue.h" #ifdef DAO_WITH_THREAD #include"daoThread.h" #endif typedef struct DaoVirtualFile DaoVirtualFile; /* // If DaoVirtualFile::offset is greater than zero, DaoVirtualFile::data will // be the path to an archive file, and DaoVirtualFile::offset will be the location // of the virtual file's data in the archive file. Otherwise, DaoVirtualFile::data // contains the data for the virtual file. */ struct DaoVirtualFile { daoint offset; daoint size; DString *data; }; DaoVirtualFile* DaoVirtualFile_New() { DaoVirtualFile *self = (DaoVirtualFile*) dao_calloc( 1, sizeof(DaoVirtualFile) ); self->data = DString_New(); return self; } void DaoVirtualFile_Delete( DaoVirtualFile *self ) { DString_Delete( self->data ); dao_free( self ); } DaoConfig daoConfig = { 1, /* cpu */ 0, /* jit */ 1, /* optimize */ 0, /* iscgi */ 8, /* tabspace */ }; DaoVmSpace *masterVmSpace = NULL; void dao_abort( const char *error ) { fprintf( stderr, "Dao aborted with fatal error: %s!\n", error ); exit(0); } void* dao_malloc( size_t size ) { void *p = malloc( size ); if( size && p == NULL ) dao_abort( "memory allocation failed" ); return p; } void* dao_calloc( size_t nmemb, size_t size ) { void *p = calloc( nmemb, size ); if( nmemb && size && p == NULL ) dao_abort( "memory allocation failed" ); return p; } void* dao_realloc( void *ptr, size_t size ) { void *p = realloc( ptr, size ); if( size && p == NULL ) dao_abort( "memory allocation failed" ); return p; } void dao_free( void *p ) { free( p ); } int DaoVmSpace_TestFile( DaoVmSpace *self, DString *fname ) { if( MAP_Find( self->vfiles, fname ) ) return 1; if( MAP_Find( self->vmodules, fname ) ) return 1; return Dao_IsFile( fname->chars ); } static int TestPath( DaoVmSpace *vms, DString *fname, int type ) { if( type == DAO_FILE_PATH ) return DaoVmSpace_TestFile( vms, fname ); return Dao_IsDir( fname->chars ); } void DaoAux_Delete( DMap *aux ) { DNode *it; typedef void (*aux_delete)(void*); for(it=DMap_First(aux); it; it=DMap_Next(aux,it)){ aux_delete del = (aux_delete) it->key.pVoid; (*del)( it->value.pVoid ); } DMap_Delete( aux ); } #define DAO_FILE_TYPE_NUM 3 static const char* const daoDllPrefix[] = { "", "", DAO_DLL_PREFIX "dao_" }; static const char* const daoFileSuffix[] = { ".dac", ".dao", DAO_DLL_SUFFIX }; static const char* const daoFileSuffix2[] = { ".dao", ".dac", DAO_DLL_SUFFIX }; static int daoModuleTypes[] = { DAO_MODULE_DAC, DAO_MODULE_DAO, DAO_MODULE_DLL }; static int daoModuleTypes2[] = { DAO_MODULE_DAO, DAO_MODULE_DAC, DAO_MODULE_DLL }; #ifndef TARGET_PLAT #define TARGET_PLAT "Undefined" #endif #ifndef CHANGESET_ID #define CHANGESET_ID "Undefined" #endif const char *const dao_copy_notice = " Dao Virtual Machine " DAO_VERSION "\n" " Target: " TARGET_PLAT "\n" " Built date: " __DATE__ "\n" " Changeset ID: " CHANGESET_ID "\n\n" " Copyright(C) 2006-2017, Limin Fu\n" " Dao is released under the terms of the Simplified BSD License\n" " Dao Language website: http://daoscript.org\n" ; static const char *const cmd_help = "\n Usage: dao [options] script_file\n" " Options:\n" " -h, --help: print this help information;\n" " -v, --version: print version information;\n" " -e, --eval: evaluate command line codes;\n" " -i, --interactive: run in interactive mode;\n" " -d, --debug: run in debug mode;\n" " -p, --profile: run in profile mode;\n" " -s, --sandbox: run in sandbox mode;\n" " -r, --restart: restart program on crash (unix) or nonzero exit (win);\n" " -c, --compile: compile to bytecodes;\n" " -a, --archive: build archive file;\n" " -l, --list-code: print compiled bytecodes;\n" " -j, --jit: enable just-in-time compiling;\n" " --autovar: enable automatic variable declaration;\n" " -Ox: optimization level (x=0 or 1);\n" " --threads=number minimum number of threads for processing tasklets;\n" " --path=directory add module searching path;\n" " --module=module preloading module;\n" " --config=config use configure file;\n" ; const char* DaoVmSpace_GetCopyNotice() { return dao_copy_notice; } void DaoVmSpace_SetOptions( DaoVmSpace *self, int options ) { self->options = options; } int DaoVmSpace_GetOptions( DaoVmSpace *self ) { return self->options; } DaoNamespace* DaoVmSpace_FindNamespace( DaoVmSpace *self, DString *name ) { DNode *node; DaoNamespace *ns = NULL; DaoVmSpace_Lock( self ); node = DMap_Find( self->nsModules, name ); if( node ) ns = (DaoNamespace*) node->value.pValue; DaoVmSpace_Unlock( self ); return ns; } DaoNamespace* DaoVmSpace_GetNamespace( DaoVmSpace *self, const char *name ) { DString str = DString_WrapChars( name ); DaoNamespace *ns = DaoVmSpace_FindNamespace( self, & str ); if( ns ) return ns; ns = DaoNamespace_New( self, name ); DaoVmSpace_Lock( self ); DMap_Insert( self->nsModules, & str, ns ); DMap_Insert( self->nsRefs, ns, NULL ); DaoVmSpace_Unlock( self ); return ns; } DaoNamespace* DaoVmSpace_MainNamespace( DaoVmSpace *self ) { return self->mainNamespace; } DaoProcess* DaoVmSpace_MainProcess( DaoVmSpace *self ) { return self->mainProcess; } DaoProcess* DaoVmSpace_AcquireProcess( DaoVmSpace *self ) { DaoProcess *proc = NULL; DaoVmSpace_LockCache( self ); if( self->processes->size ){ proc = (DaoProcess*) DList_Back( self->processes ); DList_PopBack( self->processes ); }else{ proc = DaoProcess_New( self ); DMap_Insert( self->allProcesses, proc, 0 ); } DaoVmSpace_UnlockCache( self ); return proc; } void DaoVmSpace_ReleaseProcess( DaoVmSpace *self, DaoProcess *proc ) { if( proc->refCount > 1 ) return; DaoVmSpace_LockCache( self ); if( DMap_Find( self->allProcesses, proc ) ){ DaoProcess_Reset( proc ); DList_PushBack( self->processes, proc ); } DaoVmSpace_UnlockCache( self ); } DaoRoutine* DaoVmSpace_AcquireRoutine( DaoVmSpace *self ) { DaoRoutine *rout = NULL; DaoVmSpace_LockCache( self ); if( self->routines->size ){ rout = (DaoRoutine*) DList_Back( self->routines ); DList_PopBack( self->routines ); }else{ rout = DaoRoutine_New( self->mainNamespace, NULL, 1 ); DMap_Insert( self->allRoutines, rout, 0 ); } DaoVmSpace_UnlockCache( self ); return rout; } void DaoVmSpace_ReleaseRoutine( DaoVmSpace *self, DaoRoutine *rout ) { if( rout->refCount > 1 ) return; DaoVmSpace_LockCache( self ); if( DMap_Find( self->allRoutines, rout ) ){ DList_PushBack( self->routines, rout ); } DaoVmSpace_UnlockCache( self ); } #if 0 #define SHARE_NO_PARSER #define SHARE_NO_INFERENCER #define SHARE_NO_OPTIMIZER #endif DaoParser* DaoVmSpace_AcquireParser( DaoVmSpace *self ) { DaoParser *parser = NULL; #ifdef SHARE_NO_PARSER parser = DaoParser_New(); parser->vmSpace = self; return parser; #endif DaoVmSpace_LockCache( self ); if( self->parsers->size ){ parser = (DaoParser*) DList_Back( self->parsers ); DList_PopBack( self->parsers ); }else{ parser = DaoParser_New(); parser->vmSpace = self; DMap_Insert( self->allParsers, parser, 0 ); } DaoVmSpace_UnlockCache( self ); return parser; } void DaoVmSpace_ReleaseParser( DaoVmSpace *self, DaoParser *parser ) { #ifdef SHARE_NO_PARSER DaoParser_Delete( parser ); return; #endif DaoParser_Reset( parser ); DaoVmSpace_LockCache( self ); if( DMap_Find( self->allParsers, parser ) ){ DList_PushBack( self->parsers, parser ); } DaoVmSpace_UnlockCache( self ); } DaoByteCoder* DaoVmSpace_AcquireByteCoder( DaoVmSpace *self ) { DaoByteCoder *byteCoder = NULL; #ifdef SHARE_NO_PARSER byteCoder = DaoByteCoder_New( self ); //byteCoder->vmSpace = self; return byteCoder; #endif DaoVmSpace_LockCache( self ); if( self->byteCoders->size ){ byteCoder = (DaoByteCoder*) DList_Back( self->byteCoders ); DList_PopBack( self->byteCoders ); }else{ byteCoder = DaoByteCoder_New( self ); //byteCoder->vmSpace = self; DMap_Insert( self->allByteCoders, byteCoder, 0 ); } DaoVmSpace_UnlockCache( self ); return byteCoder; } void DaoVmSpace_ReleaseByteCoder( DaoVmSpace *self, DaoByteCoder *byteCoder ) { #ifdef SHARE_NO_PARSER DaoByteCoder_Delete( byteCoder ); return; #endif DaoByteCoder_Reset( byteCoder ); DaoVmSpace_LockCache( self ); if( DMap_Find( self->allByteCoders, byteCoder ) ){ DList_PushBack( self->byteCoders, byteCoder ); } DaoVmSpace_UnlockCache( self ); } DaoInferencer* DaoVmSpace_AcquireInferencer( DaoVmSpace *self ) { DaoInferencer *inferencer = NULL; #ifdef SHARE_NO_INFERENCER return DaoInferencer_New(); #endif DaoVmSpace_LockCache( self ); if( self->inferencers->size ){ inferencer = (DaoInferencer*) DList_Back( self->inferencers ); DList_PopBack( self->inferencers ); }else{ inferencer = DaoInferencer_New(); DMap_Insert( self->allInferencers, inferencer, 0 ); } DaoVmSpace_UnlockCache( self ); return inferencer; } void DaoVmSpace_ReleaseInferencer( DaoVmSpace *self, DaoInferencer *inferencer ) { #ifdef SHARE_NO_INFERENCER DaoInferencer_Delete( inferencer ); return; #endif DaoInferencer_Reset( inferencer ); DaoVmSpace_LockCache( self ); if( DMap_Find( self->allInferencers, inferencer ) ){ DList_PushBack( self->inferencers, inferencer ); } DaoVmSpace_UnlockCache( self ); } DaoOptimizer* DaoVmSpace_AcquireOptimizer( DaoVmSpace *self ) { DaoOptimizer *optimizer = NULL; #ifdef SHARE_NO_OPTIMIZER return DaoOptimizer_New(); #endif DaoVmSpace_LockCache( self ); if( self->optimizers->size ){ optimizer = (DaoOptimizer*) DList_Back( self->optimizers ); DList_PopBack( self->optimizers ); }else{ optimizer = DaoOptimizer_New(); DMap_Insert( self->allOptimizers, optimizer, 0 ); } DaoVmSpace_UnlockCache( self ); return optimizer; } void DaoVmSpace_ReleaseOptimizer( DaoVmSpace *self, DaoOptimizer *optimizer ) { #ifdef SHARE_NO_OPTIMIZER DaoOptimizer_Delete( optimizer ); return; #endif DaoVmSpace_LockCache( self ); if( DMap_Find( self->allOptimizers, optimizer ) ){ DList_PushBack( self->optimizers, optimizer ); } DaoVmSpace_UnlockCache( self ); } DaoStream* DaoVmSpace_StdioStream( DaoVmSpace *self ) { return self->stdioStream; } DaoStream* DaoVmSpace_ErrorStream( DaoVmSpace *self ) { return self->errorStream; } DaoStream* DaoVmSpace_SetStdio( DaoVmSpace *self, DaoStream *stream ) { DaoStdStream *stdstream = (DaoStdStream*) self->stdioStream; DaoStream *prev = stdstream->redirect; stdstream->redirect = stream; return prev; } DaoStream* DaoVmSpace_SetStdError( DaoVmSpace *self, DaoStream *stream ) { DaoStdStream *stdstream = (DaoStdStream*) self->errorStream; DaoStream *prev = stdstream->redirect; stdstream->redirect = stream; return prev; } DaoDebugger* DaoVmSpace_SetDebugger( DaoVmSpace *self, DaoDebugger *handler ) { DaoDebugger *hd = self->debugger; self->debugger = handler; return hd; } DaoProfiler* DaoVmSpace_SetProfiler( DaoVmSpace *self, DaoProfiler *profiler ) { DaoProfiler *hd = self->profiler; if( profiler == NULL || profiler->EnterFrame == NULL || profiler->LeaveFrame == NULL ){ profiler = NULL; } self->profiler = profiler; return hd; } DaoHandler* DaoVmSpace_SetHandler( DaoVmSpace *self, DaoHandler *handler ) { DaoHandler *hd = self->handler; self->handler = handler; return hd; } void DaoVmSpace_ReadLine( DaoVmSpace *self, ReadLine fptr ) { self->ReadLine = fptr; } void DaoVmSpace_AddHistory( DaoVmSpace *self, AddHistory fptr ) { self->AddHistory = fptr; } void DaoVmSpace_Stop( DaoVmSpace *self, int bl ) { self->stopit = bl; } static int DaoVmSpace_InitModulePath( DaoVmSpace *self, DString *path, DString *buffer ) { DString_Reset( buffer, 0 ); DString_AppendChars( buffer, DAO_DLL_PREFIX "dao_aux" DAO_DLL_SUFFIX ); DString_MakePath( path, buffer ); if( Dao_IsFile( buffer->chars ) ){ DaoVmSpace_AddPath( self, path->chars ); return 1; } return 0; } static void DaoVmSpace_InitPath( DaoVmSpace *self ) { DString *file = DString_New(); DString *path = DString_New(); const char *const paths[] = { "../lib/dao/modules", "./lib/dao/modules" }; char *daodir; int i; DaoVmSpace_SetPath( self, self->startPath->chars ); DString_AppendChars( file, DAO_DIR ); DString_AppendChars( path, "lib/dao/modules/" ); DString_MakePath( file, path ); if( DaoVmSpace_InitModulePath( self, path, file ) ) goto Done; for(i=0; i<2; ++i){ DString_Reset( path, 0 ); DString_AppendChars( path, paths[i] ); DString_MakePath( self->daoBinPath, path ); if( DaoVmSpace_InitModulePath( self, path, file ) ) goto Done; } daodir = getenv( "DAO_DIR" ); if( daodir ){ DString_Reset( path, 0 ); DString_AppendChars( path, daodir ); if( DaoVmSpace_InitModulePath( self, path, file ) ) goto Done; } Done: DString_Delete( file ); DString_Delete( path ); } static DaoType* DaoVmSpace_InitCoreTypes( DaoVmSpace *self ); static void DaoVmSpace_InitStdTypes( DaoVmSpace *self ); DaoVmSpace* DaoVmSpace_New() { DaoType *tht; DaoNamespace *NS; DaoVmSpace *self = (DaoVmSpace*) dao_calloc( 1, sizeof(DaoVmSpace) ); DaoValue_Init( (DaoValue*) self, DAO_VMSPACE ); self->daoBinFile = DString_New(); self->daoBinPath = DString_New(); self->startPath = DString_New(); self->mainSource = DString_New(); self->vfiles = DHash_New( DAO_DATA_STRING, 0 ); self->vmodules = DHash_New( DAO_DATA_STRING, 0 ); self->nsModules = DHash_New( DAO_DATA_STRING, 0 ); self->nsPlugins = DHash_New( DAO_DATA_STRING, 0 ); self->nsRefs = DHash_New( DAO_DATA_VALUE, 0 ); self->cdataWrappers = DHash_New(0,0); self->typeKernels = DHash_New(0,0); self->spaceData = DHash_New(0,0); self->pathWorking = DString_New(); self->nameLoading = DList_New( DAO_DATA_STRING ); self->pathLoading = DList_New( DAO_DATA_STRING ); self->pathSearching = DList_New( DAO_DATA_STRING ); self->virtualPaths = DList_New( DAO_DATA_STRING ); self->sourceArchive = DList_New( DAO_DATA_STRING ); self->argParams = DList_New( DAO_DATA_VALUE );; self->processes = DList_New(0); self->routines = DList_New(0); self->parsers = DList_New(0); self->byteCoders = DList_New(0); self->inferencers = DList_New(0); self->optimizers = DList_New(0); self->allProcesses = DMap_New( DAO_DATA_VALUE, 0 ); self->allRoutines= DMap_New( DAO_DATA_VALUE, 0 ); self->allParsers = DMap_New(0,0); self->allByteCoders = DMap_New(0,0); self->allInferencers = DMap_New(0,0); self->allOptimizers = DMap_New(0,0); self->typeCores = DList_New(0); self->taskletServer = NULL; GC_IncRC( self ); #ifdef DAO_WITH_THREAD DMutex_Init( & self->moduleMutex ); DMutex_Init( & self->cacheMutex ); DMutex_Init( & self->miscMutex ); #endif tht = DaoVmSpace_InitCoreTypes( self ); self->daoNamespace = DaoNamespace_New( self, "dao" ); self->mainNamespace = DaoNamespace_New( self, "MainNamespace" ); GC_IncRC( self->daoNamespace ); GC_IncRC( self->mainNamespace ); DMap_Insert( self->nsModules, self->daoNamespace->name, self->daoNamespace ); DaoType_SetNamespace( tht, self->daoNamespace ); DaoType_SetNamespace( self->typeUdf, self->daoNamespace ); DaoType_SetNamespace( self->typeAny, self->daoNamespace ); DaoType_SetNamespace( self->typeBool, self->daoNamespace ); DaoType_SetNamespace( self->typeInt, self->daoNamespace ); DaoType_SetNamespace( self->typeFloat, self->daoNamespace ); DaoType_SetNamespace( self->typeComplex, self->daoNamespace ); DaoType_SetNamespace( self->typeString, self->daoNamespace ); DaoType_SetNamespace( self->typeEnum, self->daoNamespace ); DaoType_SetNamespace( self->typeRoutine, self->daoNamespace ); // DaoNamespace_AddParent( self->mainNamespace, self->daoNamespace ); self->mainProcess = DaoProcess_New( self ); GC_IncRC( self->mainProcess ); DaoVmSpace_InitStdTypes( self ); self->stdioStream = DaoStdStream_New( self ); self->errorStream = DaoStdStream_New( self ); self->errorStream->Read = NULL; self->errorStream->Write = DaoStdStream_WriteStderr; GC_IncRC( self->stdioStream ); GC_IncRC( self->errorStream ); NS = DaoVmSpace_GetNamespace( self, "io" ); DaoNamespace_AddConstValue( NS, "stdio", (DaoValue*) self->stdioStream ); DaoNamespace_AddConstValue( NS, "stderr", (DaoValue*) self->errorStream ); if( masterVmSpace != NULL ){ DNode *it; DaoVmSpace *master = masterVmSpace; //self->stdioStream->redirect = master->stdioStream->redirect; // TODO: GC; //self->errorStream->redirect = master->errorStream->redirect; // TODO: GC; self->stdioStream->Read = master->stdioStream->Read; self->stdioStream->Write = master->stdioStream->Write; self->errorStream->Read = master->errorStream->Read; self->errorStream->Write = master->errorStream->Write; DString_Assign( self->daoBinFile, master->daoBinFile ); DString_Assign( self->daoBinPath, master->daoBinPath ); DString_Assign( self->startPath, master->startPath ); DString_Assign( self->pathWorking, master->pathWorking ); DList_Assign( self->nameLoading, master->nameLoading ); DList_Assign( self->pathLoading, master->pathLoading ); DList_Assign( self->pathSearching, master->pathSearching ); DList_Assign( self->virtualPaths, master->virtualPaths ); DMap_Assign( self->vfiles, master->vfiles ); DMap_Assign( self->vmodules, master->vmodules ); for(it=DMap_First(master->nsPlugins); it!=NULL; it=DMap_Next(master->nsPlugins,it)){ DaoNamespace *nspace = DaoVmSpace_Load( self, it->key.pString->chars ); if( nspace != NULL ) DaoVmSpace_AddPlugin( self, nspace->name, nspace ); } } return self; } static void DaoVmSpace_DeleteData( DaoVmSpace *self ) { DNode *it; for(it=DMap_First(self->allParsers); it; it=DMap_Next(self->allParsers,it)){ DaoParser_Delete( (DaoParser*) it->key.pVoid ); } for(it=DMap_First(self->allByteCoders); it; it=DMap_Next(self->allByteCoders,it)){ DaoByteCoder_Delete( (DaoByteCoder*) it->key.pVoid ); } for(it=DMap_First(self->allInferencers); it; it=DMap_Next(self->allInferencers,it)){ DaoInferencer_Delete( (DaoInferencer*) it->key.pVoid ); } for(it=DMap_First(self->allOptimizers); it; it=DMap_Next(self->allOptimizers,it)){ DaoOptimizer_Delete( (DaoOptimizer*) it->key.pVoid ); } for(it=DMap_First(self->vfiles); it; it=DMap_Next(self->vfiles,it)){ DaoVirtualFile_Delete( (DaoVirtualFile*) it->value.pVoid ); } DaoAux_Delete( self->spaceData ); GC_DecRC( self->daoNamespace ); GC_DecRC( self->mainNamespace ); GC_DecRC( self->stdioStream ); GC_DecRC( self->errorStream ); DString_Delete( self->daoBinFile ); DString_Delete( self->daoBinPath ); DString_Delete( self->startPath ); DString_Delete( self->mainSource ); DString_Delete( self->pathWorking ); DList_Delete( self->nameLoading ); DList_Delete( self->pathLoading ); DList_Delete( self->pathSearching ); DList_Delete( self->virtualPaths ); DList_Delete( self->argParams ); DList_Delete( self->processes ); DList_Delete( self->routines ); DList_Delete( self->sourceArchive ); DList_Delete( self->parsers ); DList_Delete( self->byteCoders ); DList_Delete( self->inferencers ); DList_Delete( self->optimizers ); DMap_Delete( self->typeKernels ); DMap_Delete( self->nsRefs ); DMap_Delete( self->vfiles ); DMap_Delete( self->vmodules ); DMap_Delete( self->allProcesses ); DMap_Delete( self->allRoutines ); DMap_Delete( self->allParsers ); DMap_Delete( self->allByteCoders ); DMap_Delete( self->allInferencers ); DMap_Delete( self->allOptimizers ); GC_DecRC( self->mainProcess ); self->stdioStream = NULL; } void DaoVmSpace_Delete( DaoVmSpace *self ) { int i; for(i=0; itypeCores->size; ++i) dao_free( self->typeCores->items.pVoid[i] ); DList_Delete( self->typeCores ); DMap_Delete( self->nsModules ); DMap_Delete( self->nsPlugins ); DMap_Delete( self->cdataWrappers ); #ifdef DAO_WITH_THREAD DMutex_Destroy( & self->moduleMutex ); DMutex_Destroy( & self->cacheMutex ); DMutex_Destroy( & self->miscMutex ); #endif dao_free( self ); } void DaoVmSpace_TryDelete( DaoVmSpace *self ) { #ifdef DAO_WITH_THREAD DCondVar condv; #endif DNode *it; daoint cycle; #ifdef DAO_WITH_CONCURRENT DaoVmSpace_StopTasklets( self ); #endif if( (self->options & DAO_OPTION_PROFILE) && self->profiler ){ DaoProfiler *profiler = self->profiler; if( profiler->Report ) profiler->Report( profiler, self->stdioStream ); } DaoVmSpace_DeleteData( self ); DaoGC_SetMode( 1, self == masterVmSpace ); cycle = DaoGC_GetCycleIndex(); #ifdef DAO_WITH_THREAD DCondVar_Init( & condv ); while( self->refCount > 1 && DaoGC_GetCycleIndex() < (cycle + 3) ){ //printf( "Refcount = %i\n", self->refCount ); DaoGC_TryInvoke(); DCondVar_TimedWait( & condv, & self->moduleMutex, 0.01 ); } DCondVar_Destroy( & condv ); #else while( self->refCount > 1 && DaoGC_GetCycleIndex() < (cycle + 3) ){ //printf( "Refcount = %i\n", self->refCount ); DaoGC_TryInvoke(); } #endif //printf( "Refcount = %i\n", self->refCount ); if( self->refCount != 1 ){ printf( "Warning: VM space has unexpected refCount %i\n", self->refCount ); } #ifdef DEBUG for(it=DMap_First(self->nsModules); it; it=DMap_Next(self->nsModules,it) ){ DaoNamespace *ns = (DaoNamespace*) it->value.pValue; if( ns->vmSpace != self ) continue; printf( "Warning: namespace/module \"%s\" is not collected with reference count %i!\n", ns->name->chars, ns->refCount ); } #endif DaoGC_SetMode( 0, 0 ); GC_DecRC( self ); } void DaoVmSpace_Lock( DaoVmSpace *self ) { #ifdef DAO_WITH_THREAD DMutex_Lock( & self->miscMutex ); #endif } void DaoVmSpace_Unlock( DaoVmSpace *self ) { #ifdef DAO_WITH_THREAD DMutex_Unlock( & self->miscMutex ); #endif } void DaoVmSpace_LockCache( DaoVmSpace *self ) { #ifdef DAO_WITH_THREAD DMutex_Lock( & self->cacheMutex ); #endif } void DaoVmSpace_UnlockCache( DaoVmSpace *self ) { #ifdef DAO_WITH_THREAD DMutex_Unlock( & self->cacheMutex ); #endif } int DaoDecodeUInt16( const char *data ) { const uchar_t *p = (const uchar_t*) data; return (p[0]<<8) + p[1]; } int DaoDecodeUInt32( const char *data ) { const uchar_t *p = (const uchar_t*) data; return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } static void DaoStream_PrintFileInfo( DaoStream *self, DString *name, const char *info ) { DaoStream_WriteChars( self, info ); DaoStream_WriteString( self, name ); if( info[strlen(info)-1] == '"' ) DaoStream_WriteChar( self, '"' ); DaoStream_WriteChars( self, ";\n" ); } int DaoVmSpace_ReadFile( DaoVmSpace *self, DString *fname, DString *source ) { FILE *fin; DNode *node = MAP_Find( self->vfiles, fname ); /* printf( "reading %s\n", fname->chars ); */ if( node ){ DaoVirtualFile *vfile = (DaoVirtualFile*) node->value.pVoid; if( vfile->offset == 0 ){ DString_Assign( source, vfile->data ); return 1; } fin = Dao_OpenFile( vfile->data->chars, "r" ); if( fin == NULL ) goto Failed; DString_Reset( source, 0 ); DaoFile_ReadPart( fin, source, vfile->offset, vfile->size ); fclose( fin ); return 1; } if( DaoFile_ReadAll( Dao_OpenFile( fname->chars, "r" ), source, 1 ) ) return 1; Failed: DaoStream_PrintFileInfo( self->errorStream, fname, "ERROR: cannot open file \"" ); return 0; } /* modules/debugger */ DAO_DLL void SplitByWhiteSpaces( const char *chs, DList *tokens ) { DString temp = DString_WrapChars( chs ); DString *tok = DString_New(); DString *str = & temp; daoint i, j, k=0, size = str->size; DList_Clear( tokens ); if( (j=DString_FindChar( str, '\1', k )) != DAO_NULLPOS ){ while( (j=DString_FindChar( str, '\1', k )) != DAO_NULLPOS ){ if( j > k ){ DString_SubString( str, tok, k, j-k ); DList_Append( tokens, tok ); } k = j + 1; } if( k < str->size ){ DString_SubString( str, tok, k, str->size-k ); DList_Append( tokens, tok ); } DString_Delete( tok ); return; } for( i=0; isize > 0 ){ DList_Append( tokens, tok ); DString_Clear( tok ); } continue; } DString_AppendChar( tok, chs[i] ); } if( tok->size > 0 ) DList_Append( tokens, tok ); DString_Delete( tok ); } static void DaoConfigure_FromFile( const char *name ); int DaoVmSpace_TryInitDebugger( DaoVmSpace *self, const char *module ); int DaoVmSpace_TryInitProfiler( DaoVmSpace *self, const char *module ); int DaoVmSpace_TryInitJIT( DaoVmSpace *self, const char *module ); int DaoVmSpace_ParseOptions( DaoVmSpace *self, const char *options ) { DString *str = DString_New(); DList *array = DList_New( DAO_DATA_STRING ); DaoNamespace *ns; daoint i, j; SplitByWhiteSpaces( options, array ); for( i=0; isize; i++ ){ DString *token = array->items.pString[i]; int sandbox = self->options & DAO_OPTION_SANDBOX; if( self->evalCmdline ){ DString_Append( self->mainSource, token ); DString_AppendChar( self->mainSource, ' ' ); continue; } if( token->chars[0] =='-' && token->size >1 && token->chars[1] =='-' ){ if( strcmp( token->chars, "--help" ) ==0 ){ self->options |= DAO_OPTION_HELP; }else if( strcmp( token->chars, "--version" ) ==0 ){ self->options |= DAO_OPTION_VINFO; }else if( strcmp( token->chars, "--eval" ) ==0 ){ self->evalCmdline = 1; DString_Clear( self->mainSource ); }else if( strcmp( token->chars, "--interactive" ) ==0 ){ self->options |= DAO_OPTION_INTERUN; }else if( strcmp( token->chars, "--debug" ) ==0 ){ self->options |= DAO_OPTION_DEBUG; }else if( strcmp( token->chars, "--profile" ) ==0 ){ self->options |= DAO_OPTION_PROFILE; }else if( strcmp( token->chars, "--sandbox" ) ==0 ){ self->options |= DAO_OPTION_SANDBOX; }else if( strcmp( token->chars, "--restart" ) ==0 ){ }else if( strcmp( token->chars, "--list-code" ) ==0 ){ self->options |= DAO_OPTION_LIST_BC; }else if( strcmp( token->chars, "--compile" ) ==0 ){ self->options |= DAO_OPTION_COMP_BC; }else if( strcmp( token->chars, "--archive" ) ==0 ){ self->options |= DAO_OPTION_ARCHIVE; }else if( strcmp( token->chars, "--jit" ) ==0 ){ self->options |= DAO_OPTION_JIT; daoConfig.jit = 1; }else if( strcmp( token->chars, "--autovar" ) ==0 ){ self->options |= DAO_OPTION_AUTOVAR; }else if( strstr( token->chars, "--threads=" ) == token->chars ){ daoConfig.cpu = strtol( token->chars + 10, 0, 0 ); }else if( strstr( token->chars, "--path=" ) == token->chars ){ DaoVmSpace_AddPath( self, token->chars + 7 ); }else if( strstr( token->chars, "--module=" ) == token->chars ){ if( (ns = DaoVmSpace_Load( self, token->chars + 9 )) ){ DaoVmSpace_AddPlugin( self, ns->name, ns ); }else{ DaoStream_WriteChars( self->errorStream, "Preloading failed for module: " ); DaoStream_WriteChars( self->errorStream, token->chars ); DaoStream_WriteChars( self->errorStream, ";\n" ); } }else if( strstr( token->chars, "--config=" ) == token->chars ){ DaoConfigure_FromFile( token->chars + 9 ); }else if( token->size ){ DaoStream_WriteChars( self->errorStream, "Unknown option: " ); DaoStream_WriteChars( self->errorStream, token->chars ); DaoStream_WriteChars( self->errorStream, ";\n" ); } }else if( strcmp( token->chars, "-O0" ) ==0 ){ daoConfig.optimize = 0; }else if( strcmp( token->chars, "-O1" ) ==0 ){ daoConfig.optimize = 1; }else{ daoint len = token->size; DString_Clear( str ); for( j=0; jchars[j] ){ case 'h' : self->options |= DAO_OPTION_HELP; break; case 'v' : self->options |= DAO_OPTION_VINFO; break; case 'i' : self->options |= DAO_OPTION_INTERUN; break; case 'd' : self->options |= DAO_OPTION_DEBUG; break; case 'p' : self->options |= DAO_OPTION_PROFILE; break; case 's' : self->options |= DAO_OPTION_SANDBOX; break; case 'l' : self->options |= DAO_OPTION_LIST_BC; break; case 'c' : self->options |= DAO_OPTION_COMP_BC; break; case 'a' : self->options |= DAO_OPTION_ARCHIVE; break; case 'j' : self->options |= DAO_OPTION_JIT; daoConfig.jit = 1; break; case 'e' : self->evalCmdline = 1; DString_Clear( self->mainSource ); break; case 'r' : break; case '-' : break; default : if( token->chars[j] ){ DString_AppendChar( str, token->chars[j] ); DString_AppendChar( str, ' ' ); } break; } } if( str->size > 0 ){ DaoStream_WriteChars( self->errorStream, "Unknown option: " ); DaoStream_WriteChars( self->errorStream, str->chars ); DaoStream_WriteChars( self->errorStream, ";\n" ); } } if( sandbox == 0 && (self->options & DAO_OPTION_SANDBOX) ){ DaoStream *stream1 = self->stdioStream; DaoStream *stream2 = self->errorStream; DaoNamespace *ions = DaoVmSpace_GetNamespace( self, "io" ); DaoNamespace *mainns = DaoNamespace_New( self, "MainNamespace" ); GC_Assign( & self->mainNamespace, mainns ); DaoNamespace_AddConstValue( mainns, "io", (DaoValue*) ions ); DaoNamespace_AddConstValue( mainns, "stdio", (DaoValue*) stream1 ); DaoNamespace_AddConstValue( mainns, "stderr", (DaoValue*) stream2 ); DMap_Clear( self->nsModules ); DMap_Clear( self->nsPlugins ); } } if( self->options & DAO_OPTION_DEBUG ) daoConfig.optimize = 0; DString_Delete( str ); DList_Delete( array ); if( daoConfig.jit && dao_jit.Compile == NULL ) DaoVmSpace_TryInitJIT( self, NULL ); if( self->options & DAO_OPTION_PROFILE ) DaoVmSpace_TryInitProfiler( self, NULL ); if( self->options & DAO_OPTION_DEBUG ) DaoVmSpace_TryInitDebugger( self, NULL ); return 1; } static void DaoVmSpace_MakePath( DaoVmSpace *self, DString *path ); static DaoNamespace* DaoVmSpace_LoadDaoModuleExt( DaoVmSpace *self, DString *path, int run ); static DaoNamespace* DaoVmSpace_LoadDllModule( DaoVmSpace *self, DString *libpath ); static void DaoVmSpace_ParseArguments( DaoVmSpace *self, DaoNamespace *ns, const char *file, DList *args, DList *argNames, DList *argValues ) { DString *str = DString_New(); DString *key = DString_New(); DString *val = DString_New(); DList *array = args; daoint i, tk, offset = 0; int eq = 0; if( array == NULL && file ){ array = DList_New( DAO_DATA_STRING ); SplitByWhiteSpaces( file, array ); DString_Assign( ns->name, array->items.pString[0] ); } DString_Assign( val, array->items.pString[0] ); DaoVmSpace_MakePath( self, ns->name ); DaoNamespace_SetName( ns, ns->name->chars ); /* to update ns->path and ns->file; */ i = 1; while( i < array->size ){ DString *s = array->items.pString[i]; i ++; offset = 0; if( s->chars[0] == '-' ){ offset += 1; if( s->chars[1] == '-' ) offset += 1; } tk = DaoToken_Check( s->chars+offset, s->size-offset, & eq ); if( tk == DTOK_IDENTIFIER && s->chars[eq+offset] == '=' ){ DString_SubString( s, key, offset, eq ); DString_SubString( s, val, eq+offset+1, s->size-offset-eq ); DList_Append( argNames, key ); DList_Append( argValues, val ); }else if( tk == DTOK_IDENTIFIER && offset && i < array->size ){ DString_SubString( s, key, offset, s->size-offset ); DString_Assign( val, array->items.pString[i] ); DList_Append( argNames, key ); DList_Append( argValues, val ); i += 1; }else{ DString_Clear( key ); DString_Assign( val, s ); DList_Append( argNames, key ); DList_Append( argValues, s ); } } if( args == NULL ) DList_Delete( array ); DString_Delete( key ); DString_Delete( val ); DString_Delete( str ); } static DaoValue* DaoVmSpace_MakeNameArgument( DaoNamespace *NS, DString *name, DaoValue *argv ) { DaoEnum *em; DaoTuple *tuple; DaoType *type, *types[2]; em = DaoNamespace_MakeSymbol( NS, name->chars ); types[0] = em->etype; types[1] = NS->vmSpace->typeString; type = DaoNamespace_MakeType( NS, "tuple", DAO_TUPLE, NULL, types, 2 ); tuple = DaoTuple_Create( type, 2, 0 ); DaoTuple_SetItem( tuple, (DaoValue*) em, 0 ); DaoTuple_SetItem( tuple, argv, 1 ); return (DaoValue*) tuple; } static int DList_SetArgument( DList *self, int i, DaoType *type, DString *name, DaoValue *string, DaoNamespace *NS ) { int isnum = DaoToken_IsNumber( string->xString.value->chars, string->xString.value->size ); DaoValue ival = {DAO_INTEGER}; DaoValue fval = {DAO_FLOAT}; DaoValue *argv; DString *sym; switch( type->tid ){ case DAO_INTEGER : ival.xInteger.value = strtoll( string->xString.value->chars, 0, 0 ); DaoValue_Copy( & ival, self->items.pValue + i ); return 10 * isnum; case DAO_FLOAT : fval.xFloat.value = strtod( string->xString.value->chars, 0 ); DaoValue_Copy( & fval, self->items.pValue + i ); return 10 * isnum; case DAO_ENUM : sym = string->xString.value; argv = (DaoValue*) DaoNamespace_MakeSymbol( NS, sym->chars ); DaoValue_Copy( argv, self->items.pValue + i ); if( type && DaoType_MatchValue( type, argv, NULL ) == 0 ) return 0; return 10; default : argv = string; if( name && name->size ) argv = DaoVmSpace_MakeNameArgument( NS, name, argv ); DaoValue_Copy( argv, self->items.pValue + i ); if( type && DaoType_MatchValue( type, argv, NULL ) == 0 ) return 0; break; } return 1; } static int DaoVmSpace_ConvertArguments( DaoRoutine *routine, DList *argNames, DList *argValues ) { DString *val; DaoValue sval = {DAO_STRING}; DaoNamespace *ns = routine->nameSpace; DaoType *routype = routine->routType; DList *argParams = ns->vmSpace->argParams; int set[2*DAO_MAX_PARAM]; int i, j, s, score = 1; val = DString_New(); sval.xString.value = val; DList_Clear( argParams ); for(i=0; iargs->size - routype->variadic; ++i){ DList_Append( argParams, routine->routConsts->value->items.pValue[i] ); set[i] = 0; } for(i=0; isize; ++i){ DaoValue *argv = & sval; DString *name = argNames->items.pString[i]; DString *value = argValues->items.pString[i]; DaoType *type = (DaoType*) DList_Back( routype->args ); int ito = i; if( i < routype->args->size ) type = routype->args->items.pType[i]; DString_Assign( val, value ); if( type && type->tid == DAO_PAR_VALIST ){ DaoType *type2 = (DaoType*) type->aux; for(j=i; jsize; ++j){ name = argNames->items.pString[j]; value = argValues->items.pString[j]; DString_Assign( val, value ); DList_Append( argParams, NULL ); s = DList_SetArgument( argParams, j, type2, name, argv, ns ); if( s == 0 ) goto InvalidArgument; score += s; } break; } if( name->size ){ DNode *node = DMap_Find( routype->mapNames, name ); if( node ){ ito = node->value.pInt; name = NULL; } } if( ito >= routype->args->size ) goto InvalidArgument; type = (DaoType*) routype->args->items.pType[ito]->aux; if( set[ito] ) goto InvalidArgument; set[ito] = DList_SetArgument( argParams, ito, type, name, argv, ns ); if( set[ito] == 0 ) goto InvalidArgument; score += 10 * set[ito]; } for(i=0; iargs->size - routype->variadic; ++i){ DaoType *partype = routine->routType->args->items.pType[i]; if( set[i] == 0 && partype->tid != DAO_PAR_DEFAULT ) goto InvalidArgument; } DString_Delete( val ); return score; InvalidArgument: DString_Delete( val ); return 0; } static DaoRoutine* DaoVmSpace_FindExplicitMain( DaoNamespace *ns, DList *argNames, DList *argValues, int *error ) { DString *name; DaoRoutine *rout = NULL; DaoRoutine *best = NULL; DaoRoutine **routs = NULL; int i, max = 0, count = 0; name = DString_New(); *error = 0; DString_SetChars( name, "main" ); i = DaoNamespace_FindConst( ns, name ); if( i >= 0 ) rout = DaoValue_CastRoutine( DaoNamespace_GetConst( ns, i ) ); if( rout == NULL ){ DString_Delete( name ); return NULL; } if( rout->overloads ){ routs = rout->overloads->routines->items.pRoutine; count = rout->overloads->routines->size; }else{ routs = & rout; count = 1; } for(i=0; i max ){ best = routs[i]; max = s; } } if( best ){ DaoVmSpace_ConvertArguments( best, argNames, argValues ); }else{ *error = 1; } DString_Delete( name ); return best; } DaoNamespace* DaoVmSpace_LoadEx( DaoVmSpace *self, const char *file, int run ) { DString *path = DString_NewChars( file ); DaoNamespace *ns = DaoVmSpace_FindNamespace( self, path ); if( ns ){ DString_Delete( path ); return ns; } Dao_NormalizePath( path ); switch( DaoVmSpace_CompleteModuleName( self, path, 0 ) ){ case DAO_MODULE_NONE : ns = DaoVmSpace_FindNamespace( self, path ); break; case DAO_MODULE_DAC : case DAO_MODULE_DAO : ns = DaoVmSpace_LoadDaoModuleExt( self, path, run ); break; case DAO_MODULE_DLL : ns = DaoVmSpace_LoadDllModule( self, path ); break; case DAO_MODULE_ANY : ns = DaoVmSpace_LoadDaoModuleExt( self, path, run ); break; default : break; } DString_Delete( path ); if( ns == NULL ) return 0; return ns; } DaoNamespace* DaoVmSpace_Load( DaoVmSpace *self, const char *file ) { return DaoVmSpace_LoadEx( self, file, DAO_MODULE_MAIN_ONCE ); } /* // Link "ns" to the module/namespace corresponding to "mod". // If the module "mod" is not loaded yet, it will be loaded first. // Return the namespace corresponding to "mod". */ DaoNamespace* DaoVmSpace_LinkModule( DaoVmSpace *self, DaoNamespace *ns, const char *mod ) { DaoNamespace *modns = DaoVmSpace_Load( self, mod ); if( modns == NULL ) return NULL; DaoNamespace_AddParent( ns, modns ); return modns; } static int CheckCodeCompletion( DString *source, DaoLexer *lexer ) { DList *tokens = lexer->tokens; int i, bcount, cbcount, sbcount, tki = 0, completed = 1; DaoLexer_Tokenize( lexer, source->chars, DAO_LEX_COMMENT|DAO_LEX_SPACE ); if( tokens->size ) tki = tokens->items.pToken[tokens->size-1]->type; switch( tki ){ case DTOK_LB : case DTOK_LCB : case DTOK_LSB : case DTOK_VBT_OPEN : case DTOK_CMT_OPEN : case DTOK_MBS_OPEN : case DTOK_WCS_OPEN : completed = 0; break; } if( tokens->size && completed ){ bcount = sbcount = cbcount = 0; for(i=0; isize; i++){ DaoToken *tk = tokens->items.pToken[i]; switch( tk->type ){ case DTOK_LB : bcount --; break; case DTOK_RB : bcount ++; break; case DTOK_LCB : cbcount --; break; case DTOK_RCB : cbcount ++; break; case DTOK_LSB : sbcount --; break; case DTOK_RSB : sbcount ++; break; default : break; } } if( bcount <0 || sbcount <0 || cbcount <0 ) completed = 0; } return completed; } static void DaoVmSpace_Interun( DaoVmSpace *self ) { DaoValue *value; DaoNamespace *ns; DaoLexer *lexer = DaoLexer_New(); DString *input = DString_New(); DString *line = DString_New(); const char *varRegex = "^ %s* = %s* %S+"; const char *srcRegex = "^ %s* %w+ %. dao .* $"; const char *sysRegex = "^ %\\ %s* %w+ %s* .* $"; char *chs; int ch; self->stdioStream->mode |= DAO_STREAM_HIGHLIGHT; self->errorStream->mode |= DAO_STREAM_HIGHLIGHT; DString_SetChars( self->mainNamespace->name, "interactive codes" ); self->mainNamespace->options |= DAO_NS_AUTO_GLOBAL; ns = DaoVmSpace_LinkModule( self, self->mainNamespace, "help" ); value = ns ? DaoNamespace_FindData( ns, "help_message" ) : NULL; if( value && value->type == DAO_STRING ) printf( "%s\n", DaoValue_TryGetChars( value ) ); while(1){ DString_Clear( input ); DaoValue_Clear( self->mainProcess->stackValues ); if( self->ReadLine ){ chs = self->ReadLine( "(dao) ", line ); if( chs == NULL ){ printf( "\n" ); break; } while( chs ){ DString_AppendChars( input, chs ); DString_AppendChar( input, '\n' ); if( CheckCodeCompletion( input, lexer ) ){ DString_Trim( input, 1, 1, 0 ); if( input->size && self->AddHistory ) self->AddHistory( input->chars ); break; } chs = self->ReadLine( "..... ", line ); } }else{ printf( "(dao) " ); fflush( stdout ); ch = getchar(); if( ch == EOF ) break; while( ch != EOF ){ if( ch == '\n' ){ if( CheckCodeCompletion( input, lexer ) ) break; printf("..... "); fflush( stdout ); } DString_AppendChar( input, (char)ch ); ch = getchar(); } if( ch == EOF ) clearerr( stdin ); DString_Trim( input, 1, 1, 0 ); } if( input->size == 0 ) continue; self->stopit = 0; if( strcmp( input->chars, "q" ) == 0 ){ break; }else if( DString_Match( input, sysRegex, NULL, NULL ) ){ if( system( input->chars+1 ) ==-1) printf( "shell command failed\n" ); }else if( DString_Match( input, srcRegex, NULL, NULL ) ){ DString_InsertChars( input, "std.load(", 0, 0, 0 ); DString_AppendChars( input, ", 0, 1 )" ); DaoProcess_Eval( self->mainProcess, self->mainNamespace, input->chars ); }else if( DString_Match( input, varRegex, NULL, NULL ) ){ DString_Change( input, "^ %s* = %s*", "", 0 ); DString_InsertChars( input, "return ", 0, 0, 0 ); DaoProcess_Eval( self->mainProcess, self->mainNamespace, input->chars ); }else{ DaoProcess_Eval( self->mainProcess, self->mainNamespace, input->chars ); } #ifdef DAO_WITH_CONCURRENT if( self->mainProcess->status >= DAO_PROCESS_SUSPENDED ){ if( DaoVmSpace_GetThreadCount( self ) == 0 ){ DaoVmSpace_AddTaskletThread( self, NULL, NULL, NULL ); } } DaoVmSpace_JoinTasklets( self ); #endif /* printf( "%s\n", input->chars ); */ } self->mainNamespace->options &= ~DAO_NS_AUTO_GLOBAL; DString_Delete( line ); DString_Delete( input ); DaoLexer_Delete( lexer ); } static void DaoVmSpace_PrintCode( DaoVmSpace *self ) { DaoNamespace *ns = self->mainNamespace; DMap *printed; daoint i, j; if( !(self->options & DAO_OPTION_LIST_BC) ) return; printed = DHash_New(0,0); for(i=ns->cstUser; iconstants->size; i++){ DaoValue *p = ns->constants->items.pConst[i]->value; if( p->type == DAO_ROUTINE && p != (DaoValue*) ns->mainRoutine ){ DaoRoutine *routine = (DaoRoutine*) p; if( routine->overloads == NULL ){ if( DMap_Find( printed, routine ) ) continue; DMap_Insert( printed, routine, NULL ); DaoRoutine_PrintCode( routine, self->stdioStream ); } }else if( p->type == DAO_CLASS ){ if( DMap_Find( printed, p ) ) continue; DMap_Insert( printed, p, NULL ); DaoClass_PrintCode( & p->xClass, self->stdioStream ); DaoStream_WriteChars( self->stdioStream, "\n\n" ); }else if( p->type == DAO_CINTYPE ){ DaoCinType *cintype = (DaoCinType*) p; DNode *it; if( DMap_Find( printed, p ) ) continue; DMap_Insert( printed, p, NULL ); DaoStream_WriteChars( self->stdioStream, "Concrete Interface: " ); DaoStream_WriteString( self->stdioStream, cintype->vatype->name ); DaoStream_WriteChars( self->stdioStream, "\n" ); for(it=DMap_First(cintype->methods); it; it=DMap_Next(cintype->methods, it)){ DaoRoutine *routine = it->value.pRoutine; if( it->value.pRoutine->overloads ){ DRoutines *routs = routine->overloads; for(j=0; jroutines->size; ++j){ DaoRoutine *rout = routs->routines->items.pRoutine[j]; if( DMap_Find( printed, rout ) ) continue; DMap_Insert( printed, rout, NULL ); DaoRoutine_PrintCode( rout, self->stdioStream ); } }else{ if( DMap_Find( printed, routine ) ) continue; DMap_Insert( printed, routine, NULL ); DaoRoutine_PrintCode( routine, self->stdioStream ); } } DaoStream_WriteChars( self->stdioStream, "\n\n" ); } } DaoStream_Flush( self->stdioStream ); if( ns->mainRoutine ) DaoRoutine_PrintCode( ns->mainRoutine, self->stdioStream ); DMap_Delete( printed ); } static void DaoVmSpace_ExeCmdArgs( DaoVmSpace *self ) { if( self->options & DAO_OPTION_VINFO ){ DaoStream_WriteNewLine( self->stdioStream ); DaoStream_WriteChars( self->stdioStream, dao_copy_notice ); DaoStream_WriteNewLine( self->stdioStream ); } if( self->options & DAO_OPTION_HELP ) DaoStream_WriteChars( self->stdioStream, cmd_help ); DaoStream_Flush( self->stdioStream ); DaoVmSpace_PrintCode( self ); } void DaoVmSpace_ConvertPath( DaoVmSpace *self, DString *path ) { char *daodir = getenv( "DAO_DIR" ); char *home = getenv( "HOME" ); if( DString_Find( path, self->startPath, 0 ) == 0 ){ DString_ReplaceChars( path, "$(CMD_DIR)/", 0, self->startPath->size ); }else if( DString_Find( path, self->daoBinPath, 0 ) == 0 ){ DString_ReplaceChars( path, "$(EXE_DIR)/", 0, self->daoBinPath->size ); }else if( daodir && DString_FindChars( path, daodir, 0 ) == 0 ){ DString_ReplaceChars( path, "$(DAO_DIR)", 0, strlen(daodir) ); }else if( home && DString_FindChars( path, home, 0 ) == 0 ){ DString_ReplaceChars( path, "$(HOME)", 0, strlen(home) ); } } void DaoVmSpace_ConvertPath2( DaoVmSpace *self, DString *path ) { DString *pathLoading = self->pathLoading->items.pString[0]; char *daodir = getenv( "DAO_DIR" ); char *home = getenv( "HOME" ); if( DString_FindChars( path, "$(DAR_DIR)/", 0 ) == 0 ){ DString_Replace( path, pathLoading, 0, strlen( "$(DAR_DIR)/" ) ); }else if( DString_FindChars( path, "$(CMD_DIR)/", 0 ) == 0 ){ DString_Replace( path, self->startPath, 0, strlen( "$(CMD_DIR)/" ) ); }else if( DString_FindChars( path, "$(EXE_DIR)/", 0 ) == 0 ){ DString_Replace( path, self->daoBinPath, 0, strlen( "$(EXE_DIR)/" ) ); }else if( daodir && DString_FindChars( path, "$(DAO_DIR)", 0 ) == 0 ){ DString_ReplaceChars( path, daodir, 0, strlen( "$(DAO_DIR)" ) ); }else if( home && DString_FindChars( path, "$(HOME)", 0 ) == 0 ){ DString_ReplaceChars( path, home, 0, strlen( "$(HOME)" ) ); } } void DaoVmSpace_SaveByteCodes( DaoVmSpace *self, DaoByteCoder *coder, DaoNamespace *ns ) { FILE *fout; DString *fname = DString_New(); DString *output = DString_New(); DString_Append( fname, ns->name ); if( fname->size > ns->lang->size ) fname->size -= ns->lang->size; DString_AppendChars( fname, "dac" ); fout = Dao_OpenFile( fname->chars, "w+" ); DaoByteCoder_EncodeHeader( coder, ns->name->chars, output ); DaoByteCoder_EncodeToString( coder, output ); DaoFile_WriteString( fout, output ); DString_Delete( output ); fclose( fout ); DaoStream_WriteChars( self->stdioStream, "Source file: " ); DaoStream_WriteString( self->stdioStream, ns->name ); DaoStream_WriteChar( self->stdioStream, '\n' ); DaoStream_WriteChars( self->stdioStream, "Compiled to: " ); DaoStream_WriteString( self->stdioStream, fname ); DaoStream_WriteChars( self->stdioStream, "\n\n" ); DString_Delete( fname ); } /* // Archive File Format: // -- Header: // Byte[4] # Signature: \33\33\r\n // Byte[4] # Count of files in the archive; // -- Body (repetition of the following structure): // Byte[2] # Length of the file name; // Byte[] # File name; // Byte[4] # File size; // Byte[] # File data; // Note: the count, lengths and sizes are encoded in big endian; */ static void DaoVmSpace_SaveArchive( DaoVmSpace *self, DList *argValues ) { FILE *fin, *fout, *fout2; int i, count = 1; int slen = strlen( DAO_DLL_SUFFIX ); DaoNamespace *ns = self->mainNamespace; DMap *archives = DMap_New(DAO_DATA_STRING,DAO_DATA_STRING); DMap *counts = DMap_New(DAO_DATA_STRING,0); DString *archive = DString_New(); DString *group = DString_New(); DString *data = DString_New(); DString *pathLoading; DNode *it, *it2; DString_Append( archive, ns->name ); if( archive->size > ns->lang->size ) archive->size -= ns->lang->size; DString_AppendChars( archive, "dar" ); DaoStream_PrintFileInfo( self->stdioStream, archive, "Creating Dao archive file: " ); fout = Dao_OpenFile( archive->chars, "w+" ); archive->size = 0; count = self->sourceArchive->size/2; /* // Store the scripts and modules in the main archive: // The archive file is created in the same directory as the main script; */ for(i=0; isourceArchive->size; i+=2){ DString *name = self->sourceArchive->items.pString[i]; DString *source = self->sourceArchive->items.pString[i+1]; DaoStream_PrintFileInfo( self->stdioStream, name, "Adding to the archive: " ); DaoVmSpace_ConvertPath( self, name ); DString_AppendUInt16( archive, name->size ); DString_Append( archive, name ); DString_AppendUInt32( archive, source->size ); DString_Append( archive, source ); if( DString_FindChars( name, DAO_DLL_SUFFIX, 0 ) != name->size - slen ){ // TODO: } } /* // Store the resource files in the main archive or separated archives: // -- Resources prefixed with :: are stored in separated // archives which are identified by the ; // -- Resources without group prefixes are stored in the main archive; */ for(i=0; isize; ++i){ DString *archsource = archive; DString *file = argValues->items.pString[i]; int pos = DString_FindChars( file, "::", 0 ); DString_Reset( group, 0 ); DString_Assign( data, file ); if( pos != DAO_NULLPOS ){ DString_SubString( file, group, 0, pos ); DString_SubString( file, data, pos+2, -1 ); } DString_MakePath( self->pathWorking, data ); fin = Dao_OpenFile( data->chars, "r" ); if( fin == NULL ){ DaoStream_PrintFileInfo( self->errorStream, data, "WARNING: cannot open resource: " ); continue; } DaoStream_PrintFileInfo( self->stdioStream, data, "Adding to the archive(s): " ); if( group->size == 0 ){ count += 1; }else{ it = DMap_Find( archives, group ); it2 = DMap_Find( counts, group ); if( it == NULL ){ it = DMap_Insert( archives, group, group ); it2 = DMap_Insert( counts, group, 0 ); it->value.pString->size = 0; } archsource = it->value.pString; it2->value.pInt += 1; } DaoVmSpace_ConvertPath( self, data ); DString_AppendUInt16( archsource, data->size ); DString_Append( archsource, data ); DaoFile_ReadAll( fin, data, 1 ); DString_AppendUInt32( archsource, data->size ); DString_Append( archsource, data ); } /* // Created separated archives for each resource group: // Such archives are created in the same directory as the main archive; */ for(it=DMap_First(archives); it; it=DMap_Next(archives,it)){ DString_Assign( group, it->key.pString ); it2 = DMap_Find( counts, group ); DString_MakePath( ns->path, group ); DString_AppendChars( group, ".dar" ); fout2 = Dao_OpenFile( group->chars, "w+" ); fprintf( fout2, "\33\33\r\n" ); DString_Clear( data ); DString_AppendUInt32( data, it2->value.pInt ); DaoFile_WriteString( fout2, data ); DaoFile_WriteString( fout2, it->value.pString ); fclose( fout2 ); /* // Add place holders in the main archive to reference the separated archives: // Byte[ 2]: 0x00 0xA // Byte[10]: $(ARCHIVE) // Byte[ 4]: // Byte[ ]: $(DAR_DIR)/.dar */ count += 1; pathLoading = self->pathLoading->items.pString[0]; if( DString_Find( group, pathLoading, 0 ) == 0 ){ DString_ReplaceChars( group, "$(DAR_DIR)/", 0, pathLoading->size ); } DaoVmSpace_ConvertPath( self, group ); DString_AppendUInt16( archive, 10 ); DString_AppendChars( archive, "$(ARCHIVE)" ); DString_AppendUInt32( archive, group->size ); DString_Append( archive, group ); } fprintf( fout, "\33\33\r\n" ); DString_Clear( data ); DString_AppendUInt32( data, count ); DaoFile_WriteString( fout, data ); DaoFile_WriteString( fout, archive ); fclose( fout ); DMap_Delete( archives ); DMap_Delete( counts ); DString_Delete( archive ); DString_Delete( group ); DString_Delete( data ); } void DaoVmSpace_LoadArchive( DaoVmSpace *self, DString *archive, DString *group ) { DString *name, *source; DaoVirtualModule module = { NULL, 0, NULL, NULL }; char *data = (char*) archive->chars; int slen = strlen( DAO_DLL_SUFFIX ); int pos = 4, size = archive->size; int i, m, n, files; if( group == NULL ) DString_Clear( self->mainSource ); if( size < 8 ) return; /* // Push the archive name and path to the ::nameLoading and ::pathLoading stacks // for resolving the $(DAR_DIR) variables in the references to other archives: */ if( group != NULL ){ DString *name = DList_PushFront( self->nameLoading, group ); DString *path = DList_PushFront( self->pathLoading, group ); DString_Change( name, "^ .* ([^/\\]+) $", "%1", 0 ); DString_Change( path, "[^/\\]* $", "", 0 ); } name = DString_New(); source = DString_New(); data = (char*) archive->chars; files = DaoDecodeUInt32( data + pos ); pos += 4; for(i=0; i= size ) break; m = DaoDecodeUInt16( data + pos ); if( (pos + 2 + m + 4) >= size ) break; n = DaoDecodeUInt32( data + pos + 2 + m ); DString_SetBytes( name, data + pos + 2, m ); if( i == 0 && group == NULL ){ /* Retrieve the main script: */ DString_SetChars( self->mainSource, "/@/" ); DString_AppendBytes( self->mainSource, data + pos + 2, m ); DaoNamespace_SetName( self->mainNamespace, self->mainSource->chars ); DString_SetBytes( self->mainSource, data + pos + 2 + m + 4, n ); }else if( strcmp( name->chars, "$(ARCHIVE)" ) == 0 ){ /* Load referenced archive: */ FILE *fin; DString_SetChars( name, data + pos + 2 + m + 4 ); DaoVmSpace_ConvertPath2( self, name ); DString_MakePath( self->startPath, name ); fin = Dao_OpenFile( name->chars, "r" ); if( fin == NULL ){ DaoStream_PrintFileInfo( self->errorStream, name, "WARNING: cannot open archive: " ); continue; } DaoFile_ReadAll( fin, source, 1 ); DaoVmSpace_LoadArchive( self, source, name ); }else if( DString_FindChars( name, DAO_DLL_SUFFIX, 0 ) != m - slen ){ module.name = name->chars; module.length = n; module.data = (uchar_t*) data + pos + 2 + m + 4; if( group ){ /* Negative length to indicate the file is not from the main archive: */ module.length = - (pos + 2 + m); module.data = (uchar_t*)group->chars; } DaoVmSpace_AddVirtualModule( self, & module ); }else{ /* Ignore DLL modules: */ } pos += 2 + m + 4 + n; } if( group != NULL ){ DList_PopFront( self->nameLoading ); DList_PopFront( self->pathLoading ); } DString_Delete( source ); DString_Delete( name ); } DaoValue* DaoVmSpace_Eval( DaoVmSpace *self, const char *source ) { DaoProcess *process = DaoVmSpace_AcquireProcess( self ); DaoValue *value = DaoProcess_Eval( process, self->mainNamespace, source ); DaoVmSpace_ReleaseProcess( self, process ); return value; } int DaoVmSpace_RunMain( DaoVmSpace *self, const char *file ) { DaoNamespace *ns = self->mainNamespace; DaoProcess *vmp = self->mainProcess; DaoStream *io = self->errorStream; DaoRoutine *mainRoutine, *expMain = NULL; DaoValue **ps; DList *argNames; DList *argValues; size_t tm = 0; daoint N; int res; if( file == NULL || file[0] ==0 || self->evalCmdline ){ DList_PushFront( self->nameLoading, self->pathWorking ); DList_PushFront( self->pathLoading, self->pathWorking ); if( self->evalCmdline ){ ns = DaoProcess_Compile( vmp, ns, self->mainSource->chars ); if( ns == NULL ) return 1; DaoVmSpace_ExeCmdArgs( self ); if( DaoProcess_Call( vmp, ns->mainRoutine, NULL, NULL, 0 ) ) return 1; }else{ DaoVmSpace_ExeCmdArgs( self ); } if( (self->options & DAO_OPTION_INTERUN) && self->handler == NULL ) DaoVmSpace_Interun( self ); return 0; } argNames = DList_New( DAO_DATA_STRING ); argValues = DList_New( DAO_DATA_STRING ); DaoVmSpace_ParseArguments( self, ns, file, NULL, argNames, argValues ); DaoVmSpace_SetPath( self, ns->path->chars ); DList_PushFront( self->nameLoading, ns->name ); DList_PushFront( self->pathLoading, ns->path ); if( DMap_Find( self->nsModules, ns->name ) == NULL ){ MAP_Insert( self->nsModules, ns->name, ns ); MAP_Insert( self->nsRefs, ns, NULL ); } tm = Dao_FileChangedTime( ns->name->chars ); ns->time = tm; /* self->fileName may has been changed */ res = DaoVmSpace_ReadFile( self, ns->name, self->mainSource ); if( strncmp( self->mainSource->chars, "\33\33\r\n", 4 ) == 0 ){ DString *archive = DString_Copy( self->mainSource ); DaoVmSpace_LoadArchive( self, archive, NULL ); DString_Delete( archive ); } if( self->options & DAO_OPTION_ARCHIVE ){ DList_Append( self->sourceArchive, ns->name ); DList_Append( self->sourceArchive, self->mainSource ); } if( self->mainSource->chars[0] == DAO_BC_SIGNATURE[0] ){ DaoByteCoder *byteCoder = DaoVmSpace_AcquireByteCoder( self ); DString_Assign( byteCoder->path, ns->name ); res = DaoByteCoder_Decode( byteCoder, self->mainSource ); if( self->options & DAO_OPTION_LIST_BC ) DaoByteCoder_Disassemble( byteCoder ); res = res && DaoByteCoder_Build( byteCoder, ns ); DaoVmSpace_ReleaseByteCoder( self, byteCoder ); }else{ DaoParser *parser = DaoVmSpace_AcquireParser( self ); if( self->options & DAO_OPTION_COMP_BC ){ parser->byteCoder = DaoVmSpace_AcquireByteCoder( self ); parser->byteBlock = DaoByteCoder_Init( parser->byteCoder ); } parser->nameSpace = ns; DString_Assign( parser->fileName, ns->name ); res = res && DaoParser_LexCode( parser, self->mainSource->chars, 1 ); res = res && DaoParser_ParseScript( parser ); if( res && (self->options & DAO_OPTION_COMP_BC) ){ DaoVmSpace_SaveByteCodes( self, parser->byteCoder, ns ); if( self->options & DAO_OPTION_LIST_BC ){ DaoByteCoder_Disassemble( parser->byteCoder ); } } if( parser->byteCoder ) DaoVmSpace_ReleaseByteCoder( self, parser->byteCoder ); DaoVmSpace_ReleaseParser( self, parser ); } if( res && !(self->options & DAO_OPTION_ARCHIVE) ){ DString name = DString_WrapChars( "main" ); int error = 0; expMain = DaoVmSpace_FindExplicitMain( ns, argNames, argValues, & error ); if( error ){ res = 0; DaoVmSpace_PrintCode( self ); DaoStream_WriteChars( io, "ERROR: invalid command line arguments.\n" ); } } DList_Delete( argNames ); if( res == 0 ){ DList_Delete( argValues ); return 1; } if( self->options & DAO_OPTION_ARCHIVE ){ DaoVmSpace_SaveArchive( self, argValues ); DList_Delete( argValues ); return 0; } DList_Delete( argValues ); if( self->options & DAO_OPTION_COMP_BC ) return 0; mainRoutine = ns->mainRoutine; DaoVmSpace_ExeCmdArgs( self ); /* always execute default __main__() routine first for initialization: */ if( mainRoutine ){ DaoProcess_PushRoutine( vmp, mainRoutine, NULL ); DaoProcess_Execute( vmp ); } /* check and execute explicitly defined main() routine */ ps = self->argParams->items.pValue; N = self->argParams->size; if( expMain != NULL ){ int ret = DaoProcess_Call( vmp, expMain, NULL, ps, N ); if( ret == DAO_ERROR_ARG ){ DaoStream_WriteChars( io, "ERROR: invalid command line arguments.\n" ); } if( ret ) return 1; if( vmp->stackValues[0] && vmp->stackValues[0]->type == DAO_INTEGER ){ return vmp->stackValues[0]->xInteger.value; } } if( (self->options & DAO_OPTION_INTERUN) && self->handler == NULL ) DaoVmSpace_Interun( self ); return 0; } int DaoVmSpace_CompleteModuleName( DaoVmSpace *self, DString *fname, int lib ) { int i, modtype = DAO_MODULE_NONE; daoint slen = strlen( DAO_DLL_SUFFIX ); daoint size; size = fname->size; if( size >4 && DString_FindChars( fname, ".dac", 0 ) == size-4 ){ if( DaoVmSpace_SearchModulePath( self, fname, lib ) ) modtype = DAO_MODULE_DAC; }else if( size >4 && DString_FindChars( fname, ".dao", 0 ) == size-4 ){ if( DaoVmSpace_SearchModulePath( self, fname, lib ) ) modtype = DAO_MODULE_DAO; }else if( size > slen && DString_FindChars( fname, DAO_DLL_SUFFIX, 0 ) == size - slen ){ if( DaoVmSpace_SearchModulePath( self, fname, lib ) ) modtype = DAO_MODULE_DLL; }else{ const char* const *fileSuffix = daoFileSuffix; int *moduleTypes = daoModuleTypes; if( self->options & DAO_OPTION_COMP_BC ){ fileSuffix = daoFileSuffix2; moduleTypes = daoModuleTypes2; } DString *fn = DString_New(); DString *path = DString_New(); DString *file = DString_New(); daoint pos = fname->size; while( pos && (fname->chars[pos-1] == '_' || isalnum( fname->chars[pos-1] )) ) pos -= 1; if( pos && (fname->chars[pos-1] == '/' || fname->chars[pos-1] == '\\') ){ DString_SubString( fname, path, 0, pos ); DString_SubString( fname, file, pos, fname->size - pos ); }else{ DString_Assign( file, fname ); } for(i=0; ichars, "dao_" ) == fname->chars ){ /* See modules/canvas/canvas.dao; */ DString_Assign( fn, path ); DString_AppendChars( fn, DAO_DLL_PREFIX "" ); DString_Append( fn, file ); }else{ if( strstr( fname->chars, daoDllPrefix[i] ) == fname->chars ) break; DString_Assign( fn, path ); DString_AppendChars( fn, daoDllPrefix[i] ); DString_Append( fn, file ); } DString_AppendChars( fn, fileSuffix[i] ); if( DaoVmSpace_SearchModulePath( self, fn, lib ) ){ modtype = moduleTypes[i]; if( modtype > DAO_MODULE_DLL ) modtype = DAO_MODULE_DLL; DString_Assign( fname, fn ); break; } } if( modtype == DAO_MODULE_NONE ){ if( DaoVmSpace_SearchModulePath( self, fname, lib ) ) modtype = DAO_MODULE_ANY; }else if( modtype == DAO_MODULE_DAC ){ size_t tmdac = Dao_FileChangedTime( fname->chars ); fname->chars[ fname->size - 1 ] = 'o'; /* .dac to .dao; */ if( DaoVmSpace_TestFile( self, fname ) ){ size_t tmdao = Dao_FileChangedTime( fname->chars ); /* Check if the source file has been changed: */ if( tmdac < tmdao ) modtype = DAO_MODULE_DAO; } if( modtype == DAO_MODULE_DAC ) fname->chars[ fname->size - 1 ] = 'c'; } DString_Delete( fn ); DString_Delete( path ); DString_Delete( file ); } return modtype; } static void DaoVmSpace_PopLoadingNamePath( DaoVmSpace *self, int path ) { DaoVmSpace_Lock( self ); if( path ) DList_PopFront( self->pathLoading ); DList_PopFront( self->nameLoading ); DaoVmSpace_Unlock( self ); } /* // Loading module in Dao source file. // The first time the module is loaded: // (1) its implicit main (codes outside of any class and function) is executed; // The next time the module is loaded: // (1) its implicit main is executed, IF run != 0; (mainly for IDE) */ DaoNamespace* DaoVmSpace_LoadDaoModuleExt( DaoVmSpace *self, DString *libpath, int run ) { DString *source = NULL; DaoNamespace *ns = NULL; DaoRoutine *mainRoutine = NULL; DaoParser *parser = NULL; DaoProcess *process; int poppath = 0; size_t tm = 0; ns = DaoVmSpace_FindNamespace( self, libpath ); tm = Dao_FileChangedTime( libpath->chars ); /* printf( "time = %lli, %s %p\n", tm, libpath->chars, ns ); */ if( ns && ns->time >= tm ){ if( run == DAO_MODULE_MAIN_ALWAYS ) goto ExecuteImplicitMain; goto LoadingDone; } ns = NULL; source = DString_New(); if( ! DaoVmSpace_ReadFile( self, libpath, source ) ) goto LoadingFailed; if( sizeof(dao_integer) != 8 || sizeof(dao_float) != 8 ){ int daofile = DString_Match( libpath, "%w %. dao $", 0, 0 ); int daocmd = DString_Match( source, "^ #! [^%n]* dao %s* {{\n}}", 0, 0 ); if( daofile == 0 && daocmd == 0 ) goto LoadingFailed; } if( self->options & DAO_OPTION_ARCHIVE ){ DList_Append( self->sourceArchive, libpath ); DList_Append( self->sourceArchive, source ); } /* printf("%p : loading %s\n", self, libpath->chars ); */ ns = DaoNamespace_New( self, libpath->chars ); ns->time = tm; DaoVmSpace_Lock( self ); MAP_Insert( self->nsModules, libpath, ns ); MAP_Insert( self->nsRefs, ns, NULL ); DList_PushFront( self->nameLoading, ns->name ); if( ns->path->size ) DList_PushFront( self->pathLoading, ns->path ); DaoVmSpace_Unlock( self ); poppath = ns->path->size; if( source->chars[0] == DAO_BC_SIGNATURE[0] ){ DaoByteCoder *byteCoder = DaoVmSpace_AcquireByteCoder( self ); int bl; DString_Assign( byteCoder->path, ns->name ); bl = DaoByteCoder_Decode( byteCoder, source ); if( self->options & DAO_OPTION_LIST_BC ) DaoByteCoder_Disassemble( byteCoder ); bl = bl && DaoByteCoder_Build( byteCoder, ns ); DaoVmSpace_ReleaseByteCoder( self, byteCoder ); if( bl == 0 ) goto LoadingFailed; }else{ parser = DaoVmSpace_AcquireParser( self ); parser->vmSpace = self; parser->nameSpace = ns; DString_Assign( parser->fileName, libpath ); if( ! DaoParser_LexCode( parser, DString_GetData( source ), 1 ) ) goto LoadingFailed; if( self->options & DAO_OPTION_COMP_BC ){ parser->byteCoder = DaoVmSpace_AcquireByteCoder( self ); parser->byteBlock = DaoByteCoder_Init( parser->byteCoder ); } if( ! DaoParser_ParseScript( parser ) ) goto LoadingFailed; if( ns->mainRoutine == NULL ) goto LoadingFailed; DString_SetChars( ns->mainRoutine->routName, "__main__" ); if( parser->byteCoder ){ DaoVmSpace_SaveByteCodes( self, parser->byteCoder, ns ); DaoVmSpace_ReleaseByteCoder( self, parser->byteCoder ); } DaoVmSpace_ReleaseParser( self, parser ); parser = NULL; } ExecuteImplicitMain : if( run && ns->mainRoutine->body->vmCodes->size > 1 ){ int status; process = DaoVmSpace_AcquireProcess( self ); DaoVmSpace_Lock( self ); DList_PushFront( self->nameLoading, ns->path ); DList_PushFront( self->pathLoading, ns->path ); DaoVmSpace_Unlock( self ); DaoProcess_PushRoutine( process, ns->mainRoutine, NULL ); DaoProcess_Execute( process ); status = process->status; DaoVmSpace_ReleaseProcess( self, process ); DaoVmSpace_Lock( self ); DList_PopFront( self->nameLoading ); DList_PopFront( self->pathLoading ); DaoVmSpace_Unlock( self ); if( status == DAO_PROCESS_ABORTED ) goto LoadingFailed; } LoadingDone: DaoVmSpace_PopLoadingNamePath( self, poppath ); if( source ) DString_Delete( source ); return ns; LoadingFailed : DaoVmSpace_PopLoadingNamePath( self, poppath ); DaoVmSpace_Lock( self ); DMap_Erase( self->nsModules, ns->name ); DMap_Erase( self->nsRefs, ns ); DaoVmSpace_Unlock( self ); if( source ) DString_Delete( source ); if( parser ) DaoVmSpace_ReleaseParser( self, parser ); return NULL; } DaoNamespace* DaoVmSpace_LoadDaoModule( DaoVmSpace *self, DString *libpath ) { return DaoVmSpace_LoadDaoModuleExt( self, libpath, DAO_MODULE_MAIN_NONE ); } static DaoNamespace* DaoVmSpace_LoadDllModule( DaoVmSpace *self, DString *libpath ) { DNode *node; DString *name = NULL; DaoModuleOnLoad funpter = NULL; DaoNamespace *ns = NULL; void *handle = NULL; daoint i, retc; ns = DaoVmSpace_FindNamespace( self, libpath ); if( ns ) return ns; if( self->auxLoaded == 0 && !(self->options & DAO_OPTION_SANDBOX) ){ int load = 0; DaoVmSpace_Lock( self ); if( self->auxLoaded == 0 ){ self->auxLoaded = 1; load = 1; } DaoVmSpace_Unlock( self ); if( load ) DaoVmSpace_Load( self, "dao_aux" ); } if( (node = MAP_Find( self->vmodules, libpath ) ) ){ funpter = (DaoModuleOnLoad) node->value.pVoid; ns = DaoNamespace_New( self, libpath->chars ); }else if( self->options & DAO_OPTION_SANDBOX ){ DaoStream_WriteChars( self->errorStream, "ERROR: unable to load module \"" ); DaoStream_WriteChars( self->errorStream, libpath->chars ); DaoStream_WriteChars( self->errorStream, "\" in sandbox mode.\n"); return NULL; }else{ handle = Dao_OpenDLL( libpath->chars ); if( ! handle ){ DaoStream_WriteChars( self->errorStream, "ERROR: unable to open the library file \"" ); DaoStream_WriteChars( self->errorStream, libpath->chars ); DaoStream_WriteChars( self->errorStream, "\".\n"); return NULL; } name = DString_New(); DString_SetChars( name, "DaoOnLoad" ); ns = DaoNamespace_New( self, libpath->chars ); ns->libHandle = handle; funpter = (DaoModuleOnLoad) Dao_GetSymbolAddress( handle, "DaoOnLoad" ); if( funpter == NULL ){ int size = strlen( DAO_DLL_SUFFIX ); DString_SetBytes( name, ns->file->chars, ns->file->size - size ); for(i=0; ichars ); if( funpter == NULL ){ for(i=3; isize-7; i++) name->chars[i] = tolower( name->chars[i] ); funpter = (DaoModuleOnLoad) Dao_GetSymbolAddress( handle, name->chars ); } if( funpter == NULL ){ name->chars[3] = toupper( name->chars[3] ); funpter = (DaoModuleOnLoad) Dao_GetSymbolAddress( handle, name->chars ); } if( funpter == NULL ){ for(i=3; isize-7; i++) name->chars[i] = toupper( name->chars[i] ); funpter = (DaoModuleOnLoad) Dao_GetSymbolAddress( handle, name->chars ); } } } if( self->options & DAO_OPTION_ARCHIVE ){ if( name == NULL ) name = DString_New(); if( funpter == NULL ) DString_Clear( name ); DList_Append( self->sourceArchive, libpath ); DList_Append( self->sourceArchive, name ); } if( name ) DString_Delete( name ); DaoVmSpace_Lock( self ); MAP_Insert( self->nsModules, libpath, ns ); MAP_Insert( self->nsRefs, ns, NULL ); DaoVmSpace_Unlock( self ); /* // no warning or error for loading a C/C++ dynamic linking library // for solving symbols in Dao modules. */ if( funpter == NULL ) return ns; DaoVmSpace_Lock( self ); DList_PushFront( self->nameLoading, ns->name ); if( ns->path->size ) DList_PushFront( self->pathLoading, ns->path ); DaoVmSpace_Unlock( self ); retc = (*funpter)( self, ns ); DaoVmSpace_Lock( self ); if( ns->path->size ) DList_PopFront( self->pathLoading ); DList_PopFront( self->nameLoading ); DaoVmSpace_Unlock( self ); if( retc ){ DaoVmSpace_Lock( self ); DMap_Erase( self->nsModules, ns->name ); DMap_Erase( self->nsRefs, ns ); DaoVmSpace_Unlock( self ); return NULL; } DaoNamespace_UpdateLookupTable( ns ); return ns; } int DaoVmSpace_AddPlugin( DaoVmSpace *self, DString *name, DaoNamespace *nspace ) { DNode *it = DMap_Find( self->nsPlugins, name ); if( it != NULL && it->value.pVoid == nspace ) return 1; it = DMap_Find( self->nsModules, name ); if( it == NULL || it->value.pVoid != nspace ) return 0; DaoVmSpace_Lock( self ); DMap_Insert( self->nsPlugins, name, nspace ); DList_Append( self->mainNamespace->namespaces, nspace ); DaoNamespace_UpdateLookupTable( self->mainNamespace ); DaoVmSpace_Unlock( self ); return 1; } int DaoVmSpace_AddVirtualModules( DaoVmSpace *self, DaoVirtualModule modules[] ) { int vmods = 0; /* For $(DAR_DIR) in archive paths: */ DList_PushFront( self->nameLoading, masterVmSpace->daoBinPath ); DList_PushFront( self->pathLoading, masterVmSpace->daoBinPath ); DString_Change( self->nameLoading->items.pString[0], "^ .* ([^/\\]+) $", "%1", 0 ); DString_Change( self->pathLoading->items.pString[0], "[^/\\]* $", "", 0 ); while( modules[vmods].name ){ DaoVmSpace_AddVirtualModule( self, & modules[vmods] ); vmods ++; } return vmods; } void DaoVmSpace_AddVirtualModule( DaoVmSpace *self, DaoVirtualModule *module ) { FILE *fin; DNode *node; DString *fname = DString_New(); DString *source = DString_New(); char *data = (char*) module->data; daoint pos, n = module->length; #if 0 printf( "DaoVmSpace_AddVirtualModule: %s %s\n", module->name, module->data ); #endif if( strcmp( module->name, "$(ARCHIVE)" ) == 0 ){ /* External archive: */ DString_SetBytes( fname, data, module->length ); DaoVmSpace_ConvertPath2( self, fname ); DString_MakePath( self->startPath, fname ); fin = Dao_OpenFile( fname->chars, "r" ); if( fin != NULL ){ DaoFile_ReadAll( fin, source, 1 ); DaoVmSpace_LoadArchive( self, source, fname ); }else{ DaoStream_PrintFileInfo( self->errorStream, fname, "WARNING: cannot open archive: " ); } DString_Delete( fname ); DString_Delete( source ); return; } /* Add a fake root "/@/" to all virtual files: */ DString_SetChars( fname, "/@/" ); DString_AppendChars( fname, module->name ); if( module->onload ){ MAP_Insert( self->vmodules, fname, module->onload ); }else if( n >= 0 ){ if( n == 0 ) n = strlen( data ); node = DMap_Find( self->vfiles, fname ); if( node ){ DaoVirtualFile *vfile = (DaoVirtualFile*) node->value.pVoid; DString_AppendBytes( vfile->data, data, n ); }else{ DaoVirtualFile *vfile = DaoVirtualFile_New(); DString_SetBytes( vfile->data, data, n ); MAP_Insert( self->vfiles, fname, vfile ); } }else{ /* // Add virtual file from external archive: // Only the archive name, byte offset and byte count are stored; */ fin = Dao_OpenFile( data, "r" ); node = DMap_Find( self->vfiles, fname ); if( node == NULL && fin != NULL ){ DaoFile_ReadPart( fin, source, labs(n), 4 ); if( source->size == 4 ){ DaoVirtualFile *vfile = DaoVirtualFile_New(); DString_SetChars( vfile->data, data ); vfile->offset = labs(n) + 4; vfile->size = DaoDecodeUInt32( source->chars ); MAP_Insert( self->vfiles, fname, vfile ); } } if( fin != NULL ) fclose( fin ); } pos = DString_RFindChar( fname, '/', -1 ); DString_Erase( fname, pos, -1 ); DList_PushFront( self->virtualPaths, fname ); DString_Delete( fname ); DString_Delete( source ); } int DaoVmSpace_SearchResource( DaoVmSpace *self, DString *fname, DString *search ) { DString *path; if( fname->size == 0 ) return 0; path = DString_New(); DString_AppendChars( path, "/@/" ); DString_Append( path, fname ); if( TestPath( self, path, DAO_FILE_PATH ) == 0 ){ DString_Assign( path, fname ); DString_MakePath( search, path ); } if( TestPath( self, path, DAO_FILE_PATH ) ){ DString_Assign( fname, path ); DString_Delete( path ); return 1; } DString_Delete( path ); return 0; } static int DaoVmSpace_SearchInPaths( DaoVmSpace *self, DList *paths, DString *fname ) { DString *path = DString_New(); daoint i; for(i=0; isize; ++i){ DString_Assign( path, paths->items.pString[i] ); if( path->size && path->chars[ path->size-1 ] != '/' ) DString_AppendChars( path, "/" ); DString_Append( path, fname ); /* printf( "%s %s\n", paths->items.pString[i]->chars, path->chars ); */ if( TestPath( self, path, DAO_FILE_PATH ) ){ DString_Assign( fname, path ); DString_Delete( path ); return 1; } } DString_Delete( path ); return 0; } int DaoVmSpace_SearchModulePath( DaoVmSpace *self, DString *fname, int lib ) { char *p; DString *path = NULL; if( lib ) return DaoVmSpace_SearchInPaths( self, self->pathSearching, fname ); if( DaoVmSpace_SearchResource( self, fname, self->pathWorking ) ) return 1; DString_Change( fname, "/ %s* %. %s* /", "/", 0 ); DString_Change( fname, "[^%./] + / %. %. /", "", 0 ); /* erase the last '/' */ if( fname->size && fname->chars[ fname->size-1 ] =='/' ){ fname->size --; fname->chars[ fname->size ] = 0; } /* C:\dir\source.dao; /home/... */ if( fname->size >1 && ( fname->chars[0]=='/' || fname->chars[1]==':' ) ){ return TestPath( self, fname, DAO_FILE_PATH ); } while( ( p = strchr( fname->chars, '\\') ) !=NULL ) *p = '/'; /* Virtual paths are more preferrable than other paths: */ if( DaoVmSpace_SearchInPaths( self, self->virtualPaths, fname ) ) return 1; path = DString_Copy( self->pathWorking ); /* ./source.dao; ../../source.dao */ if( strstr( fname->chars, "./" ) !=NULL || strstr( fname->chars, "../" ) !=NULL ){ if( self->pathLoading->size ){ DString_Assign( path, self->pathLoading->items.pString[0] ); if( path->size ==0 ) goto NotFound; }else if( self->pathWorking->size == 0 ) goto NotFound; DString_MakePath( path, fname ); if( TestPath( self, fname, DAO_FILE_PATH ) ) goto Found; goto NotFound; } if( DaoVmSpace_SearchInPaths( self, self->pathLoading, fname ) ) goto Found; if( path->size > 0 && path->chars[ path->size -1 ] != '/' ) DString_AppendChars( path, "/" ); DString_Append( path, fname ); /* printf( "%s %s\n", path->chars, path->chars ); */ if( TestPath( self, path, DAO_FILE_PATH ) ){ DString_Assign( fname, path ); goto Found; } if( DaoVmSpace_SearchInPaths( self, self->pathSearching, fname ) ) goto Found; if( self->handler && self->handler->SearchModule ){ if( self->handler->SearchModule( self->handler, fname ) ) goto Found; } goto NotFound; Found: DString_Delete( path ); return 1; NotFound: DString_Delete( path ); return 0; } void DaoVmSpace_SetPath( DaoVmSpace *self, const char *path ) { char *p; DString_SetChars( self->pathWorking, path ); while( ( p = strchr( self->pathWorking->chars, '\\') ) !=NULL ) *p = '/'; } /* Make path only relative to the current loading path or working path: */ void DaoVmSpace_MakePath( DaoVmSpace *self, DString *path ) { DString *wpath = self->pathWorking; if( path->size == 0 ) return; if( path->size > 0 && path->chars[0] == '/' ) return; if( path->size > 0 && path->chars[0] == '$' ) return; if( path->size > 1 && path->chars[1] == ':' ) return; if( self->pathLoading->size ) wpath = self->pathLoading->items.pString[0]; if( path->chars[0] == '.' ){ DString_MakePath( wpath, path ); }else{ DString *tmp = DString_Copy( wpath ); if( tmp->size > 0 && tmp->chars[ tmp->size-1 ] != '/' ) DString_AppendChars( tmp, "/" ); DString_Append( tmp, path ); DString_Assign( path, tmp ); DString_Delete( tmp ); } } void DaoVmSpace_AddPath( DaoVmSpace *self, const char *path ) { DString *pstr; char *p; if( path == NULL || path[0] == '\0' ) return; pstr = DString_New(); DString_SetChars( pstr, path ); while( ( p = strchr( pstr->chars, '\\') ) !=NULL ) *p = '/'; DaoVmSpace_MakePath( self, pstr ); if( pstr->chars[pstr->size-1] == '/' ) DString_Erase( pstr, pstr->size-1, 1 ); if( Dao_IsDir( pstr->chars ) ) DList_PushFront( self->pathSearching, pstr ); DString_Delete( pstr ); /* for(i=0; ipathSearching->size; i++ ) printf( "%s\n", self->pathSearching->items.pString[i]->chars ); */ } void DaoVmSpace_DelPath( DaoVmSpace *self, const char *path ) { DString *pstr; char *p; int i, id = -1; pstr = DString_New(); DString_SetChars( pstr, path ); while( ( p = strchr( pstr->chars, '\\') ) !=NULL ) *p = '/'; DaoVmSpace_MakePath( self, pstr ); if( pstr->chars[pstr->size-1] == '/' ) DString_Erase( pstr, pstr->size-1, 1 ); for(i=0; ipathSearching->size; i++ ){ if( DString_Compare( pstr, self->pathSearching->items.pString[i] ) == 0 ){ id = i; break; } } if( id >= 0 ) DList_Erase( self->pathSearching, id, 1 ); DString_Delete( pstr ); } const char* DaoVmSpace_CurrentWorkingPath( DaoVmSpace *self ) { return self->pathWorking->chars; } const char* DaoVmSpace_CurrentLoadingPath( DaoVmSpace *self ) { if( self->pathLoading->size ==0 ) return NULL; return self->pathLoading->items.pString[0]->chars; } extern void DaoInitLexTable(); static void DaoConfigure_FromFile( const char *name ) { double number; int i, ch, isnum, isint, integer=0, yes; FILE *fin = Dao_OpenFile( name, "r" ); DaoToken *tk1, *tk2; DaoLexer *lexer; DList *tokens; DString *mbs; if( fin == NULL ) return; mbs = DString_New(); lexer = DaoLexer_New(); tokens = lexer->tokens; while( ( ch=getc(fin) ) != EOF ) DString_AppendChar( mbs, ch ); fclose( fin ); DString_ToLower( mbs ); DaoLexer_Tokenize( lexer, mbs->chars, DAO_LEX_ESCAPE ); i = 0; while( i < tokens->size ){ tk1 = tokens->items.pToken[i]; /* printf( "%s\n", tk1->string.chars ); */ if( tk1->type == DTOK_IDENTIFIER ){ if( i+2 >= tokens->size ) goto InvalidConfig; if( tokens->items.pToken[i+1]->type != DTOK_ASSN ) goto InvalidConfig; tk2 = tokens->items.pToken[i+2]; isnum = isint = 0; yes = -1; if( tk2->type >= DTOK_DIGITS_DEC && tk2->type <= DTOK_NUMBER_SCI ){ isnum = 1; isint = tk2->type <= DTOK_NUMBER_HEX; number = DaoToken_ToFloat( tk2 ); integer = number; }else if( tk2->type == DTOK_IDENTIFIER ){ if( strcmp( tk2->string.chars, "yes" )==0 ) yes = 1; if( strcmp( tk2->string.chars, "no" )==0 ) yes = 0; } if( strcmp( tk1->string.chars, "cpu" )==0 ){ /* printf( "%s %i\n", tk2->string->chars, tk2->type ); */ if( isint == 0 ) goto InvalidConfigValue; daoConfig.cpu = integer; }else if( strcmp( tk1->string.chars, "jit" )==0 ){ if( yes <0 ) goto InvalidConfigValue; daoConfig.jit = yes; }else if( strcmp( tk1->string.chars, "optimize" )==0 ){ if( yes <0 ) goto InvalidConfigValue; daoConfig.optimize = yes; }else{ goto InvalidConfigName; } i += 3; continue; }else if( tk1->type == DTOK_COMMA || tk1->type == DTOK_SEMCO ){ i ++; continue; } InvalidConfig : printf( "ERROR: invalid configuration file format at line: %i!\n", tk1->line ); break; InvalidConfigName : printf( "ERROR: invalid configuration option name: %s!\n", tk1->string.chars ); break; InvalidConfigValue : printf( "ERROR: invalid configuration option value: %s!\n", tk2->string.chars ); break; } DaoLexer_Delete( lexer ); DString_Delete( mbs ); } static void DaoConfigure() { char *daodir = getenv( "DAO_DIR" ); DString *mbs = DString_New(); DaoInitLexTable(); daoConfig.iscgi = getenv( "GATEWAY_INTERFACE" ) ? 1 : 0; DString_SetChars( mbs, DAO_DIR ); DString_AppendChars( mbs, "/dao.conf" ); DaoConfigure_FromFile( mbs->chars ); if( daodir ){ DString_SetChars( mbs, daodir ); if( daodir[ mbs->size-1 ] == '/' ){ DString_AppendChars( mbs, "dao.conf" ); }else{ DString_AppendChars( mbs, "/dao.conf" ); } DaoConfigure_FromFile( mbs->chars ); } DaoConfigure_FromFile( "./dao.conf" ); DString_Delete( mbs ); } extern void DaoType_Init(); #ifdef DAO_WITH_THREAD extern DMutex mutex_string_sharing; extern DMutex mutex_type_map; extern DMutex mutex_values_setup; extern DMutex mutex_methods_setup; extern DMutex mutex_routines_update; extern DMutex mutex_routine_specialize; extern DMutex mutex_routine_specialize2; extern DaoFunctionEntry dao_mt_methods[]; #endif extern DaoFunctionEntry dao_std_methods[]; extern DaoFunctionEntry dao_io_methods[]; #include void print_trace(); int DaoVmSpace_TryInitDebugger( DaoVmSpace *self, const char *module ) { DaoDebugger *debugger = self->debugger; DaoVmSpace_Load( self, module ? module : "debugger" ); if( self->debugger != debugger ) return 1; DaoStream_WriteChars( self->errorStream, "Failed to enable debugger!\n" ); return 0; } int DaoVmSpace_TryInitProfiler( DaoVmSpace *self, const char *module ) { DaoProfiler *profiler = self->profiler; DaoVmSpace_Load( self, module ? module : "profiler" ); if( self->profiler && self->profiler != profiler ) return 1; DaoStream_WriteChars( self->errorStream, "Failed to enable profiler!\n" ); return 0; } int DaoVmSpace_TryInitJIT( DaoVmSpace *self, const char *module ) { DaoVmSpace_Load( self, module ? module : "jit" ); if( dao_jit.Compile ) return 1; DaoStream_WriteChars( self->errorStream, "Failed to enable Just-In-Time compiling!\n" ); return 0; } static void Dao_CompleteWinExeFile( DString *path ) { #ifdef WIN32 DString_Change( path, "/", "\\", 0 ); if( DString_RFindChars( path, ".exe", -1 ) != path->size - 1 ){ DString_AppendChars( path, ".exe" ); } #endif } static int Dao_GetExecutablePath( const char *command, DString *path ) { char *PATH = getenv( "PATH" ); DString paths = DString_WrapChars( PATH ); daoint i = 0; DString_Reset( path, 0 ); if( PATH == NULL ) return 0; while( i < paths.size ){ daoint j = DString_FindChar( & paths, DAO_ENV_PATH_SEP, i ); daoint len = (j == DAO_NULLPOS) ? paths.size - i : j - i; DString base = DString_WrapBytes( paths.chars + i, len ); DString_SetChars( path, command ); DString_MakePath( & base, path ); Dao_NormalizePath( path ); Dao_CompleteWinExeFile( path ); if( Dao_IsFile( path->chars ) ) return 1; if( j == DAO_NULLPOS ) break; i = j + 1; } return 0; } DaoVmSpace* DaoVmSpace_MasterVmSpace() { return masterVmSpace; } DaoType* DaoVmSpace_InitCoreTypes( DaoVmSpace *self ) { DaoNamespace *daoNS = self->daoNamespace; DaoType *tht = DaoType_New( daoNS, "@X", DAO_THT, NULL, NULL ); self->typeUdf = DaoType_New( daoNS, "?", DAO_UDT, NULL, NULL ); self->typeAny = DaoType_New( daoNS, "any", DAO_ANY, NULL, NULL ); self->typeBool = DaoType_New( daoNS, "bool", DAO_BOOLEAN, NULL, NULL ); self->typeInt = DaoType_New( daoNS, "int", DAO_INTEGER, NULL, NULL ); self->typeFloat = DaoType_New( daoNS, "float", DAO_FLOAT, NULL, NULL ); self->typeComplex = DaoType_New( daoNS, "complex", DAO_COMPLEX, NULL, NULL ); self->typeString = DaoType_New( daoNS, "string", DAO_STRING, NULL, NULL ); self->typeEnum = DaoType_New( daoNS, "enum", DAO_ENUM, NULL, NULL ); self->typeRoutine = DaoType_New( daoNS, "routine<=>@X>", DAO_ROUTINE, (DaoValue*)tht, NULL ); self->typeEnum->subtid = DAO_ENUM_ANY; return tht; } void DaoVmSpace_InitStdTypes( DaoVmSpace *self ) { DaoNamespace *NS; DaoNamespace *daoNS = self->daoNamespace; DaoProcess_CacheValue( self->mainProcess, (DaoValue*) self->typeUdf ); DaoProcess_CacheValue( self->mainProcess, (DaoValue*) self->typeRoutine ); DaoNamespace_AddTypeConstant( daoNS, self->typeAny->name, self->typeAny ); DaoNamespace_AddTypeConstant( daoNS, self->typeBool->name, self->typeBool ); DaoNamespace_AddTypeConstant( daoNS, self->typeInt->name, self->typeInt ); DaoNamespace_AddTypeConstant( daoNS, self->typeFloat->name, self->typeFloat ); DaoNamespace_AddTypeConstant( daoNS, self->typeComplex->name, self->typeComplex ); DaoNamespace_AddTypeConstant( daoNS, self->typeString->name, self->typeString ); DaoNamespace_AddTypeConstant( daoNS, self->typeEnum->name, self->typeEnum ); self->typeNone = DaoNamespace_MakeValueType( daoNS, dao_none_value ); self->typeTuple = DaoNamespace_DefineType( daoNS, "tuple<...>", NULL ); self->typeIteratorInt = DaoNamespace_MakeIteratorType( daoNS, self->typeInt ); self->typeIteratorAny = DaoNamespace_MakeIteratorType( daoNS, self->typeAny ); DaoNamespace_SetupType( daoNS, & daoStringCore, self->typeString ); DaoNamespace_SetupType( daoNS, & daoComplexCore, self->typeComplex ); #ifdef DAO_WITH_NUMARRAY self->typeArray = DaoNamespace_WrapGenericType( daoNS, & daoArrayCore, DAO_ARRAY ); self->typeArrayEmpty = DaoType_Specialize( self->typeArray, & self->typeFloat, 1, daoNS ); self->typeArrayEmpty = DaoType_GetConstType( self->typeArrayEmpty ); self->typeArrayEmpty->empty = 1; self->typeArrays[DAO_NONE] = self->typeArrayEmpty; self->typeArrays[DAO_BOOLEAN] = DaoType_Specialize( self->typeArray, & self->typeBool, 1, daoNS ); self->typeArrays[DAO_INTEGER] = DaoType_Specialize( self->typeArray, & self->typeInt, 1, daoNS ); self->typeArrays[DAO_FLOAT] = DaoType_Specialize( self->typeArray, & self->typeFloat, 1, daoNS ); self->typeArrays[DAO_COMPLEX] = DaoType_Specialize( self->typeArray, & self->typeComplex, 1, daoNS ); #endif self->typeList = DaoNamespace_WrapGenericType( daoNS, & daoListCore, DAO_LIST ); self->typeMap = DaoNamespace_WrapGenericType( daoNS, & daoMapCore, DAO_MAP ); self->typeListAny = DaoType_Specialize( self->typeList, NULL, 0, daoNS ); self->typeMapAny = DaoType_Specialize( self->typeMap, NULL, 0, daoNS ); /* // These types should not be accessible by developers using type annotation. */ self->typeListEmpty = DaoType_Copy( self->typeListAny ); self->typeListEmpty = DaoType_GetConstType( self->typeListEmpty ); self->typeListEmpty->empty = 1; self->typeMapEmpty = DaoType_Copy( self->typeMapAny ); self->typeMapEmpty = DaoType_GetConstType( self->typeMapEmpty ); self->typeMapEmpty->empty = 1; DaoProcess_CacheValue( self->mainProcess, (DaoValue*) self->typeListEmpty ); DaoProcess_CacheValue( self->mainProcess, (DaoValue*) self->typeMapEmpty ); self->typeCdata = DaoNamespace_WrapType( daoNS, & daoCdataCore, DAO_CDATA, 1 ); DaoException_Setup( daoNS ); NS = DaoVmSpace_GetNamespace( self, "io" ); DaoNamespace_AddConstValue( daoNS, "io", (DaoValue*) NS ); self->typeIODevice = DaoNamespace_WrapInterface( NS, & daoDeviceCore ); self->typeStream = DaoNamespace_WrapType( NS, & daoStreamCore, DAO_CSTRUCT, 0 ); DaoNamespace_WrapFunctions( NS, dao_io_methods ); NS = DaoVmSpace_GetNamespace( self, "mt" ); DaoNamespace_AddConstValue( daoNS, "mt", (DaoValue*) NS ); self->typeFuture = DaoNamespace_WrapType( NS, & daoFutureCore, DAO_CSTRUCT, 0 ); #ifdef DAO_WITH_CONCURRENT self->typeChannel = DaoNamespace_WrapType( NS, & daoChannelCore, DAO_CSTRUCT, 0 ); DaoNamespace_WrapFunctions( NS, dao_mt_methods ); #endif NS = DaoVmSpace_GetNamespace( self, "std" ); DaoNamespace_AddConstValue( daoNS, "std", (DaoValue*) NS ); DaoNamespace_WrapFunctions( NS, dao_std_methods ); DaoNamespace_UpdateLookupTable( self->mainNamespace ); } DaoVmSpace* DaoInit( const char *command ) { char *cwd; if( masterVmSpace ) return masterVmSpace; /* signal( SIGSEGV, print_trace ); */ /* signal( SIGABRT, print_trace ); */ #ifdef DAO_WITH_THREAD DMutex_Init( & mutex_string_sharing ); DMutex_Init( & mutex_type_map ); DMutex_Init( & mutex_values_setup ); DMutex_Init( & mutex_methods_setup ); DMutex_Init( & mutex_routines_update ); DMutex_Init( & mutex_routine_specialize ); DMutex_Init( & mutex_routine_specialize2 ); #endif setlocale( LC_CTYPE, "" ); DaoConfigure(); DaoType_Init(); /* printf( "number of VM instructions: %i\n", DVM_NULL ); */ #if 0 for(i=0; i<=DVM_UNUSED; ++i){ printf( "%3i: %3i %s\n", i, DaoVmCode_GetOpcodeBase(i), DaoVmCode_GetOpcodeName(i) ); if( i != DaoVmCode_GetOpcodeBase(i) ) printf( "!!!!!!!!!!\n" ); } #endif #ifdef DAO_WITH_THREAD DaoInitThread(); #endif DaoGC_Start(); #ifdef DAO_USE_GC_LOGGER DaoObjectLogger_Init(); #endif #if 0 #warning"-------------using concurrent GC by default!" DaoCGC_Start(); #endif masterVmSpace = DaoVmSpace_New(); DString_Reserve( masterVmSpace->startPath, 512 ); cwd = getcwd( masterVmSpace->startPath->chars, 511 ); DString_Reset( masterVmSpace->startPath, cwd ? strlen( cwd ) : 0 ); Dao_NormalizePath( masterVmSpace->startPath ); DString_AppendPathSep( masterVmSpace->startPath ); if( command ){ DString *path; int absolute = command[0] == '/'; int relative = command[0] == '.'; DString_SetChars( masterVmSpace->daoBinPath, command ); Dao_NormalizePath( masterVmSpace->daoBinPath ); #ifdef WIN32 absolute = isalpha( command[0] ) && command[1] == ':'; #endif if( absolute == 0 ){ if( relative ){ DString_MakePath( masterVmSpace->startPath, masterVmSpace->daoBinPath ); }else{ Dao_GetExecutablePath( command, masterVmSpace->daoBinPath ); } } #ifdef DEBUG path = DString_Copy( masterVmSpace->daoBinPath ); Dao_CompleteWinExeFile( path ); if( ! Dao_IsFile( path->chars ) ){ printf( "WARNING: the path of the executable cannot be located!\n" ); } DString_Delete( path ); #endif DString_Assign( masterVmSpace->daoBinFile, masterVmSpace->daoBinPath ); DString_Change( masterVmSpace->daoBinPath, "[^/\\]* $", "", 0 ); } DaoVmSpace_InitPath( masterVmSpace ); /* printf( "initialized...\n" ); */ return masterVmSpace; } void DaoQuit() { DaoVmSpace_TryDelete( masterVmSpace ); DaoGC_Finish(); #ifdef DAO_USE_GC_LOGGER DaoObjectLogger_Quit(); #endif //dao_type_stream = NULL; // XXX: 2017-04-02; masterVmSpace = NULL; if( dao_jit.Quit ){ dao_jit.Quit(); dao_jit.Quit = NULL; dao_jit.Free = NULL; dao_jit.Compile = NULL; dao_jit.Execute = NULL; } #ifdef DAO_WITH_THREAD DMutex_Destroy( & mutex_string_sharing ); DMutex_Destroy( & mutex_type_map ); DMutex_Destroy( & mutex_values_setup ); DMutex_Destroy( & mutex_methods_setup ); DMutex_Destroy( & mutex_routines_update ); DMutex_Destroy( & mutex_routine_specialize ); DMutex_Destroy( & mutex_routine_specialize2 ); DaoQuitThread(); #endif } void DaoParser_Warn( DaoParser *self, int code, DString *ext ); DaoNamespace* DaoVmSpace_LoadModule( DaoVmSpace *self, DString *fname, DaoParser *parser ) { DaoNamespace *ns = DaoVmSpace_FindNamespace( self, fname ); DString *name; if( ns ) return ns; Dao_NormalizePath( fname ); name = DString_Copy( fname ); switch( DaoVmSpace_CompleteModuleName( self, fname, 0 ) ){ case DAO_MODULE_NONE : ns = DaoVmSpace_FindNamespace( self, fname ); break; case DAO_MODULE_DAC : case DAO_MODULE_DAO : ns = DaoVmSpace_LoadDaoModule( self, fname ); break; case DAO_MODULE_DLL : ns = DaoVmSpace_LoadDllModule( self, fname ); break; } if( ns && DaoVmSpace_CompleteModuleName( self, name, 1 ) ){ if( DString_EQ( fname, name ) == 0 && DString_FindChars( fname, "/@/", 0 ) != 0 ){ DString warning = DString_WrapChars( "conflict module names!" ); if( parser ){ DaoParser_Warn( parser, DAO_CTW_LOAD_INVA_MOD_NAME, & warning ); }else{ DaoStream_WriteChars( self->errorStream, "[[WARNING]] " ); DaoStream_WriteString( self->errorStream, & warning ); DaoStream_WriteChars( self->errorStream, "\n" ); } DaoStream_WriteChars( self->errorStream, "User module: " ); DaoStream_WriteString( self->errorStream, fname ); DaoStream_WriteChars( self->errorStream, "\nLibrary module: " ); DaoStream_WriteString( self->errorStream, name ); DaoStream_WriteChars( self->errorStream, "\n" ); } } DString_Delete( name ); return ns; } void DaoVmSpace_AddKernel( DaoVmSpace *self, DaoTypeCore *core, DaoTypeKernel *kernel ) { DaoVmSpace_LockCache( self ); DMap_Insert( self->typeKernels, core, kernel ); DaoVmSpace_UnlockCache( self ); } DaoTypeKernel* DaoVmSpace_GetKernel( DaoVmSpace *self, DaoTypeCore *core ) { DNode *it; if( core == NULL ) return NULL; DaoVmSpace_LockCache( self ); it = DMap_Find( self->typeKernels, core ); DaoVmSpace_UnlockCache( self ); if( it ) return (DaoTypeKernel*) it->value.pValue; return NULL; } DaoType* DaoVmSpace_GetType( DaoVmSpace *self, DaoTypeCore *core ) { DaoTypeKernel *kernel = DaoVmSpace_GetKernel( self, core ); if( kernel ) return kernel->abtype; return NULL; } DaoType* DaoVmSpace_GetCommonType( DaoVmSpace *self, int type, int subtype ) { switch( type ){ case DAO_ARRAY : if( subtype <= DAO_COMPLEX ) return self->typeArrays[ subtype ]; break; case DAO_LIST : switch( subtype ){ case DAO_NONE : return self->typeListEmpty; case DAO_ANY : return self->typeListAny; } break; case DAO_MAP : switch( subtype ){ case DAO_NONE : return self->typeMapEmpty; case DAO_ANY : return self->typeMapAny; } break; case DAO_NONE : return self->typeNone; case DAO_ANY : return self->typeAny; case DAO_BOOLEAN : return self->typeBool; case DAO_INTEGER : return self->typeInt; case DAO_FLOAT : return self->typeFloat; case DAO_COMPLEX : return self->typeComplex; case DAO_STRING : return self->typeString; default : break; } return NULL; } static DaoType* DaoVmSpace_MakeExceptionType2( DaoVmSpace *self, const char *name ) { DaoTypeCore *core; DaoValue *value; DaoType *type, *parent = NULL; DString *basename, sub; daoint i, offset = 0; if( strcmp( name, "Exception" ) == 0 ) return self->typeException; if( strcmp( name, "Warning" ) == 0 ) return self->typeWarning; if( strcmp( name, "Error" ) == 0 ) return self->typeError; basename = DString_NewChars( name ); offset = DString_RFindChars( basename, "::", -1 ); if( offset != DAO_NULLPOS ){ DString_Erase( basename, offset - 1, -1 ); parent = DaoVmSpace_MakeExceptionType2( self, basename->chars ); offset += 1; } DString_Delete( basename ); if( parent == NULL ) return NULL; sub = DString_WrapChars( name + offset ); value = DaoType_FindValueOnly( parent, & sub ); if( value != NULL ){ if( value->type == DAO_CTYPE ) return value->xCtype.valueType; return NULL; } core = (DaoTypeCore*) dao_calloc( 1, sizeof(DaoTypeCore) + (strlen(name)+1) * sizeof(char) ); DList_Append( self->typeCores, core ); memcpy( core, parent->core, sizeof(DaoTypeCore) ); core->name = (char*) (core + 1); strcpy( (char*) core->name, name ); core->bases[0] = parent->core; core->numbers = NULL; core->methods = NULL; type = DaoNamespace_WrapType( self->daoNamespace, core, DAO_CSTRUCT, 0 ); if( type == NULL ) return NULL; if( parent->kernel->initRoutines ){ DaoRoutine *initors = parent->kernel->initRoutines; DaoType_FindFunctionChars( type, "x" ); /* To trigger method setup; */ for(i=0; ioverloads->routines->size; ++i){ DaoRoutine *tmp = initors->overloads->routines->items.pRoutine[i]; DaoRoutine *initor = DaoRoutine_Copy( tmp, 1, 0, 0 ); DaoNamespace *nspace = self->daoNamespace; DaoType *routype = tmp->routType; routype = DaoNamespace_MakeRoutType( nspace, tmp->routType, NULL, NULL, type ); GC_Assign( & initor->nameSpace, nspace ); GC_Assign( & initor->routType, routype ); GC_Assign( & initor->routHost, type ); DString_Assign( initor->routName, type->name ); initor->attribs |= DAO_ROUT_INITOR; DaoTypeKernel_InsertInitor( type->kernel, nspace, type, initor ); DaoMethods_Insert( type->kernel->methods, initor, nspace, type ); } } type->kernel->attribs |= DAO_TYPEKERNEL_FREE; for(i=DAO_ERROR; i<=DAO_ERROR_FLOAT; i++){ if( strcmp( core->name, daoExceptionNames[i] ) == 0 ){ DString_SetChars( type->aux->xCtype.info, daoExceptionTitles[i] ); break; } } return type; } DaoType* DaoVmSpace_MakeExceptionType( DaoVmSpace *self, const char *name ) { DaoType *type; /* // Locking is necessary because these exceptions are placed in a common // namespace DaoVmSpace::daoNamespace. Also, it is necessary to lock this // method altogether, so that no duplicated exception will be created. */ DaoVmSpace_Lock( self ); type = DaoVmSpace_MakeExceptionType2( self, name ); DaoVmSpace_Unlock( self ); return type; } void* DaoVmSpace_SetSpaceData( DaoVmSpace *self, void *key, void *value ) { void *prev = DaoVmSpace_GetSpaceData( self, key ); if( prev != NULL ){ typedef void (*data_delete)(void*); data_delete del = (data_delete) key; (*del)( prev ); } DMap_Insert( self->spaceData, key, value ); return value; } void* DaoVmSpace_GetSpaceData( DaoVmSpace *self, void *key ) { DNode *node; node = DMap_Find( self->spaceData, key ); if( node ) return node->value.pVoid; return NULL; } static void DaoVmSpace_PrintWarning( DaoVmSpace *self, const char *message ) { DaoStream_WriteChars( self->errorStream, "[[WARNING]] " ); DaoStream_WriteChars( self->errorStream, message ); DaoStream_WriteChars( self->errorStream, "\n" ); } static DaoCdata* DaoVmSpace_MakeCdata2( DaoVmSpace *self, DaoType *type, void *data, int own ) { DNode *node = DMap_Find( self->cdataWrappers, data ); DaoCdata *cdata = NULL; if( node ) cdata = (DaoCdata*) node->value.pValue; if( cdata && cdata->ctype == type ){ int subtype = own ? DAO_CDATA_CXX : DAO_CDATA_PTR; /* // Wrapping a C/C++ object as owned and then as not owned is allowed, // because it may happen that an owned object is passed to C/C++ modules // and then returned. But wrapping as owned first and then as not owned // is not allowed, and should never happen if the wrapping code is written // properly. */ if( cdata->subtype == DAO_CDATA_CXX && subtype == DAO_CDATA_PTR ){ subtype = DAO_CDATA_CXX; } if( cdata->data != data || cdata->subtype != subtype ){ DaoVmSpace_PrintWarning( self, "Cdata cache inconsistency is detected!" ); goto MakeNewWrapper; } DaoGC_IncCycRC( (DaoValue*) cdata ); /* Tell GC to postpone its collection; */ return cdata; } if( cdata && cdata->data == data ){ if( DaoType_ChildOf( cdata->ctype, type ) ){ DaoGC_IncCycRC( (DaoValue*) cdata ); return cdata; }else if( DaoType_ChildOf( type, cdata->ctype ) ){ void *casted = DaoCdata_CastData( cdata, type ); if( casted == cdata->data ){ /* It is safe to keep the ownership setting: */ DaoGC_Assign( (DaoValue**) & cdata->ctype, (DaoValue*) type ); return cdata; } /* // Try to wrap the casted data as a borrowed pointer. // It might have been wrapped before. */ return DaoVmSpace_MakeCdata2( self, type, casted, 0 ); } } MakeNewWrapper: if( cdata ) cdata->vmSpace = NULL; /* Set to NULL when removed from the cache; */ cdata = DaoCdata_Allocate( type, data, own ); if( data ){ cdata->vmSpace = self; DMap_Insert( self->cdataWrappers, data, cdata ); } return cdata; } void DaoVmSpace_ReleaseCdata2( DaoVmSpace *self, DaoType *type, void *data ) { DNode *node = DMap_Find( self->cdataWrappers, data ); DaoCdata *cdata; if( node == NULL ) return; cdata = (DaoCdata*) node->value.pValue; if( cdata->ctype == type || type == NULL ){ /* // In C/C++ modules, DaoVmSpace_ReleaseCdata() could be called in // class desctructors with a null @type parameter, to remove its // wrapping cdata object from the cache. Setting its @data field // to null to prevent double deletion of the wrapped C/C++ object. // // Otherwise, do not set @data to null, because it might still // hold references to Dao values such as its wrapping cdata object, // and it is needed by the GC to handle these (potential cyclic) // references properly. */ if( type == NULL ) cdata->data = NULL; cdata->vmSpace = NULL; DMap_EraseNode( self->cdataWrappers, node ); }else{ DaoVmSpace_PrintWarning( self, "Cdata cache inconsistency is detected!" ); } } static void DaoVmSpace_UpdateCdata2( DaoVmSpace *self, DaoCdata *cdata, void *data ) { DNode *node; if( cdata->data == data ) return; node = DMap_Find( self->cdataWrappers, cdata->data ); if( node ){ DaoCdata *cd = (DaoCdata*) node->value.pValue; if( cd != cdata ){ DaoVmSpace_PrintWarning( self, "Cdata cache inconsistency is detected!" ); } DMap_EraseNode( self->cdataWrappers, node ); } cdata->data = data; if( data ) DMap_Insert( self->cdataWrappers, data, cdata ); } #ifdef DAO_WITH_THREAD DaoCdata* DaoVmSpace_MakeCdata( DaoVmSpace *self, DaoType *type, void *data, int own ) { DaoCdata *cdata; if( DaoGC_IsConcurrent() ) DaoVmSpace_LockCache( self ); cdata = DaoVmSpace_MakeCdata2( self, type, data, own ); if( DaoGC_IsConcurrent() ) DaoVmSpace_UnlockCache( self ); return cdata; } void DaoVmSpace_ReleaseCdata( DaoVmSpace *self, DaoType *type, void *data ) { if( DaoGC_IsConcurrent() ) DaoVmSpace_LockCache( self ); DaoVmSpace_ReleaseCdata2( self, type, data ); if( DaoGC_IsConcurrent() ) DaoVmSpace_UnlockCache( self ); } void DaoVmSpace_UpdateCdata( DaoVmSpace *self, DaoCdata *cdata, void *data ) { if( DaoGC_IsConcurrent() ) DaoVmSpace_LockCache( self ); DaoVmSpace_UpdateCdata2( self, cdata, data ); if( DaoGC_IsConcurrent() ) DaoVmSpace_UnlockCache( self ); } #else DaoCdata* DaoVmSpace_MakeCdata( DaoVmSpace *self, DaoType *type, void *data, int own ) { return DaoVmSpace_MakeCdata2( self, type, data, own ); } void DaoVmSpace_ReleaseCdata( DaoVmSpace *self, DaoType *type, void *data ) { DaoVmSpace_ReleaseCdata2( self, type, data ); } void DaoVmSpace_UpdateCdata( DaoVmSpace *self, DaoCdata *cdata, void *data ) { DaoVmSpace_UpdateCdata2( self, cdata, data ); } #endif