| 3017 | } |
| 3018 | |
| 3019 | void FunctionPrototype(const char* pos) |
| 3020 | { |
| 3021 | FunctionInfo &lastFunc = *currDefinedFunc.back(); |
| 3022 | // Remove function arguments used to enable typeof |
| 3023 | for(VariableInfo *curr = lastFunc.firstParam; curr; curr = curr->next) |
| 3024 | varMap.remove(curr->nameHash, curr); |
| 3025 | if(!lastFunc.retType && !lastFunc.generic) |
| 3026 | ThrowError(pos, "ERROR: function prototype with unresolved return type"); |
| 3027 | lastFunc.funcType = CodeInfo::GetFunctionType(lastFunc.retType, lastFunc.firstParam, lastFunc.paramCount); |
| 3028 | currDefinedFunc.pop_back(); |
| 3029 | if(newType && lastFunc.type == FunctionInfo::THISCALL) |
| 3030 | methodCount++; |
| 3031 | if(lastFunc.generic) |
| 3032 | { |
| 3033 | CodeInfo::nodeList.push_back(new NodeFunctionProxy(&lastFunc, pos, true)); |
| 3034 | AddOneExpressionNode(typeVoid); |
| 3035 | lastFunc.afterNode = (NodeExpressionList*)CodeInfo::nodeList.back(); |
| 3036 | }else if(lastFunc.type == FunctionInfo::LOCAL || lastFunc.type == FunctionInfo::COROUTINE){ |
| 3037 | // For a local or a coroutine function prototype, we must create a forward declaration of a context variable |
| 3038 | // When a function will be implemented, it will fill up the closure type with members, update this context variable and create closure initialization |
| 3039 | char *hiddenHame = AllocateString(lastFunc.nameLength + 24); |
| 3040 | int length = sprintf(hiddenHame, "$%s_%d_ext", lastFunc.name, lastFunc.indexInArr); |
| 3041 | unsigned beginPos = lastFunc.parentFunc ? lastFunc.parentFunc->allParamSize + NULLC_PTR_SIZE : 0; // so that a coroutine will not mistake this for argument, choose starting position carefully |
| 3042 | lastFunc.funcContext = new VariableInfo(lastFunc.parentFunc, InplaceStr(hiddenHame, length), GetStringHash(hiddenHame), beginPos, CodeInfo::GetReferenceType(typeInt), !lastFunc.parentFunc); |
| 3043 | lastFunc.funcContext->blockDepth = varInfoTop.size(); |
| 3044 | // Allocate node where the context initialization will be placed |
| 3045 | CodeInfo::nodeList.push_back(new NodeZeroOP()); |
| 3046 | AddOneExpressionNode(typeVoid); |
| 3047 | lastFunc.afterNode = (NodeExpressionList*)CodeInfo::nodeList.back(); |
| 3048 | // Context variable should be visible |
| 3049 | varMap.insert(lastFunc.funcContext->nameHash, lastFunc.funcContext); |
| 3050 | }else{ |
| 3051 | AddVoidNode(); |
| 3052 | } |
| 3053 | // Check if this function was already defined |
| 3054 | HashMap<FunctionInfo*>::Node *curr = funcMap.first(lastFunc.nameHash); |
| 3055 | while(curr) |
| 3056 | { |
| 3057 | FunctionInfo *func = curr->value; |
| 3058 | if(func->visible && func->funcType == lastFunc.funcType && func != &lastFunc) |
| 3059 | ThrowError(pos, "ERROR: function is already defined"); |
| 3060 | curr = funcMap.next(curr); |
| 3061 | } |
| 3062 | // Remove aliases defined in a prototype argument list |
| 3063 | AliasInfo *info = lastFunc.childAlias; |
| 3064 | while(info) |
| 3065 | { |
| 3066 | CodeInfo::classMap.remove(info->nameHash, info->type); |
| 3067 | info = info->next; |
| 3068 | } |
| 3069 | } |
| 3070 | |
| 3071 | void FunctionStart(const char* pos) |
| 3072 | { |
no test coverage detected