Type* find_common_type(Type* type1, Type* type2) { if (type1 == NULL) return type2; if (type1 == type2) return type1; if (type1 == TYPES.any || type2 == TYPES.any) return TYPES.any; if (is_list_based_type(type1) && is_list_based_type(type2)) return TYPES.list; return TYPES.any; }
Type* find_common_type(Type* type1, Type* type2) { if (type1 == NULL) return type2; if (type1 == type2) return type1; if (type1 == &ANY_T || type2 == &ANY_T) return &ANY_T; if (is_list_based_type(type1) && is_list_based_type(type2)) return &LIST_T; return &ANY_T; }
Type* get_field_specializeType(Term* caller) { Type* head = caller->input(0)->type; for (int nameIndex=1; nameIndex < caller->numInputs(); nameIndex++) { // Abort if input type is not correct if (!is_string(term_value(caller->input(1)))) return TYPES.any; if (!is_list_based_type(head)) return TYPES.any; Value* name = term_value(caller->input(1)); int fieldIndex = list_find_field_index_by_name(head, name); if (fieldIndex == -1) return TYPES.any; head = as_type(get_index(list_get_type_list_from_type(head),fieldIndex)); } return head; }
void tv_static_type_query(Type* type, StaticTypeQuery* query) { Term* subject = query->subject; Type* subjectType = query->subjectType; // If the type doesn't have a specific size, then accept any list. if (!list_type_has_specific_size(&type->parameter)) { if (is_list_based_type(subjectType)) return query->succeed(); else return query->fail(); } caValue* expectedElementTypes = list_get_type_list_from_type(type); // Special case when looking at a call to list(); look at inputs instead of // looking at the result. if (subject && subject->function == FUNCS.list) { if (subject->numInputs() != circa_count(expectedElementTypes)) return query->fail(); for (int i=0; i < circa_count(expectedElementTypes); i++) if (!circa::term_output_always_satisfies_type( subject->input(i), as_type(circa_index(expectedElementTypes, i)))) return query->fail(); return query->succeed(); } // Look at the subject's type. if (!list_type_has_specific_size(&subjectType->parameter)) return query->fail(); caValue* subjectElementTypes = list_get_type_list_from_type(subjectType); bool anyUnableToDetermine = false; for (int i=0; i < circa_count(expectedElementTypes); i++) { if (i >= circa_count(subjectElementTypes)) return query->fail(); StaticTypeQuery::Result result = run_static_type_query( as_type(circa_index(expectedElementTypes,i)), as_type(circa_index(subjectElementTypes,i))); // If any of these fail, then fail. if (result == StaticTypeQuery::FAIL) return query->fail(); if (result == StaticTypeQuery::UNABLE_TO_DETERMINE) anyUnableToDetermine = true; } if (anyUnableToDetermine) return query->unableToDetermine(); else return query->succeed(); }
int list_find_field_index_by_name(Type* listType, const char* name) { if (!is_list_based_type(listType)) return -1; caValue* names = list_get_name_list_from_type(listType); if (names == NULL) return -1; for (int i=0; i < circa_count(names); i++) if (string_eq(circa_index(names, i), name)) return i; // Not found return -1; }
caValue* list_get_name_list_from_type(Type* type) { ca_assert(is_list_based_type(type)); caValue* parameter = &type->parameter; switch (list_get_parameter_type(parameter)) { case name_StructType: return list_get(parameter, 1); case name_AnonStructType: case name_Untyped: case name_UniformListType: case name_Invalid: return NULL; } ca_assert(false); return NULL; }
Type* find_common_type(caValue* list) { if (list_length(list) == 0) return TYPES.any; // Check if every type in this list is the same. bool all_equal = true; for (int i=1; i < list_length(list); i++) { if (as_type(list_get(list,0)) != as_type(list_get(list,i))) { all_equal = false; break; } } if (all_equal) return as_type(list_get(list,0)); // Special case, allow ints to go into floats bool all_are_ints_or_floats = true; for (int i=0; i < list_length(list); i++) { if ((as_type(list_get(list,i)) != TYPES.int_type) && (as_type(list_get(list,i)) != TYPES.float_type)) { all_are_ints_or_floats = false; break; } } if (all_are_ints_or_floats) return TYPES.float_type; // Another special case, if all types are lists then use List bool all_are_lists = true; for (int i=0; i < list_length(list); i++) { if (!is_list_based_type(as_type(list_get(list,i)))) all_are_lists = false; } if (all_are_lists) return TYPES.list; // Otherwise give up return TYPES.any; }
bool list_equals(caValue* left, caValue* right) { ca_assert(is_list(left)); if (!is_list_based_type(right->value_type)) return false; // Shortcut: lists are equal if they have the same address. if (left->value_data.ptr == right->value_data.ptr) return true; int leftCount = list_length(left); // Not equal if lengths differ. if (leftCount != list_length(right)) return false; // Check every element. for (int i=0; i < leftCount; i++) { if (!equals(list_get(left, i), list_get(right, i))) return false; } #if 0 // Sneaky optimization. We just verified that 'left' and 'right' are deeply // equal, so no one will notice if they actually use the same data. // // TODO: This optimization can't be turned on as long as integers and numbers can // compare equal. Ditto for lists that have equal contents but different type tags. // // The best thing to do is probably have this function return two types of equality: // 'loose' and 'exact'. We can do the sneaky optimization iff there is exact equality. // // Also, don't forget to preserve the type tag for 'right'. // set_null(right); list_copy(left, right); #endif return true; }
Type* list_get_repeated_type_from_type(Type* type) { ca_assert(is_list_based_type(type)); return as_type(&type->parameter); }