Пример #1
0
bool TypeAnalyzer::isAutoboxedType(Type* type, Type** boxed) {
	if(type->type == TYPE_MATCHALL) return false;

	// shouldn't be here...throw exception?
	if(type->type == TYPE_UNUSABLE) return false;

	// need to return a List<T>
	if(type->arrayed) {
		*boxed = MakeType(TYPE_CLASS);
		Type* loweredtype = copyType(type);
		loweredtype->arrayed--;
		(*boxed)->typedata._class.classname = strdup("List");
		(*boxed)->typedata._class.parameters = MakeTypeArray();
		AddTypeToTypeArray(loweredtype, (*boxed)->typedata._class.parameters);
		return true;
	}

	// need to return a generic autoboxed type according to arguments/return
	if(type->type == TYPE_LAMBDA) {
		*boxed = MakeType(TYPE_CLASS);
		(*boxed)->typedata._class.classname = strdup("lambda");
		return true;
	}

	// shouldn't ever get here,..unless I decide to make, say, T?.exists() and/or T?.applyIfExists(fn(T))
	if(type->optional) return false;

	if(isPrimitiveTypeBool(type)) {
		*boxed = MakeType(TYPE_CLASS);
		(*boxed)->typedata._class.classname = strdup("Bool");
		return true;
	}

	if(isPrimitiveTypeText(type)) {
		*boxed = MakeType(TYPE_CLASS);
		(*boxed)->typedata._class.classname = strdup("Text");
		return true;
	}

	if(isPrimitiveTypeNum(type)) {
		*boxed = MakeType(TYPE_CLASS);
		(*boxed)->typedata._class.classname = strdup("Num");
		return true;
	}

	return false;
}
bool TypeAnalyzer::isAutoboxedType(PureType<wake::QUALIFIED>* type, PureType<wake::QUALIFIED>** boxed) {
	if(type->type == TYPE_MATCHALL) return false;

	// shouldn't be here...throw exception?
	if(type->type == TYPE_UNUSABLE) return false;

	// need to return a List<T>
	if(type->type == TYPE_LIST) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		PureType<wake::QUALIFIED>* loweredtype = new PureType<wake::QUALIFIED>(*type->typedata.list.contained);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("List");
		(*boxed)->typedata._class.parameters = new PureTypeArray<wake::QUALIFIED>();

		// the template is just for static checks, we can safely cast these
		addPureTypeToPureTypeArray(
			(PureType<wake::UNQUALIFIED>*) loweredtype,
			(PureTypeArray<wake::UNQUALIFIED>*) (*boxed)->typedata._class.parameters
		);
		return true;
	}

	// need to return a generic autoboxed type according to arguments/return
	if(type->type == TYPE_LAMBDA) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.classname = strdup("lambda");
		return true;
	}

	// shouldn't ever get here,..unless I decide to make, say, T?.exists() and/or T?.applyIfExists(fn(T))
	if(type->type == TYPE_OPTIONAL) return false;

	if(isPrimitiveTypeBool(type)) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("Bool");
		return true;
	}

	if(isPrimitiveTypeText(type)) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("Text");
		return true;
	}

	if(isPrimitiveTypeNum(type)) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("Num");
		return true;
	}

	if(isPrimitiveTypeInt(type)) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("Int");
		return true;
	}

	if(isPrimitiveTypeChar(type)) {
		*boxed = new PureType<wake::QUALIFIED>(TYPE_CLASS);
		(*boxed)->typedata._class.modulename = strdup("lang");
		(*boxed)->typedata._class.classname = strdup("Char");
		return true;
	}

	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);
	}

}