as_builder.cpp

Go to the documentation of this file.
00001 /*
00002    AngelCode Scripting Library
00003    Copyright (c) 2003-2009 Andreas Jonsson
00004 
00005    This software is provided 'as-is', without any express or implied
00006    warranty. In no event will the authors be held liable for any
00007    damages arising from the use of this software.
00008 
00009    Permission is granted to anyone to use this software for any
00010    purpose, including commercial applications, and to alter it and
00011    redistribute it freely, subject to the following restrictions:
00012 
00013    1. The origin of this software must not be misrepresented; you
00014       must not claim that you wrote the original software. If you use
00015       this software in a product, an acknowledgment in the product
00016       documentation would be appreciated but is not required.
00017 
00018    2. Altered source versions must be plainly marked as such, and
00019       must not be misrepresented as being the original software.
00020 
00021    3. This notice may not be removed or altered from any source
00022       distribution.
00023 
00024    The original version of this library can be located at:
00025    http://www.angelcode.com/angelscript/
00026 
00027    Andreas Jonsson
00028    andreas@angelcode.com
00029 */
00030 
00031 
00032 //
00033 // as_builder.cpp
00034 //
00035 // This is the class that manages the compilation of the scripts
00036 //
00037 
00038 
00039 #include "as_config.h"
00040 #include "as_builder.h"
00041 #include "as_parser.h"
00042 #include "as_compiler.h"
00043 #include "as_tokendef.h"
00044 #include "as_string_util.h"
00045 #include "as_outputbuffer.h"
00046 #include "as_texts.h"
00047 #include "as_scriptobject.h"
00048 
00049 BEGIN_AS_NAMESPACE
00050 
00051 asCBuilder::asCBuilder(asCScriptEngine *engine, asCModule *module)
00052 {
00053     this->engine = engine;
00054     this->module = module;
00055 }
00056 
00057 asCBuilder::~asCBuilder()
00058 {
00059     asUINT n;
00060 
00061     // Free all functions
00062     for( n = 0; n < functions.GetLength(); n++ )
00063     {
00064         if( functions[n] )
00065         {
00066             if( functions[n]->node )
00067             {
00068                 functions[n]->node->Destroy(engine);
00069             }
00070 
00071             asDELETE(functions[n],sFunctionDescription);
00072         }
00073 
00074         functions[n] = 0;
00075     }
00076 
00077     // Free all global variables
00078     for( n = 0; n < globVariables.GetLength(); n++ )
00079     {
00080         if( globVariables[n] )
00081         {
00082             if( globVariables[n]->nextNode )
00083             {
00084                 globVariables[n]->nextNode->Destroy(engine);
00085             }
00086 
00087             asDELETE(globVariables[n],sGlobalVariableDescription);
00088             globVariables[n] = 0;
00089         }
00090     }
00091 
00092     // Free all the loaded files
00093     for( n = 0; n < scripts.GetLength(); n++ )
00094     {
00095         if( scripts[n] )
00096         {
00097             asDELETE(scripts[n],asCScriptCode);
00098         }
00099 
00100         scripts[n] = 0;
00101     }
00102 
00103     // Free all class declarations
00104     for( n = 0; n < classDeclarations.GetLength(); n++ )
00105     {
00106         if( classDeclarations[n] )
00107         {
00108             if( classDeclarations[n]->node )
00109             {
00110                 classDeclarations[n]->node->Destroy(engine);
00111             }
00112 
00113             asDELETE(classDeclarations[n],sClassDeclaration);
00114             classDeclarations[n] = 0;
00115         }
00116     }
00117 
00118     for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
00119     {
00120         if( interfaceDeclarations[n] )
00121         {
00122             if( interfaceDeclarations[n]->node )
00123             {
00124                 interfaceDeclarations[n]->node->Destroy(engine);
00125             }
00126 
00127             asDELETE(interfaceDeclarations[n],sClassDeclaration);
00128             interfaceDeclarations[n] = 0;
00129         }
00130     }
00131 
00132     for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
00133     {
00134         if( namedTypeDeclarations[n] )
00135         {
00136             if( namedTypeDeclarations[n]->node )
00137             {
00138                 namedTypeDeclarations[n]->node->Destroy(engine);
00139             }
00140 
00141             asDELETE(namedTypeDeclarations[n],sClassDeclaration);
00142             namedTypeDeclarations[n] = 0;
00143         }
00144     }
00145 }
00146 
00147 int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy)
00148 {
00149     asCScriptCode *script = asNEW(asCScriptCode);
00150     script->SetCode(name, code, codeLength, makeCopy);
00151     script->lineOffset = lineOffset;
00152     script->idx = sectionIdx;
00153     scripts.PushLast(script);
00154 
00155     return 0;
00156 }
00157 
00158 int asCBuilder::Build()
00159 {
00160     numErrors = 0;
00161     numWarnings = 0;
00162     preMessage.isSet = false;
00163 
00164     ParseScripts();
00165     CompileClasses();
00166     CompileGlobalVariables();
00167     CompileFunctions();
00168 
00169     if( numErrors > 0 )
00170         return asERROR;
00171 
00172     return asSUCCESS;
00173 }
00174 
00175 int asCBuilder::BuildString(const char *string, asCContext *ctx)
00176 {
00177     numErrors = 0;
00178     numWarnings = 0;
00179     preMessage.isSet = false;
00180 
00181     // Add the string to the script code
00182     asCScriptCode *script = asNEW(asCScriptCode);
00183     script->SetCode(TXT_EXECUTESTRING, string, true);
00184     script->lineOffset = -1; // Compensate for "void ExecuteString() {\n"
00185     scripts.PushLast(script);
00186 
00187     // Parse the string
00188     asCParser parser(this);
00189     if( parser.ParseScript(scripts[0]) >= 0 )
00190     {
00191         // Find the function
00192         asCScriptNode *node = parser.GetScriptNode();
00193         node = node->firstChild;
00194         if( node->nodeType == snFunction )
00195         {
00196             node->DisconnectParent();
00197 
00198             sFunctionDescription *func = asNEW(sFunctionDescription);
00199             functions.PushLast(func);
00200 
00201             func->script = scripts[0];
00202             func->node = node;
00203             func->name = "";
00204         }
00205         else
00206         {
00207             // An error occurred
00208             asASSERT(false);
00209         }
00210     }
00211 
00212     if( numErrors == 0 )
00213     {
00214         // Compile the function
00215         asCCompiler compiler(engine);
00216         asCScriptFunction *execfunc = asNEW(asCScriptFunction)(engine,module);
00217         if( compiler.CompileFunction(this, functions[0]->script, functions[0]->node, execfunc) >= 0 )
00218         {
00219             execfunc->id = asFUNC_STRING;
00220 
00221             ctx->SetExecuteStringFunction(execfunc);
00222         }
00223         else
00224         {
00225             asDELETE(execfunc,asCScriptFunction);
00226         }
00227     }
00228 
00229     if( numErrors > 0 )
00230         return asERROR;
00231 
00232     return asSUCCESS;
00233 }
00234 
00235 void asCBuilder::ParseScripts()
00236 {
00237     asCArray<asCParser*> parsers((int)scripts.GetLength());
00238 
00239     // Parse all the files as if they were one
00240     asUINT n = 0;
00241     for( n = 0; n < scripts.GetLength(); n++ )
00242     {
00243         asCParser *parser = asNEW(asCParser)(this);
00244         parsers.PushLast(parser);
00245 
00246         // Parse the script file
00247         parser->ParseScript(scripts[n]);
00248     }
00249 
00250     if( numErrors == 0 )
00251     {
00252         // Find all type declarations
00253         for( n = 0; n < scripts.GetLength(); n++ )
00254         {
00255             asCScriptNode *node = parsers[n]->GetScriptNode();
00256 
00257             // Find structure definitions first
00258             node = node->firstChild;
00259             while( node )
00260             {
00261                 asCScriptNode *next = node->next;
00262                 if( node->nodeType == snClass )
00263                 {
00264                     node->DisconnectParent();
00265                     RegisterClass(node, scripts[n]);
00266                 }
00267                 else if( node->nodeType == snInterface )
00268                 {
00269                     node->DisconnectParent();
00270                     RegisterInterface(node, scripts[n]);
00271                 }
00272                 //  Handle enumeration
00273                 else if( node->nodeType == snEnum )
00274                 {
00275                     node->DisconnectParent();
00276                     RegisterEnum(node, scripts[n]);
00277                 }
00278                 //  Handle typedef
00279                 else if( node->nodeType == snTypedef )
00280                 {
00281                     node->DisconnectParent();
00282                     RegisterTypedef(node, scripts[n]);
00283                 }
00284 
00285                 node = next;
00286             }
00287         }
00288 
00289         // Register script methods found in the interfaces
00290         for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
00291         {
00292             sClassDeclaration *decl = interfaceDeclarations[n];
00293 
00294             asCScriptNode *node = decl->node->firstChild->next;
00295             while( node )
00296             {
00297                 asCScriptNode *next = node->next;
00298                 if( node->nodeType == snFunction )
00299                 {
00300                     node->DisconnectParent();
00301                     RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType, true);
00302                 }
00303 
00304                 node = next;
00305             }
00306         }
00307 
00308         // Now the interfaces have been completely established, now we need to determine if
00309         // the same interface has already been registered before, and if so reuse the interface id.
00310         module->ResolveInterfaceIds();
00311 
00312         // Register script methods found in the structures
00313         for( n = 0; n < classDeclarations.GetLength(); n++ )
00314         {
00315             sClassDeclaration *decl = classDeclarations[n];
00316 
00317             asCScriptNode *node = decl->node->firstChild->next;
00318 
00319             // Skip list of classes and interfaces
00320             while( node && node->nodeType == snIdentifier )
00321                 node = node->next;
00322 
00323             while( node )
00324             {
00325                 asCScriptNode *next = node->next;
00326                 if( node->nodeType == snFunction )
00327                 {
00328                     node->DisconnectParent();
00329                     RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType);
00330                 }
00331 
00332                 node = next;
00333             }
00334 
00335             // Make sure the default factory & constructor exists for classes
00336             if( decl->objType->beh.construct == engine->scriptTypeBehaviours.beh.construct )
00337             {
00338                 AddDefaultConstructor(decl->objType, decl->script);
00339             }
00340         }
00341 
00342         // Find other global nodes
00343         for( n = 0; n < scripts.GetLength(); n++ )
00344         {
00345             // Find other global nodes
00346             asCScriptNode *node = parsers[n]->GetScriptNode();
00347             node = node->firstChild;
00348             while( node )
00349             {
00350                 asCScriptNode *next = node->next;
00351                 node->DisconnectParent();
00352 
00353                 if( node->nodeType == snFunction )
00354                 {
00355                     RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, scripts[n], 0, false, true);
00356                 }
00357                 else if( node->nodeType == snGlobalVar )
00358                 {
00359                     RegisterGlobalVar(node, scripts[n]);
00360                 }
00361                 else if( node->nodeType == snImport )
00362                 {
00363                     RegisterImportedFunction(module->GetNextImportedFunctionId(), node, scripts[n]);
00364                 }
00365                 else
00366                 {
00367                     // Unused script node
00368                     int r, c;
00369                     scripts[n]->ConvertPosToRowCol(node->tokenPos, &r, &c);
00370 
00371                     WriteWarning(scripts[n]->name.AddressOf(), TXT_UNUSED_SCRIPT_NODE, r, c);
00372 
00373                     node->Destroy(engine);
00374                 }
00375 
00376                 node = next;
00377             }
00378         }
00379     }
00380 
00381     for( n = 0; n < parsers.GetLength(); n++ )
00382     {
00383         asDELETE(parsers[n],asCParser);
00384     }
00385 }
00386 
00387 void asCBuilder::CompileFunctions()
00388 {
00389     // Compile each function
00390     for( asUINT n = 0; n < functions.GetLength(); n++ )
00391     {
00392         if( functions[n] == 0 ) continue;
00393 
00394         asCCompiler compiler(engine);
00395         asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
00396 
00397         if( functions[n]->node )
00398         {
00399             int r, c;
00400             functions[n]->script->ConvertPosToRowCol(functions[n]->node->tokenPos, &r, &c);
00401 
00402             asCString str = func->GetDeclarationStr();
00403             str.Format(TXT_COMPILING_s, str.AddressOf());
00404             WriteInfo(functions[n]->script->name.AddressOf(), str.AddressOf(), r, c, true);
00405 
00406             compiler.CompileFunction(this, functions[n]->script, functions[n]->node, func);
00407 
00408             preMessage.isSet = false;
00409         }
00410         else
00411         {
00412             // This is the default constructor, that is generated
00413             // automatically if not implemented by the user.
00414             asASSERT( functions[n]->name == functions[n]->objType->name );
00415             compiler.CompileDefaultConstructor(this, functions[n]->script, func);
00416         }
00417     }
00418 }
00419 
00420 int asCBuilder::ParseDataType(const char *datatype, asCDataType *result)
00421 {
00422     numErrors = 0;
00423     numWarnings = 0;
00424     preMessage.isSet = false;
00425 
00426     asCScriptCode source;
00427     source.SetCode("", datatype, true);
00428 
00429     asCParser parser(this);
00430     int r = parser.ParseDataType(&source);
00431     if( r < 0 )
00432         return asINVALID_TYPE;
00433 
00434     // Get data type and property name
00435     asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
00436 
00437     *result = CreateDataTypeFromNode(dataType, &source, true);
00438 
00439     if( numErrors > 0 )
00440         return asINVALID_TYPE;
00441 
00442     return asSUCCESS;
00443 }
00444 
00445 int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCString *subtypeName)
00446 {
00447     numErrors = 0;
00448     numWarnings = 0;
00449     preMessage.isSet = false;
00450 
00451     asCScriptCode source;
00452     source.SetCode("", decl, true);
00453 
00454     asCParser parser(this);
00455     int r = parser.ParseTemplateDecl(&source);
00456     if( r < 0 )
00457         return asINVALID_TYPE;
00458 
00459     // Get the template name and subtype name
00460     asCScriptNode *node = parser.GetScriptNode()->firstChild;
00461 
00462     name->Assign(&decl[node->tokenPos], node->tokenLength);
00463     node = node->next;
00464     subtypeName->Assign(&decl[node->tokenPos], node->tokenLength);
00465 
00466     // TODO: template: check for name conflicts
00467 
00468     if( numErrors > 0 )
00469         return asINVALID_DECLARATION;
00470 
00471     return asSUCCESS;
00472 }
00473 
00474 int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &name, asCDataType &type)
00475 {
00476     numErrors = 0;
00477     numWarnings = 0;
00478     preMessage.isSet = false;
00479 
00480     if( dt )
00481     {
00482         // Verify that the object type exist
00483         if( dt->GetObjectType() == 0 )
00484             return asINVALID_OBJECT;
00485     }
00486 
00487     // Check property declaration and type
00488     asCScriptCode source;
00489     source.SetCode(TXT_PROPERTY, decl, true);
00490 
00491     asCParser parser(this);
00492     int r = parser.ParsePropertyDeclaration(&source);
00493     if( r < 0 )
00494         return asINVALID_DECLARATION;
00495 
00496     // Get data type and property name
00497     asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
00498 
00499     asCScriptNode *nameNode = dataType->next;
00500 
00501     type = CreateDataTypeFromNode(dataType, &source);
00502     name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
00503 
00504     // Verify property name
00505     if( dt )
00506     {
00507         if( CheckNameConflictMember(*dt, name.AddressOf(), nameNode, &source) < 0 )
00508             return asNAME_TAKEN;
00509     }
00510     else
00511     {
00512         if( CheckNameConflict(name.AddressOf(), nameNode, &source) < 0 )
00513             return asNAME_TAKEN;
00514     }
00515 
00516     if( numErrors > 0 )
00517         return asINVALID_DECLARATION;
00518 
00519     return asSUCCESS;
00520 }
00521 
00522 asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop)
00523 {
00524     asASSERT(obj.GetObjectType() != 0);
00525 
00526     // TODO: Only search in config groups to which the module has access
00527     // TODO: optimize: Improve linear search
00528     asCArray<asCObjectProperty *> &props = obj.GetObjectType()->properties;
00529     for( asUINT n = 0; n < props.GetLength(); n++ )
00530         if( props[n]->name == prop )
00531             return props[n];
00532 
00533     return 0;
00534 }
00535 
00536 asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue)
00537 {
00538     asUINT n;
00539 
00540     if( isCompiled ) *isCompiled = true;
00541     if( isPureConstant ) *isPureConstant = false;
00542 
00543     // TODO: optimize: Improve linear search
00544     // Check application registered properties
00545     asCArray<asCGlobalProperty *> *props = &(engine->registeredGlobalProps);
00546     for( n = 0; n < props->GetLength(); ++n )
00547         if( (*props)[n] && (*props)[n]->name == prop )
00548         {
00549             if( module )
00550             {
00551                 // Find the config group for the global property
00552                 asCConfigGroup *group = engine->FindConfigGroupForGlobalVar((*props)[n]->id);
00553                 if( !group || group->HasModuleAccess(module->name.AddressOf()) )
00554                     return (*props)[n];
00555             }
00556             else
00557             {
00558                 // We're not compiling a module right now, so it must be a registered global property
00559                 return (*props)[n];
00560             }
00561         }
00562 
00563     // TODO: optimize: Improve linear search
00564     // Check properties being compiled now
00565     asCArray<sGlobalVariableDescription *> *gvars = &globVariables;
00566     for( n = 0; n < gvars->GetLength(); ++n )
00567     {
00568         if( (*gvars)[n] && (*gvars)[n]->name == prop )
00569         {
00570             if( isCompiled ) *isCompiled = (*gvars)[n]->isCompiled;
00571 
00572             if( isPureConstant ) *isPureConstant = (*gvars)[n]->isPureConstant;
00573             if( constantValue  ) *constantValue  = (*gvars)[n]->constantValue;
00574 
00575             return (*gvars)[n]->property;
00576         }
00577     }
00578 
00579     // TODO: optimize: Improve linear search
00580     // Check previously compiled global variables
00581     if( module )
00582     {
00583         props = &module->scriptGlobals;
00584         for( n = 0; n < props->GetLength(); ++n )
00585             if( (*props)[n]->name == prop )
00586                 return (*props)[n];
00587     }
00588 
00589     return 0;
00590 }
00591 
00592 int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray<bool> *paramAutoHandles, bool *returnAutoHandle)
00593 {
00594     numErrors = 0;
00595     numWarnings = 0;
00596     preMessage.isSet = false;
00597 
00598     asCScriptCode source;
00599     source.SetCode(TXT_SYSTEM_FUNCTION, decl, true);
00600 
00601     asCParser parser(this);
00602     int r = parser.ParseFunctionDefinition(&source);
00603     if( r < 0 )
00604         return asINVALID_DECLARATION;
00605 
00606     asCScriptNode *node = parser.GetScriptNode();
00607 
00608     // Find name
00609     asCScriptNode *n = node->firstChild->next->next;
00610     func->name.Assign(&source.code[n->tokenPos], n->tokenLength);
00611 
00612     // Initialize a script function object for registration
00613     bool autoHandle;
00614 
00615     // Scoped reference types are allowed to use handle when returned from application functions
00616     func->returnType = CreateDataTypeFromNode(node->firstChild, &source, true, objType);
00617     func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle);
00618     if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) )
00619             return asINVALID_DECLARATION;
00620     if( returnAutoHandle ) *returnAutoHandle = autoHandle;
00621 
00622     // Reference types cannot be returned by value from system functions
00623     if( isSystemFunction &&
00624         (func->returnType.GetObjectType() &&
00625          (func->returnType.GetObjectType()->flags & asOBJ_REF)) &&
00626         !(func->returnType.IsReference() ||
00627           func->returnType.IsObjectHandle()) )
00628         return asINVALID_DECLARATION;
00629 
00630     // Count number of parameters
00631     int paramCount = 0;
00632     n = n->next->firstChild;
00633     while( n )
00634     {
00635         paramCount++;
00636         n = n->next->next;
00637         if( n && n->nodeType == snIdentifier )
00638             n = n->next;
00639     }
00640 
00641     // Preallocate memory
00642     func->parameterTypes.Allocate(paramCount, false);
00643     func->inOutFlags.Allocate(paramCount, false);
00644     if( paramAutoHandles ) paramAutoHandles->Allocate(paramCount, false);
00645 
00646     n = node->firstChild->next->next->next->firstChild;
00647     while( n )
00648     {
00649         asETypeModifiers inOutFlags;
00650         asCDataType type = CreateDataTypeFromNode(n, &source, false, objType);
00651         type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle);
00652 
00653         // Reference types cannot be passed by value to system functions
00654         if( isSystemFunction &&
00655             (type.GetObjectType() &&
00656              (type.GetObjectType()->flags & asOBJ_REF)) &&
00657             !(type.IsReference() ||
00658               type.IsObjectHandle()) )
00659             return asINVALID_DECLARATION;
00660 
00661         // Store the parameter type
00662         func->parameterTypes.PushLast(type);
00663         func->inOutFlags.PushLast(inOutFlags);
00664 
00665         // Don't permit void parameters
00666         if( type.GetTokenType() == ttVoid )
00667             return asINVALID_DECLARATION;
00668 
00669         if( autoHandle && (!type.IsObjectHandle() || type.IsReference()) )
00670             return asINVALID_DECLARATION;
00671 
00672         if( paramAutoHandles ) paramAutoHandles->PushLast(autoHandle);
00673 
00674         // Make sure that var type parameters are references
00675         if( type.GetTokenType() == ttQuestion &&
00676             !type.IsReference() )
00677             return asINVALID_DECLARATION;
00678 
00679         // Move to next parameter
00680         n = n->next->next;
00681         if( n && n->nodeType == snIdentifier )
00682             n = n->next;
00683     }
00684 
00685     // Set the read-only flag if const is declared after parameter list
00686     if( node->lastChild->nodeType == snUndefined && node->lastChild->tokenType == ttConst )
00687         func->isReadOnly = true;
00688     else
00689         func->isReadOnly = false;
00690 
00691     if( numErrors > 0 || numWarnings > 0 )
00692         return asINVALID_DECLARATION;
00693 
00694     return 0;
00695 }
00696 
00697 int asCBuilder::ParseVariableDeclaration(const char *decl, asCObjectProperty *var)
00698 {
00699     numErrors = 0;
00700     numWarnings = 0;
00701     preMessage.isSet = false;
00702 
00703     asCScriptCode source;
00704     source.SetCode(TXT_VARIABLE_DECL, decl, true);
00705 
00706     asCParser parser(this);
00707 
00708     int r = parser.ParsePropertyDeclaration(&source);
00709     if( r < 0 )
00710         return asINVALID_DECLARATION;
00711 
00712     asCScriptNode *node = parser.GetScriptNode();
00713 
00714     // Find name
00715     asCScriptNode *n = node->firstChild->next;
00716     var->name.Assign(&source.code[n->tokenPos], n->tokenLength);
00717 
00718     // Initialize a script variable object for registration
00719     var->type = CreateDataTypeFromNode(node->firstChild, &source);
00720 
00721     if( numErrors > 0 || numWarnings > 0 )
00722         return asINVALID_DECLARATION;
00723 
00724     return 0;
00725 }
00726 
00727 int asCBuilder::CheckNameConflictMember(asCDataType &dt, const char *name, asCScriptNode *node, asCScriptCode *code)
00728 {
00729     // It's not necessary to check against object types
00730 
00731     // Check against other members
00732     asCObjectType *t = dt.GetObjectType();
00733 
00734     // TODO: optimize: Improve linear search
00735     asCArray<asCObjectProperty *> &props = t->properties;
00736     for( asUINT n = 0; n < props.GetLength(); n++ )
00737     {
00738         if( props[n]->name == name )
00739         {
00740             if( code )
00741             {
00742                 int r, c;
00743                 code->ConvertPosToRowCol(node->tokenPos, &r, &c);
00744 
00745                 asCString str;
00746                 str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name);
00747                 WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
00748             }
00749 
00750             return -1;
00751         }
00752     }
00753 
00754     // TODO: Property names must be checked against method names
00755 
00756     return 0;
00757 }
00758 
00759 int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code)
00760 {
00761     // TODO: Must verify object types in all config groups, whether the module has access or not
00762     // Check against object types
00763     if( engine->GetObjectType(name) != 0 )
00764     {
00765         if( code )
00766         {
00767             int r, c;
00768             code->ConvertPosToRowCol(node->tokenPos, &r, &c);
00769 
00770             asCString str;
00771             str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, name);
00772             WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
00773         }
00774 
00775         return -1;
00776     }
00777 
00778     // TODO: Must verify global properties in all config groups, whether the module has access or not
00779     // Check against global properties
00780     asCGlobalProperty *prop = GetGlobalProperty(name, 0, 0, 0);
00781     if( prop )
00782     {
00783         if( code )
00784         {
00785             int r, c;
00786             code->ConvertPosToRowCol(node->tokenPos, &r, &c);
00787 
00788             asCString str;
00789             str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, name);
00790 
00791             WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
00792         }
00793 
00794         return -1;
00795     }
00796 
00797     // TODO: Property names must be checked against function names
00798 
00799     // Check against class types
00800     asUINT n;
00801     for( n = 0; n < classDeclarations.GetLength(); n++ )
00802     {
00803         if( classDeclarations[n]->name == name )
00804         {
00805             if( code )
00806             {
00807                 int r, c;
00808                 code->ConvertPosToRowCol(node->tokenPos, &r, &c);
00809 
00810                 asCString str;
00811                 str.Format(TXT_NAME_CONFLICT_s_STRUCT, name);
00812 
00813                 WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
00814             }
00815 
00816             return -1;
00817         }
00818     }
00819 
00820     // Check against named types
00821     for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
00822     {
00823         if( namedTypeDeclarations[n]->name == name )
00824         {
00825             if( code )
00826             {
00827                 int r, c;
00828                 code->ConvertPosToRowCol(node->tokenPos, &r, &c);
00829 
00830                 asCString str;
00831 
00832                 // TODO: Need a TXT constant
00833                 str.Format("Name conflict. '%s' is a named type (FIXME!).", name);
00834 
00835                 WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
00836             }
00837 
00838             return -1;
00839         }
00840     }
00841 
00842     return 0;
00843 }
00844 
00845 
00846 int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file)
00847 {
00848     // What data type is it?
00849     asCDataType type = CreateDataTypeFromNode(node->firstChild, file);
00850 
00851     if( !type.CanBeInstanciated() )
00852     {
00853         asCString str;
00854         // TODO: Change to "'type' cannot be declared as variable"
00855         str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
00856 
00857         int r, c;
00858         file->ConvertPosToRowCol(node->tokenPos, &r, &c);
00859 
00860         WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
00861     }
00862 
00863     asCScriptNode *n = node->firstChild->next;
00864 
00865     while( n )
00866     {
00867         // Verify that the name isn't taken
00868         asCString name(&file->code[n->tokenPos], n->tokenLength);
00869         CheckNameConflict(name.AddressOf(), n, file);
00870 
00871         // Register the global variable
00872         sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
00873         globVariables.PushLast(gvar);
00874 
00875         gvar->script      = file;
00876         gvar->name        = name;
00877         gvar->isCompiled  = false;
00878         gvar->datatype    = type;
00879         gvar->isEnumValue = false;
00880 
00881         // TODO: Give error message if wrong
00882         asASSERT(!gvar->datatype.IsReference());
00883 
00884         gvar->idNode = n;
00885         gvar->nextNode = 0;
00886         if( n->next &&
00887             (n->next->nodeType == snAssignment ||
00888              n->next->nodeType == snArgList    ||
00889              n->next->nodeType == snInitList     ) )
00890         {
00891             gvar->nextNode = n->next;
00892             n->next->DisconnectParent();
00893         }
00894 
00895         gvar->property = module->AllocateGlobalProperty(name.AddressOf(), gvar->datatype);
00896         gvar->index    = gvar->property->id;
00897 
00898         n = n->next;
00899     }
00900 
00901     node->Destroy(engine);
00902 
00903     return 0;
00904 }
00905 
00906 int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file)
00907 {
00908     asCScriptNode *n = node->firstChild;
00909     asCString name(&file->code[n->tokenPos], n->tokenLength);
00910 
00911     int r, c;
00912     file->ConvertPosToRowCol(n->tokenPos, &r, &c);
00913 
00914     CheckNameConflict(name.AddressOf(), n, file);
00915 
00916     sClassDeclaration *decl = asNEW(sClassDeclaration);
00917     classDeclarations.PushLast(decl);
00918     decl->name       = name;
00919     decl->script     = file;
00920     decl->validState = 0;
00921     decl->node       = node;
00922 
00923     asCObjectType *st = asNEW(asCObjectType)(engine);
00924     st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
00925 
00926     if( node->tokenType == ttHandle )
00927         st->flags |= asOBJ_IMPLICIT_HANDLE;
00928 
00929     st->size      = sizeof(asCScriptObject);
00930     st->name      = name;
00931     module->classTypes.PushLast(st);
00932     engine->classTypes.PushLast(st);
00933     st->AddRef();
00934     decl->objType = st;
00935 
00936     // Use the default script class behaviours
00937     st->beh = engine->scriptTypeBehaviours.beh;
00938 
00939     return 0;
00940 }
00941 
00942 int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file)
00943 {
00944     asCScriptNode *n = node->firstChild;
00945     asCString name(&file->code[n->tokenPos], n->tokenLength);
00946 
00947     int r, c;
00948     file->ConvertPosToRowCol(n->tokenPos, &r, &c);
00949 
00950     CheckNameConflict(name.AddressOf(), n, file);
00951 
00952     sClassDeclaration *decl = asNEW(sClassDeclaration);
00953     interfaceDeclarations.PushLast(decl);
00954     decl->name       = name;
00955     decl->script     = file;
00956     decl->validState = 0;
00957     decl->node       = node;
00958 
00959     // Register the object type for the interface
00960     asCObjectType *st = asNEW(asCObjectType)(engine);
00961     st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
00962     st->size = 0; // Cannot be instanciated
00963     st->name = name;
00964     module->classTypes.PushLast(st);
00965     engine->classTypes.PushLast(st);
00966     st->AddRef();
00967     decl->objType = st;
00968 
00969     // Use the default script class behaviours
00970     st->beh.construct = 0;
00971     st->beh.addref = engine->scriptTypeBehaviours.beh.addref;
00972     st->beh.release = engine->scriptTypeBehaviours.beh.release;
00973     st->beh.copy = 0;
00974 
00975     return 0;
00976 }
00977 
00978 void asCBuilder::CompileGlobalVariables()
00979 {
00980     asUINT n;
00981 
00982     bool compileSucceeded = true;
00983 
00984     asCByteCode finalInit(engine);
00985 
00986     // Store state of compilation (errors, warning, output)
00987     int currNumErrors = numErrors;
00988     int currNumWarnings = numWarnings;
00989 
00990     // Backup the original message stream
00991     bool                       msgCallback     = engine->msgCallback;
00992     asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc;
00993     void                      *msgCallbackObj  = engine->msgCallbackObj;
00994 
00995     // Set the new temporary message stream
00996     asCOutputBuffer outBuffer;
00997     engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL);
00998 
00999     asCOutputBuffer finalOutput;
01000 
01001     // We first try to compile all the primitive global variables, and only after that
01002     // compile the non-primitive global variables. This permits the constructors 
01003     // for the complex types to use the already initialized variables of primitive 
01004     // type. Note, we currently don't know which global variables are used in the 
01005     // constructors, so we cannot guarantee that variables of complex types are 
01006     // initialized in the correct order, so we won't reorder those.
01007     bool compilingPrimitives = true;
01008 
01009     // Compile each global variable
01010     while( compileSucceeded )
01011     {
01012         compileSucceeded = false;
01013 
01014         int accumErrors = 0;
01015         int accumWarnings = 0;
01016 
01017         // Restore state of compilation
01018         finalOutput.Clear();
01019         for( asUINT n = 0; n < globVariables.GetLength(); n++ )
01020         {
01021             asCByteCode init(engine);
01022             numWarnings = 0;
01023             numErrors = 0;
01024             outBuffer.Clear();
01025 
01026             sGlobalVariableDescription *gvar = globVariables[n];
01027             if( gvar->isCompiled )
01028                 continue;
01029 
01030             // Skip this for now if we're not compiling complex types yet
01031             if( compilingPrimitives && !gvar->datatype.IsPrimitive() )
01032                 continue;
01033 
01034             if( gvar->nextNode )
01035             {
01036                 int r, c;
01037                 gvar->script->ConvertPosToRowCol(gvar->nextNode->tokenPos, &r, &c);
01038                 asCString str = gvar->datatype.Format();
01039                 str += " " + gvar->name;
01040                 str.Format(TXT_COMPILING_s, str.AddressOf());
01041                 WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), r, c, true);
01042             }
01043 
01044             if( gvar->isEnumValue )
01045             {
01046                 int r;
01047                 if( gvar->nextNode )
01048                 {
01049                     asCCompiler comp(engine);
01050 
01051                     // Temporarily switch the type of the variable to int so it can be compiled properly
01052                     asCDataType saveType;
01053                     saveType = gvar->datatype;
01054                     gvar->datatype = asCDataType::CreatePrimitive(ttInt, true);
01055                     r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar);
01056                     gvar->datatype = saveType;
01057                 }
01058                 else
01059                 {
01060                     r = 0;
01061 
01062                     // When there is no assignment the value is the last + 1
01063                     int enumVal = 0;
01064                     if( n > 0 )
01065                     {
01066                         sGlobalVariableDescription *gvar2 = globVariables[n-1];
01067                         if( gvar2->datatype == gvar->datatype )
01068                         {
01069                             // The integer value is stored in the lower bytes
01070                             enumVal = (*(int*)&gvar2->constantValue) + 1;
01071 
01072                             if( !gvar2->isCompiled )
01073                             {
01074                                 // TODO: Need to get the correct script position
01075                                 int row, col;
01076                                 gvar->script->ConvertPosToRowCol(0, &row, &col);
01077 
01078                                 asCString str = gvar->datatype.Format();
01079                                 str += " " + gvar->name;
01080                                 str.Format(TXT_COMPILING_s, str.AddressOf());
01081                                 WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), row, col, true);
01082 
01083                                 str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, gvar2->name.AddressOf());
01084                                 WriteError(gvar->script->name.AddressOf(), str.AddressOf(), row, col);
01085                                 r = -1;
01086                             }
01087                         }
01088                     }
01089 
01090                     // The integer value is stored in the lower bytes
01091                     *(int*)&gvar->constantValue = enumVal;
01092                 }
01093 
01094                 if( r >= 0 )
01095                 {
01096                     // Set the value as compiled
01097                     gvar->isCompiled = true;
01098                     compileSucceeded = true;
01099                 }
01100             }
01101             else
01102             {
01103                 // Compile the global variable
01104                 asCCompiler comp(engine);
01105                 int r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar);
01106                 if( r >= 0 )
01107                 {
01108                     // Compilation succeeded
01109                     gvar->isCompiled = true;
01110                     compileSucceeded = true;
01111 
01112                     init.AddCode(&comp.byteCode);
01113                 }
01114             }
01115 
01116             if( gvar->isCompiled )
01117             {
01118                 // Add warnings for this constant to the total build
01119                 if( numWarnings )
01120                 {
01121                     currNumWarnings += numWarnings;
01122                     if( msgCallback )
01123                         outBuffer.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
01124                 }
01125 
01126                 // Add compiled byte code to the final init and exit functions
01127                 finalInit.AddCode(&init);
01128             }
01129             else
01130             {
01131                 // Add output to final output
01132                 finalOutput.Append(outBuffer);
01133                 accumErrors += numErrors;
01134                 accumWarnings += numWarnings;
01135             }
01136 
01137             preMessage.isSet = false;
01138         }
01139 
01140         if( !compileSucceeded )
01141         {
01142             if( compilingPrimitives )
01143             {
01144                 // No more primitives could be compiled, so 
01145                 // switch to compiling the complex variables
01146                 compilingPrimitives = false;
01147                 compileSucceeded    = true;
01148             }
01149             else
01150             {
01151                 // No more variables can be compiled
01152                 // Add errors and warnings to total build
01153                 currNumWarnings += accumWarnings;
01154                 currNumErrors   += accumErrors;
01155                 if( msgCallback )
01156                     finalOutput.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
01157             }
01158         }
01159     }
01160 
01161     // Restore states
01162     engine->msgCallback     = msgCallback;
01163     engine->msgCallbackFunc = msgCallbackFunc;
01164     engine->msgCallbackObj  = msgCallbackObj;
01165 
01166     numWarnings = currNumWarnings;
01167     numErrors   = currNumErrors;
01168 
01169     // Register init code and clean up code
01170     finalInit.Ret(0);
01171 
01172     finalInit.Finalize();
01173 
01174     int id = engine->GetNextScriptFunctionId();
01175     asCScriptFunction *init = asNEW(asCScriptFunction)(engine,module);
01176 
01177     init->id = id;
01178     module->initFunction = init;
01179     engine->SetScriptFunction(init);
01180 
01181     init->byteCode.SetLength(finalInit.GetSize());
01182     finalInit.Output(init->byteCode.AddressOf());
01183     init->AddReferences();
01184     init->stackNeeded = finalInit.largestStackUsed;
01185 
01186     // Convert all variables compiled for the enums to true enum values
01187     for( n = 0; n < globVariables.GetLength(); n++ )
01188     {
01189         asCObjectType *objectType;
01190         sGlobalVariableDescription *gvar = globVariables[n];
01191         if( !gvar->isEnumValue )
01192             continue;
01193 
01194         objectType = gvar->datatype.GetObjectType();
01195         asASSERT(NULL != objectType);
01196 
01197         asSEnumValue *e = asNEW(asSEnumValue);
01198         e->name = gvar->name;
01199         e->value = *(int*)&gvar->constantValue;
01200 
01201         objectType->enumValues.PushLast(e);
01202 
01203         // Destroy the gvar property
01204         if( gvar->nextNode )
01205             gvar->nextNode->Destroy(engine);
01206         if( gvar->property )
01207             asDELETE(gvar->property, asCGlobalProperty);
01208 
01209         asDELETE(gvar, sGlobalVariableDescription);
01210         globVariables[n] = 0;
01211     }
01212 
01213 #ifdef AS_DEBUG
01214     // DEBUG: output byte code
01215     finalInit.DebugOutput("__@init.txt", module, engine);
01216 #endif
01217 }
01218 
01219 void asCBuilder::CompileClasses()
01220 {
01221     asUINT n;
01222     asCArray<sClassDeclaration*> toValidate((int)classDeclarations.GetLength());
01223 
01224     // Determine class inheritances and interfaces
01225     for( n = 0; n < classDeclarations.GetLength(); n++ )
01226     {
01227         sClassDeclaration *decl = classDeclarations[n];
01228         asCScriptCode *file = decl->script;
01229 
01230         // Find the base class that this class inherits from
01231         bool multipleInheritance = false;
01232         asCScriptNode *node = decl->node->firstChild->next;
01233         while( node && node->nodeType == snIdentifier )
01234         {
01235             // Get the interface name from the node
01236             asCString name(&file->code[node->tokenPos], node->tokenLength);
01237 
01238             // Find the object type for the interface
01239             asCObjectType *objType = GetObjectType(name.AddressOf());
01240 
01241             if( objType == 0 )
01242             {
01243                 int r, c;
01244                 file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01245                 asCString str;
01246                 str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, name.AddressOf());
01247                 WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
01248             }
01249             else if( !(objType->flags & asOBJ_SCRIPT_OBJECT) )
01250             {
01251                 int r, c;
01252                 file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01253                 asCString str;
01254                 str.Format(TXT_CANNOT_INHERIT_FROM_s, objType->name.AddressOf());
01255                 WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
01256             }
01257             else if( objType->size != 0 )
01258             {
01259                 // The class inherits from another script class
01260                 if( decl->objType->derivedFrom != 0 )
01261                 {
01262                     if( !multipleInheritance )
01263                     {
01264                         int r, c;
01265                         file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01266                         WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, r, c);
01267                         multipleInheritance = true;
01268                     }
01269                 }
01270                 else
01271                 {
01272                     // Make sure none of the base classes inherit from this one
01273                     asCObjectType *base = objType;
01274                     bool error = false;
01275                     while( base != 0 )
01276                     {
01277                         if( base == decl->objType )
01278                         {
01279                             int r, c;
01280                             file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01281                             WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_SELF, r, c);
01282                             error = true;
01283                             break;
01284                         }
01285 
01286                         base = base->derivedFrom;
01287                     }
01288 
01289                     if( !error )
01290                     {
01291                         decl->objType->derivedFrom = objType;
01292                         objType->AddRef();
01293                     }
01294                 }
01295             }
01296             else
01297             {
01298                 // The class implements an interface
01299                 if( decl->objType->Implements(objType) )
01300                 {
01301                     int r, c;
01302                     file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01303                     asCString msg;
01304                     msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, objType->GetName());
01305                     WriteWarning(file->name.AddressOf(), msg.AddressOf(), r, c);
01306                 }
01307                 else
01308                 {
01309                     decl->objType->interfaces.PushLast(objType);
01310 
01311                     // Make sure all the methods of the interface are implemented
01312                     for( asUINT i = 0; i < objType->methods.GetLength(); i++ )
01313                     {
01314                         if( !DoesMethodExist(decl->objType, objType->methods[i]) )
01315                         {
01316                             int r, c;
01317                             file->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
01318                             asCString str;
01319                             str.Format(TXT_MISSING_IMPLEMENTATION_OF_s,
01320                                 engine->GetFunctionDeclaration(objType->methods[i]).AddressOf());
01321                             WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
01322                         }
01323                     }
01324                 }
01325             }
01326 
01327             node = node->next;
01328         }
01329     }
01330 
01331     // Order class declarations so that base classes are compiled before derived classes.
01332     // This will allow the derived classes to copy properties and methods in the next step.
01333     for( n = 0; n < classDeclarations.GetLength(); n++ )
01334     {
01335         sClassDeclaration *decl = classDeclarations[n];
01336         asCObjectType *derived = decl->objType;
01337         asCObjectType *base = derived->derivedFrom;
01338 
01339         if( base == 0 ) continue;
01340 
01341         // If the base class is found after the derived class, then move the derived class to the end of the list
01342         for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ )
01343         {
01344             sClassDeclaration *declBase = classDeclarations[m];
01345             if( base == declBase->objType )
01346             {
01347                 classDeclarations.RemoveIndex(n);
01348                 classDeclarations.PushLast(decl);
01349 
01350                 // Decrease index so that we don't skip an entry
01351                 n--;
01352                 break;
01353             }
01354         }
01355     }
01356 
01357     // Go through each of the classes and register the object type descriptions
01358     for( n = 0; n < classDeclarations.GetLength(); n++ )
01359     {
01360         sClassDeclaration *decl = classDeclarations[n];
01361 
01362         // Add all properties and methods from the base class
01363         if( decl->objType->derivedFrom )
01364         {
01365             asCObjectType *baseType = decl->objType->derivedFrom;
01366 
01367             // The derived class inherits all interfaces from the base class
01368             for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ )
01369             {
01370                 if( !decl->objType->Implements(baseType->interfaces[n]) )
01371                 {
01372                     decl->objType->interfaces.PushLast(baseType->interfaces[n]);
01373                 }
01374                 else
01375                 {
01376                     // Warn if derived class already implements the interface
01377                     int r, c;
01378                     decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
01379                     asCString msg;
01380                     msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, baseType->interfaces[n]->GetName());
01381                     WriteWarning(decl->script->name.AddressOf(), msg.AddressOf(), r, c);
01382                 }
01383             }
01384 
01385             // TODO: Need to check for name conflict with new class methods
01386 
01387             // Copy properties from base class to derived class
01388             for( asUINT p = 0; p < baseType->properties.GetLength(); p++ )
01389             {
01390                 asCObjectProperty *prop = AddPropertyToClass(decl, baseType->properties[p]->name, baseType->properties[p]->type);
01391 
01392                 // The properties must maintain the same offset
01393                 asASSERT(prop->byteOffset == baseType->properties[p]->byteOffset); UNUSED_VAR(prop);
01394             }
01395 
01396             // Copy methods from base class to derived class
01397             for( asUINT m = 0; m < baseType->methods.GetLength(); m++ )
01398             {
01399                 // If the derived class implements the same method, then don't add the base class' method
01400                 asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]);
01401                 asCScriptFunction *derivedFunc = 0;
01402                 bool found = false;
01403                 for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ )
01404                 {
01405                     derivedFunc = GetFunctionDescription(decl->objType->methods[d]);
01406                     if( derivedFunc->IsSignatureEqual(baseFunc) )
01407                     {
01408                         decl->objType->methods.RemoveIndex(d);
01409                         found = true;
01410                         break;
01411                     }
01412                 }
01413 
01414                 if( !found )
01415                 {
01416                     // Push the base class function on the virtual function table
01417                     decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]);
01418                 }
01419                 else
01420                 {
01421                     // Push the derived class function on the virtual function table
01422                     decl->objType->virtualFunctionTable.PushLast(derivedFunc);
01423                 }
01424                 decl->objType->methods.PushLast(baseType->methods[m]);
01425             }
01426         }
01427 
01428         // Move this class' methods into the virtual function table
01429         for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ )
01430         {
01431             asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[m]);
01432             if( func->funcType != asFUNC_VIRTUAL )
01433             {
01434                 decl->objType->virtualFunctionTable.PushLast(GetFunctionDescription(decl->objType->methods[m]));
01435 
01436                 // Substitute the function description in the method list for a virtual method
01437                 // Make sure the methods are in the same order as the virtual function table
01438                 decl->objType->methods.RemoveIndex(m);
01439                 decl->objType->methods.PushLast(CreateVirtualFunction(func, (int)decl->objType->virtualFunctionTable.GetLength() - 1));
01440                 m--;
01441             }
01442         }
01443 
01444         // Enumerate each of the declared properties
01445         asCScriptNode *node = decl->node->firstChild->next;
01446 
01447         // Skip list of classes and interfaces
01448         while( node && node->nodeType == snIdentifier )
01449             node = node->next;
01450 
01451         while( node )
01452         {
01453             if( node->nodeType == snDeclaration )
01454             {
01455                 asCScriptCode *file = decl->script;
01456                 asCDataType dt = CreateDataTypeFromNode(node->firstChild, file);
01457                 asCString name(&file->code[node->lastChild->tokenPos], node->lastChild->tokenLength);
01458 
01459                 if( dt.IsReadOnly() )
01460                 {
01461                     int r, c;
01462                     file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01463 
01464                     WriteError(file->name.AddressOf(), TXT_PROPERTY_CANT_BE_CONST, r, c);
01465                 }
01466 
01467                 asCDataType st;
01468                 st.SetObjectType(decl->objType);
01469                 CheckNameConflictMember(st, name.AddressOf(), node->lastChild, file);
01470 
01471                 AddPropertyToClass(decl, name, dt, file, node);
01472             }
01473             else
01474                 asASSERT(false);
01475 
01476             node = node->next;
01477         }
01478 
01479         toValidate.PushLast(decl);
01480     }
01481 
01482     // Verify that the declared structures are valid, e.g. that the structure
01483     // doesn't contain a member of its own type directly or indirectly
01484     while( toValidate.GetLength() > 0 )
01485     {
01486         asUINT numClasses = (asUINT)toValidate.GetLength();
01487 
01488         asCArray<sClassDeclaration*> toValidateNext((int)toValidate.GetLength());
01489         while( toValidate.GetLength() > 0 )
01490         {
01491             sClassDeclaration *decl = toValidate[toValidate.GetLength()-1];
01492             int validState = 1;
01493             for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ )
01494             {
01495                 // A valid structure is one that uses only primitives or other valid objects
01496                 asCObjectProperty *prop = decl->objType->properties[n];
01497                 asCDataType dt = prop->type;
01498 
01499                 if( dt.IsTemplate() )
01500                 {
01501                     asCDataType sub = dt;
01502                     while( sub.IsTemplate() && !sub.IsObjectHandle() )
01503                         sub = sub.GetSubType();
01504 
01505                     dt = sub;
01506                 }
01507 
01508                 if( dt.IsObject() && !dt.IsObjectHandle() )
01509                 {
01510                     // Find the class declaration
01511                     sClassDeclaration *pdecl = 0;
01512                     for( asUINT p = 0; p < classDeclarations.GetLength(); p++ )
01513                     {
01514                         if( classDeclarations[p]->objType == dt.GetObjectType() )
01515                         {
01516                             pdecl = classDeclarations[p];
01517                             break;
01518                         }
01519                     }
01520 
01521                     if( pdecl )
01522                     {
01523                         if( pdecl->objType == decl->objType )
01524                         {
01525                             int r, c;
01526                             decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
01527                             WriteError(decl->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
01528                             validState = 2;
01529                             break;
01530                         }
01531                         else if( pdecl->validState != 1 )
01532                         {
01533                             validState = pdecl->validState;
01534                             break;
01535                         }
01536                     }
01537                 }
01538             }
01539 
01540             if( validState == 1 )
01541             {
01542                 decl->validState = 1;
01543                 toValidate.PopLast();
01544             }
01545             else if( validState == 2 )
01546             {
01547                 decl->validState = 2;
01548                 toValidate.PopLast();
01549             }
01550             else
01551             {
01552                 toValidateNext.PushLast(toValidate.PopLast());
01553             }
01554         }
01555 
01556         toValidate = toValidateNext;
01557         toValidateNext.SetLength(0);
01558 
01559         if( numClasses == toValidate.GetLength() )
01560         {
01561             int r, c;
01562             toValidate[0]->script->ConvertPosToRowCol(toValidate[0]->node->tokenPos, &r, &c);
01563             WriteError(toValidate[0]->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
01564             break;
01565         }
01566     }
01567 
01568     if( numErrors > 0 ) return;
01569 
01570     // TODO: The declarations form a graph, all circles in
01571     //       the graph must be flagged as potential circles
01572 
01573     // Verify potential circular references
01574     for( n = 0; n < classDeclarations.GetLength(); n++ )
01575     {
01576         sClassDeclaration *decl = classDeclarations[n];
01577         asCObjectType *ot = decl->objType;
01578 
01579         // Is there some path in which this structure is involved in circular references?
01580         for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
01581         {
01582             asCDataType dt = ot->properties[p]->type;
01583             if( dt.IsObject() )
01584             {
01585                 if( dt.IsObjectHandle() )
01586                 {
01587                     // TODO: Can this handle really generate a circular reference?
01588                     // Only if the handle is of a type that can reference this type, either directly or indirectly
01589 
01590                     ot->flags |= asOBJ_GC;
01591                 }
01592                 else if( dt.GetObjectType()->flags & asOBJ_GC )
01593                 {
01594                     // TODO: Just because the member type is a potential circle doesn't mean that this one is
01595                     // Only if the object is of a type that can reference this type, either directly or indirectly
01596 
01597                     ot->flags |= asOBJ_GC;
01598                 }
01599 
01600                 if( dt.IsArrayType() )
01601                 {
01602                     asCDataType sub = dt.GetSubType();
01603                     while( sub.IsObject() )
01604                     {
01605                         if( sub.IsObjectHandle() || (sub.GetObjectType()->flags & asOBJ_GC) )
01606                         {
01607                             decl->objType->flags |= asOBJ_GC;
01608 
01609                             // Make sure the array object is also marked as potential circle
01610                             sub = dt;
01611                             while( sub.IsTemplate() )
01612                             {
01613                                 sub.GetObjectType()->flags |= asOBJ_GC;
01614                                 sub = sub.GetSubType();
01615                             }
01616 
01617                             break;
01618                         }
01619 
01620                         if( sub.IsTemplate() )
01621                             sub = sub.GetSubType();
01622                         else
01623                             break;
01624                     }
01625                 }
01626             }
01627         }
01628     }
01629 }
01630 
01631 int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx)
01632 {
01633     asCScriptFunction *vf =  asNEW(asCScriptFunction)(engine, module);
01634 
01635     vf->funcType = asFUNC_VIRTUAL;
01636     vf->name = func->name;
01637     vf->returnType = func->returnType;
01638     vf->parameterTypes = func->parameterTypes;
01639     vf->inOutFlags = func->inOutFlags;
01640     vf->id = engine->GetNextScriptFunctionId();
01641     vf->scriptSectionIdx = func->scriptSectionIdx;
01642     vf->isReadOnly = func->isReadOnly;
01643     vf->objectType = func->objectType;
01644     vf->signatureId = func->signatureId;
01645     vf->vfTableIdx = idx;
01646 
01647     module->AddScriptFunction(vf);
01648 
01649     // Add a dummy to the builder so that it doesn't mix up function ids
01650     functions.PushLast(0);
01651 
01652     return vf->id;
01653 }
01654 
01655 asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, asCScriptCode *file, asCScriptNode *node)
01656 {
01657     // Store the properties in the object type descriptor
01658     asCObjectProperty *prop = asNEW(asCObjectProperty);
01659     prop->name = name;
01660     prop->type = dt;
01661 
01662     int propSize;
01663     if( dt.IsObject() )
01664     {
01665         propSize = dt.GetSizeOnStackDWords()*4;
01666         if( !dt.IsObjectHandle() )
01667         {
01668             if( !dt.CanBeInstanciated() )
01669             {
01670                 asASSERT( file && node );
01671 
01672                 int r, c;
01673                 file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01674                 asCString str;
01675                 str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
01676                 WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
01677             }
01678             prop->type.MakeReference(true);
01679         }
01680     }
01681     else
01682     {
01683         propSize = dt.GetSizeInMemoryBytes();
01684         if( propSize == 0 && file && node )
01685         {
01686             int r, c;
01687             file->ConvertPosToRowCol(node->tokenPos, &r, &c);
01688             asCString str;
01689             str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
01690             WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
01691         }
01692     }
01693 
01694     // Add extra bytes so that the property will be properly aligned
01695     if( propSize == 2 && (decl->objType->size & 1) ) decl->objType->size += 1;
01696     if( propSize > 2 && (decl->objType->size & 3) ) decl->objType->size += 4 - (decl->objType->size & 3);
01697 
01698     prop->byteOffset = decl->objType->size;
01699     decl->objType->size += propSize;
01700 
01701     decl->objType->properties.PushLast(prop);
01702 
01703     // Make sure the struct holds a reference to the config group where the object is registered
01704     asCConfigGroup *group = engine->FindConfigGroupForObjectType(prop->type.GetObjectType());
01705     if( group != 0 ) group->AddRef();
01706 
01707     return prop;
01708 }
01709 
01710 bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId)
01711 {
01712     asCScriptFunction *method = GetFunctionDescription(methodId);
01713 
01714     for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
01715     {
01716         asCScriptFunction *m = GetFunctionDescription(objType->methods[n]);
01717 
01718         if( m->name           != method->name           ) continue;
01719         if( m->returnType     != method->returnType     ) continue;
01720         if( m->isReadOnly     != method->isReadOnly     ) continue;
01721         if( m->parameterTypes != method->parameterTypes ) continue;
01722         if( m->inOutFlags     != method->inOutFlags     ) continue;
01723 
01724         return true;
01725     }
01726 
01727     return false;
01728 }
01729 
01730 void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file)
01731 {
01732     int funcId = engine->GetNextScriptFunctionId();
01733 
01734     asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false);
01735     asCArray<asCDataType> parameterTypes;
01736     asCArray<asETypeModifiers> inOutFlags;
01737 
01738     // Add the script function
01739     module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), false, objType);
01740 
01741     // Set it as default constructor
01742     objType->beh.construct = funcId;
01743     objType->beh.constructors[0] = funcId;
01744 
01745     // The bytecode for the default constructor will be generated
01746     // only after the potential inheritance has been established
01747     sFunctionDescription *func = asNEW(sFunctionDescription);
01748     functions.PushLast(func);
01749 
01750     func->script  = file;
01751     func->node    = 0;
01752     func->name    = objType->name;
01753     func->objType = objType;
01754     func->funcId  = funcId;
01755 
01756     // Add a default factory as well
01757     funcId = engine->GetNextScriptFunctionId();
01758     objType->beh.factory = funcId;
01759     objType->beh.factories[0] = funcId;
01760     returnType = asCDataType::CreateObjectHandle(objType, false);
01761     module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
01762     functions.PushLast(0);
01763     asCCompiler compiler(engine);
01764     compiler.CompileFactory(this, file, engine->scriptFunctions[funcId]);
01765 }
01766 
01767 int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file)
01768 {
01769     // Grab the name of the enumeration
01770     asCScriptNode *tmp = node->firstChild;
01771     asASSERT(snDataType == tmp->nodeType);
01772 
01773     asCString name;
01774     asASSERT(snIdentifier == tmp->firstChild->nodeType);
01775     name.Assign(&file->code[tmp->firstChild->tokenPos], tmp->firstChild->tokenLength);
01776 
01777     // Check the name and add the enum
01778     int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file);
01779     if( asSUCCESS == r )
01780     {
01781         asCObjectType *st;
01782         asCDataType dataType;
01783 
01784         st = asNEW(asCObjectType)(engine);
01785         dataType.CreatePrimitive(ttInt, false);
01786 
01787         st->flags     = asOBJ_ENUM;
01788         st->size      = dataType.GetSizeInMemoryBytes();
01789         st->name      = name;
01790 
01791         module->enumTypes.PushLast(st);
01792         st->AddRef();
01793         engine->classTypes.PushLast(st);
01794 
01795         // Store the location of this declaration for reference in name collisions
01796         sClassDeclaration *decl = asNEW(sClassDeclaration);
01797         decl->name       = name;
01798         decl->script     = file;
01799         decl->validState = 0;
01800         decl->node       = NULL;
01801         decl->objType    = st;
01802         namedTypeDeclarations.PushLast(decl);
01803 
01804         asCDataType type = CreateDataTypeFromNode(tmp, file);
01805         asASSERT(!type.IsReference());
01806 
01807         tmp = tmp->next;
01808 
01809         while( tmp )
01810         {
01811             asASSERT(snIdentifier == tmp->nodeType);
01812 
01813             asCString name(&file->code[tmp->tokenPos], tmp->tokenLength);
01814 
01815             // TODO: Should only have to check for conflicts within the enum type
01816             // Check for name conflict errors
01817             r = CheckNameConflict(name.AddressOf(), tmp, file);
01818             if(asSUCCESS != r)
01819             {
01820                 continue;
01821             }
01822 
01823             //  check for assignment
01824             asCScriptNode *asnNode = tmp->next;
01825             if( asnNode && snAssignment == asnNode->nodeType )
01826                 asnNode->DisconnectParent();
01827             else
01828                 asnNode = 0;
01829 
01830             // Create the global variable description so the enum value can be evaluated
01831             sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
01832             globVariables.PushLast(gvar);
01833 
01834             gvar->script          = file;
01835             gvar->idNode          = 0;
01836             gvar->nextNode        = asnNode;
01837             gvar->name            = name;
01838             gvar->datatype        = type;
01839             // No need to allocate space on the global memory stack since the values are stored in the asCObjectType
01840             gvar->index           = 0;
01841             gvar->isCompiled      = false;
01842             gvar->isPureConstant  = true;
01843             gvar->isEnumValue     = true;
01844             gvar->constantValue   = 0xdeadbeef;
01845 
01846             // Allocate dummy property so we can compile the value. 
01847             // This will be removed later on so we don't add it to the engine.
01848             gvar->property        = asNEW(asCGlobalProperty);
01849             gvar->property->name  = name;
01850             gvar->property->type  = gvar->datatype;
01851             gvar->property->id    = 0;
01852 
01853             tmp = tmp->next;
01854         }
01855     }
01856 
01857     node->Destroy(engine);
01858 
01859     return r;
01860 }
01861 
01862 int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file)
01863 {
01864     // Get the native data type
01865     asCScriptNode *tmp = node->firstChild;
01866     asASSERT(NULL != tmp && snDataType == tmp->nodeType);
01867     asCDataType dataType;
01868     dataType.CreatePrimitive(tmp->tokenType, false);
01869     dataType.SetTokenType(tmp->tokenType);
01870     tmp = tmp->next;
01871 
01872     // Grab the name of the typedef
01873     asASSERT(NULL != tmp && NULL == tmp->next);
01874     asCString name;
01875     name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength);
01876 
01877     // If the name is not already in use add it
01878     int r = CheckNameConflict(name.AddressOf(), tmp, file);
01879     if( asSUCCESS == r )
01880     {
01881         // Create the new type
01882         asCObjectType *st = asNEW(asCObjectType)(engine);
01883 
01884         st->flags           = asOBJ_TYPEDEF;
01885         st->size            = dataType.GetSizeInMemoryBytes();
01886         st->name            = name;
01887         st->templateSubType = dataType;
01888 
01889         st->AddRef();
01890 
01891         module->typeDefs.PushLast(st);
01892         engine->classTypes.PushLast(st);
01893 
01894         // Store the location of this declaration for reference in name collisions
01895         sClassDeclaration *decl = asNEW(sClassDeclaration);
01896         decl->name       = name;
01897         decl->script     = file;
01898         decl->validState = 0;
01899         decl->node       = NULL;
01900         decl->objType    = st;
01901         namedTypeDeclarations.PushLast(decl);
01902     }
01903 
01904     node->Destroy(engine);
01905 
01906     if( r < 0 )
01907     {
01908         engine->ConfigError(r);
01909     }
01910 
01911     return 0;
01912 }
01913 
01914 int asCBuilder::RegisterScriptFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction)
01915 {
01916     // Find name
01917     bool isConstructor = false;
01918     bool isDestructor = false;
01919     asCScriptNode *n = 0;
01920     if( node->firstChild->nodeType == snDataType )
01921         n = node->firstChild->next->next;
01922     else
01923     {
01924         // If the first node is a ~ token, then we know it is a destructor
01925         if( node->firstChild->tokenType == ttBitNot )
01926         {
01927             n = node->firstChild->next;
01928             isDestructor = true;
01929         }
01930         else
01931         {
01932             n = node->firstChild;
01933             isConstructor = true;
01934         }
01935     }
01936 
01937     // Check for name conflicts
01938     asCString name(&file->code[n->tokenPos], n->tokenLength);
01939     if( !isConstructor && !isDestructor )
01940     {
01941         asCDataType dt = asCDataType::CreateObject(objType, false);
01942         if( objType )
01943             CheckNameConflictMember(dt, name.AddressOf(), n, file);
01944         else
01945             CheckNameConflict(name.AddressOf(), n, file);
01946     }
01947     else
01948     {
01949         // Verify that the name of the constructor/destructor is the same as the class
01950         if( name != objType->name )
01951         {
01952             int r, c;
01953             file->ConvertPosToRowCol(n->tokenPos, &r, &c);
01954             WriteError(file->name.AddressOf(), TXT_CONSTRUCTOR_NAME_ERROR, r, c);
01955         }
01956 
01957         if( isDestructor )
01958             name = "~" + name;
01959     }
01960 
01961     if( !isInterface )
01962     {
01963         sFunctionDescription *func = asNEW(sFunctionDescription);
01964         functions.PushLast(func);
01965 
01966         func->script  = file;
01967         func->node    = node;
01968         func->name    = name;
01969         func->objType = objType;
01970         func->funcId  = funcID;
01971     }
01972 
01973     // Initialize a script function object for registration
01974     asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false);
01975     if( !isConstructor && !isDestructor )
01976     {
01977         returnType = CreateDataTypeFromNode(node->firstChild, file);
01978         returnType = ModifyDataTypeFromNode(returnType, node->firstChild->next, file, 0, 0);
01979     }
01980 
01981     // Is this a const method?
01982     bool isConstMethod = false;
01983     if( objType && n->next->next && n->next->next->tokenType == ttConst )
01984         isConstMethod = true;
01985 
01986     // Count the number of parameters
01987     int count = 0;
01988     asCScriptNode *c = n->next->firstChild;
01989     while( c )
01990     {
01991         count++;
01992         c = c->next->next;
01993         if( c && c->nodeType == snIdentifier )
01994             c = c->next;
01995     }
01996 
01997     // Destructors may not have any parameters
01998     if( isDestructor && count > 0 )
01999     {
02000         int r, c;
02001         file->ConvertPosToRowCol(node->tokenPos, &r, &c);
02002 
02003         WriteError(file->name.AddressOf(), TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, r, c);
02004     }
02005 
02006     asCArray<asCDataType> parameterTypes(count);
02007     asCArray<asETypeModifiers> inOutFlags(count);
02008     n = n->next->firstChild;
02009     while( n )
02010     {
02011         asETypeModifiers inOutFlag;
02012         asCDataType type = CreateDataTypeFromNode(n, file);
02013         type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
02014 
02015         // Store the parameter type
02016         parameterTypes.PushLast(type);
02017         inOutFlags.PushLast(inOutFlag);
02018 
02019         // Move to next parameter
02020         n = n->next->next;
02021         if( n && n->nodeType == snIdentifier )
02022             n = n->next;
02023     }
02024 
02025     // TODO: Much of this can probably be reduced by using the IsSignatureEqual method
02026     // Check that the same function hasn't been registered already
02027     asCArray<int> funcs;
02028     GetFunctionDescriptions(name.AddressOf(), funcs);
02029     if( funcs.GetLength() )
02030     {
02031         for( asUINT n = 0; n < funcs.GetLength(); ++n )
02032         {
02033             asCScriptFunction *func = GetFunctionDescription(funcs[n]);
02034 
02035             if( parameterTypes.GetLength() == func->parameterTypes.GetLength() )
02036             {
02037                 bool match = true;
02038                 if( func->objectType != objType )
02039                 {
02040                     match = false;
02041                     break;
02042                 }
02043 
02044                 for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
02045                 {
02046                     if( parameterTypes[p] != func->parameterTypes[p] )
02047                     {
02048                         match = false;
02049                         break;
02050                     }
02051                 }
02052 
02053                 if( match )
02054                 {
02055                     int r, c;
02056                     file->ConvertPosToRowCol(node->tokenPos, &r, &c);
02057 
02058                     WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
02059                     break;
02060                 }
02061             }
02062         }
02063     }
02064 
02065     // Register the function
02066     module->AddScriptFunction(file->idx, funcID, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), isInterface, objType, isConstMethod, isGlobalFunction);
02067 
02068     if( objType )
02069     {
02070         if( isConstructor )
02071         {
02072             if( parameterTypes.GetLength() == 0 )
02073             {
02074                 // Overload the default constructor
02075                 objType->beh.construct = funcID;
02076                 objType->beh.constructors[0] = funcID;
02077 
02078                 // Register the default factory as well
02079                 objType->beh.factory = engine->GetNextScriptFunctionId();
02080                 objType->beh.factories[0] = objType->beh.factory;
02081 
02082                 asCDataType dt = asCDataType::CreateObjectHandle(objType, false);
02083                 module->AddScriptFunction(file->idx, objType->beh.factory, name.AddressOf(), dt, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
02084 
02085                 // Add a dummy function to the module so that it doesn't mix up the func Ids
02086                 functions.PushLast(0);
02087 
02088                 // Compile the factory immediately
02089                 asCCompiler compiler(engine);
02090                 compiler.CompileFactory(this, file, engine->scriptFunctions[objType->beh.factory]);
02091             }
02092             else
02093             {
02094                 objType->beh.constructors.PushLast(funcID);
02095 
02096                 // TODO: This is almost identical to above if block. Should be reduced to common code.
02097                 // Register the factory as well
02098                 int factoryId = engine->GetNextScriptFunctionId();
02099                 objType->beh.factories.PushLast(factoryId);
02100 
02101                 asCDataType dt = asCDataType::CreateObjectHandle(objType, false);
02102                 module->AddScriptFunction(file->idx, factoryId, name.AddressOf(), dt, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
02103 
02104                 // Add a dummy function to the module so that it doesn't mix up the fund Ids
02105                 functions.PushLast(0);
02106 
02107                 // Compile the factory immediately
02108                 asCCompiler compiler(engine);
02109                 compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]);
02110             }
02111         }
02112         else if( isDestructor )
02113             objType->beh.destruct = funcID;
02114         else
02115             objType->methods.PushLast(funcID);
02116     }
02117 
02118     // We need to delete the node already if this is an interface method
02119     if( isInterface && node )
02120     {
02121         node->Destroy(engine);
02122     }
02123 
02124     return 0;
02125 }
02126 
02127 int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCScriptCode *file)
02128 {
02129     // Find name
02130     asCScriptNode *f = node->firstChild;
02131     asCScriptNode *n = f->firstChild->next->next;
02132 
02133     // Check for name conflicts
02134     asCString name(&file->code[n->tokenPos], n->tokenLength);
02135     CheckNameConflict(name.AddressOf(), n, file);
02136 
02137     // Initialize a script function object for registration
02138     asCDataType returnType;
02139     returnType = CreateDataTypeFromNode(f->firstChild, file);
02140     returnType = ModifyDataTypeFromNode(returnType, f->firstChild->next, file, 0, 0);
02141 
02142     // Count the parameters
02143     int count = 0;
02144     asCScriptNode *c = n->next->firstChild;
02145     while( c )
02146     {
02147         count++;
02148         c = c->next->next;
02149         if( c && c->nodeType == snIdentifier )
02150             c = c->next;
02151     }
02152 
02153     asCArray<asCDataType> parameterTypes(count);
02154     asCArray<asETypeModifiers> inOutFlags(count);
02155     n = n->next->firstChild;
02156     while( n )
02157     {
02158         asETypeModifiers inOutFlag;
02159         asCDataType type = CreateDataTypeFromNode(n, file);
02160         type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
02161 
02162         // Store the parameter type
02163         n = n->next->next;
02164         parameterTypes.PushLast(type);
02165         inOutFlags.PushLast(inOutFlag);
02166 
02167         // Move to next parameter
02168         if( n && n->nodeType == snIdentifier )
02169             n = n->next;
02170     }
02171 
02172     // Check that the same function hasn't been registered already
02173     asCArray<int> funcs;
02174     GetFunctionDescriptions(name.AddressOf(), funcs);
02175     if( funcs.GetLength() )
02176     {
02177         for( asUINT n = 0; n < funcs.GetLength(); ++n )
02178         {
02179             asCScriptFunction *func = GetFunctionDescription(funcs[n]);
02180 
02181             // TODO: Isn't the name guaranteed to be equal, because of GetFunctionDescriptions()?
02182             if( name == func->name &&
02183                 parameterTypes.GetLength() == func->parameterTypes.GetLength() )
02184             {
02185                 bool match = true;
02186                 for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
02187                 {
02188                     if( parameterTypes[p] != func->parameterTypes[p] )
02189                     {
02190                         match = false;
02191                         break;
02192                     }
02193                 }
02194 
02195                 if( match )
02196                 {
02197                     int r, c;
02198                     file->ConvertPosToRowCol(node->tokenPos, &r, &c);
02199 
02200                     WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
02201                     break;
02202                 }
02203             }
02204         }
02205     }
02206 
02207     // Read the module name as well
02208     n = node->firstChild->next;
02209     asCString moduleName;
02210     moduleName.Assign(&file->code[n->tokenPos+1], n->tokenLength-2);
02211 
02212     node->Destroy(engine);
02213 
02214     // Register the function
02215     module->AddImportedFunction(importID, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), moduleName);
02216 
02217     return 0;
02218 }
02219 
02220 
02221 asCScriptFunction *asCBuilder::GetFunctionDescription(int id)
02222 {
02223     // TODO: This should be improved
02224     // Get the description from the engine
02225     if( (id & 0xFFFF0000) == 0 )
02226         return engine->scriptFunctions[id];
02227     else
02228         return module->importedFunctions[id & 0xFFFF];
02229 }
02230 
02231 void asCBuilder::GetFunctionDescriptions(const char *name, asCArray<int> &funcs)
02232 {
02233     asUINT n;
02234     // TODO: optimize: Improve linear search
02235     for( n = 0; n < module->scriptFunctions.GetLength(); n++ )
02236     {
02237         if( module->scriptFunctions[n]->name == name &&
02238             module->scriptFunctions[n]->objectType == 0 )
02239             funcs.PushLast(module->scriptFunctions[n]->id);
02240     }
02241 
02242     // TODO: optimize: Improve linear search
02243     for( n = 0; n < module->importedFunctions.GetLength(); n++ )
02244     {
02245         if( module->importedFunctions[n]->name == name )
02246             funcs.PushLast(module->importedFunctions[n]->id);
02247     }
02248 
02249     // TODO: optimize: Improve linear search
02250     for( n = 0; n < engine->scriptFunctions.GetLength(); n++ )
02251     {
02252         if( engine->scriptFunctions[n] &&
02253             engine->scriptFunctions[n]->funcType == asFUNC_SYSTEM &&
02254             engine->scriptFunctions[n]->objectType == 0 &&
02255             engine->scriptFunctions[n]->name == name )
02256         {
02257             // Find the config group for the global function
02258             asCConfigGroup *group = engine->FindConfigGroupForFunction(engine->scriptFunctions[n]->id);
02259             if( !group || group->HasModuleAccess(module->name.AddressOf()) )
02260                 funcs.PushLast(engine->scriptFunctions[n]->id);
02261         }
02262     }
02263 }
02264 
02265 void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope)
02266 {
02267     if( scope != "" )
02268     {
02269         // Find the base class with the specified scope
02270         while( objectType && objectType->name != scope )
02271             objectType = objectType->derivedFrom;
02272 
02273         // If the scope is not any of the base classes, then return no methods
02274         if( objectType == 0 )
02275             return;
02276     }
02277 
02278     // TODO: optimize: Improve linear search
02279     if( objIsConst )
02280     {
02281         // Only add const methods to the list
02282         for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
02283         {
02284             if( engine->scriptFunctions[objectType->methods[n]]->name == name &&
02285                 engine->scriptFunctions[objectType->methods[n]]->isReadOnly )
02286             {
02287                 // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
02288                 if( scope == "" )
02289                     methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
02290                 else
02291                 {
02292                     asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
02293                     asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
02294                     methods.PushLast(realFunc->id);
02295                 }
02296             }
02297         }
02298     }
02299     else
02300     {
02301         // TODO: Prefer non-const over const
02302         for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
02303         {
02304             if( engine->scriptFunctions[objectType->methods[n]]->name == name )
02305             {
02306                 // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
02307                 if( scope == "" )
02308                     methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
02309                 else
02310                 {
02311                     asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
02312                     asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
02313                     methods.PushLast(realFunc->id);
02314                 }
02315             }
02316         }
02317     }
02318 }
02319 
02320 void asCBuilder::WriteInfo(const char *scriptname, const char *message, int r, int c, bool pre)
02321 {
02322     // Need to store the pre message in a structure
02323     if( pre )
02324     {
02325         preMessage.isSet = true;
02326         preMessage.c = c;
02327         preMessage.r = r;
02328         preMessage.message = message;
02329     }
02330     else
02331     {
02332         preMessage.isSet = false;
02333         engine->WriteMessage(scriptname, r, c, asMSGTYPE_INFORMATION, message);
02334     }
02335 }
02336 
02337 void asCBuilder::WriteError(const char *scriptname, const char *message, int r, int c)
02338 {
02339     numErrors++;
02340 
02341     // Need to pass the preMessage first
02342     if( preMessage.isSet )
02343         WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
02344 
02345     engine->WriteMessage(scriptname, r, c, asMSGTYPE_ERROR, message);
02346 }
02347 
02348 void asCBuilder::WriteWarning(const char *scriptname, const char *message, int r, int c)
02349 {
02350     numWarnings++;
02351 
02352     // Need to pass the preMessage first
02353     if( preMessage.isSet )
02354         WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
02355 
02356     engine->WriteMessage(scriptname, r, c, asMSGTYPE_WARNING, message);
02357 }
02358 
02359 
02360 asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, bool acceptHandleForScope, asCObjectType *templateType)
02361 {
02362     asASSERT(node->nodeType == snDataType);
02363 
02364     asCDataType dt;
02365 
02366     asCScriptNode *n = node->firstChild;
02367 
02368     bool isConst = false;
02369     bool isImplicitHandle = false;
02370     if( n->tokenType == ttConst )
02371     {
02372         isConst = true;
02373         n = n->next;
02374     }
02375 
02376     if( n->tokenType == ttIdentifier )
02377     {
02378         asCString str;
02379         str.Assign(&file->code[n->tokenPos], n->tokenLength);
02380 
02381         asCObjectType *ot = 0;
02382 
02383         // If this is for a template type, then we must first determine if the 
02384         // identifier matches any of the template subtypes
02385         // TODO: template: it should be possible to have more than one subtypes
02386         if( templateType && (templateType->flags & asOBJ_TEMPLATE) && str == templateType->templateSubType.GetObjectType()->name )
02387             ot = templateType->templateSubType.GetObjectType();
02388 
02389         if( ot == 0 )
02390             ot = GetObjectType(str.AddressOf());
02391 
02392         if( ot == 0 )
02393         {
02394             asCString msg;
02395             msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, (const char *)str.AddressOf());
02396 
02397             int r, c;
02398             file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02399 
02400             WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
02401 
02402             dt.SetTokenType(ttInt);
02403         }
02404         else
02405         {
02406             if( ot->flags & asOBJ_IMPLICIT_HANDLE )
02407                 isImplicitHandle = true;
02408 
02409             // Find the config group for the object type
02410             asCConfigGroup *group = engine->FindConfigGroupForObjectType(ot);
02411             if( !module || !group || group->HasModuleAccess(module->name.AddressOf()) )
02412             {
02413                 if(asOBJ_TYPEDEF == (ot->flags & asOBJ_TYPEDEF))
02414                 {
02415                     // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two)
02416                     // Create primitive data type based on object flags
02417                     dt = ot->templateSubType;
02418                     dt.MakeReadOnly(isConst);
02419                 }
02420                 else
02421                 {
02422                     if( ot->flags & asOBJ_TEMPLATE )
02423                     {
02424                         n = n->next;
02425                         
02426                         // Check if the subtype is a type or the template's subtype
02427                         // if it is the template's subtype then this is the actual template type,
02428                         // orderwise it is a template instance.
02429                         asCDataType subType = CreateDataTypeFromNode(n, file, false, ot);
02430                         if( subType.GetObjectType() != ot->templateSubType.GetObjectType() )
02431                         {
02432                             // This is a template instance
02433                             // Need to find the correct object type
02434                             asCObjectType *otInstance = engine->GetTemplateInstanceType(ot, subType);
02435 
02436                             if( !otInstance )
02437                             {
02438                                 asCString msg;
02439                                 msg.Format(TXT_CANNOT_INSTANCIATE_TEMPLATE_s_WITH_s, ot->name.AddressOf(), subType.Format().AddressOf());
02440                                 int r, c;
02441                                 file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02442                                 WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
02443                             }
02444 
02445                             ot = otInstance;
02446                         }
02447                     }
02448 
02449                     // Create object data type
02450                     if( ot )
02451                         dt = asCDataType::CreateObject(ot, isConst);
02452                     else
02453                         dt = asCDataType::CreatePrimitive(ttInt, isConst);
02454                 }
02455             }
02456             else
02457             {
02458                 asCString msg;
02459                 msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf());
02460 
02461                 int r, c;
02462                 file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02463 
02464                 WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
02465 
02466                 dt.SetTokenType(ttInt);
02467             }
02468         }
02469     }
02470     else
02471     {
02472         // Create primitive data type
02473         dt = asCDataType::CreatePrimitive(n->tokenType, isConst);
02474     }
02475 
02476     // Determine array dimensions and object handles
02477     n = n->next;
02478     while( n && (n->tokenType == ttOpenBracket || n->tokenType == ttHandle) )
02479     {
02480         if( n->tokenType == ttOpenBracket )
02481         {
02482             // Make sure the sub type can be instanciated
02483             if( !dt.CanBeInstanciated() )
02484             {
02485                 int r, c;
02486                 file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02487 
02488                 asCString str;
02489                 // TODO: Change to "Array sub type cannot be 'type'"
02490                 str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
02491 
02492                 WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
02493             }
02494 
02495             // Make the type an array (or multidimensional array)
02496             if( dt.MakeArray(engine) < 0 )
02497             {
02498                 int r, c;
02499                 file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02500                 WriteError(file->name.AddressOf(), TXT_TOO_MANY_ARRAY_DIMENSIONS, r, c);
02501                 break;
02502             }
02503         }
02504         else
02505         {
02506             // Make the type a handle
02507             if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
02508             {
02509                 int r, c;
02510                 file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02511                 WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
02512                 break;
02513             }
02514         }
02515         n = n->next;
02516     }
02517 
02518     if( isImplicitHandle )
02519     {
02520         // Make the type a handle
02521         if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
02522         {
02523             int r, c;
02524             file->ConvertPosToRowCol(n->tokenPos, &r, &c);
02525             WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
02526         }
02527     }
02528 
02529     return dt;
02530 }
02531 
02532 asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle)
02533 {
02534     asCDataType dt = type;
02535 
02536     if( inOutFlags ) *inOutFlags = asTM_NONE;
02537 
02538     // Is the argument sent by reference?
02539     asCScriptNode *n = node->firstChild;
02540     if( n && n->tokenType == ttAmp )
02541     {
02542         dt.MakeReference(true);
02543         n = n->next;
02544 
02545         if( n )
02546         {
02547             if( inOutFlags )
02548             {
02549                 if( n->tokenType == ttIn )
02550                     *inOutFlags = asTM_INREF;
02551                 else if( n->tokenType == ttOut )
02552                     *inOutFlags = asTM_OUTREF;
02553                 else if( n->tokenType == ttInOut )
02554                     *inOutFlags = asTM_INOUTREF;
02555                 else
02556                     asASSERT(false);
02557             }
02558 
02559             n = n->next;
02560         }
02561         else
02562         {
02563             if( inOutFlags )
02564                 *inOutFlags = asTM_INOUTREF; // ttInOut
02565         }
02566 
02567         if( !engine->ep.allowUnsafeReferences &&
02568             inOutFlags && *inOutFlags == asTM_INOUTREF )
02569         {
02570             // Verify that the base type support &inout parameter types
02571             if( !dt.IsObject() || dt.IsObjectHandle() || !dt.GetObjectType()->beh.addref || !dt.GetObjectType()->beh.release )
02572             {
02573                 int r, c;
02574                 file->ConvertPosToRowCol(node->firstChild->tokenPos, &r, &c);
02575                 WriteError(file->name.AddressOf(), TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, r, c);
02576             }
02577         }
02578     }
02579 
02580     if( autoHandle ) *autoHandle = false;
02581 
02582     if( n && n->tokenType == ttPlus )
02583     {
02584         if( autoHandle ) *autoHandle = true;
02585     }
02586 
02587     return dt;
02588 }
02589 
02590 const asCString &asCBuilder::GetConstantString(int strID)
02591 {
02592     return module->GetConstantString(strID);
02593 }
02594 
02595 asCObjectType *asCBuilder::GetObjectType(const char *type)
02596 {
02597     // TODO: Only search in config groups to which the module has access
02598     asCObjectType *ot = engine->GetObjectType(type);
02599     if( !ot && module )
02600         ot = module->GetObjectType(type);
02601 
02602     return ot;
02603 }
02604 
02605 int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue)
02606 {
02607     if( !objType || !(objType->flags & asOBJ_ENUM) )
02608         return 0;
02609 
02610     for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n )
02611     {
02612         if( objType->enumValues[n]->name == name )
02613         {
02614             outDt = asCDataType::CreateObject(objType, true);
02615             outValue = objType->enumValues[n]->value;
02616             return 1;
02617         }
02618     }
02619 
02620     return 0;
02621 }
02622 
02623 int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue)
02624 {
02625     bool found = false;
02626 
02627     // Search all available enum types
02628     asUINT t;
02629     for( t = 0; t < engine->objectTypes.GetLength(); t++ )
02630     {
02631         asCObjectType *ot = engine->objectTypes[t];
02632         if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
02633         {
02634             if( !found )
02635             {
02636                 found = true;
02637             }
02638             else
02639             {
02640                 // Found more than one value in different enum types
02641                 return 2;
02642             }
02643         }
02644     }
02645 
02646     for( t = 0; t < module->enumTypes.GetLength(); t++ )
02647     {
02648         asCObjectType *ot = module->enumTypes[t];
02649         if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
02650         {
02651             if( !found )
02652             {
02653                 found = true;
02654             }
02655             else
02656             {
02657                 // Found more than one value in different enum types
02658                 return 2;
02659             }
02660         }
02661     }
02662 
02663     if( found )
02664         return 1;
02665 
02666     // Didn't find any value
02667     return 0;
02668 }
02669 
02670 END_AS_NAMESPACE

Generated on Mon Jan 11 12:03:40 2010 for Werewolf by  doxygen 1.6.1