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(); }
Type* List__append_specializeType(Term* term) { Term* listInput = term->input(0); switch (list_get_parameter_type(&listInput->type->parameter)) { case sym_Untyped: return listInput->type; case sym_UniformListType: { Type* listElementType = list_get_repeated_type_from_type(listInput->type); Type* commonType = find_common_type(listElementType, term->input(1)->type); if (commonType == listElementType) return listInput->type; else return create_typed_unsized_list_type(commonType); } case sym_AnonStructType: case sym_StructType: { List elementTypes; copy(list_get_type_list_from_type(listInput->type), &elementTypes); set_type(elementTypes.append(), term->input(1)->type); return create_typed_unsized_list_type(find_common_type(&elementTypes)); } case sym_Invalid: default: return TYPES.any; } }
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_initialize(Type* type, caValue* value) { ca_assert(value->value_data.ptr == NULL); // If the parameter has a fixed size list, then initialize to that. if (list_type_has_specific_size(&type->parameter)) { caValue* typeList = list_get_type_list_from_type(type); int count = list_length(typeList); list_resize(value, count); for (int i=0; i < count; i++) make(as_type(list_get(typeList, i)), list_get(value, i)); } }
Type* infer_type_of_get_index(Term* input) { if (input == NULL) return &ANY_T; switch (list_get_parameter_type(&input->type->parameter)) { case LIST_UNTYPED: return &ANY_T; case LIST_TYPED_UNSIZED: return list_get_repeated_type_from_type(input->type); case LIST_TYPED_SIZED: case LIST_TYPED_SIZED_NAMED: return find_common_type(list_get_type_list_from_type(input->type)); case LIST_INVALID_PARAMETER: default: return &ANY_T; } }
Type* infer_type_of_get_index(Term* input) { if (input == NULL) return TYPES.any; switch (list_get_parameter_type(&input->type->parameter)) { case name_Untyped: return TYPES.any; case name_UniformListType: return list_get_repeated_type_from_type(input->type); case name_StructType: case name_AnonStructType: return find_common_type(list_get_type_list_from_type(input->type)); case name_Invalid: default: return TYPES.any; } }
void tv_cast(CastResult* result, caValue* value, Type* type, bool checkOnly) { if (!is_list(value)) { result->success = false; return; } int sourceLength = list_length(value); // If the requested type doesn't have a specific size restriction, then // the input data is fine as-is. if (!list_type_has_specific_size(&type->parameter)) { if (!checkOnly) value->value_type = type; return; } List& destTypes = *List::checkCast(list_get_type_list_from_type(type)); // Check for correct number of elements. if (sourceLength != destTypes.length()) { result->success = false; return; } if (!checkOnly) { INCREMENT_STAT(Touch_ListCast); list_touch(value); value->value_type = type; } for (int i=0; i < sourceLength; i++) { caValue* sourceElement = list_get(value, i); Type* expectedType = as_type(destTypes[i]); INCREMENT_STAT(Cast_ListCastElement); cast(result, sourceElement, expectedType, checkOnly); if (!result->success) return; } }