llvm::Value* MemberAccess::getPointer(Context &context) { if (isStatic) { // find class Class *cls = targetClass->getClass(context); if (!cls) throw SymbolNotFound("No such class '" + targetClass->getName() + "'"); if (cls->getMangleName()[0] == 'J') throw InvalidType("'" + cls->getFullName() + "' is an interface"); // find symbol Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("No such static member '" + identifier->getName() + "' in class '" + cls->getFullName() + "'"); if (symbol->type != Symbol::STATIC_MEMBER_VAR) throw InvalidType("'" + identifier->getName() + "' in '" + targetClass->getName() + "' is not a static member variable"); // check permission if (symbol->data.identifier.isPrivate && cls != context.currentClass) throw CompileException("'" + identifier->getName() + "' is private"); if (symbol->data.identifier.isProtected && !Class::isA(context.currentClass, cls)) throw CompileException("'" + identifier->getName() + "' is protected"); return symbol->data.identifier.value; } else { // find class if (!target->getType(context)->isObject()) throw InvalidType(std::string("Access member of a ") + target->getType(context)->getName()); Class *cls = target->getType(context)->getClass(); // find symbol Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound(std::string("No such member variable in class ") + cls->getName()); if (symbol->type != Symbol::MEMBER_VAR) throw InvalidType("'" + identifier->getName() + "' in '" + targetClass->getName() + "' is not a member variable"); // check permission if (symbol->data.identifier.isPrivate && cls != context.currentClass) throw CompileException("'" + identifier->getName() + "' is private"); if (symbol->data.identifier.isProtected && !Class::isA(context.currentClass, cls)) throw CompileException("'" + identifier->getName() + "' is protected"); return addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, target->load(context), symbol->data.member.index), loc); } }
Type* MemberAccess::getType(Context &context) { if (isStatic) { Class *cls = targetClass->getClass(context); if (!cls) throw SymbolNotFound("No such class '" + targetClass->getName() + "'"); if (cls->getMangleName()[0] == 'J') throw InvalidType("'" + cls->getFullName() + "' is an interface"); Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("No such static member '" + identifier->getName() + "' in class '" + cls->getFullName() + "'"); return symbol->data.identifier.type; } else { if (!target->getType(context)->isObject()) throw InvalidType(std::string("Access member of a ") + target->getType(context)->getName()); Class *cls = target->getType(context)->getClass(); Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound(std::string("No such member variable in class ") + cls->getName()); return symbol->data.member.type; } }
Type* FunctionCall::getType(Context &context) { Symbol *symbol = NULL; if (target) symbol = target->getType(context)->getClass()->findSymbol(identifier->getName()); else if (identifier->getName().rfind("::") != std::string::npos) { Class *targetClass = context.findClass(identifier->getName().substr(0, identifier->getName().rfind("::"))); if (!targetClass) throw SymbolNotFound(identifier->getName().substr(0, identifier->getName().rfind("::"))); symbol = targetClass->findSymbol(identifier->getName().substr(identifier->getName().rfind("::") + 2)); } else symbol = context.currentClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound(identifier->getName()); switch (symbol->type) { case Symbol::STATIC_FUNCTION: return symbol->data.static_function.function->getReturnType(); case Symbol::FUNCTION: return symbol->data.function.function->getReturnType(); default: throw InvalidType("calling a symbol which is not a function"); } }
llvm::Value* FunctionCall::load(Context &context) { std::vector<Type*> actual_type; for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++) actual_type.push_back((*it)->getType(context)); Symbol *symbol = NULL; Class *targetClass = NULL; if (target == NULL) { // static call or self call if (identifier->getName().rfind("::") != std::string::npos) { // static call // find class targetClass = context.findClass(identifier->getName().substr(0, identifier->getName().rfind("::"))); if (!targetClass) throw SymbolNotFound("Class '" + identifier->getName().substr(0, identifier->getName().rfind("::")) + "'"); // find function symbol = targetClass->findSymbol(identifier->getName().substr(identifier->getName().rfind("::") + 2)); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); // match the best override symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is static function if (symbol->type != Symbol::STATIC_FUNCTION) throw InvalidType("'" + symbol->data.function.function->getName() + "' is not a static function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } else { // self call targetClass = context.currentClass; // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("'" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); } } else { // member function call targetClass = target->getType(context)->getClass(); // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is normal function if (symbol->type != Symbol::FUNCTION) throw InvalidType("function '" + symbol->data.static_function.function->getName() + "' is not a member function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } llvm::Value *function; std::vector<llvm::Value*> arg_code; switch (symbol->type) { case Symbol::FUNCTION: { Expression *tmpTarget = target ? target : new Identifier("this"); if (!tmpTarget->getType(context)->isObject()) throw InvalidType(std::string("calling a function of ") + tmpTarget->getType(context)->getName()); llvm::Value *thisval = tmpTarget->load(context); if (!target) delete tmpTarget; if (targetClass->getMangleName()[0] == 'J') { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( thisval ), loc ); // for interface call, we have to recalculate the object base address // load offset from vtable llvm::Value *baseOffset = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, 0 ), loc ) ), loc ); // calculate the base address thisval = addDebugLoc( context, context.getBuilder().CreateIntToPtr( addDebugLoc( context, context.getBuilder().CreateSub( addDebugLoc( context, context.getBuilder().CreatePtrToInt( thisval, context.getBuilder().getInt32Ty() ), loc ), baseOffset ), loc ), context.getBuilder().getInt8PtrTy(0) ), loc ); } else { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, thisval, symbol->data.function.vtableOffset ), loc ) ), loc ); // for object call, we only need type cast thisval = context.getBuilder().CreatePointerCast( thisval, context.getBuilder().getInt8PtrTy(0) ); } // add thisval as the first argument arg_code.push_back(thisval); // load function pointer from vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, symbol->data.function.funcPtrOffset ), loc ) ), loc ); break; } case Symbol::STATIC_FUNCTION: function = symbol->data.static_function.function->getLLVMFunction(context); if (target) throw CompileException("Calling a static function of an object"); break; default: throw InvalidType("calling a symbol which is not a function"); } // load remaining arguments { Function *func = symbol->type == Symbol::FUNCTION ? symbol->data.function.function : symbol->data.static_function.function; Function::arg_iterator it2 = func->arg_begin(); for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++, it2++) arg_code.push_back(Type::cast(context, (*it)->getType(context), (*it)->load(context), it2->first)); } // do the call llvm::Value *ans = addDebugLoc( context, context.getBuilder().CreateCall(function, llvm::ArrayRef<llvm::Value*>(arg_code)), loc); return ans; }