static void trace_dynamic(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type, ast_t* orig, ast_t* tuple, LLVMBasicBlockRef next_block) { switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: trace_dynamic_union_or_isect(c, ctx, object, type, orig, tuple, next_block); break; case TK_TUPLETYPE: { // This is a boxed tuple. Trace the box, then handle the elements. trace_tag(c, ctx, object); LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef ptr = gendesc_ptr_to_fields(c, object, desc); trace_dynamic_tuple(c, ctx, ptr, desc, type, orig, tuple); break; } case TK_NOMINAL: trace_dynamic_nominal(c, ctx, object, type, orig, tuple, next_block); break; default: {} } }
static bool static_tuple(compile_t* c, LLVMValueRef value, ast_t* type, ast_t* pattern, LLVMBasicBlockRef next_block) { switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: { // Read the dynamic type and get a base pointer. LLVMValueRef desc = gendesc_fetch(c, value); LLVMValueRef ptr = gendesc_ptr_to_fields(c, value, desc); return dynamic_tuple_ptr(c, ptr, desc, pattern, next_block); } case TK_TUPLETYPE: return static_tuple_from_tuple(c, value, type, pattern, next_block); case TK_ARROW: return static_tuple(c, value, ast_childidx(type, 1), pattern, next_block); default: {} } // Can't match. LLVMBuildBr(c->builder, next_block); return true; }
static bool dynamic_match_object(compile_t* c, LLVMValueRef object, LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block) { switch(ast_id(pattern)) { case TK_NONE: return true; case TK_MATCH_CAPTURE: // Capture the match expression (or element thereof). return dynamic_capture_object(c, object, desc, pattern, next_block); case TK_TUPLE: { // Treat a one element tuple as its component expression. ast_t* child = ast_child(pattern); if(ast_sibling(child) == NULL) return dynamic_match_object(c, object, desc, child, next_block); // Build a base pointer that skips the object header. LLVMValueRef ptr = gendesc_ptr_to_fields(c, object, desc); // Destructure the match expression (or element thereof). return dynamic_tuple_ptr(c, ptr, desc, pattern, next_block); } default: // Test the match expression (or element thereof). return dynamic_value_object(c, object, desc, pattern, next_block); } return true; }
static bool check_tuple(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc, ast_t* pattern_type, LLVMBasicBlockRef next_block) { // First check cardinality. size_t size = ast_childcount(pattern_type); check_cardinality(c, desc, size, next_block); // If we get here, the match expression has the right cardinality. ast_t* pattern_child = ast_child(pattern_type); for(int i = 0; pattern_child != NULL; i++) { // Get the field offset and field descriptor from the tuple descriptor. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, i); LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info); LLVMValueRef field_desc = gendesc_fielddesc(c, field_info); // If we have a null descriptor, load the object. LLVMBasicBlockRef null_block = codegen_block(c, "null_desc"); LLVMBasicBlockRef nonnull_block = codegen_block(c, "nonnull_desc"); LLVMBasicBlockRef continue_block = codegen_block(c, "merge_desc"); LLVMValueRef test = LLVMBuildIsNull(c->builder, field_desc, ""); LLVMBuildCondBr(c->builder, test, null_block, nonnull_block); // Load the object, load its descriptor, and continue from there. LLVMPositionBuilderAtEnd(c->builder, null_block); LLVMTypeRef ptr_type = LLVMPointerType(c->object_ptr, 0); LLVMValueRef object_ptr = LLVMBuildIntToPtr(c->builder, field_ptr, ptr_type, ""); LLVMValueRef object = LLVMBuildLoad(c->builder, object_ptr, ""); LLVMValueRef object_desc = gendesc_fetch(c, object); object_ptr = gendesc_ptr_to_fields(c, object, object_desc); if(!check_type(c, object_ptr, object_desc, pattern_child, next_block)) return false; LLVMBuildBr(c->builder, continue_block); // Continue with the pointer and descriptor. LLVMPositionBuilderAtEnd(c->builder, nonnull_block); if(!check_type(c, field_ptr, field_desc, pattern_child, next_block)) return false; LLVMBuildBr(c->builder, continue_block); // Merge the two branches. LLVMPositionBuilderAtEnd(c->builder, continue_block); pattern_child = ast_sibling(pattern_child); } return true; }
static bool dynamic_value_object(compile_t* c, LLVMValueRef object, LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block) { // Get the type of the right-hand side of the pattern's eq() function. ast_t* param_type = eq_param_type(c, pattern); // Build a base pointer that skips the object header. LLVMValueRef ptr = gendesc_ptr_to_fields(c, object, desc); // Check the runtime type. We pass a pointer to the fields because we may // still need to match a tuple type inside a type expression. if(!check_type(c, ptr, desc, param_type, next_block)) return false; return check_value(c, pattern, param_type, object, next_block); }
static bool dynamic_capture_object(compile_t* c, LLVMValueRef object, LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block) { ast_t* pattern_type = ast_type(pattern); // Build a base pointer that skips the object header. LLVMValueRef ptr = gendesc_ptr_to_fields(c, object, desc); // Check the runtime type. We pass a pointer to the fields because we may // still need to match a tuple type inside a type expression. if(!check_type(c, ptr, desc, pattern_type, next_block)) return false; // As long as the type is correct, we can assign it, with gen_assign_value() // handling boxing and unboxing. We pass the type of the pattern as the type // of the object. return gen_assign_value(c, pattern, object, pattern_type) != NULL; }