// Process the given provided method for the given entity. // The method passed should be reified already and will be freed by this // function. static bool provided_method(ast_t* entity, ast_t* reified_method, ast_t* raw_method, ast_t** last_method) { assert(entity != NULL); assert(reified_method != NULL); assert(last_method != NULL); const char* entity_name = ast_name(ast_child(entity)); if(ast_id(reified_method) == TK_BE || ast_id(reified_method) == TK_NEW) { // Modify return type to the inheritting type ast_t* ret_type = ast_childidx(reified_method, 4); assert(ast_id(ret_type) == TK_NOMINAL); const char* pkg_name = package_name(ast_nearest(entity, TK_PACKAGE)); ast_set_name(ast_childidx(ret_type, 0), pkg_name); ast_set_name(ast_childidx(ret_type, 1), entity_name); } // Ignore docstring ast_t* doc = ast_childidx(reified_method, 7); if(ast_id(doc) == TK_STRING) { ast_set_name(doc, ""); ast_setid(doc, TK_NONE); } // Check for existing method of the same name const char* name = ast_name(ast_childidx(reified_method, 1)); assert(name != NULL); ast_t* existing = ast_get(entity, name, NULL); if(existing != NULL && is_field(existing)) { ast_error(existing, "field '%s' clashes with provided method", name); ast_error(raw_method, "method is defined here"); ast_free_unattached(reified_method); return false; } existing = add_method(entity, existing, reified_method, last_method); if(existing == NULL) { ast_free_unattached(reified_method); return false; } method_t* info = (method_t*)ast_data(existing); assert(info != NULL); if(!record_default_body(reified_method, raw_method, info)) ast_free_unattached(reified_method); return true; }
// Process the given provided method for the given entity. // The method passed should be reified already and will be freed by this // function. static bool provided_method(pass_opt_t* opt, ast_t* entity, ast_t* reified_method, ast_t* raw_method, ast_t** last_method) { assert(entity != NULL); assert(reified_method != NULL); assert(last_method != NULL); AST_GET_CHILDREN(reified_method, cap, id, typeparams, params, result, can_error, body, doc); if(ast_id(reified_method) == TK_BE || ast_id(reified_method) == TK_NEW) { // Modify return type to the inheriting type ast_t* this_type = type_for_this(opt, entity, ast_id(cap), TK_EPHEMERAL, true); ast_replace(&result, this_type); } // Ignore docstring if(ast_id(doc) == TK_STRING) { ast_set_name(doc, ""); ast_setid(doc, TK_NONE); } // Check for existing method of the same name const char* name = ast_name(id); assert(name != NULL); ast_t* existing = ast_get(entity, name, NULL); if(existing != NULL && is_field(existing)) { ast_error(existing, "field '%s' clashes with provided method", name); ast_error(raw_method, "method is defined here"); ast_free_unattached(reified_method); return false; } existing = add_method(entity, existing, reified_method, last_method); if(existing == NULL) { ast_free_unattached(reified_method); return false; } method_t* info = (method_t*)ast_data(existing); assert(info != NULL); if(!record_default_body(reified_method, raw_method, info)) ast_free_unattached(reified_method); return true; }
bool binspector_parser_t::is_named_statement() { return is_invariant() || is_constant() || is_skip() || is_slot() || is_signal() || is_field(); // field should be last because atoms only // require an expression which most everything // falls into; the more explicit stuff should // come first. }
// Process the methods required for delegation to all the fields in the given // entity. static bool delegated_methods(ast_t* entity, pass_opt_t* opt) { assert(entity != NULL); bool r = true; // Check all fields. for(ast_t* field = ast_child(ast_childidx(entity, 4)); field != NULL; field = ast_sibling(field)) { if(is_field(field)) { AST_GET_CHILDREN(field, id, f_type, value, delegates); // Check all delegates for field. for(ast_t* trait_ref = ast_child(delegates); trait_ref != NULL; trait_ref = ast_sibling(trait_ref)) { ast_t* trait = (ast_t*)ast_data(trait_ref); assert(trait != NULL); if(!trait_entity(trait, opt)) return false; // Run through the methods of each delegated type. for(ast_t* method = ast_child(ast_childidx(trait, 4)); method != NULL; method = ast_sibling(method)) { if(!delegated_method(entity, method, field, trait_ref, opt)) r = false; } } } } return r; }
// Process all field delegations in the given type. // Stage 3. static bool field_delegations(ast_t* entity) { assert(entity != NULL); ast_t* members = ast_childidx(entity, 4); assert(members != NULL); bool r = true; // Check all fields for(ast_t* f = ast_child(members); f != NULL; f = ast_sibling(f)) { if(is_field(f)) { AST_GET_CHILDREN(f, id, f_type, value, delegates); // Check all delegates for field for(ast_t* d = ast_child(delegates); d != NULL; d = ast_sibling(d)) { if(!check_delegate(entity, f_type, d)) { r = false; continue; } // Mark all methods in delegate trait as targets for this field ast_t* trait = (ast_t*)ast_data(d); assert(trait != NULL); ast_t* t_members = ast_childidx(trait, 4); for(ast_t* m = ast_child(t_members); m != NULL; m = ast_sibling(m)) { if(is_method(m)) { // Mark method as delegate target for this field const char* method_name = ast_name(ast_childidx(m, 1)); assert(method_name != NULL); ast_t* local_method = ast_get(entity, method_name, NULL); assert(local_method != NULL); method_t* info = (method_t*)ast_data(local_method); assert(info != NULL); if(info->delegate_field_1 == NULL) { // First delegate field for this method info->delegate_field_1 = f; info->delegate_target_1 = d; } else if(info->delegate_field_2 == NULL && info->delegate_field_1 != f) { // We already have one delegate field, record second info->delegate_field_2 = f; info->delegate_target_2 = d; } } } } } } return r; }
// Puts "field" from "section" from .ini file "f" into "s". // If "section" does not exist or "field" does not exist in // section then s=""; void ini_fgets(FILE *f, const char *section, const char *field, char *s) { int i; long start_pos,string_start_pos; char ts[INI_STRING_SIZE*2]; if (f!=current_file) reset_buffer(f); // Default to "Not found" s[0]=0; // See if section is in buffer for (i=0;i<NUM_SECTION_BUFFERS;i++) if (strnicmp(section_buffers[i].name,section,MAX_SECTION_WIDTH)==0) break; // If section is in buffer, seek to it if necessary if (i<NUM_SECTION_BUFFERS) { if (i!=current_section) { current_section=i; fseek(f,section_buffers[i].offset,SEEK_SET); } } // else look through .ini file for it. else { // Make sure we are not at eof or this will cause trouble. if (feof(f)) rewind(f); start_pos=ftell(f); while (1) { stripped_fgets(ts,INI_STRING_SIZE*2,f); // If it is a section, add it to the section buffer if (is_section(ts,"*")) current_section=add_section(ts,ftell(f)); // If it is the section we are looking for, break. if (is_section(ts,section)) break; // If we reach the end of the file, rewind to the start. if (feof(f)) rewind(f); if (ftell(f)==start_pos) return; } } // See if field is in buffer for (i=0;i<NUM_FIELD_BUFFERS;i++) if (field_buffers[i].section==current_section) if (strnicmp(field_buffers[i].name,field,MAX_FIELD_WIDTH)==0) break; // If field is in buffer, seek to it and read it if (i<NUM_FIELD_BUFFERS) { fseek(f,field_buffers[i].offset,SEEK_SET); stripped_fgets(ts,INI_STRING_SIZE*2,f); get_field_string(s,ts); } else // else search through section for field. { // Make sure we do not start at eof or this will cause problems. if (feof(f)) fseek(f,section_buffers[current_section].offset,SEEK_SET); start_pos=ftell(f); while (1) { string_start_pos=ftell(f); stripped_fgets(ts,INI_STRING_SIZE*2,f); // If it is a field, add it to the buffer if (is_field(ts,"*")) add_field(ts,current_section,string_start_pos); // If it is the field we are looking for, save it if (is_field(ts,field)) { get_field_string(s,ts); break; } // If we reach the end of the section, start over if (feof(f) || is_section(ts,"*")) fseek(f,section_buffers[current_section].offset,SEEK_SET); if (ftell(f)==start_pos) return; } } }
static int release_parse_line(void *ptr, const char *line, uint mask) { release_t *release = (release_t *) ptr; int ret = 0; unsigned int count = 0; char **list = 0; static int reading_md5sums = 0; #ifdef HAVE_SHA256 static int reading_sha256sums = 0; #endif switch (*line) { case 'A': if (is_field("Architectures", line)) { release->architectures = parse_list(line, &release->architectures_count, ' ', 0); } break; case 'C': if (is_field("Codename", line)) { release->name = parse_simple("Codename", line); } else if (is_field("Components", line)) { release->components = parse_list(line, &release->components_count, ' ', 0); } break; case 'D': if (is_field("Date", line)) { release->datestring = parse_simple("Date", line); } break; case 'M': if (is_field("MD5sum", line)) { reading_md5sums = 1; if (release->md5sums == NULL) { release->md5sums = xcalloc(1, sizeof(cksum_list_t)); cksum_list_init(release->md5sums); } goto dont_reset_flags; } break; #ifdef HAVE_SHA256 case 'S': if (is_field("SHA256", line)) { reading_sha256sums = 1; if (release->sha256sums == NULL) { release->sha256sums = xcalloc(1, sizeof(cksum_list_t)); cksum_list_init(release->sha256sums); } goto dont_reset_flags; } break; #endif case ' ': if (reading_md5sums) { list = parse_list(line, &count, ' ', 1); cksum_list_append(release->md5sums, list); goto dont_reset_flags; } #ifdef HAVE_SHA256 else if (reading_sha256sums) { list = parse_list(line, &count, ' ', 1); cksum_list_append(release->sha256sums, list); goto dont_reset_flags; } #endif break; default: ret = 1; } reading_md5sums = 0; #ifdef HAVE_SHA256 reading_sha256sums = 0; #endif dont_reset_flags: return ret; }
// Add a new method to the given entity, based on the specified method from // the specified type. // The trait_ref is the entry in the provides / delegates list that causes this // method inclusion. Needed for error reporting. // The basis_method is the reified method in the trait to add. // The adjective parameter is used for error reporting and should be "provided" // or similar. // Return the newly added method or NULL on error. static ast_t* add_method(ast_t* entity, ast_t* trait_ref, ast_t* basis_method, const char* adjective, pass_opt_t* opt) { assert(entity != NULL); assert(trait_ref != NULL); assert(basis_method != NULL); assert(adjective != NULL); const char* name = ast_name(ast_childidx(basis_method, 1)); // Check behaviour compatability. if(ast_id(basis_method) == TK_BE) { switch(ast_id(entity)) { case TK_PRIMITIVE: ast_error(opt->check.errors, trait_ref, "cannot add a behaviour (%s) to a primitive", name); return NULL; case TK_STRUCT: ast_error(opt->check.errors, trait_ref, "cannot add a behaviour (%s) to a struct", name); return NULL; case TK_CLASS: ast_error(opt->check.errors, trait_ref, "cannot add a behaviour (%s) to a class", name); return NULL; default: break; } } // Check for existing method of the same name. ast_t* existing = ast_get(entity, name, NULL); if(existing != NULL) { assert(is_field(existing)); // Should already have checked for methods. ast_error(opt->check.errors, trait_ref, "%s method '%s' clashes with field", adjective, name); ast_error_continue(opt->check.errors, basis_method, "method is defined here"); return NULL; } // Check for clash with existing method. ast_t* case_clash = ast_get_case(entity, name, NULL); if(case_clash != NULL) { const char* clash_name = ""; switch(ast_id(case_clash)) { case TK_FUN: case TK_BE: case TK_NEW: clash_name = ast_name(ast_childidx(case_clash, 1)); break; case TK_LET: case TK_VAR: case TK_EMBED: clash_name = ast_name(ast_child(case_clash)); break; default: assert(0); break; } ast_error(opt->check.errors, trait_ref, "%s method '%s' differs only in case from '%s'", adjective, name, clash_name); ast_error_continue(opt->check.errors, basis_method, "clashing method is defined here"); return NULL; } AST_GET_CHILDREN(basis_method, cap, id, typeparams, params, result, can_error, body, doc); // Ignore docstring. if(ast_id(doc) == TK_STRING) { ast_set_name(doc, ""); ast_setid(doc, TK_NONE); } ast_t* local = ast_append(ast_childidx(entity, 4), basis_method); ast_set(entity, name, local, SYM_DEFINED, false); ast_t* body_donor = (ast_t*)ast_data(basis_method); method_t* info = attach_method_t(local); info->trait_ref = trait_ref; if(ast_id(body) != TK_NONE) info->body_donor = body_donor; return local; }