Exemplo n.º 1
0
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);
	}
}
Exemplo n.º 2
0
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;
	}
}
Exemplo n.º 3
0
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");
	}
}
Exemplo n.º 4
0
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;
}