Example #1
0
bool TypeAnalyzer::isException(Type* type) {
	Type* exception = MakeType(TYPE_CLASS);
	exception->typedata._class.classname = strdup("Exception");
	bool ret = isASubtypeOfB(type, exception);
	freeType(exception);
	return ret;
}
bool TypeAnalyzer::isException(PureType<wake::QUALIFIED>* type) {
	PureType<wake::QUALIFIED> exception(TYPE_CLASS);
	exception.typedata._class.modulename = strdup("lang");
	exception.typedata._class.classname = strdup("Exception");
	bool ret = isASubtypeOfB(type, &exception);
	return ret;
}
Example #3
0
bool TypeAnalyzer::isASubtypeOfB(string a, string b) {
	try {
		if(a == b) return true;

		ReadOnlyPropertySymbolTable* a_data = reference->find(a);

		for(map<string, bool>::const_iterator it = a_data->getParentage().begin(); it != a_data->getParentage().end(); ++it) {
			if(isASubtypeOfB(it->first, b)) return true;
		}

	} catch(SymbolNotFoundException* e) {
		delete e;
	}

	return false;
}
bool TypeAnalyzer::isASubtypeOfB(string a, string b) {
	try {
		if(a == b) return true;

		ReadOnlyPropertySymbolTable* a_data = reference->findFullyQualified(a);

		for(map<string, bool>::const_iterator it = a_data->getParentage().begin(); it != a_data->getParentage().end(); ++it) {
			PropertySymbolTable* a_child_data = reference->findFullyQualifiedModifiable(it->first);
			if(isASubtypeOfB(a_child_data->getAsPureType()->getFQClassname(), b)) return true;
		}

	} catch(SymbolNotFoundException* e) {
		delete e;
	}

	return false;
}
bool TypeAnalyzer::isASubtypeOfB(PureType<wake::QUALIFIED>* a, PureType<wake::QUALIFIED>* b) {
	//if(a == NULL || b == NULL) return false;
	if(a->type == TYPE_MATCHALL || b->type == TYPE_MATCHALL) return true;
	if(a->type != b->type) {
		if(b->type == TYPE_OPTIONAL) {
			return isASubtypeOfB(a, b->typedata.optional.contained);
		}
		 // TODO: parameterized types need logic here
		return false;
	}

	if(a->type == TYPE_LAMBDA) {

		// if one or the other is a null pointer, or has no args, and the other one has arguments.
		if((a->typedata.lambda.arguments == NULL || !a->typedata.lambda.arguments->typecount) != (b->typedata.lambda.arguments == NULL || !b->typedata.lambda.arguments->typecount))
			return false;

		// Bool -- fn() is a subtype of void -- fn(), since the subtype will simply ignore the returnval
		// however, void --fn() is not a subtype of Bool -- fn() as you probably guessed
		if(a->typedata.lambda.returntype == NULL && b->typedata.lambda.returntype != NULL)
			return false;
		else if(b->typedata.lambda.returntype != NULL && !isASubtypeOfB(a->typedata.lambda.returntype, b->typedata.lambda.returntype)) // ChildClass -- fn() is a subtype of ParentClass -- fn()
			return false;

		if(a->typedata.lambda.arguments != NULL && a->typedata.lambda.arguments->typecount) {
			// A fn taking 3 arguments is not a subtype of a fn taking 2 or 4
			if(a->typedata.lambda.arguments->typecount != b->typedata.lambda.arguments->typecount)
				return false;

			int i;
			for(i = 0; i < a->typedata.lambda.arguments->typecount; i++)
			if(!isASubtypeOfB(b->typedata.lambda.arguments->types[i], a->typedata.lambda.arguments->types[i])) // fn(ParentClass) is a subtype of fn(ChildClass), but not vice versa! (contravariance)
				return false;
		}

		return true;

	} else if(a->type == TYPE_CLASS) {
		// check if one pointer exists and the other is null: !ptr == 0 and !NULL == 1
		if(!a->typedata._class.parameters != !b->typedata._class.parameters) {
			return false;
		}

		if(a->typedata._class.parameters) { // Here if A is not null, neither is B
			int len = a->typedata._class.parameters->typecount;
			if(b->typedata._class.parameters->typecount != len) {
				return false;
			}

			for(int i = 0; i < len; i++)
			if(!isAExactlyB(a->typedata._class.parameters->types[i], b->typedata._class.parameters->types[i]))
				return false;
		}

		if(a->getFQClassname() == b->getFQClassname()) {
			return true;
		}

		try {
			if(isASubtypeOfB(a->getFQClassname(), b->getFQClassname())) return true;
		} catch(SymbolNotFoundException* e) {
			delete e;
		}

		// special case...
		if(isPrimitiveTypeInt(a) && isPrimitiveTypeNum(b)) {
			return true;
		}

		return false;
	} else if(a->type == TYPE_PARAMETERIZED || a->type == TYPE_PARAMETERIZED_ARG) {
		if(a->typedata.parameterized.label == string(b->typedata.parameterized.label)) return true;
		// TODO: lower/upper bounds comparison
		return false;
	} else if(a->type == TYPE_LIST) {
		return isAExactlyB(a->typedata.list.contained, b->typedata.list.contained);
	} else if(a->type == TYPE_OPTIONAL) {
		return isASubtypeOfB(a->typedata.optional.contained, b->typedata.optional.contained);
	}

}
boost::optional<PureType<wake::QUALIFIED>*> TypeAnalyzer::getCommonSubtypeOf(PureType<wake::QUALIFIED>* a, PureType<wake::QUALIFIED>* b) {
	if(a->type == TYPE_UNUSABLE || b->type == TYPE_UNUSABLE) return boost::optional<PureType<wake::QUALIFIED>*>(); // this maybe should return TYPE_UNUSABLE...but unusable types aren't necessarily similar at all
	if(a->type == TYPE_MATCHALL) return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*b));
	if(b->type == TYPE_MATCHALL) return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*a));

	if(a->type == TYPE_OPTIONAL || b->type == TYPE_OPTIONAL) {
		PureType<wake::QUALIFIED>* optional = a->type == TYPE_OPTIONAL ? a : b;
		PureType<wake::QUALIFIED>* other = a == optional ? b : a;
		if(other->type == TYPE_OPTIONAL) other = other->typedata.optional.contained;

		// [nothing, Text?] is common to type Text?
		// [X, Y?] is common to type Z? where Z is the common type to [X, Y]
		boost::optional<PureType<wake::QUALIFIED>*> nonoptcommon = getCommonSubtypeOf(optional->typedata.optional.contained, other);

		if(!nonoptcommon) {
			return nonoptcommon;
		}

		PureType<wake::QUALIFIED>* common = new PureType<wake::QUALIFIED>(TYPE_OPTIONAL);

		// [Text?, Text] becomes Text?
		common->typedata.optional.contained = *nonoptcommon;
		return boost::optional<PureType<wake::QUALIFIED>*>(common);
	}

	if(a->type != b->type) return boost::optional<PureType<wake::QUALIFIED>*>();

	if(a->type == TYPE_LIST) {
		// [Text[], Num[]] and [Printer[], DisabledPrinter[]] are both common to nothing
		if(!isAExactlyB(a, b)) return boost::optional<PureType<wake::QUALIFIED>*>();
		// but [Text[], Text[]] is common to Text[]
		return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*a));

	} else if(a->type == TYPE_CLASS) {
		// check if one pointer exists and the other is null: !ptr == 0 and !NULL == 1
		if(!a->typedata._class.parameters != !b->typedata._class.parameters) {
			return boost::optional<PureType<wake::QUALIFIED>*>();
		}

		if(a->typedata._class.parameters) { // Here if A is not null, neither is B
			int len = a->typedata._class.parameters->typecount;
			if(b->typedata._class.parameters->typecount != len) {
				return boost::optional<PureType<wake::QUALIFIED>*>();
			}

			for(int i = 0; i < len; i++)
			if(!isAExactlyB(a->typedata._class.parameters->types[i], b->typedata._class.parameters->types[i]))
				return boost::optional<PureType<wake::QUALIFIED>*>();
		}

		if(isASubtypeOfB(a, b)) return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*b));

		if(isASubtypeOfB(b, a)) return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*a));

		boost::optional<pair<int, string> > common = getCommonFQClassnamesWithDepth(a->getFQClassname(), b->getFQClassname(), 0);
		if(!common || common->second == "") {
			return boost::optional<PureType<wake::QUALIFIED>*>();
		} else {
			PureType<wake::QUALIFIED>* classType = new PureType<wake::QUALIFIED>(TYPE_CLASS);
			classType->typedata._class.classname = strdup(common->second.c_str());
			return boost::optional<PureType<wake::QUALIFIED>*>(classType);
		}
	} else if(a->type == TYPE_PARAMETERIZED || a->type == TYPE_PARAMETERIZED_ARG) {
		if(a->typedata.parameterized.label == string(b->typedata.parameterized.label)) return boost::optional<PureType<wake::QUALIFIED>*>(new PureType<wake::QUALIFIED>(*a));
		// TODO: lower/upper bounds comparison
		return boost::optional<PureType<wake::QUALIFIED>*>();
	}

	if(a->type == TYPE_LAMBDA) {

		// if one or the other is a null, and the other one has arguments
		if((a->typedata.lambda.arguments == NULL || !a->typedata.lambda.arguments->typecount) != (b->typedata.lambda.arguments == NULL || !b->typedata.lambda.arguments->typecount))
			return boost::optional<PureType<wake::QUALIFIED>*>();

		if(a->typedata.lambda.arguments != NULL && a->typedata.lambda.arguments->typecount) {
			// A fn taking 3 arguments is not a subtype of a fn taking 2 or 4
			if(a->typedata.lambda.arguments->typecount != b->typedata.lambda.arguments->typecount)
				return boost::optional<PureType<wake::QUALIFIED>*>();

			int i;
			for(i = 0; i < a->typedata.lambda.arguments->typecount; i++)
			if(!isAExactlyB(a->typedata.lambda.arguments->types[i], b->typedata.lambda.arguments->types[i]))
				return boost::optional<PureType<wake::QUALIFIED>*>();
		}

		// Bool -- fn() is a subtype of void -- fn(), since the subtype will simply ignore the returnval
		// however, void --fn() is not a subtype of Bool -- fn() as you probably guessed
		if(a->typedata.lambda.returntype == NULL || b->typedata.lambda.returntype == NULL) {
			PureType<wake::QUALIFIED>* newlambda = new PureType<wake::QUALIFIED>(*a);

			if(newlambda->typedata.lambda.returntype) {
				delete newlambda->typedata.lambda.returntype;
			}

			newlambda->typedata.lambda.returntype = NULL;
			return boost::optional<PureType<wake::QUALIFIED>*>(newlambda);
		}


		boost::optional<PureType<wake::QUALIFIED>*> commonReturn = getCommonSubtypeOf(a->typedata.lambda.returntype, b->typedata.lambda.returntype);
		if(!commonReturn) {
			PureType<wake::QUALIFIED>* newlambda = new PureType<wake::QUALIFIED>(*a);
			delete newlambda->typedata.lambda.returntype;
			newlambda->typedata.lambda.returntype = NULL;
			return boost::optional<PureType<wake::QUALIFIED>*>(newlambda);
		}

		PureType<wake::QUALIFIED>* newlambda = new PureType<wake::QUALIFIED>(*a);
		delete newlambda->typedata.lambda.returntype;
		newlambda->typedata.lambda.returntype = *commonReturn;;
		return boost::optional<PureType<wake::QUALIFIED>*>(newlambda);

	}
}
Example #7
0
bool TypeAnalyzer::isASubtypeOfB(Type* a, Type* b) {
	//if(a == NULL || b == NULL) return false;
	if(a->type == TYPE_MATCHALL || b->type == TYPE_MATCHALL) return true;
	if(a->type == TYPE_NOTHING) return b->optional;
	if(a->arrayed != b->arrayed) return false;
	if(a->type != b->type) return false; // TODO: parameterized types don't always follow this logic!

	if(a->type == TYPE_LAMBDA) {

		// if one or the other is a pointer
		if((a->typedata.lambda.arguments == NULL) != (b->typedata.lambda.arguments == NULL))
			return false;

		// Bool -- fn() is a subtype of void -- fn(), since the subtype will simply ignore the returnval
		// however, void --fn() is not a subtype of Bool -- fn() as you probably guessed
		if(a->typedata.lambda.returntype == NULL && b->typedata.lambda.returntype != NULL)
			return false;
		else if(b->typedata.lambda.returntype != NULL && !isASubtypeOfB(a->typedata.lambda.returntype, b->typedata.lambda.returntype))
			return false;

		if(a->typedata.lambda.arguments != NULL) {
			// A fn taking 3 arguments is not a subtype of a fn taking 2 or 4
			if(a->typedata.lambda.arguments->typecount != b->typedata.lambda.arguments->typecount)
				return false;

			int i;
			for(i = 0; i < a->typedata.lambda.arguments->typecount; i++)
			if(!isASubtypeOfB(a->typedata.lambda.arguments->types[i], b->typedata.lambda.arguments->types[i]))
				return false;
		}

		return true;

	} else if(a->type == TYPE_CLASS) {
		// check if one pointer exists and the other is null: !ptr == 0 and !NULL == 1
		if(!a->typedata._class.parameters != !b->typedata._class.parameters) {
			return false;
		}

		if(a->typedata._class.parameters) { // Here if A is not null, neither is B
			int len = a->typedata._class.parameters->typecount;
			if(b->typedata._class.parameters->typecount != len) {
				return false;
			}

			for(int i = 0; i < len; i++)
			if(!isAExactlyB(a->typedata._class.parameters->types[i], b->typedata._class.parameters->types[i]))
				return false;
		}

		if(string(a->typedata._class.classname) == b->typedata._class.classname) {
			return a->optional <= b->optional;
		}

		try {

			ReadOnlyPropertySymbolTable* a_data = reference->find(a->typedata._class.classname);

			for(map<string, bool>::const_iterator it = a_data->getParentage().begin(); it != a_data->getParentage().end(); ++it) {
				if(isASubtypeOfB(it->first, b->typedata._class.classname)) return true;
			}

		} catch(SymbolNotFoundException* e) {
			delete e;
		}

		return false;
	} else if(a->type == TYPE_PARAMETERIZED) {
		if(a->typedata.parameterized.label == string(b->typedata.parameterized.label)) return true;
		// TODO: lower/upper bounds comparison
		return false;
	}

}